Bachelorthesis/Modbus-CAPL/include/CAPL/include/DeviceInformation.cin
Jonny007-MKD 93dd56469d ModbusClientCommon.cin
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
2014-06-17 14:21:45 +00:00

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;
}
}