====== LamaPLC: Arduino code collection ======
===== Modbus code collection =====
==== Convert 2 registers to float ====
call: [float] = //modbus_2regs_2_float//([1.register], [2.register]) \\
float modbus_2regs_2_float(uint16_t a, uint16_t b) {
uint32_t combined = ((uint32_t)a << 16) | b;
float f;
memcpy(&f, &combined, sizeof f);
return f;
}
call: [float] = //modbus_2regs_2_float//([first register]) \\
float modbus_2regs_2_float(uint16_t addr) {
uint16_t a = node.getResponseBuffer(addr);
uint16_t b = node.getResponseBuffer(addr+1);
uint32_t combined = ((uint32_t)a << 16) | b;
float f;
memcpy(&f, &combined, sizeof f);
return f;
}
==== Convert float 2 registers ====
def: int16_t regs[2]; \\
call: //modbus_set_float//([float], regs); \\
back: register1: regs[1], register2: [regs[2] \\
void modbus_set_float(float f, uint16_t *dest)
{
uint32_t i = 0;
memcpy(&i, &f, sizeof(uint32_t));
dest[0] = (uint16_t)i;
dest[1] = (uint16_t)(i >> 16);
}
Source: https://docs.ros.org/en/melodic/api/libmodbus/html/modbus-data_8c.html
==== Convert 2 registers to int32 ====
uint32_t make_32bit_word(uint16_t hi_word, uint16_t lo_word)
{
uint16_t words_16bit[2] = {hi_word, lo_word};
uint32_t word_32bit = 0;
memcpy(&word_32bit, words_16bit, 4);
return word_32bit;
}
int32 convert direct to float by division by a thousand: \\
float make_float_32bit_word(uint16_t hi_word, uint16_t lo_word)
{
uint16_t words_16bit[2] = {hi_word, lo_word};
uint32_t word_32bit = 0;
float back;
memcpy(&word_32bit, words_16bit, 4);
back = word_32bit / 1000.0;
return back;
}
call: [float] = //make_float_32bit_word//([first reg]) \\
float make_float_32bit_word(uint16_t addr)
{
uint16_t words_16bit[2];
words_16bit[1] = node.getResponseBuffer(addr);
words_16bit[0] = node.getResponseBuffer(addr+1);
uint32_t word_32bit = 0;
float back;
memcpy(&word_32bit, words_16bit, 4);
back = word_32bit / 1000.0;
return back;
}
==== Float to / from one register ====
Note: The maximum value of the int16 type is 32767, so in this format only the value range 0 .. 327.67 can be stored with 2 decimal places!
// float 2 reg
holdingRegs[REG_HUM] = (int16_t)(Humidity * 100);
// back one reg to float
float Humidity = holdingRegs[REG_HUM] / 100.0;
==== Modbus #define conversions ====
#define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
#define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
#define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
(((int64_t) tab_int16[(index)] << 48) | ((int64_t) tab_int16[(index) + 1] << 32) | \
((int64_t) tab_int16[(index) + 2] << 16) | (int64_t) tab_int16[(index) + 3])
#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) \
(((int32_t) tab_int16[(index)] << 16) | (int32_t) tab_int16[(index) + 1])
#define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) \
(((int16_t) tab_int8[(index)] << 8) | (int16_t) tab_int8[(index) + 1])
#define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
do { \
((int8_t *) (tab_int8))[(index)] = (int8_t) ((value) >> 8); \
((int8_t *) (tab_int8))[(index) + 1] = (int8_t) (value); \
} while (0)
#define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
do { \
((int16_t *) (tab_int16))[(index)] = (int16_t) ((value) >> 16); \
((int16_t *) (tab_int16))[(index) + 1] = (int16_t) (value); \
} while (0)
#define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
do { \
((int16_t *) (tab_int16))[(index)] = (int16_t) ((value) >> 48); \
((int16_t *) (tab_int16))[(index) + 1] = (int16_t) ((value) >> 32); \
((int16_t *) (tab_int16))[(index) + 2] = (int16_t) ((value) >> 16); \
((int16_t *) (tab_int16))[(index) + 3] = (int16_t) (value); \
} while (0)
==== Modbus messages ====
bool getResultMsg(uint8_t result)
{
String tmpstr2;
switch (result) {
case node.ku8MBSuccess:
return true;
break;
case node.ku8MBIllegalFunction:
tmpstr2 = "Illegal Function";
break;
case node.ku8MBIllegalDataAddress:
tmpstr2 = "Illegal Data Address";
break;
case node.ku8MBIllegalDataValue:
tmpstr2 = "Illegal Data Value";
break;
case node.ku8MBSlaveDeviceFailure:
tmpstr2 = "Slave Device Failure";
break;
case node.ku8MBInvalidSlaveID:
tmpstr2 = "Invalid Slave ID";
break;
case node.ku8MBInvalidFunction:
tmpstr2 = "Invalid Function";
break;
case node.ku8MBResponseTimedOut:
tmpstr2 = "Response Timed Out";
break;
case node.ku8MBInvalidCRC:
tmpstr2 = "Invalid CRC";
break;
default:
tmpstr2 = "Unknown error: " + String(result);
break;
}
Serial.println(tmpstr2);
return false;
}
===== General code collection =====
==== MAC random generator ====
Generate random MAC using pseudo random generator, bytes 0, 1 and 2 are static (MAC_START), bytes 3, 4 and 5 are generated randomly
void generateMac() {
// Marsaglia algorithm from https://github.com/RobTillaart/randomHelpers
seed1 = 36969L * (seed1 & 65535L) + (seed1 >> 16);
seed2 = 18000L * (seed2 & 65535L) + (seed2 >> 16);
uint32_t randomBuffer = (seed1 << 16) + seed2; /* 32-bit random */
memcpy(data.mac, MAC_START, 3); // set first 3 bytes
for (byte i = 0; i < 3; i++) {
data.mac[i + 3] = randomBuffer & 0xFF; // random last 3 bytes
randomBuffer >>= 8;
}
}