/** ****************************************************************************** * @file modbus_data.c * @brief Функции доступа к данным Modbus ****************************************************************************** * @details Модуль реализует функции валидации адресов и доступа к данным: - Проверка корректности запрашиваемых адресов - Определение указателей на реальные данные в памяти - Поддержка пользовательских массивов регистров и coils @section Валидация адресов: - MB_Check_Address_For_Arr() - проверка принадлежности адреса массиву - MB_DefineRegistersAddress() - получение указателя на регистры - MB_DefineCoilsAddress() - получение указателя на coils ******************************************************************************/ #include "modbus_core.h" #include "modbus_coils.h" #include "modbus_holdregs.h" #include "modbus_inputregs.h" #include "modbus_devid.h" /** * @brief Check is address valid for certain array. * @param Addr Начальный адресс. * @param Qnt Количество запрашиваемых элементов. * @param R_ARR_ADDR Начальный адресс массива R_ARR. * @param R_ARR_NUMB Количество элементов в массиве R_ARR. * @return ExceptionCode - ET_ILLEGAL_DATA_ADRESS если адресс недействителен, и ET_NO_ERRORS если все ок. * * @details Позволяет определить, принадлежит ли адресс Addr массиву R_ARR: * Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR. * Если адресс Addr находится за пределами адрессов массива R_ARR - ET_ILLEGAL_DATA_ADDRESSю. */ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB) { // if address from this array if(Addr >= R_ARR_ADDR) { // if quantity too big return error if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB) { return ET_ILLEGAL_DATA_ADDRESS; // return exception code } // if all ok - return no errors return ET_NO_ERRORS; } // if address isnt from this array return error else return ET_ILLEGAL_DATA_ADDRESS; // return exception code } /** * @brief Define Address Origin for Input/Holding Registers * @param pRegs Указатель на указатель регистров. * @param Addr Адрес начального регистра. * @param Qnt Количество запрашиваемых регистров. * @param WriteFlag Флаг регистр нужны для чтения или записи. * @return ExceptionCode Код исключения если есть, и ET_NO_ERRORS если нет. * * @details Определение адреса начального регистра. * @note WriteFlag пока не используется. */ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType) { /* check quantity error */ if (Qnt > DATA_SIZE) { return ET_ILLEGAL_DATA_VALUE; // return exception code } if(RegisterType == RegisterType_Holding) { // Default holding registers if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == ET_NO_ERRORS) { *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр } // if address doesnt match any array - return illegal data address response else { return ET_ILLEGAL_DATA_ADDRESS; } } else if(RegisterType == RegisterType_Input) { // Default input registers if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == ET_NO_ERRORS) { *pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr - R_INPUT_ADDR); // указатель на выбранный по Addr регистр } // if address doesnt match any array - return illegal data address response else { return ET_ILLEGAL_DATA_ADDRESS; } } else { return ET_ILLEGAL_FUNCTION; } // if found requeried array return no err return ET_NO_ERRORS; // return no errors } /** * @brief Define Address Origin for coils * @param pCoils Указатель на указатель коилов. * @param Addr Адресс начального коила. * @param Qnt Количество запрашиваемых коилов. * @param start_shift Указатель на переменную содержащую сдвиг внутри регистра для начального коила. * @param WriteFlag Флаг коилы нужны для чтения или записи. * @return ExceptionCode Код исключения если есть, и ET_NO_ERRORS если нет. * * @details Определение адреса начального регистра запрашиваемых коилов. * @note WriteFlag используется для определния регистров GPIO: ODR или IDR. */ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag) { /* check quantity error */ if (Qnt > 2000) { return ET_ILLEGAL_DATA_VALUE; // return exception code } // Default coils if(MB_Check_Address_For_Arr(Addr, Qnt, C_CONTROL_ADDR, C_CONTROL_QNT) == ET_NO_ERRORS) { *pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr - C_CONTROL_ADDR); // указатель на выбранный по Addr массив коилов } // if address doesnt match any array - return illegal data address response else { return ET_ILLEGAL_DATA_ADDRESS; } *start_shift = Addr % 16; // set shift to requested coil // if found requeried array return no err return ET_NO_ERRORS; // return no errors }