diff --git a/Inc/modbus.h b/Inc/modbus.h index 3781189..38b7538 100644 --- a/Inc/modbus.h +++ b/Inc/modbus.h @@ -36,15 +36,26 @@ #include "modbus.h" MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); - MODBUS_Config(&hmodbus1, 0, 1000, MODBUS_MODE_MASTER); // - если нужны другие настройки, не из modbus_config.h + MODBUS_Config(&hmodbus1, 0, 1000, MODBUS_MODE_MASTER); // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); - void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) - { - // modbus_msg содержит ответ от устройства - } + void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) + { + // MB_RespGet_... Чтобы достать нужные данные из ответа + if(hmodbus->RS_STATUS == RS_OK) + { + for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) + { + uint16_t value; + if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) + { + read_hold[i] = value; + } + } + } + } @endverbatim @@ -82,6 +93,13 @@ #include "modbus_diag.h" +#ifdef MODBUS_ENABLE_MASTER +#define MODBUS_MODE_MASTER 1 +#endif + +#ifdef MODBUS_ENABLE_SLAVE +#define MODBUS_MODE_SLAVE 0 +#endif ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// @@ -99,7 +117,7 @@ HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*)); -//---------PROCESS MODBUS COMMAND FUNCTIONS--------- + /////////////////////////---FUNCTIONS---///////////////////////////// #endif //__MODBUS_H_ diff --git a/Inc/modbus_coils.h b/Inc/modbus_coils.h index cecedd6..c03cf8b 100644 --- a/Inc/modbus_coils.h +++ b/Inc/modbus_coils.h @@ -34,90 +34,11 @@ Coils упакованы в 16-битные слова для эффективн //-------------------------------------------------- -/** - * @addtogroup MODBUS_COILS - * @{ - */ - -/** - * @brief Макрос для установки указателя на регистр, содержащий запрашиваемый коил - * @param _parr_ - массив коилов. - * @param _coil_ - Номер коила от начала массива _arr_. - * @note Используется вместе с @ref MB_Set_Coil_Mask - @verbatim Пояснение выражений - - (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_ - -Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0) - xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx - |register[0]----| |register[1]----| - |skip this------| |get this-------| - |shift to 14 bit| - @endverbatim - */ -#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) -/** - * @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра - * @param _coil_ - Номер коила от начала массива _arr_. - * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr - @verbatim Пояснение выражений - - (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра - - _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре - - Визуальный пример: 30 коил будет регистре[1], на 14 бите: - register = 30/16 = 1 - bit = 30 - (16*30/16) = 30 - 16 = 14 - - xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx - |register[0]----| |register[1]----| - |skip this------| |get this-------| - |shift to 14 bit| - @endverbatim - */ -#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) - -/** MODBUS_COILS - * @} - */ - ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// -/** - * @addtogroup MODBUS_REQ_COILS_API API for Coils - * @ingroup MODBUS_REQUEST_MSG - * @brief API для чтения coils из ответа в режиме мастер - * @details Примеры использования: - * - * @code - * // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25 - * int coil_state; - * if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state)) - * { - * printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF"); - * } - * - * // Пример: Получить состояние всех запрошенных coils - * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) - * { - * int state; - * if(MB_RespGet_CoilState(&MODBUS_MSG, addr, &state)) - * { - * printf("Coil %d: %s\n", addr, state ? "ON" : "OFF"); - * } - * } - * @endcode - * @{ - */ - -int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state); - -/** MODBUS_REQ_COILS_API - * @} - */ - - /** @@ -127,7 +48,7 @@ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coi * @{ */ -/** @brief Structure for coils operation */ +/** @brief Enum for coils operation */ typedef enum { SET_COIL, @@ -178,7 +99,6 @@ uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); * @} */ -//---------PROCESS MODBUS COMMAND FUNCTIONS--------- /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS @{ @@ -195,8 +115,4 @@ uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg); */ /////////////////////////---FUNCTIONS---///////////////////////////// -#endif //__MODBUS_COILS_H_ - -/** MODBUS_COILS - * @} - */ \ No newline at end of file +#endif //__MODBUS_COILS_H_ \ No newline at end of file diff --git a/Inc/modbus_core.h b/Inc/modbus_core.h index 8997477..cf11c46 100644 --- a/Inc/modbus_core.h +++ b/Inc/modbus_core.h @@ -194,6 +194,42 @@ extern RS_MsgTypeDef MODBUS_MSG; */ #define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_)) +/** + * @brief Макрос для установки указателя на регистр, содержащий запрашиваемый коил + * @param _parr_ - массив коилов. + * @param _coil_ - Номер коила от начала массива _arr_. + * @note Используется вместе с @ref MB_Set_Coil_Mask + @verbatim Пояснение выражений + - (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_ + +Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0) + xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx + |register[0]----| |register[1]----| + |skip this------| |get this-------| + |shift to 14 bit| + @endverbatim + */ +#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) +/** + * @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра + * @param _coil_ - Номер коила от начала массива _arr_. + * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr + @verbatim Пояснение выражений + - (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра + - _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре + + Визуальный пример: 30 коил будет регистре[1], на 14 бите: + register = 30/16 = 1 + bit = 30 - (16*30/16) = 30 - 16 = 14 + + xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx + |register[0]----| |register[1]----| + |skip this------| |get this-------| + |shift to 14 bit| + @endverbatim + */ +#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) + /** GENERAL_MODBUS_STUFF * @} */ @@ -233,7 +269,6 @@ extern RS_MsgTypeDef MODBUS_MSG; ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// -//---------PROCESS MODBUS COMMAND FUNCTIONS--------- /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS @{ diff --git a/Inc/modbus_devid.h b/Inc/modbus_devid.h index c6fe850..1d37fbb 100644 --- a/Inc/modbus_devid.h +++ b/Inc/modbus_devid.h @@ -86,52 +86,6 @@ void MB_DeviceInentificationInit(void); ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// -/** - * @addtogroup MODBUS_REQ_DEFID_API API for Device Identifications - * @ingroup MODBUS_REQUEST_MSG - * @brief API для чтения идентификторов из ответа в режиме мастер - * @details Примеры использования: - * - * @code - * // Пример 1: Получить VendorName (ID = 0x00) - * uint8_t length; - * char vendor_name[64]; - * if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length)) - * { - * // получено - * } - * - * // Пример 2: Перебрать все объекты в сообщении - * uint8_t obj_id, obj_length; - * char obj_data[256]; - * - * int obj_count = MB_RespGet_NumberOfObjects(&MODBUS_MSG); - * printf("Total objects: %d\n", obj_count); - * - * for(int i = 0; i < obj_count; i++) - * { - * if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, i, &obj_id, obj_data, &obj_length)) - * { - * // получено - * } - * } - * @endcode - * @{ - */ - -/* Получить количество объектов в сообщении */ -int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg); -/* Найти объект по ID в сообщении */ -int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length); -/* Получить объект по индексу в сообщении */ -int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length); - - -/** MODBUS_REQ_DEFID_API -* @} -*/ - - /** * @addtogroup MODBUS_DEVID * @{ @@ -145,7 +99,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj); /** MODBUS_DEVID * @} */ -//---------PROCESS MODBUS COMMAND FUNCTIONS--------- + /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS @{ diff --git a/Inc/modbus_diag.h b/Inc/modbus_diag.h index 86d7ac4..90d256d 100644 --- a/Inc/modbus_diag.h +++ b/Inc/modbus_diag.h @@ -65,29 +65,6 @@ void MB_DiagnosticsInit(void); * @} */ -/** - * @addtogroup MODBUS_REQ_DIAG_API API for Diagnostics - * @ingroup MODBUS_REQUEST_MSG - * @brief API для чтения диагностической информации из ответа в режиме мастер - * @details Примеры использования: - * - * @code - * // Получить данные диагностики (значение счетчика) - * uint16_t counter_value; - * if(MB_RespGet_Diagnostic(&MODBUS_MSG, &counter_value)) - * { - * printf("Counter value: %d\n", counter_value); - * } - * @endcode - * @{ - */ - -int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data); - -/** MODBUS_REQ_DIAG_API - * @} - */ - @@ -121,7 +98,6 @@ void MB_Diagnostics_SlaveBusyCnt(void); * @} */ -//---------PROCESS MODBUS COMMAND FUNCTIONS--------- /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS @{ diff --git a/Inc/modbus_holdregs.h b/Inc/modbus_holdregs.h index bfe3b81..7ab4e67 100644 --- a/Inc/modbus_holdregs.h +++ b/Inc/modbus_holdregs.h @@ -23,7 +23,22 @@ ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// -//---------PROCESS MODBUS COMMAND FUNCTIONS--------- +/** + * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS + * @{ + */ + +/* Записать регистр хранения по глобальному адресу. */ +MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal); +/* Считать регистр хранения по глобальному адресу. */ +uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); + +/** MODBUS_DATA_ACCESS_FUNCTIONS + * @} + */ + + + /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS @{ diff --git a/Inc/modbus_inputregs.h b/Inc/modbus_inputregs.h index 9fa47e2..7912553 100644 --- a/Inc/modbus_inputregs.h +++ b/Inc/modbus_inputregs.h @@ -21,7 +21,21 @@ ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// -//---------PROCESS MODBUS COMMAND FUNCTIONS--------- +/** + * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS + * @{ + */ + +/* Записать входной регистр по глобальному адресу. */ +MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal); +/* Считать входной регистр по глобальному адресу. */ +uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); + +/** MODBUS_DATA_ACCESS_FUNCTIONS + * @} + */ + + /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions * @ingroup MODBUS_INTERNAL diff --git a/Inc/modbus_master.h b/Inc/modbus_master.h index 1852593..60df97f 100644 --- a/Inc/modbus_master.h +++ b/Inc/modbus_master.h @@ -14,10 +14,6 @@ #include "rs_message.h" -#ifdef MODBUS_ENABLE_MASTER -#define MODBUS_MODE_MASTER 1 -#endif - /** * @addtogroup MODBUS_REQUEST_MSG API for Master Requests * @ingroup MODBUS_FUNCTIONS @@ -109,6 +105,115 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1 * @} */ + +/** + * @addtogroup MODBUS_REQ_COILS_API API for Coils + * @ingroup MODBUS_REQUEST_MSG + * @brief API для чтения coils из ответа в режиме мастер + * @details Примеры использования: + * + * @code + * // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25 + * int coil_state; + * if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state)) + * { + * printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF"); + * } + * + * // Пример: Получить состояние всех запрошенных coils + * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) + * { + * int state; + * if(MB_RespGet_CoilState(&MODBUS_MSG, addr, &state)) + * { + * printf("Coil %d: %s\n", addr, state ? "ON" : "OFF"); + * } + * } + * @endcode + * @{ + */ + +int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state); + +/** MODBUS_REQ_COILS_API + * @} + */ + + +/** + * @addtogroup MODBUS_REQ_DEFID_API API for Device Identifications + * @ingroup MODBUS_REQUEST_MSG + * @brief API для чтения идентификторов из ответа в режиме мастер + * @details Примеры использования: + * + * @code + * // Пример 1: Получить VendorName (ID = 0x00) + * uint8_t length; + * char vendor_name[64]; + * if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length)) + * { + * // получено + * } + * + * // Пример 2: Перебрать все объекты в сообщении + * uint8_t obj_id, obj_length; + * char obj_data[256]; + * + * int obj_count = MB_RespGet_NumberOfObjects(&MODBUS_MSG); + * printf("Total objects: %d\n", obj_count); + * + * for(int i = 0; i < obj_count; i++) + * { + * if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, i, &obj_id, obj_data, &obj_length)) + * { + * // получено + * } + * } + * @endcode + * @{ + */ + +/* Получить количество объектов в сообщении */ +int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg); +/* Найти объект по ID в сообщении */ +int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length); +/* Получить объект по индексу в сообщении */ +int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length); + + +/** MODBUS_REQ_DEFID_API +* @} +*/ + + + +/** + * @addtogroup MODBUS_REQ_DIAG_API API for Diagnostics + * @ingroup MODBUS_REQUEST_MSG + * @brief API для чтения диагностической информации из ответа в режиме мастер + * @details Примеры использования: + * + * @code + * // Получить данные диагностики (значение счетчика) + * uint16_t counter_value; + * if(MB_RespGet_Diagnostic(&MODBUS_MSG, &counter_value)) + * { + * printf("Counter value: %d\n", counter_value); + * } + * @endcode + * @{ + */ + +int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data); + +/** MODBUS_REQ_DIAG_API + * @} + */ + + + + + /** * @addtogroup MODBUS_MASTER * @{ diff --git a/Inc/modbus_slave.h b/Inc/modbus_slave.h index 89e18aa..9db55a4 100644 --- a/Inc/modbus_slave.h +++ b/Inc/modbus_slave.h @@ -15,9 +15,6 @@ #include "rs_message.h" -#ifdef MODBUS_ENABLE_SLAVE -#define MODBUS_MODE_SLAVE 0 -#endif /** * @addtogroup MODBUS_SLAVE * @{ diff --git a/Inc/rs_message.h b/Inc/rs_message.h index 6fcdc71..ee8dd34 100644 --- a/Inc/rs_message.h +++ b/Inc/rs_message.h @@ -115,6 +115,10 @@ static int dummy; #ifndef RS_USER_VARS_NUMB #define RS_USER_VARS_NUMB 0 #endif + +#ifndef local_time +#define local_time() uwTick +#endif /** @endcond */ @@ -141,9 +145,10 @@ typedef enum // RS_StatusTypeDef /*0x03*/ RS_ABORTED, /*0x04*/ RS_BUSY, /*0x05*/ RS_SKIP, + /*0x06*/ RS_TIMEOUT, - /*0x06*/ RS_COLLECT_MSG_ERR, - /*0x07*/ RS_PARSE_MSG_ERR, + /*0x07*/ RS_COLLECT_MSG_ERR, + /*0x08*/ RS_PARSE_MSG_ERR, // reserved values // /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero) diff --git a/README.md b/README.md index 97ab023..7a4e12b 100644 --- a/README.md +++ b/README.md @@ -123,12 +123,15 @@ ProjectRoot/ void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { // MB_RespGet_... Чтобы достать нужные данные из ответа - for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) + if(hmodbus->RS_STATUS == RS_OK) { - uint16_t value; - if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) + for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) { - read_hold[i] = value; + uint16_t value; + if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) + { + read_hold[i] = value; + } } } } diff --git a/Src/modbus_coils.c b/Src/modbus_coils.c index 529a5e1..5b2d4d9 100644 --- a/Src/modbus_coils.c +++ b/Src/modbus_coils.c @@ -57,7 +57,7 @@ MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteV /** * @brief Считать коил по глобальному адресу. * @param Addr Адрес коила. - * @param Exception Указатель на переменную для кода исключения, в случа неудачи при чтении. + * @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении. * @return uint16_t Возвращает весь регистр с маской на запрошенном коиле. * * @details Позволяет обратиться к любому коилу по его глобальному адрессу. @@ -86,51 +86,6 @@ uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) } - -/** - * @brief Получить состояние coil в ответе по его адресу - * @param modbus_msg Указатель на структуру сообщения - * @param coil_addr Адрес coil, состояние которого нужно получить - * @param coil_state Указатель для состояния coil (1 - ON, 0 - OFF) - * @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса - */ -int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) -{ - if(modbus_msg == NULL || coil_state == NULL) - return 0; - - // Проверяем что ответ связан с коилами - if(modbus_msg->Func_Code != MB_R_COILS) - { - return 0; - } - - // Проверяем что coil_addr в пределах запрошенного диапазона - if(coil_addr < modbus_msg->Addr || coil_addr >= modbus_msg->Addr + modbus_msg->Qnt) - return 0; - - // Вычисляем индекс coil в полученных данных - uint16_t coil_index = coil_addr - modbus_msg->Addr; - - // Вычисляем байт и бит - uint8_t byte_index = coil_index / 8; - uint8_t data_index = coil_index / 16; - uint8_t bit_index = coil_index % 16; - - // Проверяем что байт существует в данных - if(byte_index >= modbus_msg->ByteCnt) - return 0; - - // Получаем байт и проверяем бит - if(bit_index < 8) - *coil_state = (modbus_msg->DATA[data_index] >> (bit_index+8)) & 0x01; - else - *coil_state = (modbus_msg->DATA[data_index] >> bit_index) & 0x01; - - - return 1; -} - /** * @brief Обработать функцию Read Coils (01 - 0x01). * @param modbus_msg Указатель на структуру собщения modbus. @@ -284,7 +239,6 @@ uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg) #else //MODBUS_ENABLE_COILS -int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) {return 0;} MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal) {return ILLEGAL_FUNCTION;} uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) {return 0;} uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg) {return 0;} diff --git a/Src/modbus_core.c b/Src/modbus_core.c index 9cbf9fe..69d74ea 100644 --- a/Src/modbus_core.c +++ b/Src/modbus_core.c @@ -1,7 +1,7 @@ /** ****************************************************************************** * @file modbus_core.c -* @brief Базовая реализация ядра Modbus (заглушка) +* @brief Базовая реализация ядра Modbus ****************************************************************************** * @details В текущей реализации этот файл служит заглушкой для будущего расширения diff --git a/Src/modbus_devid.c b/Src/modbus_devid.c index 7218bee..129b1c7 100644 --- a/Src/modbus_devid.c +++ b/Src/modbus_devid.c @@ -21,132 +21,6 @@ MB_DeviceIdentificationsTypeDef MB_DEVID; ///< Глобальная структура идентификаторов устройства -/** - * @brief Получить количество объектов в сообщении - * @param modbus_msg Указатель на структуру сообщения - * @return int Количество объектов - */ -int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg) -{ - if(modbus_msg == NULL) - { - return 0; - } - // Проверяем что ответ связан с диагностикой - if(modbus_msg->Func_Code != MB_R_DEVICE_INFO) - { - return 0; - } - - return modbus_msg->DevId.NumbOfObj; -} - -/** - * @brief Найти объект по ID в сообщении - * @param modbus_msg Указатель на структуру сообщения - * @param obj_id ID искомого объекта - * @param obj_data Буфер для данных объекта (может быть NULL) - * @param obj_length Указатель для длины объекта - * @return int Найден ли объект (1 - да, 0 - нет) - */ -int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) -{ - if((modbus_msg == NULL) || (obj_data == NULL)) - return 0; - - // Проверяем что ответ связан с диагностикой - if(modbus_msg->Func_Code != MB_R_DEVICE_INFO) - { - return 0; - } - - uint8_t *data = (uint8_t*)modbus_msg->DATA; - unsigned ind = 0; - - for(int i = 0; i < modbus_msg->DevId.NumbOfObj; i++) - { - uint8_t current_id = data[ind++]; - uint8_t current_length = data[ind++]; - - if(current_id == obj_id) - { - if(obj_length) - *obj_length = current_length; - - for(int j = 0; j < current_length; j++) - { - obj_data[j] = data[ind++]; - } - obj_data[current_length] = '\0'; // добавляем \0 - - return 1; - } - else - { - // Пропускаем данные этого объекта - ind += current_length; - } - } - - return 0; -} - -/** - * @brief Получить объект по индексу в сообщении - * @param modbus_msg Указатель на структуру сообщения - * @param index Индекс объекта (0..N-1) - * @param obj_id Указатель для ID объекта - * @param obj_data Буфер для данных объекта - * @param obj_length Указатель для длины объекта - * @return int Успешность получения (1 - получен, 0 - не найден) - */ -int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length) -{ - if((modbus_msg == NULL) || (obj_data == NULL)) - return 0; - - // Проверяем что ответ связан с диагностикой - if(modbus_msg->Func_Code != MB_R_DEVICE_INFO) - { - return 0; - } - - if(index >= modbus_msg->DevId.NumbOfObj) - return 0; - - uint8_t *data = (uint8_t*)modbus_msg->DATA; - unsigned ind = 0; - - for(int i = 0; i <= index; i++) - { - uint8_t current_id = data[ind++]; - uint8_t current_length = data[ind++]; - - if(obj_id) - *obj_id = current_id; - if(obj_length) - *obj_length = current_length; - - if(i == index) - { - for(int j = 0; j < current_length; j++) - { - obj_data[j] = data[ind++]; - } - obj_data[current_length] = '\0'; // добавляем \0 - return 1; - } - else - { - // Пропускаем данные этого объекта - ind += current_length; - } - } - - return 0; -} - - /** @@ -674,9 +548,7 @@ void MB_DeviceInentificationInit(void) #else //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS /* Получить количество объектов в сообщении */ -int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg) {return 0;} -int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) {return 0;} -int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length) {return 0;} + void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj) {} void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) {} uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg) {return 0;} diff --git a/Src/modbus_diag.c b/Src/modbus_diag.c index 0d18122..e2cd966 100644 --- a/Src/modbus_diag.c +++ b/Src/modbus_diag.c @@ -36,29 +36,6 @@ void MB_DiagnosticsInit(void) } -/** - * @brief Получить данные диагностики из сообщения (DATA[1]) - * @param modbus_msg Указатель на структуру сообщения - * @param data Указатель куда положить данные - * @return 1 - успех, 0 - ошибка - */ -int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data) -{ - if(modbus_msg == NULL || data == NULL) - return 0; - - // Проверяем что ответ связан с диагностикой - if(modbus_msg->Func_Code != MB_R_DIAGNOSTIC) - { - return 0; - } - - - - *data = modbus_msg->DATA[1]; - return 1; -} - /** * @brief Выставить бит в регистре диагностике * @param bit_num Номер бита для выставления (1-15, 0 бит нельзя выставить) @@ -319,7 +296,6 @@ MB_DeviceModeTypeDef MB_GetDeviceMode(void) #else //MODBUS_ENABLE_DIAGNOSTICS void MB_DiagnosticsInit(void) {} -int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data) {return 0;} int MB_Diagnostics_WriteBit(int bit_num, int bit_state) {return 0;} int MB_Diagnostics_GetBit(int bit_num) {return 0;} uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg) {return 0;} diff --git a/Src/modbus_holdregs.c b/Src/modbus_holdregs.c index 786552a..57503cf 100644 --- a/Src/modbus_holdregs.c +++ b/Src/modbus_holdregs.c @@ -24,6 +24,66 @@ #ifdef MODBUS_ENABLE_HOLDINGS + +/** + * @brief Записать регистр хранения по глобальному адресу. + * @param Addr Адрес регистра. + * @param WriteVal Число для записи. + * @return ExceptionCode Код исключения если регистра по адресу не существует, и NO_ERRORS если все ок. + * + * @details Позволяет обратиться к любому регистру по его глобальному адрессу. + Вне зависимости от того как регистры размещены в памяти. + */ +MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal) +{ + //---------CHECK FOR ERRORS---------- + MB_ExceptionTypeDef Exception = NO_ERRORS; + uint16_t *pHoldRegs; + + //------------WRITE COIL------------- + Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding); + if(Exception == NO_ERRORS) + { + *(pHoldRegs) = WriteVal; + } + return Exception; +} + + +/** + * @brief Считать регистр хранения по глобальному адресу. + * @param Addr Адрес регистра. + * @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении. + * @return uint16_t Возвращает значение регистра. + * + * @details Позволяет обратиться к любому регистру по его глобальному адрессу. + Вне зависимости от того как регистры размещены в памяти. + */ +uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) +{ + //---------CHECK FOR ERRORS---------- + MB_ExceptionTypeDef Exception_tmp = 0; + + uint16_t *pHoldRegs; + + //------------READ COIL-------------- + Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding); + + if(Exception) // if exception is not given to func fill it + *Exception = Exception_tmp; + + if(Exception_tmp == NO_ERRORS) + { + return *(pHoldRegs); + } + else + { + return 0; + } +} + + + /** * @brief Обработать функцию Read Holding Registers (03 - 0x03). * @param modbus_msg Указатель на структуру собщения modbus. @@ -34,7 +94,7 @@ uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) { //---------CHECK FOR ERRORS---------- // get origin address for data - uint16_t *pHoldRegs; + uint16_t *pHoldRegs; modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров if(modbus_msg->Except_Code != NO_ERRORS) return 0; @@ -102,6 +162,8 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) #else //MODBUS_ENABLE_HOLDINGS +MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal) {return ILLEGAL_FUNCTION;} +uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) {return 0;} uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) {return 0;} uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) {return 0;} uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) {return 0;} diff --git a/Src/modbus_inputregs.c b/Src/modbus_inputregs.c index 3bc34c9..06d8981 100644 --- a/Src/modbus_inputregs.c +++ b/Src/modbus_inputregs.c @@ -14,6 +14,65 @@ #ifdef MODBUS_ENABLE_INPUTS + +/** + * @brief Записать входной регистр по глобальному адресу. + * @param Addr Адрес регистра. + * @param WriteVal Число для записи. + * @return ExceptionCode Код исключения если регистра по адресу не существует, и NO_ERRORS если все ок. + * + * @details Позволяет обратиться к любому регистру по его глобальному адрессу. + Вне зависимости от того как регистры размещены в памяти. + */ +MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal) +{ + //---------CHECK FOR ERRORS---------- + MB_ExceptionTypeDef Exception = NO_ERRORS; + uint16_t *pInRegs; + + //------------WRITE COIL------------- + Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input); + if(Exception == NO_ERRORS) + { + *(pInRegs) = WriteVal; + } + return Exception; +} + + +/** + * @brief Считать входной регистр по глобальному адресу. + * @param Addr Адрес регистра. + * @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении. + * @return uint16_t Возвращает значение регистра. + * + * @details Позволяет обратиться к любому регистру по его глобальному адрессу. + Вне зависимости от того как регистры размещены в памяти. + */ +uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) +{ + //---------CHECK FOR ERRORS---------- + MB_ExceptionTypeDef Exception_tmp = 0; + + uint16_t *pInRegs; + + //------------READ COIL-------------- + Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input); + + if(Exception) // if exception is not given to func fill it + *Exception = Exception_tmp; + + if(Exception_tmp == NO_ERRORS) + { + return *(pInRegs); + } + else + { + return 0; + } +} + + /** * @brief Обработать функцию Read Input Registers (04 - 0x04). * @param modbus_msg Указатель на структуру собщения modbus. @@ -47,6 +106,8 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) #else //MODBUS_ENABLE_INPUTS +MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal) {return ILLEGAL_FUNCTION;} +uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) {return 0;} uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) {return 0;} #endif \ No newline at end of file diff --git a/Src/modbus_master.c b/Src/modbus_master.c index d45b68a..a6d5709 100644 --- a/Src/modbus_master.c +++ b/Src/modbus_master.c @@ -53,6 +53,203 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1 return 1; } + + +/** + * @brief Получить состояние coil в ответе по его адресу + * @param modbus_msg Указатель на структуру сообщения + * @param coil_addr Адрес coil, состояние которого нужно получить + * @param coil_state Указатель для состояния coil (1 - ON, 0 - OFF) + * @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса + */ +int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) +{ + if(modbus_msg == NULL || coil_state == NULL) + return 0; + + // Проверяем что ответ связан с коилами + if(modbus_msg->Func_Code != MB_R_COILS) + { + return 0; + } + + // Проверяем что coil_addr в пределах запрошенного диапазона + if(coil_addr < modbus_msg->Addr || coil_addr >= modbus_msg->Addr + modbus_msg->Qnt) + return 0; + + // Вычисляем индекс coil в полученных данных + uint16_t coil_index = coil_addr - modbus_msg->Addr; + + // Вычисляем байт и бит + uint8_t byte_index = coil_index / 8; + uint8_t data_index = coil_index / 16; + uint8_t bit_index = coil_index % 16; + + // Проверяем что байт существует в данных + if(byte_index >= modbus_msg->ByteCnt) + return 0; + + // Получаем байт и проверяем бит + if(bit_index < 8) + *coil_state = (modbus_msg->DATA[data_index] >> (bit_index+8)) & 0x01; + else + *coil_state = (modbus_msg->DATA[data_index] >> bit_index) & 0x01; + + + return 1; +} + + +/** + * @brief Получить количество объектов в сообщении + * @param modbus_msg Указатель на структуру сообщения + * @return int Количество объектов + */ +int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg) +{ + if(modbus_msg == NULL) + { + return 0; + } + // Проверяем что ответ связан с диагностикой + if(modbus_msg->Func_Code != MB_R_DEVICE_INFO) + { + return 0; + } + + return modbus_msg->DevId.NumbOfObj; +} + +/** + * @brief Найти объект по ID в сообщении + * @param modbus_msg Указатель на структуру сообщения + * @param obj_id ID искомого объекта + * @param obj_data Буфер для данных объекта (может быть NULL) + * @param obj_length Указатель для длины объекта + * @return int Найден ли объект (1 - да, 0 - нет) + */ +int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) +{ + if((modbus_msg == NULL) || (obj_data == NULL)) + return 0; + + // Проверяем что ответ связан с диагностикой + if(modbus_msg->Func_Code != MB_R_DEVICE_INFO) + { + return 0; + } + + uint8_t *data = (uint8_t*)modbus_msg->DATA; + unsigned ind = 0; + + for(int i = 0; i < modbus_msg->DevId.NumbOfObj; i++) + { + uint8_t current_id = data[ind++]; + uint8_t current_length = data[ind++]; + + if(current_id == obj_id) + { + if(obj_length) + *obj_length = current_length; + + for(int j = 0; j < current_length; j++) + { + obj_data[j] = data[ind++]; + } + obj_data[current_length] = '\0'; // добавляем \0 + + return 1; + } + else + { + // Пропускаем данные этого объекта + ind += current_length; + } + } + + return 0; +} + +/** + * @brief Получить объект по индексу в сообщении + * @param modbus_msg Указатель на структуру сообщения + * @param index Индекс объекта (0..N-1) + * @param obj_id Указатель для ID объекта + * @param obj_data Буфер для данных объекта + * @param obj_length Указатель для длины объекта + * @return int Успешность получения (1 - получен, 0 - не найден) + */ +int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length) +{ + if((modbus_msg == NULL) || (obj_data == NULL)) + return 0; + + // Проверяем что ответ связан с диагностикой + if(modbus_msg->Func_Code != MB_R_DEVICE_INFO) + { + return 0; + } + + if(index >= modbus_msg->DevId.NumbOfObj) + return 0; + + uint8_t *data = (uint8_t*)modbus_msg->DATA; + unsigned ind = 0; + + for(int i = 0; i <= index; i++) + { + uint8_t current_id = data[ind++]; + uint8_t current_length = data[ind++]; + + if(obj_id) + *obj_id = current_id; + if(obj_length) + *obj_length = current_length; + + if(i == index) + { + for(int j = 0; j < current_length; j++) + { + obj_data[j] = data[ind++]; + } + obj_data[current_length] = '\0'; // добавляем \0 + return 1; + } + else + { + // Пропускаем данные этого объекта + ind += current_length; + } + } + + return 0; +} + + +/** + * @brief Получить данные диагностики из сообщения (DATA[1]) + * @param modbus_msg Указатель на структуру сообщения + * @param data Указатель куда положить данные + * @return 1 - успех, 0 - ошибка + */ +int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data) +{ + if(modbus_msg == NULL || data == NULL) + return 0; + + // Проверяем что ответ связан с диагностикой + if(modbus_msg->Func_Code != MB_R_DIAGNOSTIC) + { + return 0; + } + + + + *data = modbus_msg->DATA[1]; + return 1; +} + + /** * @brief Определить размер модбас запроса (МАСТЕР версия). * @param hRS Указатель на хендлер RS. @@ -487,6 +684,11 @@ RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t obj RS_MsgTypeDef msg_dummy = {0}; int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value) {return 0;} +int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) {return 0;} +int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg) {return 0;} +int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) {return 0;} +int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length) {return 0;} +int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data) {return 0;} RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;} RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;} diff --git a/Src/rs_message.c b/Src/rs_message.c index 6572259..a298b97 100644 --- a/Src/rs_message.c +++ b/Src/rs_message.c @@ -348,16 +348,18 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS) RS_Set_RX_End(hRS); // Парсим наше сообщение - RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); + hRS->RS_STATUS = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // Если сообещине принято корректно - if(parse_res == RS_OK) + if(hRS->RS_STATUS == RS_OK) { RS_Timeout_Stop(hRS); - hRS->lastPacketTick = uwTick; + hRS->lastPacketTick = local_time(); if(hRS->sRS_Mode < RS_MASTER_MODE_START) + { RS_Response(hRS, hRS->pMessagePtr); // отвечаем на запрос + } else { if(hRS->pCallback) @@ -435,12 +437,20 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS) HAL_TIM_IRQHandler(hRS->htim); RS_Abort(hRS, ABORT_RS); + - if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению - TrackerCnt_Err(hRS->rs_err); + hRS->RS_STATUS = RS_TIMEOUT; + + if(hRS->sRS_Mode < RS_MASTER_MODE_START) + if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению + TrackerCnt_Err(hRS->rs_err); - if(hRS->sRS_Mode == RS_MASTER_REQUEST) { - // Мастер: таймаут ответа -> освобождаем для нового запроса + if(hRS->sRS_Mode >= RS_MASTER_MODE_START) + { // Мастер: коллбек и освобождение для нового запроса + if(hRS->pCallback) + { + hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ + } RS_Set_Free(hRS); } else { // Слейв: перезапускаем прием diff --git a/__modbus_config.h b/__modbus_config.h index 12ecb7f..53aec6f 100644 --- a/__modbus_config.h +++ b/__modbus_config.h @@ -9,9 +9,11 @@ ****************************************************************************** * @details Файл содержит настройки для работы Modbus: -- Идентификатор устройства и таймауты +- Подключение библиотек контроллера +- ID устройства и таймауты - Строковые идентификаторы (Vendor, Product, Revision) - Настройки периферии (UART, TIMER) +- Подключение модулей Modbus - Опциональные функции (переключение команд 0x03/0x04) ******************************************************************************/ #ifndef _MODBUS_CONFIG_H_