/* This example application sets up an RTU server and polls from modbus requests This server supports the following function codes: FC 01 (0x01) Read Coils FC 03 (0x03) Read Holding Registers FC 15 (0x0F) Write Multiple Coils FC 16 (0x10) Write Multiple registers */ #include "nanomodbus.h" // The data model of this sever will support coils addresses 0 to 100 and registers addresses from 0 to 32 #define COILS_ADDR_MAX 100 #define REGS_ADDR_MAX 32 // Our RTU address #define RTU_SERVER_ADDRESS 1 // A single nmbs_bitfield variable can keep 2000 coils nmbs_bitfield server_coils = {0}; uint16_t server_registers[REGS_ADDR_MAX] = {0}; int32_t read_serial(uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg) { Serial.setTimeout(byte_timeout_ms); return Serial.readBytes(buf, count); } int32_t write_serial(const uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg) { Serial.setTimeout(byte_timeout_ms); return Serial.write(buf, count); } void onError() { // Make the LED blink on error while (true) { digitalWrite(LED_BUILTIN, HIGH); delay(1000); digitalWrite(LED_BUILTIN, LOW); delay(1000); } } nmbs_error handle_read_coils(uint16_t address, uint16_t quantity, nmbs_bitfield coils_out) { if (address + quantity > COILS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS; // Read our coils values into coils_out for (int i = 0; i < quantity; i++) { bool value = nmbs_bitfield_read(server_coils, address + i); nmbs_bitfield_write(coils_out, i, value); } return NMBS_ERROR_NONE; } nmbs_error handle_write_multiple_coils(uint16_t address, uint16_t quantity, const nmbs_bitfield coils) { if (address + quantity > COILS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS; // Write coils values to our server_coils for (int i = 0; i < quantity; i++) { nmbs_bitfield_write(server_coils, address + i, nmbs_bitfield_read(coils, i)); } return NMBS_ERROR_NONE; } nmbs_error handler_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t* registers_out) { if (address + quantity > REGS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS; // Read our registers values into registers_out for (int i = 0; i < quantity; i++) registers_out[i] = server_registers[address + i]; return NMBS_ERROR_NONE; } nmbs_error handle_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t* registers) { if (address + quantity > REGS_ADDR_MAX + 1) return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS; // Write registers values to our server_registers for (int i = 0; i < quantity; i++) server_registers[address + i] = registers[i]; return NMBS_ERROR_NONE; } void setup() { pinMode (LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); Serial.begin(9600); while (!Serial); } void loop() { nmbs_platform_conf platform_conf = {0}; platform_conf.transport = NMBS_TRANSPORT_RTU; platform_conf.read = read_serial; platform_conf.write = write_serial; platform_conf.arg = NULL; // These functions are defined in server.h nmbs_callbacks callbacks = {0}; callbacks.read_coils = handle_read_coils; callbacks.write_multiple_coils = handle_write_multiple_coils; callbacks.read_holding_registers = handler_read_holding_registers; callbacks.write_multiple_registers = handle_write_multiple_registers; // Create the modbus server nmbs_t nmbs; nmbs_error err = nmbs_server_create(&nmbs, RTU_SERVER_ADDRESS, &platform_conf, &callbacks); if (err != NMBS_ERROR_NONE) { onError(); } nmbs_set_read_timeout(&nmbs, 1000); nmbs_set_byte_timeout(&nmbs, 100); while (true) { err = nmbs_server_poll(&nmbs); // This will probably never happen, since we don't return < 0 in our platform funcs if (err == NMBS_ERROR_TRANSPORT) break; } // Turn off the led at the end digitalWrite(LED_BUILTIN, LOW); // No need to destroy the nmbs instance, bye bye exit(0); }