Jonny007-MKD
93dd56469d
Introduced loops to automatically split requests that are too large for Modbus ModbusClient.can Modified Modbus events so that the split requests (see above) will be written at the correct position in sys vars ModbusFunctions.cin DeviceInformation.cin Introduced new file that will handle most device specific things ModbusStructs.cin Introduced new constants with maximum Modbus values MakeConfig.can Increment IP address with swapDWord Moved detection stuff to DeviceInformation.cin
285 lines
7.6 KiB
Plaintext
285 lines
7.6 KiB
Plaintext
/*@!Encoding:1252*/
|
|
variables
|
|
{
|
|
word gDevOutputBitAddr, gDevOutputRegAddr;
|
|
word gDevInputBitAddr, gDevInputRegAddr;
|
|
word gDevBitMaxCount, gDevRegMaxCount;
|
|
word gDevReceiveWindow;
|
|
|
|
enum Vendor
|
|
{
|
|
Wago = 23,
|
|
BuR = 2
|
|
};
|
|
struct deviceIOs
|
|
{
|
|
byte InputRegisters;
|
|
word InputBits;
|
|
byte OutputRegisters;
|
|
word OutputBits;
|
|
char Modules[1024];
|
|
};
|
|
struct device // A structure that contains information about an Modbus device
|
|
{
|
|
char Ip[16]; // String: The IP address
|
|
char IpLsb[4]; // String: The last byte of the IP address. Used as index of node name
|
|
char IpNet[4]; // String: The second last byte of the IP. Used as index of net
|
|
enum Vendor Vendor; // The Vendor (Wago / B&R)
|
|
word SerialCode; // Serial Code
|
|
word DeviceCode; // Device Code
|
|
struct deviceIOs DeviceIOs; // A structure with more information about IOs
|
|
};
|
|
}
|
|
|
|
// This is for the normal client and for making the sysvars
|
|
/// <ModbusClient>
|
|
void DeviceInit(byte vendor)
|
|
{
|
|
switch ((enum Vendor) vendor)
|
|
{
|
|
case Wago:
|
|
gDevInputBitAddr = 0x0000; // Wago inputs start at 0x000
|
|
gDevInputRegAddr = 0x0000;
|
|
gDevOutputBitAddr = 0x0200; // Wago outputs start at 0x200
|
|
gDevOutputRegAddr = 0x0200;
|
|
gDevBitMaxCount = 0x0100; // Wago allows up to 256 inputs
|
|
gDevRegMaxCount = 0x0100;
|
|
gDevReceiveWindow = 5; // Wago can handle 5 requests simultaneously
|
|
break;
|
|
case BuR:
|
|
gDevInputBitAddr = 0x0000; // B&R inputs start at 0x000
|
|
gDevInputRegAddr = 0x0000;
|
|
gDevOutputBitAddr = 0x0000; // B&R digital outputs start at 0x000
|
|
gDevOutputRegAddr = 0x0800; // B&R analog outputs start at 0x800
|
|
gDevBitMaxCount = 0x4000; // B&R allows up to 16348 digital inputs
|
|
gDevRegMaxCount = 0x0800; // B&R allows up to 2048 analog inputs
|
|
gDevReceiveWindow = 1; // B&R can only handle 1 request at a time
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// This is for making the sysvars (MakeConfig)
|
|
/// <MakeConfig>
|
|
void DeviceParseCode(word dev, enum Vendor vendor, struct deviceIOs dios)
|
|
{
|
|
byte input;
|
|
byte numChannels;
|
|
char module[10];
|
|
|
|
switch(vendor)
|
|
{
|
|
case Wago: // if this is a Wago device
|
|
if (dev & 0x8000) // Digital Module
|
|
{
|
|
numChannels = (dev >> 8) & 0x007F;
|
|
|
|
if (dev & 0x0001) // Input Module
|
|
{
|
|
input = 1;
|
|
strncpy(module, "DI%d,", elCount(module));
|
|
}
|
|
else if (dev & 0x0002) // Output Module
|
|
{
|
|
input = 0;
|
|
strncpy(module, "DO%d,", elCount(module));
|
|
}
|
|
else // mhm. What is it?
|
|
{
|
|
writeDbg(AlgoError, "ParseDeviceCode: Device code 0x%X cannot be decoded", dev);
|
|
OnModbusClientPanics(DeviceCodeUnknown);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// http://www.wago.com/wagoweb/documentation/navigate/nm0dx__d.htm
|
|
// http://www.wago.com/wagoweb/documentation/navigate/nm0dy__d.htm
|
|
switch (dev)
|
|
{
|
|
case 881: // devices that have no inputs/outputs
|
|
return;
|
|
case 491: // devices that have 1 inputs
|
|
input = 1;
|
|
numChannels = 1;
|
|
break;
|
|
case 452: // devices that have 2 inputs
|
|
case 465:
|
|
case 470:
|
|
case 472:
|
|
case 480:
|
|
case 454:
|
|
case 473:
|
|
case 474:
|
|
case 466:
|
|
case 484:
|
|
case 485:
|
|
case 492:
|
|
case 482:
|
|
case 475:
|
|
case 467:
|
|
case 477:
|
|
case 478:
|
|
case 456:
|
|
case 479:
|
|
case 476:
|
|
case 483:
|
|
case 461:
|
|
case 481:
|
|
case 462:
|
|
case 469:
|
|
case 487:
|
|
input = 1;
|
|
numChannels = 2;
|
|
break;
|
|
case 493: // devices that have 3 inputs
|
|
case 494:
|
|
case 495:
|
|
input = 1;
|
|
numChannels = 3;
|
|
break;
|
|
case 459: // devices that have 4 inputs
|
|
case 453:
|
|
case 455:
|
|
case 468:
|
|
case 457:
|
|
case 464:
|
|
case 460:
|
|
case 463:
|
|
input = 1;
|
|
numChannels = 4;
|
|
break;
|
|
case 552: // devices that have 2 inputs
|
|
case 585:
|
|
case 563:
|
|
case 554:
|
|
case 550:
|
|
case 560:
|
|
case 562:
|
|
case 556:
|
|
input = 0;
|
|
numChannels = 2;
|
|
case 555: // devices that have 4 inputs
|
|
case 553:
|
|
case 557:
|
|
case 559:
|
|
input = 0;
|
|
numChannels = 4;
|
|
default: // unknown device. Ouch!
|
|
writeDbg(AlgoInfo, "Connected device: 750-%d", dev);
|
|
return;
|
|
}
|
|
if (input)
|
|
strncpy(module, "AI%d,", elCount(module));
|
|
else
|
|
strncpy(module, "AO%d,", elCount(module));
|
|
}
|
|
break; // switch(vendor)
|
|
default:
|
|
writeDbg(AlgoError, "ParseDeviceCode: Unknown vendor id: %d", vendor);
|
|
OnModbusClientPanics(VendorIdUnknown);
|
|
return;
|
|
}
|
|
|
|
snprintf(module, elCount(module), module, numChannels);
|
|
strncat(dios.Modules, module, elCount(dios.Modules));
|
|
}
|
|
|
|
// This function requests more information from the device and return the number of expected results
|
|
/// <MakeConfig>
|
|
byte DeviceGetInformation(enum Vendor vendor)
|
|
{
|
|
switch (vendor)
|
|
{
|
|
case Wago:
|
|
ModbusReadRegisters(0x2011, 1); // Serial Code
|
|
ModbusReadRegisters(0x2012, 1); // Device Code
|
|
ModbusReadRegisters(0x1022, 1); // Number of AOs (= size in bits)
|
|
ModbusReadRegisters(0x1023, 1); // Number of AIs (= size in bits)
|
|
ModbusReadRegisters(0x1024, 1); // Number of DOs
|
|
ModbusReadRegisters(0x1025, 1); // Number of DIs
|
|
ModbusReadRegisters(0x2030, 65); // Connected IO 1
|
|
ModbusReadRegisters(0x2031, 64); // Connected IO 2
|
|
ModbusReadRegisters(0x2032, 64); // Connected IO 3
|
|
ModbusReadRegisters(0x2033, 63); // Connected IO 4
|
|
return 10;
|
|
case BuR:
|
|
ModbusReadRegisters(0x1083, 1); // Product Code
|
|
ModbusReadRegisters(0x1101, 1); // Number of AIs
|
|
ModbusReadRegisters(0x1103, 1); // Number of AOs
|
|
ModbusReadRegisters(0x1105, 1); // Number of DIs
|
|
ModbusReadRegisters(0x1107, 1); // Number of DOs
|
|
return 5;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// This function parses the received registers
|
|
/// <MakeConfig>
|
|
void DeviceParseRegister(struct device device, word address, word data[], word count)
|
|
{
|
|
byte i;
|
|
|
|
switch (device.Vendor)
|
|
{
|
|
case Wago:
|
|
// Parse the received data
|
|
switch (address)
|
|
{
|
|
case 0x2011:
|
|
device.serialCode = data[0];
|
|
break;
|
|
case 0x2012:
|
|
device.deviceCode = data[0];
|
|
break;
|
|
case 0x1022:
|
|
device.DeviceIOs.OutputRegisters = data[0] / 16; // Wago returns the size in bits allocated by the module
|
|
break;
|
|
case 0x1023:
|
|
device.DeviceIOs.InputRegisters = data[0] / 16;
|
|
break;
|
|
case 0x1024:
|
|
device.DeviceIOs.OutputBits = data[0];
|
|
break;
|
|
case 0x1025:
|
|
device.DeviceIOs.InputBits = data[0];
|
|
break;
|
|
case 0x2030:
|
|
case 0x2031:
|
|
case 0x2032:
|
|
case 0x2033:
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (data[i] == 0x0000) // No more devices --> end
|
|
break;
|
|
DeviceParseCode(data[i], device.Vendor, device.DeviceIOs);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case BuR:
|
|
// Parse the received data
|
|
switch (address)
|
|
{
|
|
case 0x1083:
|
|
device.serialCode = data[0];
|
|
break;
|
|
case 0x1101:
|
|
device.DeviceIOs.InputRegisters = data[0];
|
|
break;
|
|
case 0x1103:
|
|
device.DeviceIOs.OutputRegisters = data[0];
|
|
break;
|
|
case 0x1105:
|
|
device.DeviceIOs.InputBits = data[0] * 8; // Unfortunately this is quite imprecise:
|
|
// in the process image one module will always fill a whole number of bytes.
|
|
// So 4 12DI modules not allocate not 4*12 bit = 6 byte, but 4*16 bit = 64 bit = 8 byte
|
|
// See Modbus X20BC0087 documentation v1.11 p. 22
|
|
break;
|
|
case 0x1107:
|
|
device.DeviceIOs.OutputBits = data[0] * 8;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
} |