Common.cin

Added hbin_to_strhex and dbin_to_strhex
ModbusClientCommon.cin
  Introduced timers to watch for timeouts
  Enhanced OnModbusReceive
  Added exception handling
  Added ModbusReadWriteRegisters and ModbusWriteMasks
This commit is contained in:
Jonny007-MKD 2014-05-15 12:43:52 +00:00
parent 2884b48093
commit 8c9f78a0a9
9 changed files with 1349 additions and 601 deletions

View file

@ -2,7 +2,7 @@
void bin_to_strhex(byte bin[], char result[])
{
char hex_str[17]= "0123456789ABCDEF";
char hex_str[17] = "0123456789ABCDEF";
word i;
word binsz;
@ -24,4 +24,58 @@ void bin_to_strhex(byte bin[], char result[])
result[58] = '.';
}
result[binsz * 3 - 1] = 0;
}
void hbin_to_strhex(byte bin[], char result[])
{
char hex_str[17] = "0123456789ABCDEF";
word i;
word binsz;
binsz = elCount(bin);
if (binsz > 20)
binsz = 20;
for (i = 0; i < binsz; i++)
{
result[i * 2 + 0] = hex_str[bin[i] & 0x0F];
result[i * 2 + 1] = ' ';
}
if (elCount(bin) > 20) // trailing "..."
{
result[36] = '.';
result[37] = '.';
result[38] = '.';
}
result[binsz * 2 - 1] = 0;
}
void dbin_to_strhex(word bin[], char result[])
{
char hex_str[17] = "0123456789ABCDEF";
word i;
word binsz;
byte offset;
binsz = elCount(bin);
if (binsz > 20)
binsz = 20;
for (i = 0; i < binsz; i++)
{
result[i * 5 + 0] = hex_str[(bin[i] >> 12) & 0x0F];
result[i * 5 + 1] = hex_str[(bin[i] >> 8) & 0x0F];
result[i * 5 + 2] = hex_str[(bin[i] >> 4) & 0x0F];
result[i * 5 + 3] = hex_str[(bin[i] ) & 0x0F];
result[i * 5 + 4] = ' ';
}
if (elCount(bin) > 20) // trailing "..."
{
result[96] = '.';
result[97] = '.';
result[98] = '.';
}
result[(byte)(binsz * 2.5) - 1] = 0;
}

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ includes
variables
{
msTimer muster;
msTimer muster, clock;
byte gX[2] = {1, 0};
}
@ -16,7 +16,7 @@ variables
on preStart
{
writeClear(0);
setStartdelay(1000);
setStartdelay(10);
}
on start
@ -47,23 +47,33 @@ void OnModbusWriteRegistersFailed(enum ModbusRequestError error, enum ModbusExce
{
}
void OnModbusReadBitsSuccess(byte result[])
void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbr, byte bitStatus[], word numBits)
{
char str[20*2];
hbin_to_strhex(mbr.Data, str);
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusReceiveBits: Received %d bits (in %d bytes): %s", numBits, mbr.ByteCount, str);
}
void OnModbusReadRegistersSuccess(byte result[])
void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbr, word numRegs)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusReceiveRegisters: Received %d registers (%d bytes): %X %X %X %X...", mbr.ByteCount, mbr.Data[0], mbr.Data[1], mbr.Data[2], mbr.Data[3]);
}
void OnModbusWriteBitSuccess(byte result[])
void OnModbusWriteBitSuccess(struct ModbusResConfirmSingle mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmBit: Set bit 0x%X to %d", mbc.Address, (mbc.Value > 0 ? 1 : 0));
}
void OnModbusWriteRegisterSuccess(byte result[])
void OnModbusWriteRegisterSuccess(struct ModbusResConfirmSingle mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmRegister: Set register 0x%X to %d", mbc.Address, mbc.Value);
}
void OnModbusWriteBitsSuccess(byte result[])
void OnModbusWriteBitsSuccess(struct ModbusResConfirmMultiple mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmBits: Set %d bits beginning with 0x%X", mbc.Count, mbc.Address);
}
void OnModbusWriteRegistersSuccess(byte result[])
void OnModbusWriteRegistersSuccess(struct ModbusResConfirmMultiple mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmRegisters: Set %d registers beginning with 0x%X", mbc.Count, mbc.Address);
}
@ -132,11 +142,11 @@ on key '-'
ModbusWriteBits(0, 16, x);
}
on key 't'
on key 'z'
{
setTimerCyclic(muster, 100);
}
on key 'T'
on key 'Z'
{
cancelTimer(muster);
}
@ -167,4 +177,20 @@ on timer muster
//ModbusReadBits(0, 512);
}
/**/
on key 't'
{
setTimerCyclic(clock, 100);
}
on key 'T'
{
clock.Cancel();
}
on timer clock
{
byte s, x[2];
s = (timeNow() / 100000) % 30;
x[0] = (s & 0x01) | (s & 0x02) | ((s & 0x04) << 1) | ((s & 0x08) << 4);
x[1] = (s & 0x10) << 3;
ModbusWriteBits(0, 16, x);
}

View file

@ -7,8 +7,13 @@ includes
variables
{
msTimer muster;
char gNodeName[10] = "ClientUDP";
msTimer muster, clock;
byte gX[2] = {1, 0};
enum MbClientState {INIT, ConfWago1, ConfWago2, ConfWago3, ConfWago4, DATA};
enum MbClientState gState = INIT;
}
// Get information of local network interface such like ip address
@ -16,14 +21,18 @@ variables
on preStart
{
writeClear(0);
setStartdelay(1000);
sysDefineNamespace("%NETWORK_NAME%::%BASE_FILE_NAME%::Info");
sysDefineNamespace("%NETWORK_NAME%::%BASE_FILE_NAME%::Data");
setStartdelay(10);
}
on start
{
long fehler;
ModbusInit("192.168.1.3", 502);
// Read serial code, additional stuff is done in OnModbusReceiveRegisters
gState = ConfWago1;
ModbusReadRegisters(0x2011, 1);
}
@ -46,50 +55,110 @@ void OnModbusWriteBitsFailed(enum ModbusRequestError error, enum ModbusException
void OnModbusWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
{
}
void OnModbusWriteMasksFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
{
}
void OnModbusReadWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
{
}
void OnModbusReadBitsSuccess(byte result[])
void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbr, byte bitStatus[], word numBits)
{
char str[20*2];
hbin_to_strhex(mbr.Data, str);
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusReceiveBits: Received %d bits (in %d bytes): %s", numBits, mbr.ByteCount, str);
}
void OnModbusReadRegistersSuccess(byte result[])
void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbr, word numRegs)
{
char str[20*5];
long fehler;
dbin_to_strhex(mbr.Data, str);
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusReceiveRegisters: Received %d bytes: %s", mbr.ByteCount, str);
switch (gState)
{
case ConfWago1:
sysDefineVariableInt("%NETWORK_NAME%::%BASE_FILE_NAME%::Info", "SerialCode", mbr.Data[0]);
gState = ConfWago2;
ModbusReadRegisters(0x2012, 1);
break;
case ConfWago2:
sysDefineVariableInt("%NETWORK_NAME%::%BASE_FILE_NAME%::Info", "DeviceCode", mbr.Data[0]);
gState = ConfWago3;
ModbusReadRegisters(0x2030, 1);
break;
case ConfWago3:
break;
default:
break;
}
}
void OnModbusWriteBitSuccess(byte result[])
void OnModbusWriteBitSuccess(struct ModbusResConfirmSingle mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmBit: Set bit 0x%X to %d", mbc.Address, (mbc.Value > 0 ? 1 : 0));
}
void OnModbusWriteRegisterSuccess(byte result[])
void OnModbusWriteRegisterSuccess(struct ModbusResConfirmSingle mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmRegister: Set register 0x%X to %d", mbc.Address, mbc.Value);
}
void OnModbusWriteBitsSuccess(byte result[])
void OnModbusWriteBitsSuccess(struct ModbusResConfirmMultiple mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmBits: Set %d bits beginning with 0x%X", mbc.Count, mbc.Address);
}
void OnModbusWriteRegistersSuccess(byte result[])
void OnModbusWriteRegistersSuccess(struct ModbusResConfirmMultiple mbc)
{
writeLineEx(0, 1, "<%BASE_FILE_NAME%> OnModbusConfirmRegisters: Set %d registers beginning with 0x%X", mbc.Count, mbc.Address);
}
void OnModbusWriteMasksSuccess(struct ModbusResConfirmMasks mbc)
{
}
// Key events -------------------------------------------------------------------------
on key 'r'
on key 'i' // read the configuration
{
ModbusReadBits(0, 512);
}
on key 'r' // read the first bits
{
ModbusReadBits(0, 51);
}
on key 'R' // read constant registers
{
ModbusReadRegisters(0x2000, 8);
}
on key 'a'
on key 'a' // set left bar
{
byte x[16] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
ModbusWriteBitsB(0, 16, x);
}
on key 'A' // read the output bits
{
ModbusReadBits(0x200, 16);
}
on key 's'
on key 's' // set right bar
{
byte x[16] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
ModbusWriteBitsB(0, 16, x);
}
on key 'Y'
on key 'e' // write register
{
ModbusWriteRegister(0, 0x5555);
}
on key 'E' // read register
{
ModbusWriteRegister(0, 0);
}
on key 'Y' // write bit on
{
ModbusWriteBit(0, 0);
}
on key 'y'
on key 'y' // write bit off
{
ModbusWriteBit(0, 1);
}
@ -121,22 +190,22 @@ on key 'v'
ModbusWriteBit(3, 1);
}
on key '+'
on key '+' // set all bits on
{
byte x[2] = {0xFF, 0xFF};
ModbusWriteBits(0, 16, x);
}
on key '-'
on key '-' // set all bits off
{
byte x[2] = {0x00, 0x00};
ModbusWriteBits(0, 16, x);
}
on key 't'
on key 'z' // start timer muster
{
setTimerCyclic(muster, 100);
}
on key 'T'
on key 'Z' // stop timer muster
{
cancelTimer(muster);
}
@ -167,4 +236,20 @@ on timer muster
//ModbusReadBits(0, 512);
}
/**/
on key 't' // show clock on output
{
setTimerCyclic(clock, 1000);
}
on key 'T' // show clock on output
{
clock.Cancel();
}
on timer clock
{
byte s, x[2];
s = (timeNow() / 100000) % 30;
x[0] = (s & 0x01) | (s & 0x02) | ((s & 0x04) << 1) | ((s & 0x08) << 4);
x[1] = (s & 0x10) << 3;
ModbusWriteBits(0, 16, x);
}

View file

@ -0,0 +1,122 @@
/*@!Encoding:1252*/
variables
{
// A normal Modbus Application Header. Every Modbus Packet begins with these 7 (+FuncCode) Bytes
_align(1) struct ModbusApHeader
{
word TxID;
word Protocol;
word Length;
byte UnitID;
byte FuncCode;
};
// Read Data from the host. We only need the start address and the number of bits/registers we want to read
_align(1) struct ModbusReqRead
{
struct ModbusApHeader Header;
word Address;
word Count;
};
// Write a single value to a bit/register
_align(1) struct ModbusReqWriteSingle
{
struct ModbusApHeader Header;
word Address;
word Value;
};
// Write several values to a bit/register starting with Address
_align(1) struct ModbusReqWriteBits
{
struct ModbusApHeader Header;
word Address;
word Count;
byte ByteCount;
byte Data[246]; // Max length: 1968 bits
};
// Write several values to bits starting with Address
_align(1) struct ModbusReqWriteRegisters
{
struct ModbusApHeader Header;
word Address;
word Count;
byte ByteCount;
word Data[123]; // Max length: 123 registers
};
// Write AND and OR masks to a holding register
_align(1) struct ModbusReqWriteMasks
{
struct ModbusApHeader Header;
word Address;
word And;
word Or;
};
// Read and write multiple registers
_align(1) struct ModbusReqReadWriteRegisters
{
struct ModbusApHeader Header;
word ReadAddress;
word ReadCount;
word WriteAddress;
word WriteCount;
byte ByteCount;
word Data[121]; // Max length: 123-2 registers
};
// Receive several bit values
_align(1) struct ModbusResReceiveBits
{
struct ModbusApHeader Header;
byte ByteCount;
byte Data[250]; // Max length: 2000 bits
};
// Receive several register values
_align(1) struct ModbusResReceiveRegisters
{
struct ModbusApHeader Header;
byte ByteCount;
word Data[125]; // Max length: 125 registers
};
// Confirm the write of a single bit/register
_align(1) struct ModbusResConfirmSingle
{
struct ModbusApHeader Header;
word Address;
int Value;
};
// Confirm the write of several bits/registers
_align(1) struct ModbusResConfirmMultiple
{
struct ModbusApHeader Header;
word Address;
word Count;
};
// Confirm the write of AND and OR mask
_align(1) struct ModbusResConfirmMasks
{
struct ModbusApHeader Header;
word Address;
word And;
word Or;
};
enum ModbusRequestError
{
Exception,
Timeout
};
enum ModbusException
{
None = 0x00,
IllegalFuncCode = 0x01,
IllegalDataAddress = 0x02,
IllegalDataValue = 0x03,
ServerFailure = 0x04,
Acknowledge = 0x05,
ServerBusy = 0x06,
GatewayPathsNA = 0x0A,
TargetOffline = 0x0B
};
}

View file

@ -34,19 +34,19 @@ word TcpOpenSocket()
if (gSocket.GetLastSocketError() != 0)
{
gSocket.GetLastSocketErrorAsString(errorText, elcount(errorText));
writeLineEx(0, 1, "<%NODE_NAME%> Error: could not open Tcp socket on %s:%d, %s (%d)!", Local_IP, localPort, errorText, gSocket.GetLastSocketError());
writeLineEx(0, 1, "<%BASE_FILE_NAME%> Error: could not open Tcp socket on %s:%d, %s (%d)!", Local_IP, localPort, errorText, gSocket.GetLastSocketError());
}
}
while (gSocket.GetLastSocketError() != 0 && i++ < 9);
if (gSocket.GetLastSocketError() != 0)
{
writeLineEx(0, 1, "<%NODE_NAME%> Error: could not open Tcp socket!");
writeLineEx(0, 1, "<%BASE_FILE_NAME%> Error: could not open Tcp socket!");
return gSocket.GetLastSocketError();
}
else
{
writeLineEx(0, 1, "<%NODE_NAME%> Tcp socket opened on %s:%d.", Local_IP, localPort);
writeLineEx(0, 1, "<%BASE_FILE_NAME%> Tcp socket opened on %s:%d.", Local_IP, localPort);
}
return 0;
@ -60,7 +60,7 @@ word TcpConnectTo(char Remote_IP[], word remotePort)
remoteIp = IpGetAddressAsNumber(Remote_IP);
if (remoteIp == INVALID_IP)
{
writeLineEx(0, 1, "<%NODE_NAME%> Error: invalid server Ip address!");
writeLineEx(0, 1, "<%BASE_FILE_NAME%> Error: invalid server Ip address!");
return 1;
}
@ -91,7 +91,7 @@ word TcpConnectTo(dword remoteIp, word remotePort)
if (fehler != WSAEWOULDBLOCK) // OnTcpConnect will be called otherwise
{
write("<%NODE_NAME%> No Port-Connection: %d", fehler);
write("<%BASE_FILE_NAME%> No Port-Connection: %d", fehler);
gSocketState = ERROR;
return fehler;
}
@ -99,7 +99,7 @@ word TcpConnectTo(dword remoteIp, word remotePort)
}
else
{
writeLineEx(0, 1, "<%NODE_NAME%> Successfully connected to server");
writeLineEx(0, 1, "<%BASE_FILE_NAME%> Successfully connected to server");
gSocketState = OK;
return 0;
}
@ -110,13 +110,13 @@ void OnTcpConnect(dword socket, long result)
if (result != 0)
{
gSocket.GetLastSocketErrorAsString(gIpLastErrStr, elcount(gIpLastErrStr));
writeLineEx(0, 2, "<%NODE_NAME%> OnTcpConnect error (%d): %s", gSocket.GetLastSocketError(), gIpLastErrStr);
writeLineEx(0, 2, "<%BASE_FILE_NAME%> OnTcpConnect error (%d): %s", gSocket.GetLastSocketError(), gIpLastErrStr);
gSocketState = ERROR;
return;
}
else
{
writeLineEx(0, 1, "<%NODE_NAME%> Successfully connected to server");
writeLineEx(0, 1, "<%BASE_FILE_NAME%> Successfully connected to server");
gSocketState = OK;
}
}
@ -140,7 +140,7 @@ void TcpRecv()
if (gIpLastErr != WSA_IO_PENDING) // Calling OnTcpReceive otherwise
{
gSocket.GetLastSocketErrorAsString(gIpLastErrStr, elcount(gIpLastErrStr));
writeLineEx(0, 2, "<%NODE_NAME%> TcpReceive error (%d): %s", gIpLastErr, gIpLastErrStr);
writeLineEx(0, 2, "<%BASE_FILE_NAME%> TcpReceive error (%d): %s", gIpLastErr, gIpLastErrStr);
gSocket.Close();
gSocketState = CLOSED;
}
@ -151,7 +151,7 @@ void TcpRecv()
void TcpSnd(byte buffer[], word length)
{
char str[20*3];
//char str[20*3];
switch (gSocketState)
{
@ -159,18 +159,18 @@ void TcpSnd(byte buffer[], word length)
TcpConnectTo(gRemoteIP, gRemotePort);
if (gSocketState != OK)
{
writeLineEx(0, 2, "TcpSnd: Reconnecting failed!");
writeLineEx(0, 2, "<%BASE_FILE_NAME%> TcpSnd: Reconnecting failed!");
return;
}
case OK:
break;
default:
writeLineEx(0, 2, "TcpSnd: Socket status is not OK!");
writeLineEx(0, 2, "<%BASE_FILE_NAME%> TcpSnd: Socket status is not OK!");
return;
}
bin_to_strhex(buffer, str);
writeLineEx(0, 1, "<%NODE_NAME%> TcpSnd: %s (Länge: %d)", str, length);
//bin_to_strhex(buffer, str);
//writeLineEx(0, 1, "<%BASE_FILE_NAME%> TcpSnd: %s (Länge: %d)", str, length);
if (gSocket.Send(buffer, length) != 0)
{
@ -179,7 +179,7 @@ void TcpSnd(byte buffer[], word length)
if (gIpLastErr != WSA_IO_PENDING)
{
gSocket.GetLastSocketErrorAsString(gIpLastErrStr, elcount(gIpLastErrStr));
writeLineEx(0, 2, "<%NODE_NAME%> TcpSnd error (%d): %s", gIpLastErr, gIpLastErrStr);
writeLineEx(0, 2, "<%BASE_FILE_NAME%> TcpSnd error (%d): %s", gIpLastErr, gIpLastErrStr);
gSocket.Close();
gSocketState = CLOSED;
}

View file

@ -29,7 +29,7 @@ dword SetupIp(char Local_IP[])
long error;
adapterCount = IpGetAdapterCount();
adapterIndex = @sysvar::TCPIP::AdapterIndex;
adapterIndex = @sysvar::Config::TcpIp::AdapterIndex;
switch (adapterCount)
{

View file

@ -116,7 +116,7 @@ void UdpRecv()
void UdpSnd(byte buffer[], word length)
{
char str[20*3];
//char str[20*3];
switch (gSocketState)
{
@ -134,8 +134,8 @@ void UdpSnd(byte buffer[], word length)
return;
}
bin_to_strhex(buffer, str);
writeLineEx(0, 1, "<%BASE_FILE_NAME%> UdpSnd: %s (Länge: %d)", str, length);
//bin_to_strhex(buffer, str);
//writeLineEx(0, 1, "<%BASE_FILE_NAME%> UdpSnd: %s (Länge: %d)", str, length);
if (gSocket.SendTo(gRemoteIP, gRemotePort, buffer, length) != 0)
{

File diff suppressed because it is too large Load diff