; Velbus server 1.0 by Golfy (Purebasic 4.60) ; v2 -> try to delay message from Ethernet -> Velbus ; v2.1 -> inform about bad frame (from wich client) ; v2.2 -> correction with CRC checksum (add & $FF) ; Default parameters : COM4 and 8080 CompilerIf #PB_Compiler_OS = #PB_OS_Windows Port$ = "COM4" CompilerElse Port$ = "/dev/ttyS0" CompilerEndIf Port = 8080 OpenConsole() EnableGraphicalConsole(1) ; declare useful procedures Declare.i AnalyseMessage(*bus,Len.i, clientID.i) Declare.s Hexa2(*B,longueur.i) Declare.i LectureNet() Declare.i CheckSum(*B,longueur.i) ; if parameter are transmit after commandline If FindString(UCase(ProgramParameter(0)),"H",1) Or FindString(UCase(ProgramParameter(0)),"?",1) PrintN("PB_Velbus-server.exe SERIALport NETWORKport (ex: PB_Velbus-server.exe COM4 8131)") PrintN("PB_Velbus-server.exe default = COM4 and 8080") Input() End EndIf If ProgramParameter(0) : port$ = ProgramParameter(0) : EndIf If ProgramParameter(1) : port = Val(ProgramParameter(1)) : EndIf If OpenSerialPort(0, Port$, 9600, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 2048, 2048) PrintN("PB_Velbus-Server v2.2 : open port "+port$+" done") Else PrintN("Erreur port "+port$) Delay(2000) End EndIf If InitNetwork() = 0 PrintN("Error : Can't initialize the network !") Delay(2000) End EndIf ;declare structure and variables *BSin = AllocateMemory(4096) *BNin = AllocateMemory(4096) *BFull = AllocateMemory(7) *BReady = AllocateMemory(7) PokeB(*BFull+0,$0F) PokeB(*BFull+1,$F8) PokeB(*BFull+2,$00) PokeB(*BFull+3,$01) PokeB(*BFull+4,$0B) PokeB(*BFull+5,$ED) PokeB(*BFull+6,$04) PokeB(*BReady+0,$0F) PokeB(*BReady+1,$F8) PokeB(*BReady+2,$00) PokeB(*BReady+3,$01) PokeB(*BReady+4,$0C) PokeB(*BReady+5,$EC) PokeB(*BReady+6,$04) Structure Vmsg Len.i *cmd EndStructure Structure netclient portID.i CRCErr.i IPAdd.s CRCDelay.i EndStructure Global NewList messages.Vmsg() Global NewList Client.netclient() Global TXNET.q = 0 Global TXBUS.q = 0 Global BPnet.q = 0 Global BPbus.q = 0 If CreateNetworkServer(0, Port) PrintN("Listening on Ethernet port : "+Str(port)) HauteurCurseur = 0 d = ElapsedMilliseconds() dbp = ElapsedMilliseconds() uptime=Date() Repeat ; server is alive : show date (french format) If Date() <> dd dd = Date() ConsoleLocate(60,2) PrintN(FormatDate("%dd/%mm/%yyyy %hh:%ii:%ss",Date())) ConsoleLocate(0,4) utime = Date()-uptime yt = utime/31536000 mt = (utime-31536000*yt)/2635200 dt = (utime-2635200*mt)/86400 PrintN("Velbus-server UpTime : "+Str(yt)+" year, "+Str(mt)+" month, "+Str(dt)+" day(s) and "+FormatDate("%hh:%ii:%ss",utime)) ForEach Client() de = (ElapsedMilliseconds()-Client()\CRCDelay)/1000 If client()\CRCErr>10 And de > 60 ConsoleLocate(0,9) PrintN("Closing client "+client()\IPAdd+", "+Str(Client()\portID)+" because too many errors in one minut ("+Str(client()\CRCErr)+")") CloseNetworkConnection(Client()\portID) DeleteElement(Client(),1) ElseIf de > 60 Client()\CRCErr = 0 Client()\CRCDelay = ElapsedMilliseconds() EndIf Next EndIf u= ElapsedMilliseconds()-dbp If u > 1000 debitnet.f = ((TXNET-BPnet)*8/(u/1000))/1024 debitbus.f = ((TXBUS-BPbus)*8/(u/1000))/1024 ConsoleColor(14,0) ConsoleLocate(20,3) PrintN("BP Net : "+StrF(debitnet.f,2)+" kbps ") ConsoleColor(15,0) ConsoleLocate(42,3) PrintN("BP Velbus : "+StrF(debitbus.f,2)+" kbps ") ConsoleColor(7,0) BPnet = TXNET BPbus = TXBUS dbp=ElapsedMilliseconds() EndIf ; Send bufferised messages with 60ms delay If ListSize(messages()) And ElapsedMilliseconds()-d > 40 Err = FirstElement(messages()) Err = WriteSerialPortData(0, messages()\cmd, messages()\len) err = FreeMemory(messages()\cmd) Err = DeleteElement(messages(),1) d = ElapsedMilliseconds() EndIf SEvent = NetworkServerEvent() If SEvent ConsoleLocate(0,2) PrintN("[N]") ClientID = EventClient() Select SEvent Case #PB_NetworkEvent_Connect ; new client connected ConsoleLocate(0,7) AddElement(Client()) Client()\portID = ClientID IP$=IPString(GetClientIP(ClientID)) Client()\IPAdd = IP$ Client()\CRCErr + 0 Client()\CRCDelay = ElapsedMilliseconds() Space(80) ConsoleLocate(0,7) PrintN("Opening Connexion ID "+Str(Client())+" for "+ip$+" (Client Number : "+Str(ListSize(Client()))+") ") ConsoleLocate(5,2) PrintN("Nb Client:"+Str(ListSize(Client()))) Case #PB_NetworkEvent_Data RXLen = ReceiveNetworkData(ClientID, *BNin, 4096) If RXLen > 5 N = AnalyseMessage(*BNin,RXLen,ClientID) TXNET=TXNET+RXLen ConsoleLocate(20,2) PrintN("Ethernet-> "+Str(TXNET)+" ") ;PrintN("NET --> VelBUS : "+Str(N)+" messages received ("+Str(RXLen)+" bytes received)") EndIf Case #PB_NetworkEvent_Disconnect ; client has diconnected ConsoleLocate(0,7) ForEach Client() If Client()\portID = ClientID DeleteElement(Client(),1) Space(80) ConsoleLocate(0,7) PrintN("Closing Connexion ID "+Str(ClientID)+" (Client Number : "+Str(ListSize(Client()))+") ") EndIf Next ConsoleLocate(5,2) PrintN("Nb Client:"+Str(ListSize(Client()))) EndSelect EndIf ; SERIAL TO NETWORK ========================================================================== Serial = AvailableSerialPortInput(0) If Serial ConsoleLocate(0,2) PrintN("[S]") RXLen = ReadSerialPortData(0,*BSin,Serial) If RXlen = Serial z = 0 For y=0 To RXLen a$ = RSet(Hex(PeekB(*Bsin+y) & $FF),2,"0") If a$ = "0F" cmd$ = "<-- 0F " z = y ElseIf a$ = "04" And y-z > 3 cmd$=cmd$+"04 ("+Str(y)+")-" Debug cmd$ cmd$ = "" Else cmd$=cmd$+a$+" " EndIf Next y ForEach Client() Err = SendNetworkData(Client()\portID, *BSin, RXLen) Next TXBUS = TXBUS + RXLen ConsoleLocate(42,2) PrintN("Velbus-> "+Str(TXBUS)+" ") Else Debug "Oct disponibles : "+Str(Serial)+" / Oct envoyés : "+Str(RXLen) EndIf EndIf Until Quit = 1 CloseNetworkServer(0) Else PrintN("Error : Can't create the server (port in use ?).") EndIf End ; ------ ; Procedure for Network/BUS command ; _______________________________________________________________________________________________________ Procedure.i AnalyseMessage(*bus,full.i,ClientID) ; Format de trame : ; OF FB ** RL xx xx xx CK 04 - 0F FB ** .... ; 12 34 56 78 9A ..... stx = 0 etx = 0 lng = 0 counter = 0 z = 0 For y=0 To full a$ = RSet(Hex(PeekB(*bus+y) & $FF),2,"0") If a$ = "0F" cmd$ = "--> 0F " z = y ElseIf a$ = "04" cmd$=cmd$+"04 ("+Str(y)+")-" Debug cmd$ cmd$ = "" Else cmd$=cmd$+a$+" " EndIf Next y t = 0 Repeat If PeekB(*bus+t) & $FF = $0F counter+1 fixlen = 4 varlen = PeekB(*bus+t+3) & $0F fintrame = t+fixlen+varlen+1 crcloc = fintrame-1 tlen = fixlen+varlen+2 crc = checksum(*bus+t,tlen-3) If PeekB(*bus+fintrame) & $FF = $04 And (PeekB(*bus+crcloc) & $FF)=crc AddElement(messages()) messages()\len = tlen messages()\Cmd = AllocateMemory(messages()\len) CopyMemory(*bus+t,messages()\cmd,messages()\len) t = t+(messages()\len-2) Else Debug "CRC Velbus : "+Str(PeekB(*bus+crcloc) & $FF)+" CRC PB : "+Str(crc) ForEach client() If Client()\portID = ClientID Client()\CRCErr + 1 ConsoleLocate(0,8) ConsoleColor(12,0) PrintN("Bad frame from "+Str(ClientID)+ ": Event has become "+Str(Client()\CRCErr)+" times. ") ConsoleColor(7,0) EndIf Next EndIf EndIf t = t + 1 Until t=>full ProcedureReturn ListSize(messages()) EndProcedure ; _______________________________________________________________________________________________________ Procedure.i CheckSum(*B,longueur.i) somme=0 ; Initialize Counter For tr=0 To longueur ; Loop from 0 to checksum byte -1 Somme=Somme+(PeekB(*B+tr) & $FF ) ; Adding each byte from the packet Next tr Somme = (Somme & $FF) ! $FF ; As PureBasic use signed integer, need to remove higher value Somme = (Somme + 1) & $FF ; (AND operation) and inverse with XOR (!), them add '1' ProcedureReturn Somme ; Return the checksum value EndProcedure ; IDE Options = PureBasic 4.51 (Windows - x86) ; CursorPosition = 37 ; FirstLine = 3 ; Folding = - ; EnableXP ; Executable = ..\..\PB_Velbus-server.exe