From f790d3ddde9c8b8c5b80684ebf768e6dc594e4dd Mon Sep 17 00:00:00 2001 From: Jan Mrna Date: Fri, 17 Jun 2022 09:22:32 +0200 Subject: [PATCH] Deleted old modbus files --- fw/Core/Inc/modbus.h | 231 ----------------------- fw/Core/Src/modbus.c | 431 ------------------------------------------- 2 files changed, 662 deletions(-) delete mode 100644 fw/Core/Inc/modbus.h delete mode 100644 fw/Core/Src/modbus.c diff --git a/fw/Core/Inc/modbus.h b/fw/Core/Inc/modbus.h deleted file mode 100644 index ff01f65..0000000 --- a/fw/Core/Inc/modbus.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * modbus.h - * - * Created on: Jul 18, 2021 - * Author: user - * - * Modbus slave RTU library (does NOT support ASCII and TCP) - * - * Useful links: - * https://www.picotech.com/library/oscilloscopes/modbus-serial-protocol-decoding - * https://ipc2u.com/articles/knowledge-base/modbus-rtu-made-simple-with-detailed-descriptions-and-examples/ - * https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf - * https://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf - * - * Note that byte order is big endian. - * - * USAGE: - * - * 1) Implement functions modbus_callback_function() and modbus_uart_transmit_function() - * - modbus_uart_transmit_function() sends data via UART - * - modbus_callback_function() does the real work: read sensors, set outputs... - * note that when filling buffers (e.g. input_registers[]) user must - * ensure that all data is big-endian - * These functions are implementation-specific. - * 2) Set device address (variable modbus_device_address); you can do this either - * - setting modbus_device_address directly (modbus.h needs to be included, duh) - * - using modbus_set_device_address(uint8_t address) function - * Or you can leave address as-is (MODBUS_DEFAULT_SLAVE_ADDRESS) and set it via - * Modbus during runtime - * 3) Call modbus_process_msg() after message reception; you need to observe Modbus RTU timing: - * - pauses between chars in frame are less or equal to 1.5 char - * - pauses between frames are at least 3.5 chars (of silence) - * For more information see section 2.5.1.1 (MODBUS Message RTU Framing) - * in "MODBUS over Serial Line: Specification and Implementation Guide" - * - */ - -#ifndef SRC_MODBUS_H_ -#define SRC_MODBUS_H_ - -#include "stdint.h" -#include "stddef.h" -#include "string.h" - -/* - * Defines & macros - */ - -#define MODBUS_BROADCAST_ADDR 0 -#define MODBUS_DEFAULT_SLAVE_ADDRESS 247 /* 255 may be used for bridge device */ -/* minimal frame length is 4 bytes: 1 B slave address, 1 B function code, 2 B CRC */ -#define MODBUS_MINIMAL_FRAME_LEN 4 -#define MODBUS_MINIMAL_READWRITE_LEN 4 -#define MODBUS_MINIMAL_WRITE_MULTIPLE_LEN 5 -#define MODBUS_READ_DEVICE_ID_REQUEST_LEN 4 -#define MODBUS_READ_DEVICE_ID_RESPONSE_HEADER_LEN 4 -#define MODBUS_READ_DEVICE_ID_RESPONSE_OFFSET 3 -#define MODBUS_MAX_RTU_FRAME_SIZE 256 -#define MODBUS_BUFFER_SIZE MODBUS_MAX_RTU_FRAME_SIZE /* alias */ -#define MODBUS_ERROR_FLAG 0x80 -#define MODBUS_MAX_REGISTERS 125 -/* read device id constants */ -#define MODBUS_MEI 0x0E -#define MODBUS_DEVICE_ID_INDIVIDUAL_ACCESS_FLAG 0x80 -#define MODBUS_MORE_FOLLOWS 0xFF -#define MODBUS_NO_MORE_FOLLOWS 0x00 -#define MODBUS_BASIC_OBJECT_COUNT 3 -#define MODBUS_REGULAR_OBJECT_COUNT 7 - -/* - * Return values - */ - -#define MODBUS_OK 0 -#define MODBUS_ERROR -1 // generic error -#define MODBUS_ERROR_CRC -2 // checksum failed -#define MODBUS_ERROR_FRAME_INVALID -3 // invalid frame format / length -#define MODBUS_ERROR_OUT_OF_BOUNDS -4 // requested register is out of bounds -#define MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED -5 // function not implemented in callback -#define MODBUS_ERROR_REGISTER_NOT_IMPLEMENTED -6 // register not implemented in callback -#define MODBUS_ERROR_DEVICE_ID_NOT_IMPLEMENTED -7 - -/* - * Data types - */ - -/* Public functions codes (Modbus Application protocol specification, section 5.1) */ -typedef enum { - /* single bit access functions */ - MODBUS_READ_COILS = 1, - MODBUS_READ_DO = 1, // alias - MODBUS_READ_DISCRETE_INPUTS = 2, - MODBUS_READ_DI = 2, // alias - MODBUS_WRITE_SINGLE_COIL = 5, - MODBUS_WRITE_SINGLE_DO = 5, // alias - MODBUS_WRITE_MULTIPLE_COILS = 15, - MODBUS_WRITE_MULTIPLE_DO = 15, // alias - /* 16-bit access functions */ - MODBUS_READ_HOLDING_REGISTERS = 3, - MODBUS_READ_AO = 3, // alias - MODBUS_READ_INPUT_REGISTERS = 4, - MODBUS_READ_AI = 4, // alias - MODBUS_WRITE_SINGLE_REGISTER = 6, - MODBUS_WRITE_SINGLE_AO = 6, // alias - MODBUS_WRITE_MULTIPLE_REGISTERS = 16, - MODBUS_WRITE_MULTIPLE_AO = 16, // alias - MODBUS_MASK_WRITE_REGISTER = 22, - MODBUS_READ_WRITE_MULTIPLE_REGISTERS = 23, - MODBUS_READ_FIFO_QUEUE = 24, - /* file record access */ - MODBUS_READ_FILE_RECORD = 20, - MODBUS_WRITE_FILE_RECORD = 21, - /* diagnostics */ - MODBUS_READ_EXCEPTION_STATUS = 7, - MODBUS_DIAGNOSTIC = 8, /* sub codes: 00-18,20 */ - MODBUS_GET_COM_EVENT_COUNTER = 11, - MODBUS_GET_COM_EVENT_LOG = 12, - MODBUS_REPORT_SLAVE_ID = 17, - MODBUS_READ_DEVICE_IDENTIFICATION = 43, /* sub codes: 14 */ -} modbus_function_code_t; - -typedef enum { - MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 1, - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS = 2, - MODBUS_EXCEPTION_ILLEGAL_REGISTER_QUANTITY = 2, - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE = 3, - MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE = 4, - MODBUS_EXCEPTION_ACKNOWLEDGE = 5, - MODBUS_EXCEPTION_SLAVE_DEVICE_BUSY = 6, - MODBUS_EXCEPTION_MEMORY_PARITY_ERROR = 8, - MODBUS_EXCEPTION_GATEWAY_PATH_UNAVAILABLE = 10, - MODBUS_EXCEPTION_GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 11, - MODBUS_EXCEPTION_ILLEGAL_DEVICE_ID_CODE = 3 -} modbus_exception_code_t; - -typedef struct { - modbus_function_code_t function_code : 8; - uint16_t register_address; // e.g. first register of A0: 0 - uint16_t register_number; // e.g. first register of A0: 40001 - uint8_t register_count; // number of registers to be read/written - - modbus_exception_code_t exception; - - uint8_t broadcast; // 1 if broadcast, 0 otherwise - - union { - uint8_t buffer8b[MODBUS_MAX_RTU_FRAME_SIZE]; - uint16_t buffer16b[MODBUS_MAX_RTU_FRAME_SIZE/2]; - uint16_t input_registers[MODBUS_MAX_REGISTERS]; - uint16_t holding_registers[MODBUS_MAX_REGISTERS]; - int16_t input_registers_signed[MODBUS_MAX_REGISTERS]; - int16_t holding_registers_signed[MODBUS_MAX_REGISTERS]; - }; - - /* process device id */ - uint8_t read_device_id_code; - uint8_t object_id; -} modbus_transaction_t; - -typedef enum { - MODBUS_DO_START_NUMBER = 1, // Discrete output coils - MODBUS_DO_END_NUMBER = 9999, - MODBUS_DI_START_NUMBER = 10001, // Discrete input contacts - MODBUS_DI_END_NUMBER = 19999, - MODBUS_AI_START_NUMBER = 30001, // Analog input registers - MODBUS_AI_END_NUMBER = 39999, - MODBUS_AO_START_NUMBER = 40001, // Analog output (holding registers) - MODBUS_AO_END_NUMBER = 49999 -} modbus_register_number_t; - -typedef enum { - MODBUS_CONFORMITY_BASIC = 1, - MODBUS_CONFORMITY_REGULAR = 2, - MODBUS_CONFORMITY_EXTENDED = 3, - MODBUS_INDIVIDUAL_ACCESS = 4 /* not actually part of conformity, but I'll keep it here anyway */ -} modbus_conformity_level_t; - -/* Device ID datatypes */ -#define MODBUS_DEVICE_ID_OBJECT_NUM 7 -typedef struct { - union { - struct { - /* Basic category (mandatory part) */ - char *VendorName; - char *ProductCode; - char *MajorMinorRevision; - /* Regular category (optional part) */ - char *VendorUrl; - char *ProductName; - char *ModelName; - char *UserApplicationName; - /* Extended category (optional part) */ - // Nothing here yet! - } object_name; - char *object_id[MODBUS_DEVICE_ID_OBJECT_NUM]; - }; - uint8_t conformity_level; -} modbus_device_id_t; - -/* - * Global variables - */ - -/* device address: declared in modbus.c */ -extern uint8_t modbus_slave_address; - -/* shared modbus buffer; defined in modbus.c; may be used elsewhere in code */ -extern uint8_t modbus_buffer[]; - -/* modbus device id struct */ -extern modbus_device_id_t *modbus_device_id; - -/* - * Function prototypes - */ - -/* process message: should be called in when modbus message was received (e.g. in main.c) - * modbus_process_msg() may call following functions: - * - modbus_callback_function() if data readout is requested - * - modbus_uart_transmit_function() if response is required - * Both functions have to be implemented by user. - */ -int8_t modbus_slave_process_msg(const uint8_t *buffer, int len); -int8_t modbus_slave_init_device_id(modbus_device_id_t *device_id); -int8_t modbus_slave_set_address(uint8_t address); -/* modbus callback function type - should be implemented by user (e.g. in main.c) */ -int8_t modbus_slave_callback(modbus_transaction_t *transaction); -/* UART transmit function type - should be implemented by user (e.g. in main.c) */ -int8_t modbus_transmit_function(uint8_t *buffer, uint16_t data_len); - -#endif /* SRC_MODBUS_H_ */ diff --git a/fw/Core/Src/modbus.c b/fw/Core/Src/modbus.c deleted file mode 100644 index ddf37b6..0000000 --- a/fw/Core/Src/modbus.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * modbus.c - * - * Created on: Jul 18, 2021 - * Author: user - */ - -#include "modbus.h" - -/* - * Global variables - */ - -/* Modbus TX buffer; can be also used for RX in memory constrained systems (e.g. in main.c); - * NOTE if shared buffer is used for TX/RX, care must be taken to prevent writing into buffer - * during execution of modbus_process_message() */ -uint8_t modbus_buffer[MODBUS_MAX_RTU_FRAME_SIZE]; - -/* MODBUS device address */ -uint8_t modbus_slave_address = MODBUS_DEFAULT_SLAVE_ADDRESS; - -/* Device ID struct */ -modbus_device_id_t *modbus_device_id = NULL; - -/* - * CRC16 functions - * see https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf - * section 6.2.2 - */ - -/* CRC16 (without memory mapped values) - * taken from https://ctlsys.com/support/how_to_compute_the_modbus_rtu_message_crc/ */ -uint16_t modbus_CRC16(const uint8_t *buf, int len) -{ - uint16_t crc = 0xFFFF; - - for (int pos = 0; pos < len; pos++) { - crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc - - for (int i = 8; i != 0; i--) { // Loop over each bit - if ((crc & 0x0001) != 0) { // If the LSB is set - crc >>= 1; // Shift right and XOR 0xA001 - crc ^= 0xA001; - } else { // Else LSB is not set - crc >>= 1; // Just shift right - } - } - } - // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes) - return crc; -} - -/* - * Private functions - */ - -static uint8_t modbus_fill_device_id_objects(uint8_t *buffer, modbus_transaction_t *transaction) -{ - /* we assume buffer is 256 - MODBUS_READ_DEVICE_ID_RESPONSE_HEADER_LEN = 252 bytes long */ - /* find out how many objects we copy to buffer */ - int len; - uint8_t object_index = transaction->object_id; - uint8_t object_count; - uint8_t more_follows = MODBUS_NO_MORE_FOLLOWS; - uint8_t next_object_id; - uint8_t last_object; - const uint8_t max_len = 256 - MODBUS_READ_DEVICE_ID_RESPONSE_HEADER_LEN; - - /* last object index */ - if (transaction->read_device_id_code == MODBUS_CONFORMITY_BASIC) { - last_object = MODBUS_BASIC_OBJECT_COUNT; - } else if (transaction->read_device_id_code == MODBUS_CONFORMITY_REGULAR) { - last_object = MODBUS_REGULAR_OBJECT_COUNT; - /* extended not implemented */ -// } else if (transaction->read_device_id_code == MODBUS_CONFORMITY_EXTENDED){ -// last_object = MODBUS_EXTENDED_OBJECT_COUNT; - } else { - /* fallback: regular */ - last_object = MODBUS_REGULAR_OBJECT_COUNT; - } - last_object--; // we need index - /* copy as many objects as possible */ - do { - /* copy object */ - int object_len = strlen(modbus_device_id->object_id[object_index]); - if (len + object_len + 2 > max_len) { - more_follows = MODBUS_MORE_FOLLOWS; - next_object_id = object_index; - break; - } - /* offset is for "more follows", "next object id", "object count" */ - buffer[MODBUS_READ_DEVICE_ID_RESPONSE_OFFSET + len++] = object_index; - buffer[MODBUS_READ_DEVICE_ID_RESPONSE_OFFSET + len++] = object_len; - /* note that string copied to buffer is not null-terminated */ - strncpy((char*)(buffer + len), (char*)modbus_device_id->object_id[object_index++], object_len); - len += object_len; - object_count++; - } while (object_index < last_object); - buffer[0] = more_follows; - buffer[1] = next_object_id; - buffer[2] = object_count; - return MODBUS_READ_DEVICE_ID_RESPONSE_OFFSET + len; -} - -/* here we assume buffer has minimal size of MODBUS_MAX_RTU_FRAME_SIZE; - * this function is private, so hopefully it's going to be ok */ -static int8_t modbus_transaction_to_buffer(uint8_t *buffer, uint8_t *msg_len, modbus_transaction_t *transaction) -{ - uint16_t crc16; - uint8_t byte_count; - uint8_t buffer_pos = 0; - - // TODO use relative indices (increments) instead of absolute - buffer[buffer_pos++] = modbus_slave_address; - buffer[buffer_pos++] = transaction->function_code; - *msg_len = 5; - - if (transaction->function_code & MODBUS_ERROR_FLAG) { - /* sending error reply */ - buffer[buffer_pos++] = transaction->exception; - } else { - switch (transaction->function_code) { - case MODBUS_READ_HOLDING_REGISTERS: - case MODBUS_READ_INPUT_REGISTERS: - byte_count = transaction->register_count * 2; - buffer[buffer_pos++] = byte_count; - *msg_len = byte_count + 5; - for (int i = 0; i < transaction->register_count; i++) { - // TODO endianness handling - /* buffer16b is alias for both holding and input register buffers */ - buffer[buffer_pos++] = transaction->buffer16b[i] >> 8; - buffer[buffer_pos++] = transaction->buffer16b[i] & 0xff; - } - break; - case MODBUS_WRITE_SINGLE_REGISTER: - buffer[buffer_pos++] = (uint8_t) (transaction->register_address >> 8); - buffer[buffer_pos++] = (uint8_t) transaction->register_address; - buffer[buffer_pos++] = (uint8_t) (transaction->holding_registers[0] >> 8); - buffer[buffer_pos++] = (uint8_t) transaction->holding_registers[0]; - *msg_len = 8; /* includes 2 bytes for CRC */ - break; - case MODBUS_WRITE_MULTIPLE_REGISTERS: - buffer[buffer_pos++] = (uint8_t) (transaction->register_address >> 8); - buffer[buffer_pos++] = (uint8_t) transaction->register_address; - buffer[buffer_pos++] = (uint8_t) (transaction->register_count >> 8); - buffer[buffer_pos++] = (uint8_t) transaction->register_count; - *msg_len = 8; /* includes 2 bytes for CRC */ - break; - case MODBUS_READ_DEVICE_IDENTIFICATION: - /* MEI type */ - buffer[buffer_pos++] = MODBUS_MEI; - /* read device id */ - buffer[buffer_pos++] = transaction->read_device_id_code; - /* conformity level */ - buffer[buffer_pos++] = modbus_device_id->conformity_level; - /* fill buffer with as many objects as possible */ - *msg_len = modbus_fill_device_id_objects(buffer+buffer_pos, transaction); - *msg_len += 7; /* includes 2 bytes for CRC */ - break; - } - } - crc16 = modbus_CRC16(buffer, buffer_pos); /* last two bytes is the checksum itself */ - buffer[buffer_pos++] = crc16 & 0xff; - buffer[buffer_pos++] = crc16 >> 8; - return MODBUS_OK; -} - -static int8_t modbus_process_device_id_request(const uint8_t *buffer, int len, modbus_transaction_t *transaction) -{ - uint8_t MEI_type; - uint8_t read_device_id_code; - uint8_t object_id; - uint8_t buffer_pos = 0; - - if (transaction->broadcast == 1) { - /* Read device ID broadcast - invalid; ignore (master will get timeout) */ - return MODBUS_ERROR; - } - if (modbus_device_id == NULL) { - /* modbus_device_id not initialized; user should use modbus_slave_init_device_id() first */ - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_DEVICE_ID_CODE; - return MODBUS_OK; - } - if (len < MODBUS_READ_DEVICE_ID_REQUEST_LEN) { - /* frame too short, ignore */ - return MODBUS_ERROR; - } - /* next byte should be MEI = 0x0E */ - MEI_type = buffer[buffer_pos++]; - if (MEI_type != MODBUS_MEI) { - /* invalid MEI, ignore. I have no idea what MEI does, but it should always be 0x0E */ - return MODBUS_ERROR; - } - /* next byte is read device id code */ - read_device_id_code = buffer[buffer_pos++]; - /* read device id code can only have values 1,2,3,4 */ - if (read_device_id_code < 1 || read_device_id_code > 4) { - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_DEVICE_ID_CODE; - return MODBUS_OK; - } - transaction->read_device_id_code = read_device_id_code; - /* next byte is object id */ - object_id = buffer[buffer_pos++]; - transaction->object_id = object_id; - if (object_id > MODBUS_DEVICE_ID_OBJECT_NUM) { - /* illegal object ID */ - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; - return MODBUS_OK; - } - /* Message processed */ - return MODBUS_OK; -} - -/* returns ERROR only when no response to master is needed */ -static int8_t modbus_process_read_write_request(const uint8_t *buffer, int len, modbus_transaction_t *transaction) -{ - uint8_t byte_count; - int8_t callback_result; - uint8_t buffer_pos = 0; - - /* set starting register number */ - switch (transaction->function_code) { - /* coils */ - case MODBUS_READ_DO: - case MODBUS_WRITE_SINGLE_DO: - case MODBUS_WRITE_MULTIPLE_DO: - transaction->register_number = MODBUS_DO_START_NUMBER; - break; - /* discrete inputs */ - case MODBUS_READ_DI: - transaction->register_number = MODBUS_DI_START_NUMBER; - break; - /* input registers */ - case MODBUS_READ_AI: - transaction->register_number = MODBUS_AI_START_NUMBER; - break; - /* holding registers */ - case MODBUS_READ_AO: - case MODBUS_WRITE_SINGLE_AO: - case MODBUS_WRITE_MULTIPLE_AO: - case MODBUS_READ_WRITE_MULTIPLE_REGISTERS: - transaction->register_number = MODBUS_AO_START_NUMBER; - break; - } - - #define MODBUS_FLAG_WRITE 0x01 - #define MODBUS_FLAG_SINGLE 0x02 - uint8_t flags = 0x00; - - /* process message */ - switch (transaction->function_code) { - case MODBUS_WRITE_SINGLE_COIL: - case MODBUS_WRITE_SINGLE_REGISTER: /* holding register */ - flags |= MODBUS_FLAG_SINGLE; - case MODBUS_WRITE_MULTIPLE_COILS: - case MODBUS_WRITE_MULTIPLE_REGISTERS: - flags |= MODBUS_FLAG_WRITE; - case MODBUS_READ_DISCRETE_INPUTS: - case MODBUS_READ_COILS: - case MODBUS_READ_INPUT_REGISTERS: - case MODBUS_READ_HOLDING_REGISTERS: - if (len < MODBUS_MINIMAL_READWRITE_LEN) { - /* buffer too short to contain everything we need */ - return MODBUS_ERROR; - } - transaction->register_address = (buffer[buffer_pos] << 8) | buffer[buffer_pos + 1]; - buffer += 2; - // TODO check length! - if (flags & MODBUS_FLAG_WRITE) { - if (flags & MODBUS_FLAG_SINGLE) { - transaction->holding_registers[0] = (buffer[buffer_pos] << 8) | buffer[buffer_pos + 1]; - buffer_pos += 2; - } else { - /* Write multiple registers */ - transaction->register_count = (buffer[buffer_pos] << 8) | buffer[buffer_pos + 1]; - buffer_pos += 2; - if (len < MODBUS_MINIMAL_WRITE_MULTIPLE_LEN) { - return MODBUS_ERROR; - } - byte_count = buffer[buffer_pos++]; - if (transaction->register_count > 123 || 2*transaction->register_count != byte_count) { - /* Max number of register is defined by Modbus_Application_Protocol_V1_1b, section 6.12 */ - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_REGISTER_QUANTITY; - } else { - if (len < MODBUS_MINIMAL_WRITE_MULTIPLE_LEN + byte_count) { - return MODBUS_ERROR; - } - for (uint8_t i = 0; i < transaction->register_count; i++) { - transaction->holding_registers[i] = (buffer[buffer_pos] << 8) | buffer[buffer_pos + 1]; - buffer_pos += 2; - } - } - } - } else { - transaction->register_count = (buffer[buffer_pos] << 8) | buffer[buffer_pos + 1]; - buffer_pos += 2; - if ( - transaction->register_count < 1 || - transaction->register_count > MODBUS_MAX_REGISTERS - ) { - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE; - } - } - // add offset to register number - transaction->register_number += transaction->register_address; - break; - default: - /* function code not known / not implemented, reply with - * ExceptionCode 1 */ - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_FUNCTION; - break; - } - /* data in modbus_buffer have been processed and buffer can be re-used for TX */ - /* handle reply */ - if (transaction->exception != 0) { - /* indicate error */ - transaction->function_code |= MODBUS_ERROR_FLAG; - } else { - callback_result = modbus_slave_callback(transaction); - /* error handling */ - if (callback_result != MODBUS_OK) { - transaction->function_code |= MODBUS_ERROR_FLAG; - if (callback_result == MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED) { - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_FUNCTION; - } else if (callback_result == MODBUS_ERROR_REGISTER_NOT_IMPLEMENTED) { - transaction->exception = MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; - } - } - } - return MODBUS_OK; -} - -/* - * Public function definitions - */ - -int8_t modbus_slave_set_address(uint8_t address) -{ - if (address == 0) { - /* address 0 is broadcast address */ - return MODBUS_ERROR; - } - modbus_slave_address = address; - return MODBUS_OK; -} - - -int8_t modbus_slave_process_msg(const uint8_t *buffer, int len) -{ - - - /* - * TODO list: - * - * 1) check that errors and exceptions are handled according to Modbus_Application_Protocol_V1_1b.pdf - * 2) buffer overflow prevention: for each function code, check that buffer is long enough - */ - - - /* transaction holds message context and content: - * it wraps all necessary buffers and variables */ - modbus_transaction_t transaction; - uint8_t buffer_pos = 0; - - if (len < MODBUS_MINIMAL_FRAME_LEN) { - /* frame too short; return error (no reply needed) */ - return MODBUS_ERROR_FRAME_INVALID; - } - /* check CRC first */ - uint16_t crc_received = (buffer[len - 1] << 8) | buffer[len - 2]; - uint16_t crc_calculated = modbus_CRC16(buffer, len - 2); - if (crc_received != crc_calculated) { - /* CRC mismatch, return error (no reply needed) */ - return MODBUS_ERROR_CRC; - } - /* check if address matches ours */ - uint8_t address = buffer[buffer_pos++]; - transaction.broadcast = (address == MODBUS_BROADCAST_ADDR); - if (address != modbus_slave_address && transaction.broadcast != 1) { - /* Message is not for us (no reply needed) */ - return MODBUS_OK; - } - /* get function code */ - transaction.function_code = buffer[buffer_pos++]; - transaction.exception = 0; - uint8_t request_processing_result; - if (transaction.function_code == MODBUS_READ_DEVICE_IDENTIFICATION) { - /* Read device ID request is quite complicated, therefore it has its own processing function */ - request_processing_result = modbus_process_device_id_request(buffer + buffer_pos, len - buffer_pos, &transaction); - } else { - /* process other requests: input register read, holding register read/write */ - request_processing_result = modbus_process_read_write_request(buffer + buffer_pos, len - buffer_pos, &transaction); - } - uint8_t msg_len; - /* reply only if request was processed successfully and message was not broadcast */ - if (request_processing_result == MODBUS_OK && transaction.broadcast == 0) { - modbus_transaction_to_buffer(modbus_buffer, &msg_len, &transaction); - /* send reply */ - modbus_transmit_function(modbus_buffer, msg_len); - } - return MODBUS_OK; -} - -int8_t modbus_slave_init_device_id(modbus_device_id_t *device_id) -{ - if (device_id == NULL) { - return MODBUS_ERROR; - } - /* at least basic category objects have to be implemented */ - if ( device_id->object_name.VendorName == NULL || - device_id->object_name.ProductCode == NULL || - device_id->object_name.MajorMinorRevision == NULL - ) { - return MODBUS_ERROR; - } - /* set conformity level: currently only "basic" and "regular" is implemented */ - if ( device_id->object_id[3] != NULL && - device_id->object_id[4] != NULL && - device_id->object_id[5] != NULL - - ) { - /* strings are present in regular category (optional) */ - device_id->conformity_level = MODBUS_CONFORMITY_REGULAR; - } else { - device_id->conformity_level = MODBUS_CONFORMITY_BASIC; - } - /* we support both stream and individual access to objects */ - device_id->conformity_level |= MODBUS_DEVICE_ID_INDIVIDUAL_ACCESS_FLAG; - modbus_device_id = device_id; - return MODBUS_OK; -}