Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Rem "PeteModbus 0.4"
- ' Simplified implementation with no priority connections (no way to get sender IP) and all processing is immediately done in this task (may cause delays).
- ' Consider it a bad idea to attempt any kind of connection multiplexing in this environment.
- Include "MODBUS.INC"
- Print #.CONNLOG., "=== Start of the Program ==="
- Print #.CONNLOG., "T Initializing server sock " + Str$(.SERVER_SOCK_NUMBER.) + "."
- SockCreate .SERVER_SOCK_NUMBER.,0
- If E1% < 0
- *SERVER_SOCK_ERR
- .retrydelay. = Min(.retrydelay. + .RETRY_DELAY_INC.,.RETRY_DELAY_MAX.)
- Print #.CONNLOG., "E Server sock: " + Str$(E1%) + Chr$(44) + " " + Str$(E2%) + "; wait " + Str$(.retrydelay.) + " s."
- Pause Max(.retrydelay.*1000,1)
- End
- EndIf
- SockBind .SERVER_SOCK_NUMBER.,.PORT.
- Print #.CONNLOG., "T Server sock bound to port " + Str$(.PORT.) + "."
- If E1% < 0 Then *SERVER_SOCK_ERR
- .retrydelay. = 0
- *MAINLOOP
- Print #.CONNLOG.,"T Polling; server: " + Str$(.SERVER_SOCK_NUMBER.) + Chr$(44) + " comm: " + Str$(.COMM_SOCK_NUMBER.) + "."
- SockWait .SERVER_SOCK_NUMBER.,.COMM_SOCK_NUMBER.,.SERVER_WAIT_TIMEOUT.
- If E1% = -7 Then *LISTEN_TIMEOUT ' No new messages, close the socket.
- If E1% < 0 Then *SERVER_SOCK_ERR
- Print #.CONNLOG.,"T Opened comm sock."
- Print #.COMMLOG.,"M !!! New Modbus connection !!!"
- *INNERLOOP
- Print #.CONNLOG.,"T Polling comm sock " + Str$(.COMM_SOCK_NUMBER.) + " for MB-header."
- SockRecv .COMM_SOCK_NUMBER.,.HDRBUFF.,7,.RECEIVE_TIMEOUT.,.reclen.
- If E1% = -7
- *LISTEN_TIMEOUT
- Print #.CONNLOG.,"T Closing comm sock " + Str$(.COMM_SOCK_NUMBER.) + Chr$(44) + " wait time exceeded."
- SockClose .COMM_SOCK_NUMBER.
- GoTo *MAINLOOP
- EndIf
- If E1% < 0
- *COMM_SOCK_ERR
- Print #.CONNLOG., "E Comm sock " + Str$(.COMM_SOCK_NUMBER.) + Chr$(44) + " err: " + Str$(E1%) + Chr$(44) + Str$(E2%) + "."
- SockClose .COMM_SOCK_NUMBER.
- End
- EndIf
- Print #.COMMLOG., "M Reading header."
- .fn. = 0
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- GetByte .HDRBUFF.,.recbyte1.,0
- GetByte .HDRBUFF.,.recbyte2.,1
- .tranid. = &H100*.recbyte1. + .recbyte2.
- GetByte .HDRBUFF.,.recbyte1.,2
- GetByte .HDRBUFF.,.recbyte2.,3
- .protid. = &H100*.recbyte1. + .recbyte2.
- GetByte .HDRBUFF.,.recbyte1.,4
- GetByte .HDRBUFF.,.recbyte2.,5
- .meslen. = &H100*.recbyte1. + .recbyte2.
- GetByte .HDRBUFF.,.recbyte1.,6
- .unitid. = .recbyte1. ' This must be done because socket commands and buffer READ (writes are OK) only operate on global variables.
- If .meslen. > .MAX_DATA. Then *ERRORCODE
- Print #.COMMLOG.,"M :" + Str$(.tranid.) + ":" + Str$(.protid.) + ":" + Str$(.meslen.) + ":" + Str$(.unitid.) + "."
- Print #.CONNLOG.,"T Polling comm sock " + Str$(.COMM_SOCK_NUMBER.) + " for MB-message."
- Print #.COMMLOG., "M Reading message body."
- SockRecv .COMM_SOCK_NUMBER.,.REQBUFF.,.meslen.-1,.RECEIVE_TIMEOUT.,.reclen.
- If E1% < 0 Then *COMM_SOCK_ERR
- Print #.COMMLOG., "M Read " + Str$(.reclen.) + " bytes."
- If (.reclen. + 1 < .meslen. And .ERR_ON_MESLEN.) Or (.protid. <> .PROTOCOL_ID. And .ERR_ON_PROTID.) Or (.unitid. <> .UNIT_ID. And .ERR_ON_UNITID.) Then *ERRORCODE
- Print #.COMMLOG.,"M Header ok."
- GetByte .REQBUFF.,.recbyte1.,0
- .fn. = .recbyte1.
- Print #.COMMLOG.,"M Fn-code is " + Str$(.fn.) + "."
- Switch .fn.
- Case .COM_READ_COILS.
- Print #.COMMLOG., "C Read multiple coils."
- GoTo *COM02
- Case .COM_READ_DISCRETE_INPUTS.
- Print #.COMMLOG., "C Read multiple input bits."
- *COM02
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 5 Then *ERRORCODE
- GoSub *GET2WORDS
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- If .regnum. < 1 Or .regnum. > 2000 Then *ERRORCODE
- .hlp2. = .RESBUFFOFFS. + 2
- .errcode.=.ERR_NO_ERROR.
- .hlp1.=.regstart.
- .bytecount. = 0
- While .hlp1. + 8 <= .regstart.+.regnum.
- .mbaddr. = .hlp1.
- .bytelim. = 8
- GoSub *GET_MB_BYTE
- SetByte .RESBUFF.,.byteval.,.hlp2.
- .hlp1.=.hlp1. + 8.
- .hlp2.=.hlp2. + 1
- .bytecount. = .bytecount. + 1
- EndW
- .bytelim. = .regnum. Mod 8
- .mbaddr. = .hlp1.
- GoSub *GET_MB_BYTE
- SetByte .RESBUFF.,.byteval.,.hlp2. ' Last incomplete byte, wont cause harm even if mod is 0
- If .errcode. Then *ERRORCODE
- .bytecount. = .bytecount. + Min(.bytelim.,1)
- .meslen. = .bytecount. + 3
- SetByte .RESBUFF.,.bytecount.,.RESBUFFOFFS. + 1 ' Byte count
- GoSub *MKFNHEADER
- GoTo *SENDRES
- Case .COM_READ_HOLDING_REGISTERS.
- Print #.COMMLOG., "C Read multiple holding registers."
- GoTo *COM04
- Case .COM_READ_INPUT_REGISTERS.
- Print #.COMMLOG., "C Read multiple input registers."
- *COM04
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 5 Then *ERRORCODE
- GoSub *GET2WORDS
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- If .regnum. < 0 Or .regnum. > 125 Then *ERRORCODE
- .errcode.= .ERR_NO_ERROR.
- .hlp2. = .RESBUFFOFFS. + 2
- .hlp1. = .regstart.
- .bytecount. = 0;
- While .hlp1. < .regstart.+.regnum.
- .mbaddr. = .hlp1.
- GoSub *GET_MB_WORD
- SetByte .RESBUFF.,.wordval./&H100,.hlp2.
- SetByte .RESBUFF.,.wordval.,.hlp2.+1.
- .hlp1.=.hlp1.+1
- .hlp2.=.hlp2.+2
- .bytecount. = .bytecount. + 2;
- EndW
- If .errcode. Then *ERRORCODE
- .meslen.= .bytecount. + 3
- SetByte .RESBUFF.,.bytecount.,.RESBUFFOFFS. + 1 ' Byte count
- GoSub *MKFNHEADER
- GoTo *SENDRES
- Case .COM_WRITE_SINGLE_COIL.
- Print #.COMMLOG., "C Set single coil."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 5 Then *ERRORCODE
- GoSub *GET2WORDS
- If .outval. <> &HFF00 And .outval. <> &H0000 Then *ERRORCODE
- .bitaddr. = .outaddr.
- .bitval. = .outval.
- GoSub *SET_MB_BIT
- If .errcode. Then *ERRORCODE
- GoSub *MK2WORDHEADER
- GoTo *SENDRES
- Case .COM_WRITE_SINGLE_REGISTER.
- Print #.COMMLOG., "Com: Write single holding reg."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 5 Then *ERRORCODE
- GoSub *GET2WORDS
- .errcode. = .ERR_NO_ERROR.
- .mbaddr. = .outaddr.
- .wordval. = .outval.
- GoSub *SET_MB_WORD
- If .errcode. Then *ERRORCODE
- GoSub *MK2WORDHEADER
- GoTo *SENDRES
- Case .COM_WRITE_MULTIPLE_COILS.
- Print #.COMMLOG., "C Set multiple coils."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 6 Then *ERRORCODE
- GoSub *GET2WORDS
- GetByte .REQBUFF.,.bytecount.,.MESBUFFOFFS. + 5
- If .regnum. < 1 Or .regnum. > 2000 Then *ERRORCODE
- .hlp2. = .MESBUFFOFFS. + 6
- .errcode. = .ERR_NO_ERROR.
- .hlp1.=.regstart.
- .bitcount. = 0
- While .hlp1. + 8 <= .regstart. + .regnum.
- GetByte .REQBUFF.,.recbyte1.,.hlp2.
- .mbaddr. = .hlp1.
- .byteval. = .recbyte1.
- .bytelim. = 8
- GoSub *SET_MB_BYTE
- .hlp1.=.hlp1. + 8
- .hlp2.=.hlp2. + 1
- .bitcount. = .bitcount. + 8
- EndW
- GetByte .REQBUFF.,.recbyte1.,.hlp2.
- .mbaddr. = .hlp1.
- .byteval. = .recbyte1.
- .bytelim. = .regnum. Mod 8
- GoSub *SET_MB_BYTE
- If .errcode. Then *ERRORCODE
- .meslen.= .RESLENOFFS. + 5
- .1stword. = .regstart.
- .2ndword. = .bitcount. + .bytelim.
- GoSub *MK2WORDHEADER
- GoTo *SENDRES
- Case .COM_WRITE_MULTIPLE_REGISTERS.
- Print #.COMMLOG., "C Write multiple holding regs."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 5 Then *ERRORCODE
- GoSub *GET2WORDS
- GetByte .REQBUFF.,.bytecount.,.MESBUFFOFFS. + 5
- If .regnum. < 0 Or .regnum. > 123 Then *ERRORCODE
- .hlp2.= .MESBUFFOFFS. + 6
- .hlp1.=.regstart. To .regstart.+.regnum.
- .errcode. = 0
- While .hlp1. < .regstart.+.regnum.
- GetByte .REQBUFF.,.recbyte1.,.hlp2.
- GetByte .REQBUFF.,.recbyte2.,.hlp2.+1.
- .mbaddr. = .hlp1.
- .wordval. = .recbyte1.*&H100 + .recbyte2.
- GoSub *SET_MB_WORD
- .hlp1. = .hlp1. + 1
- .hlp2. = .hlp2. + 2
- EndW
- If .errcode. Then *ERRORCODE
- .meslen.= .RESLENOFFS. + 5
- GoSub *MK2WORDHEADER
- GoTo *SENDRES
- Case .COM_REPORT_SLAVE_ID.
- Print #.COMMLOG., "C Report slave ID."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. Then *ERRORCODE
- SetByte .RESBUFF.,.UNIT_ID., .RESBUFFOFFS. + 2
- SetByte .RESBUFF.,&HFF, .RESBUFFOFFS. + 3
- .resstr. = "PeteModbus by Kauppisen ropottivirma ltd."
- SetStr .RESBUFF.,.resstr.,.RESBUFFOFFS. + 4,len(.resstr.)
- .meslen.= .RESLENOFFS. + 4 + len(.resstr.)
- SetByte .RESBUFF.,.meslen.-3, .RESBUFFOFFS. + 1
- GoSub *MKFNHEADER
- GoTo *SENDRES
- Case .COM_READ_FILE_RECORD.
- Print #.COMMLOG., "C Read file."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 9 Then *ERRORCODE
- GetByte .REQBUFF., .bytecount. , .MESBUFFOFFS. + 1
- If .bytecount. > &HF5 Then *ERRORCODE
- .hlp1. = .MESBUFFOFFS. + 2
- .hlp2. = .bytecount.
- .hlp3. = .RESBUFFOFFS. + 2
- While .hlp2. >= 7
- GetByte .REQBUFF., .reftype. , .hlp1.
- GetByte .REQBUFF.,.recbyte1., .hlp1.+1
- GetByte .REQBUFF.,.recbyte2., .hlp1.+2
- .filenum. = &H100*.recbyte1. + .recbyte2.
- GetByte .REQBUFF.,.recbyte1., .hlp1.+3
- GetByte .REQBUFF.,.recbyte2., .hlp1.+4
- .recordnum. = &H100*.recbyte1. + .recbyte2.
- GetByte .REQBUFF.,.recbyte1., .hlp1.+5
- GetByte .REQBUFF.,.recbyte2., .hlp1.+6
- .recordlen. = &H100*.recbyte1. + .recbyte2.
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- If .filenum.<1 Or .filenum.>50 Or .recordnum.<0 Or (.recordnum.>200 And Not .recordnum.=&HFFFF) Or .recordlen.<0 Or (.recordlen.+.recordnum.>200 And Not .recordlen.=&HFFFF) Or .reftype.<>&H06
- GoTo *ERRORCODE
- EndIf
- If .recordlen. = &HFFFF And .recordnum. = &HFFFF
- .resstr. = V$[.filenum.]
- .recbyte1. = Len(.resstr.)
- Else
- .resstr. = Mid$(V$[.filenum.],.recordnum.,.recordlen.)
- .recbyte1. = Len(.resstr.)
- While .recbyte1. < .recordlen.
- .resstr. = .resstr. + Chr$(.FILLINCHAR.)
- .recbyte1. = .recbyte1. + 1
- EndW
- EndIf
- SetByte .RESBUFF., .recbyte1.*2 + 1, .hlp3.
- SetByte .RESBUFF., &H06 , .hlp3. + 1
- .recbyte2. = 1
- .hlp3. = .hlp3. + 2
- While .recbyte2. <= .recbyte1.
- .wordval. = Ord(Mid$(.resstr.,.recbyte2.,1))
- SetByte .RESBUFF., .wordval. / &H100 , .hlp3.
- SetByte .RESBUFF., .wordval. , .hlp3. +1
- .hlp3. = .hlp3. + 2
- .recbyte2. = .recbyte2. + 1
- EndW
- .hlp1. = .hlp1. + 7
- .hlp2. = .hlp2. - 7
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .hlp3. > 253 Then *ERRORCODE
- EndW
- SetByte .RESBUFF., .hlp3. - .RESBUFFOFFS. - 2, .RESBUFFOFFS.+1
- .meslen. = .hlp3. - .RESBUFFOFFS. + 1
- GoSub *MKFNHEADER
- GoTo *SENDRES
- Case .COM_WRITE_FILE_RECORD.
- Print #.COMMLOG., "C Write file."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 9 Then *ERRORCODE
- GetByte .REQBUFF., .bytecount., .MESBUFFOFFS. + 1
- .hlp1. = .MESBUFFOFFS. + 2
- .hlp2. = .bytecount.
- .hlp3. = .RESBUFFOFFS. + 2
- .bytecount. = 0
- While .hlp2. >= 7
- GetByte .REQBUFF., .reftype. , .hlp1.
- GetByte .REQBUFF., .recbyte1., .hlp1.+1
- GetByte .REQBUFF., .recbyte2., .hlp1.+2
- .filenum. = &H100*.recbyte1. + .recbyte2.
- GetByte .REQBUFF., .recbyte1., .hlp1.+3
- GetByte .REQBUFF., .recbyte2., .hlp1.+4
- .recordnum. = &H100*.recbyte1. + .recbyte2.
- GetByte .REQBUFF., .recbyte1., .hlp1.+5
- GetByte .REQBUFF., .recbyte2., .hlp1.+6
- .recordlen. = &H100*.recbyte1. + .recbyte2.
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- If .filenum.<1 Or .filenum.>50 Or ((.recordnum.<0 Or .recordnum.>200 Or .recordnum.+.recordlen.>200) And (.recordnum. <> &HFFFF)) Or .reftype.<>&H06 Then *ERRORCODE
- SetByte .RESBUFF., .reftype. , .hlp3.
- SetByte .RESBUFF., .filenum. / &H100 , .hlp3.+1
- SetByte .RESBUFF., .filenum. , .hlp3.+2
- SetByte .RESBUFF., .recordnum. / &H100 , .hlp3.+3
- SetByte .RESBUFF., .recordnum. , .hlp3.+4
- SetByte .RESBUFF., .recordlen. / &H100 , .hlp3.+5
- SetByte .RESBUFF., .recordlen. , .hlp3.+6
- .hlp1. = .hlp1. + 7
- .hlp3. = .hlp3. + 7
- .bytecount. = .bytecount. + 7
- .resstr. = ""
- if .recordnum. <> &HFFFF
- .uhlp1. = 0
- .uhlp2. = Len(V$[.filenum.])
- While .uhlp1. < .uhlp2. And .uhlp1. < .recordnum.
- .resstr. = .resstr. + Mid$(V$[.filenum.],.uhlp1.,1)
- .uhlp1. = .uhlp1. + 1
- EndW
- While .uhlp1. < .recordnum.
- .resstr. = .resstr. + Chr$(.FILLINCHAR.)
- .uhlp1. = .uhlp1. + 1
- EndW
- EndIf
- .uhlp2. = 0
- While .uhlp2. < .recordlen.
- GetByte .REQBUFF., .recbyte1., .hlp1.
- GetByte .REQBUFF., .recbyte2., .hlp1.+1
- SetByte .RESBUFF., .recbyte1., .hlp3.
- SetByte .RESBUFF., .recbyte2., .hlp3.+1
- .resstr. = .resstr. + Chr$(.recbyte2.)
- .hlp1. = .hlp1. + 2
- .hlp3. = .hlp3. + 2
- .uhlp1. = .uhlp1. + 1
- .uhlp2. = .uhlp2. + 1
- .bytecount. = .bytecount. + 2
- EndW
- if .recordnum. <> &HFFFF
- .uhlp2. = Len(V$[.filenum.])
- While .uhlp1. < .uhlp2.
- .resstr. = .resstr. + Mid$(V$[.filenum.],.uhlp1.,1)
- .uhlp1. = .uhlp1. + 1
- EndW
- EndIf
- V$[.filenum.] = .resstr.
- .hlp2. = .hlp2. - 7 - .recordlen.*2
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .hlp3. > 253 Then *ERRORCODE
- EndW
- SetByte .RESBUFF., .bytecount. , .RESBUFFOFFS.+1
- .meslen. = .hlp3. - .RESBUFFOFFS. + 1
- GoSub *MKFNHEADER
- GoTo *SENDRES
- Case .COM_MASK_WRITE_REGISTER.
- Print #.COMMLOG., "C Mask write multiple holding regs."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 7 Then *ERRORCODE
- GoSub *GET3WORDS
- If .regnum. > 125 Or .regnum. < 0 Then *ERRORCODE
- .errcode. = .ERR_NO_ERROR.
- .mbaddr. = .regstart.
- GoSub *GET_MB_WORD
- If .errcode. Then *ERRORCODE
- .mbaddr. = .regstart.
- .wordval. = (.wordval. And .andmask.) Or (.ormask. And (Not .andmask.))
- GoSub *SET_MB_WORD
- If .errcode. Then *ERRORCODE
- GoSub *MK3WORDHEADER
- GoTo *SENDRES
- Case .COM_READ_WRITE_MULTIPLE_REGISTERS.
- Print #.COMMLOG., "C Read write multiple holding regs."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 10 Then *ERRORCODE
- GoSub *GET4WORDS
- GetByte .REQBUFF.,.bytecount.,.MESBUFFOFFS.+ 8
- If .readlen. > 32 Or .writelen. > 32 Or .readlen. < 1 Or .writelen. < 1 Then *ERRORCODE
- .errcode. = .ERR_NO_ERROR.
- .hlp2.= .MESBUFFOFFS. + 10
- .hlp1.=.writestart.
- While .hlp1. < .writestart.+.writelen.
- GetByte .REQBUFF., .recbyte1. ,.hlp2.
- GetByte .REQBUFF., .recbyte2. ,.hlp2.+1
- .mbaddr. = .hlp1.
- .wordval. = .recbyte1.*&H100+.recbyte2.
- GoSub *SET_MB_WORD
- If .errcode. Then *ERRORCODE
- .hlp1. = .hlp1. + 1
- .hlp2. = .hlp2. + 2
- EndW
- .hlp2.= .RESBUFFOFFS. + 2
- .hlp1.=.readstart.
- .bytecount. = 0
- While .hlp1. < .readstart.+.readlen.
- .mbaddr. = .hlp1.
- GoSub *GET_MB_WORD
- If .errcode. Then *ERRORCODE
- SetByte .RESBUFF.,.wordval./&H100,.hlp2.
- SetByte .RESBUFF.,.wordval. And &HFF,.hlp2.+1
- .hlp1. = .hlp1. + 1
- .hlp2. = .hlp2. + 2
- .bytecount. = .bytecount. + 2
- EndW
- .meslen. = .bytecount. + 3
- SetByte .RESBUFF.,.bytecount., .RESBUFFOFFS. + 1
- GoSub *MKFNHEADER
- GoTo *SENDRES
- Case .COM_READ_FIFO_QUEUE.
- Print #.COMMLOG., "C Read fifo."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 3 Then *ERRORCODE
- GoSub *GET1WORD
- .mbaddr. = .fifoptr.
- GoSub *GET_MB_WORD
- If .wordval. < 0 Or .wordval. > 31 Then *ERRORCODE
- .hlp3. = .wordval.
- .hlp2. = .RESBUFFOFFS. + 5
- .hlp1. = .fifoptr.+1
- .bytecount. = 0
- .errcode. = .ERR_NO_ERROR.
- While .hlp1. <= .fifoptr. + .hlp3.
- .mbaddr. = .hlp1.
- GoSub *GET_MB_WORD
- SetByte .RESBUFF., .wordval./&H100, .hlp2.
- SetByte .RESBUFF., .wordval., .hlp2.+1
- .hlp1. = .hlp1. + 1
- .hlp2. = .hlp2. + 2
- .bytecount. = .bytecount. + 2
- EndW
- .1stword. = .bytecount. + 2
- .2ndword. = .hlp3.
- .meslen. = .bytecount. + 6
- GoSub *MK2WORDHEADER
- GoTo *SENDRES
- Case .COM_READ_DEVICE_IDENTIFICATION.
- Case .COM_READ_DEVICE_IDENTIFICATION_ALT.
- Print #.COMMLOG., "C Read device identification."
- .errcode. = .ERR_ILLEGAL_DATA_VALUE.
- If .meslen. < .MESLENOFFS. + 4 Then *ERRORCODE
- GetByte .REQBUFF.,.meitype.,1
- GetByte .REQBUFF.,.deviceid.,2
- GetByte .REQBUFF.,.objectid.,3
- If .meitype. <> &H0E Or (.deviceid. <> 1 And .deviceid. <> 4) Then *ERRORCODE
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- If .objectid. < 0 Or .objectid. > 2 Then *ERRORCODE
- SetByte .RESBUFF.,&H0E, .RESBUFFOFFS. + 1 ' MEI type
- SetByte .RESBUFF.,.deviceid., .RESBUFFOFFS. + 2 ' Device ID
- SetByte .RESBUFF.,&H81, .RESBUFFOFFS. + 3 ' Conformity level
- SetByte .RESBUFF.,&H00, .RESBUFFOFFS. + 4 ' More follows
- SetByte .RESBUFF.,&H00, .RESBUFFOFFS. + 5 ' Next obj
- .hlp1. = 7
- If .deviceid. = 1
- SetByte .RESBUFF.,3,.RESBUFFOFFS. + 6 ' Number of obj
- Else
- SetByte .RESBUFF.,1,.RESBUFFOFFS. + 6 ' Number of obj
- On .objectid. Goto *MEIPROD, *MEIPRODNUM
- EndIf
- SetByte .RESBUFF.,&H00,.RESBUFFOFFS. + .hlp1. ' Object ID
- .resstr. = "Kauppisen ropottivirma ltd."
- SetByte .RESBUFF.,Len(.resstr.),.RESBUFFOFFS. + 1 + .hlp1. ' Object Len
- SetStr .RESBUFF.,.resstr.,.RESBUFFOFFS. + 2 + .hlp1. ,Len(.resstr.) ' Object Val
- .hlp1. = .hlp1. + 2 + Len(.resstr.)
- If .deviceid. = 4 Then *MEIDONE
- *MEIPROD
- SetByte .RESBUFF.,&H01,.RESBUFFOFFS. + .hlp1. ' Object ID
- .resstr. = "PeteModbus"
- SetByte .RESBUFF.,Len(.resstr.),.RESBUFFOFFS. + 1 + .hlp1. ' Object Len
- SetStr .RESBUFF.,.resstr.,.RESBUFFOFFS. + 2 + .hlp1.,Len(.resstr.) ' Object Val
- .hlp1. = .hlp1. + 2 + Len(.resstr.)
- If .deviceid. = 4 Then *MEIDONE
- *MEIPRODNUM
- SetByte .RESBUFF.,&H02,.RESBUFFOFFS. + .hlp1. ' Object ID
- .resstr. = "1.0"
- SetByte .RESBUFF.,Len(.resstr.),.RESBUFFOFFS. + 1 + .hlp1. ' Object Len
- SetStr .RESBUFF.,.resstr.,.RESBUFFOFFS. + 2 + .hlp1.,Len(.resstr.) ' Object Val
- .hlp1. = .hlp1. + 2 + Len(.resstr.)
- *MEIDONE
- .meslen. = .RESBUFFOFFS. + .hlp1. - 6
- GoSub *MKFNHEADER
- GoTo *SENDRES
- Case ' Unsupported function code
- .errcode. = .ERR_ILLEGAL_FUNCTION.
- *ERRORCODE
- Print #.COMMLOG.,"E Fn " + Str$(.fn.) + " terminated with err " + Str$(.errcode.) + "."
- .fn. = .fn. + &H80
- .meslen. = .RESLENOFFS. + 2
- SetByte .RESBUFF., .errcode., 8
- GoSub *MKFNHEADER
- *SENDRES
- Print #.CONNLOG.,"T Sending MB-response with sock " + Str$(.COMM_SOCK_NUMBER.) + "."
- SockSend .COMM_SOCK_NUMBER.,.RESBUFF.,.meslen. + 6,.SEND_TIMEOUT.,.reclen.
- If .meslen. +6 < .reclen. Or E1% < 0 Then *LISTEN_TIMEOUT
- Print #.COMMLOG.,"M Reply sent."
- EndS
- GoTo *INNERLOOP
- *MK4WORDHEADER
- SetByte .RESBUFF.,.4thword.,15
- SetByte .RESBUFF.,.4thword./&H100,14
- *MK3WORDHEADER
- SetByte .RESBUFF.,.3rdword.,13
- SetByte .RESBUFF.,.3rdword./&H100,12
- *MK2WORDHEADER
- SetByte .RESBUFF.,.2ndword.,11
- SetByte .RESBUFF.,.2ndword./&H100,10
- *MK1WORDHEADER
- SetByte .RESBUFF.,.1stword.,9
- SetByte .RESBUFF.,.1stword./&H100,8
- *MKFNHEADER
- SetByte .RESBUFF.,.fn.,7
- *MKHEADER
- SetByte .RESBUFF.,.unitid.,6
- SetByte .RESBUFF.,.meslen.,5
- SetByte .RESBUFF.,.meslen./&H100,4
- SetByte .RESBUFF.,.protid.,3
- SetByte .RESBUFF.,.protid./&H100,2
- SetByte .RESBUFF.,.tranid.,1
- SetByte .RESBUFF.,.tranid./&H100,0
- Print #.COMMLOG., "M Reply header:" + Str$(.tranid.) + ":" + Str$(.protid.) + ":" + Str$(.meslen.) + ";" + Str$(.unitid.) + "."
- Return
- *GET4WORDS
- GetByte .REQBUFF.,.recbyte2.,8
- GetByte .REQBUFF.,.recbyte1.,7
- .4thword. = &H100*.recbyte1. + .recbyte2.
- *GET3WORDS
- GetByte .REQBUFF.,.recbyte2.,6
- GetByte .REQBUFF.,.recbyte1.,5
- .3rdword. = &H100*.recbyte1. + .recbyte2.
- *GET2WORDS
- GetByte .REQBUFF.,.recbyte2.,4
- GetByte .REQBUFF.,.recbyte1.,3
- .2ndword. = &H100*.recbyte1. + .recbyte2.
- *GET1WORD
- GetByte .REQBUFF.,.recbyte2.,2
- GetByte .REQBUFF.,.recbyte1.,1
- .1stword. = &H100*.recbyte1. + .recbyte2.
- Return
- *GET_MB_WORD ' In: .mbaddr., Out: .wordval.
- .trueaddr. = .mbaddr. + .MB_ADDR_OFFS.
- If .trueaddr. >= .COILBANK_ST. And .trueaddr. <= .COILBANK_MAX.
- .trueaddr. = .trueaddr. - .COILBANK.
- .wordval. = 0
- For .uhlp1.=0 To 15
- .wordval. = .wordval. + O[.trueaddr. + .uhlp1.]*(2^.uhlp1.)
- Next
- ElseIf .trueaddr. >= .INBANK_ST. And .trueaddr. <= .INBANK_MAX.
- .trueaddr. = .trueaddr. - .INBANK.
- .wordval. = 0
- For .uhlp1.=0 To 15
- .wordval. = .wordval. + I[.trueaddr. + .uhlp1.]*(2^.uhlp1.)
- Next
- ElseIf .trueaddr. >= .MEMBANK_ST. And .trueaddr. <= .MEMBANK_MAX.
- .trueaddr. = .trueaddr. - .MEMBANK.
- .wordval. = V%[.trueaddr.] And &HFFFF
- ElseIf .trueaddr. >= .MEMRBANK_ST. And .trueaddr. <= .MEMRBANK_MAX.
- .trueaddr. = .trueaddr. - .MEMRBANK.
- .real.=V![(.trueaddr.+1)/2]
- If (.trueaddr. Mod 2) = .NUXI. 'Odd
- GoSub *GETLOWREAL
- Else 'Even
- GoSub *GETHIGHREAL
- EndIf
- .wordval. = .realint.
- ElseIf .trueaddr. >= .MEMLBANK_ST. And .trueaddr. <= .MEMLBANK_MAX.
- .trueaddr. = .trueaddr. - .MEMLBANK.
- If (.trueaddr. Mod 2) = .NUXI. 'Odd
- .wordval. = V%[(.trueaddr.+1)/2] And &HFFFF
- Else 'Even
- .wordval. = V%[(.trueaddr.+1)/2] / &H10000
- EndIf
- Else ' Out of bounds
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- Print #.DATALOG., "E WORD " + Str$(.mbaddr.) + " addr out of bounds."
- EndIf
- Print #.DATALOG., "A Got WORD " + Str$(.mbaddr.) + ": " + Str$(.wordval.) + "."
- Return
- *SET_MB_WORD ' In: .mbaddr., .wordval.
- .trueaddr. = .mbaddr. + .MB_ADDR_OFFS.
- If .trueaddr. >= .COILBANK_ST. And .trueaddr. <= .COILBANK_MAX.
- .trueaddr. = .trueaddr. - .COILBANK.
- For .uhlp1.=.trueaddr. To .trueaddr. + 15
- If .wordval. And 2^.uhlp1.
- Set O[.uhlp1.]
- Else
- Reset O[.uhlp1.]
- EndIf
- Next
- ElseIf .trueaddr. >= .MEMBANK_ST. And .trueaddr. <= .MEMBANK_MAX.
- .trueaddr. = .trueaddr. - .MEMBANK.
- V%[.trueaddr.] = .wordval.
- ElseIf .trueaddr. >= .MEMRBANK_ST. And .trueaddr. <= .MEMRBANK_MAX.
- .trueaddr. = .trueaddr. - .MEMRBANK.
- .real. = V![(.trueaddr.+1)/2]
- .realint. = .wordval.
- If (.trueaddr. Mod 2) = .NUXI. 'Odd
- GoSub *SETLOWREAL
- Else 'Even
- GoSub *SETHIGHREAL
- EndIf
- V![(.trueaddr.+1)/2] = .real.
- ElseIf .trueaddr. >= .MEMLBANK_ST. And .trueaddr. <= .MEMLBANK_MAX.
- .trueaddr. = .trueaddr. - .MEMLBANK.
- If (.trueaddr. Mod 2) = .NUXI. 'Odd
- V%[(.trueaddr.+1)/2] = (V%[(.trueaddr.+1)/2] And &HFFFF0000) + .wordval.
- Else 'Even
- V%[(.trueaddr.+1)/2] = (V%[(.trueaddr.+1)/2] And &H0000FFFF) + .wordval.*&H10000
- EndIf
- Else ' Out of bounds
- Print #.DATALOG., "E WORD " + .mbaddr. + " addr out of bounds."
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- EndIf
- Print #.DATALOG., "A Set WORD " + Str$(.mbaddr.) + "=" + Str$(.wordval.) + "."
- Return
- *GET_MB_BYTE ' In: .mbaddr., .bytelim., Out: .byteval.
- Print #.DATALOG., "A Getting BYTE " + Str$(.mbaddr.) + Chr$(44) + " " + Str$(.bytelim.) + " bits."
- .uhlp2. = 0
- .uhlp1. = 0
- While .uhlp1. < .bytelim.
- .bitaddr. = .uhlp1. + .mbaddr.
- GoSub *GET_MB_BIT
- .uhlp2. = .uhlp2. + 2^.uhlp1.*.bitval.
- .uhlp1. = .uhlp1. + 1
- EndW
- .byteval. = .uhlp2.
- Return
- *SET_MB_BYTE ' In: .mbaddr., .byteval., .bytelim.
- Print #.DATALOG., "A Setting BYTE " + Str$(.mbaddr.) + Chr$(44) + " " + Str$(.bytelim.) + " bits."
- .uhlp1. = 0
- While .uhlp1. < .bytelim.
- .bitaddr.= .mbaddr. + .uhlp1.
- .bitval.= .byteval. And 2^.uhlp1.
- GoSub *SET_MB_BIT
- .uhlp1.=.uhlp1.+1
- EndW
- Return
- *GET_MB_BIT ' In: .bitaddr., Out: .bitval.
- .bitaddr. = .bitaddr. + .MB_ADDR_OFFS.
- If .COILBANK_BST. >= 1 And .bitaddr. <= .COILBANK_BMAX.
- .bitaddr. = .bitaddr. - .COILBANK.
- .bitval. = O[.bitaddr.]
- ElseIf .INBANK_BST. >= 1 And .bitaddr. <= .INBANK_BMAX.
- .bitaddr. = .bitaddr. - .INBANK.
- .bitval. = I[.bitaddr.]
- ElseIf .bitaddr. >= .MEMBANK_BST. And .bitaddr. <= .MEMBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMBANK.
- .bitval. =(V%[(.bitaddr.-1) / 16 + 1] And (2^((.bitaddr.-1) Mod 16))) <> 0
- ElseIf .bitaddr. >= .MEMRBANK_BST. And .bitaddr. <= .MEMRBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMRBANK.
- .real.=V![(.bitaddr.-1) / 32 + 1]
- If (((.bitaddr.-1) / 16) Mod 2) = .NUXI. 'Odd
- GoSub *GETLOWREAL
- .bitval. =(.realint. And 2^((.bitaddr.-1) Mod 16)) <> 0
- Else 'Even
- GoSub *GETHIGHREAL
- .bitval. =(.realint. And 2^((.bitaddr.-1) Mod 16)) <> 0
- EndIf
- ElseIf .bitaddr. >= .MEMLBANK_BST. And .bitaddr. <= .MEMLBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMLBANK.
- If (((.bitaddr.-1) / 16) Mod 2) = .NUXI. 'Odd
- .bitval. =(V%[(.bitaddr.-1) / 32 + 1] And 2^((.bitaddr.-1) Mod 16)) <> 0
- Else 'Even
- .bitval. =(V%[(.bitaddr.-1) / 32 + 1] / &H10000 And 2^((.bitaddr.-1) Mod 16)) <> 0
- EndIf
- Else ' Out of bounds
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- Print #.DATALOG., "BIT " + Str$(.bitaddr.) + " out of bounds."
- Return
- EndIf
- Print #.DATALOG., "A Got BIT " + Str$(.bitaddr.) + ": " + Str$(.bitval.) + "."
- Return
- *SET_MB_BIT ' In: .bitaddr., .bitval.
- If .bitval.
- .bitaddr. = .bitaddr. + .MB_ADDR_OFFS.
- If .bitaddr. >= .COILBANK_BST. And .bitaddr. <= .COILBANK_BMAX.
- .bitaddr. = .bitaddr. - .COILBANK.
- Set O[.bitaddr.]
- ElseIf .bitaddr. >= .MEMBANK_BST. And .bitaddr. <= .MEMBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMBANK.
- V%[(.bitaddr.-1) / 16 + 1] = V%[(.bitaddr.-1) / 16 + 1] Or 2^((.bitaddr.-1) Mod 16)
- ElseIf .bitaddr. >= .MEMRBANK_BST. And .bitaddr. <= .MEMRBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMRBANK.
- .real.=V![(.bitaddr.-1)/32 + 1]
- If (((.bitaddr.-1) / 16 + 1) Mod 2) = .NUXI. 'Odd
- GoSub *GETLOWREAL
- .realint. = .realint. Or 2^((.bitaddr.-1) Mod 16)
- GoSub *SETLOWREAL
- Else 'Even
- GoSub *GETHIGHREAL
- .realint. = .realint. Or 2^((.bitaddr.-1) Mod 16)
- GoSub *SETHIGHREAL
- EndIf
- V![(.bitaddr.-1)/32 + 1]=.real.
- ElseIf .bitaddr. >= .MEMLBANK_BST. And .bitaddr. <= .MEMLBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMLBANK.
- If (((.bitaddr.-1) / 16 + 1) Mod 2) = .NUXI. 'Odd
- V%[(.bitaddr.-1) / 32 + 1] = V%[(.bitaddr.-1) / 32 + 1] Or 2^((.bitaddr.-1) Mod 16)
- Else 'Even
- V%[(.bitaddr.-1) / 32 + 1] = V%[(.bitaddr.-1) / 32 + 1] Or 2^((.bitaddr.-1) Mod 16)*&H10000
- EndIf
- Else ' Out of bounds
- Print #.DATALOG., "E BIT out of bounds."
- .errcode.=.ERR_ILLEGAL_DATA_ADDRESS.
- Return
- EndIf
- Print #.DATALOG., "A Set BIT " + Str$(.bitaddr.) + "."
- Else
- .bitaddr. = .bitaddr. + .MB_ADDR_OFFS.
- If .COILBANK_BST. >= 1 And .bitaddr. <= .COILBANK_BMAX.
- .bitaddr. = .bitaddr. - .COILBANK.
- Reset O[.bitaddr.]
- ElseIf .bitaddr. >= .MEMBANK_BST. And .bitaddr. <= .MEMBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMBANK.
- V%[(.bitaddr.-1) / 16 + 1] = V%[(.bitaddr.-1) / 16 + 1] And (Not (2^((.bitaddr.-1) Mod 16)))
- ElseIf .bitaddr. >= .MEMRBANK_BST. And .bitaddr. <= .MEMRBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMRBANK.
- .real.=V![(.bitaddr.-1) / 32 + 1]
- If (((.bitaddr.-1) / 16 + 1) Mod 2) = .NUXI. 'Odd
- GoSub *GETLOWREAL
- .realint. = .realint. And Not (2^((.bitaddr.-1) Mod 16))
- GoSub *SETLOWREAL
- Else 'Even
- GoSub *GETHIGHREAL
- .realint. = .realint. And Not (2^((.bitaddr.-1) Mod 16))
- GoSub *SETHIGHREAL
- EndIf
- V![(.bitaddr.-1) / 32 + 1] = .real.
- ElseIf .bitaddr. >= .MEMLBANK_BST. And .bitaddr. <= .MEMLBANK_BMAX.
- .bitaddr. = .bitaddr. - .MEMLBANK.
- If (((.bitaddr.-1) / 16 + 1) Mod 2) = .NUXI. 'Odd
- V%[(.bitaddr.-1) / 32 + 1] = V%[(.bitaddr.-1) / 32 + 1] And (Not (2^((.bitaddr.-1) Mod 16)))
- Else 'Even
- V%[(.bitaddr.-1) / 32 + 1] = V%[(.bitaddr.-1) / 32 + 1] And (Not (2^((.bitaddr.-1) Mod 16)*&H10000))
- EndIf
- Else ' Out of bounds
- Print #.DATALOG., "E BIT out of bounds."
- .errcode. = .ERR_ILLEGAL_DATA_ADDRESS.
- Return
- EndIf
- Print #.DATALOG., "A Reset BIT " + Str$(.bitaddr.) + "."
- EndIf
- Return
- *GETLOWREAL
- SetReal .REALBUFF., .real., 0
- GetInt .REALBUFF., .realint., 0
- .realint. = .realint. And &H0000FFFF
- Return
- *GETHIGHREAL
- SetReal .REALBUFF., .real., 2
- GetInt .REALBUFF., .realint., 0
- .realint. = .realint. And &H0000FFFF
- Return
- *SETLOWREAL
- SetReal .REALBUFF.,.real., 0
- SetByte .REALBUFF., (.realint. And &H0000FFFF) / &H100 , 2
- SetByte .REALBUFF., (.realint. And &H000000FF) , 3
- GetReal .REALBUFF.,.real., 0
- Return
- *SETHIGHREAL
- SetReal .REALBUFF.,.real., 2
- SetInt .REALBUFF.,.realint., 0
- GetReal .REALBUFF.,.real., 2
- Return
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement