Code: Select all
;
; ModBus RTU
;
#ModBus_RTU = #True
Global ModBus_RTU_Echo.i
XIncludeFile "ModBus_Helpers.pbi"
XIncludeFile "ModBus_CRC.pbi"
Procedure.i ModBus_RTU_ReadCoils(Port.i, Address.i, StartCoil.i, Quantity.i, Array BitField.a(1))
Protected Result.i, *Buffer, i.i, Timeout.i, Size.i, Bytes.i, Mask.i, Byte.i, Ptr.i
Result = -1
*Buffer = AllocateMemory(128)
If *Buffer
PokeA(*Buffer, Address)
PokeA(*Buffer + 1, #ModBus_FunctionCode_ReadCoils)
PokeU(*Buffer + 2, ModBus_BigEndian16(StartCoil))
PokeU(*Buffer + 4, ModBus_BigEndian16(Quantity))
PokeU(*Buffer + 6, ModBus_CalcCRC(*Buffer, 1 + 1 + 2 + 2))
WriteSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
If ModBus_RTU_Echo
ReadSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
EndIf
i = 0
Timeout = 1000
Repeat
If AvailableSerialPortInput(Port)
ReadSerialPortData(Port, *Buffer + i, 1)
i + 1
If i = 5 And PeekA(*Buffer + 1) = $80 | #ModBus_FunctionCode_ReadCoils
Result = PeekA(*Buffer + 2)
Break
EndIf
Bytes = PeekA(*Buffer + 2)
Size = 1 + 1 + 1 + (Bytes / 8) + 2
If Bytes & $07 : Size + 1 : EndIf
If i = Size
If ModBus_CheckCRC(*Buffer, Size)
Quantity - 1
ReDim BitField(Quantity)
For i = 0 To Quantity
If i % 8 = 0
Mask = $01
Byte = PeekA(*Buffer + 3 + Ptr)
Ptr + 1
EndIf
BitField(i) = Byte & Mask
Mask << 1
Next i
Result = 0
Else
Result = -2
EndIf
Break
EndIf
Else
Delay(1)
Timeout - 1
EndIf
Until Timeout = 0
If Timeout = 0
Result = -10
EndIf
FreeMemory(*Buffer)
EndIf
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_ReadDiscreteInputs(Port.i, Address.i, StartInput.i, Quantity.i, Array BitField.a(1))
Protected Result.i
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_ReadHoldingRegisters(Port.i, Address.i, StartRegister.i, Quantity.i, Array Words.u(1))
Protected Result.i, *Buffer, i.i, Timeout.i, Size.i
Result = -1
*Buffer = AllocateMemory(128)
If *Buffer
PokeA(*Buffer, Address)
PokeA(*Buffer + 1, #ModBus_FunctionCode_ReadHoldingRegisters)
PokeU(*Buffer + 2, ModBus_BigEndian16(StartRegister))
PokeU(*Buffer + 4, ModBus_BigEndian16(Quantity))
PokeU(*Buffer + 6, ModBus_CalcCRC(*Buffer, 1 + 1 + 2 + 2))
WriteSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
If ModBus_RTU_Echo
ReadSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
EndIf
i = 0
Timeout = 1000
Repeat
If AvailableSerialPortInput(Port)
ReadSerialPortData(Port, *Buffer + i, 1)
Debug Hex(PeekA(*Buffer + i))
i + 1
If i = 5 And PeekA(*Buffer + 1) = $80 | #ModBus_FunctionCode_ReadHoldingRegisters
Result = PeekA(*Buffer + 2)
Break
EndIf
Size = 1 + 1 + 1 + PeekA(*Buffer + 2) + 2
If i = Size
If ModBus_CheckCRC(*Buffer, Size)
Quantity - 1
ReDim Words(Quantity)
For i = 0 To Quantity
Words(i) = ModBus_BigEndian16(PeekU(*Buffer + 3 + 2 * i))
Next i
Result = 0
Else
Result = -2
EndIf
Break
EndIf
Else
Delay(1)
Timeout - 1
EndIf
Until Timeout = 0
If Timeout = 0
Result = -10
EndIf
FreeMemory(*Buffer)
EndIf
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_ReadInputRegisters(Port.i, Address.i, StartRegister.i, Quantity.i, Array Words.u(1))
Protected Result.i, *Buffer, i.i, Timeout.i, Size.i
Result = -1
*Buffer = AllocateMemory(128)
If *Buffer
PokeA(*Buffer, Address)
PokeA(*Buffer + 1, #ModBus_FunctionCode_ReadInputRegisters)
PokeU(*Buffer + 2, ModBus_BigEndian16(StartRegister))
PokeU(*Buffer + 4, ModBus_BigEndian16(Quantity))
PokeU(*Buffer + 6, ModBus_CalcCRC(*Buffer, 1 + 1 + 2 + 2))
WriteSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
If ModBus_RTU_Echo
ReadSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
EndIf
i = 0
Timeout = 1000
Repeat
If AvailableSerialPortInput(Port)
ReadSerialPortData(Port, *Buffer + i, 1)
Debug Hex(PeekA(*Buffer + i))
i + 1
If i = 5 And PeekA(*Buffer + 1) = $80 | #ModBus_FunctionCode_ReadHoldingRegisters
Result = PeekA(*Buffer + 2)
Break
EndIf
Size = 1 + 1 + 1 + PeekA(*Buffer + 2) + 2
If i = Size
If ModBus_CheckCRC(*Buffer, Size)
Quantity - 1
ReDim Words(Quantity)
For i = 0 To Quantity
Words(i) = ModBus_BigEndian16(PeekU(*Buffer + 3 + 2 * i))
Next i
Result = 0
Else
Result = -2
EndIf
Break
EndIf
Else
Delay(1)
Timeout - 1
EndIf
Until Timeout = 0
If Timeout = 0
Result = -10
EndIf
FreeMemory(*Buffer)
EndIf
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_WriteSingleCoil(Port.i, Address.i, Coil.i, Value.i)
Protected Result.i
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_WriteSingleRegister(Port.i, Address.i, Register.i, Value.i)
Protected Result.i
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_ReadExceptionStatus(Port.i, Address.i)
Protected Result.i
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_WriteMultipleCoils(Port.i, Address.i, StartCoil.i, Coils.i, Array Values.a(1))
Protected Result.i
ProcedureReturn Result
EndProcedure
Procedure.i ModBus_RTU_WriteMultipleRegisters(Port.i, Address.i, StartRegister.i, Quantity.i, Array Values.u(1))
Protected Result.i, *Buffer, i.i, Timeout.i
Result = -1
*Buffer = AllocateMemory(1 + 1 + 2 + 2 + 1 + 2 * Quantity + 2)
If *Buffer
PokeA(*Buffer, Address)
PokeA(*Buffer + 1, #ModBus_FunctionCode_WriteMultipleRegisters)
PokeU(*Buffer + 2, ModBus_BigEndian16(StartRegister))
PokeU(*Buffer + 4, ModBus_BigEndian16(Quantity))
PokeA(*Buffer + 6, 2 * Quantity)
For i = 0 To Quantity - 1
PokeU(*Buffer + 7 + i * 2, ModBus_BigEndian16(Values(i)))
Next i
PokeU(*Buffer + 7 + i * 2, ModBus_CalcCRC(*Buffer, 1 + 1 + 2 + 2 + 1 + 2 * Quantity))
WriteSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 1 + 2 * Quantity + 2)
If ModBus_RTU_Echo
ReadSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 1 + 2 * Quantity + 2)
EndIf
i = 0
Timeout = 1000
Repeat
If AvailableSerialPortInput(Port)
ReadSerialPortData(Port, *Buffer + i, 1)
i + 1
If i = 5 And PeekA(*Buffer + 1) = $80 | #ModBus_FunctionCode_WriteMultipleRegisters
Result = PeekA(*Buffer + 2)
Break
EndIf
If i = 8
If ModBus_CheckCRC(*Buffer, 8)
Result = 0
Else
Result = -2
EndIf
Break
EndIf
Else
Delay(1)
Timeout - 1
EndIf
Until Timeout = 0
If Timeout = 0
Result = -10
EndIf
FreeMemory(*Buffer)
EndIf
ProcedureReturn Result
EndProcedure