#include "at32f403a_407.h" #include "common_config.h" #include "modbus.h" #include "update.h" #include "FreeRTOS.h" #include "task.h" #include "mb.h" #include "mbport.h" #include "mbrtu.h" #include "tim_delay.h" #include "modbus_params.h" #include "common_gpio.h" #include "io_utils.h" #include #include #include #define REG_HOLDING_START ( 1 ) #define REG_HOLDING_NREGS ( 5 ) static USHORT usRegHoldingStart = REG_HOLDING_START; extern UCHAR rcvAddress; //osThreadId modbus_task_handle; static void modbus_task(void *params); //osThreadId modbus_params_handle; static void modbus_params(void *params); //osTimerId reset_timer_handle; //osTimerId settings_timer_handle; //osTimerId modbus_timer_handle; mb_delay_action_t mb_action = MB_NO_ACTION; uint8_t new_slave_addr; bool mb_package_flag = false; // void mb_init(void) { uint32_t baud = 115200; eMBParity par = MB_PAR_NONE; UCHAR mb_addr = cm_gpio_get_mb_addr(); unsigned int stop_bits = 1; const UCHAR ucSlaveID[] = {0xAA, 0xBB, 0xCC}; mb_init_params(); mb_helper_tim_init(baud); eMBInit(MB_RTU, mb_addr, 4, baud, par, stop_bits); eMBSetSlaveID(0x34, TRUE, ucSlaveID, 3); eMBEnable(); xTaskCreate(modbus_task, "modbus_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL); xTaskCreate(modbus_params, "modbus_params", 4*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL); // Таймер для перехода в IAP update_create_timer(); #if 0 osTimerDef(vResetTimer, modbus_reset); reset_timer_handle = osTimerCreate(osTimer(vResetTimer), osTimerOnce, NULL); osTimerDef(vSettingsTimer, settings_timer); settings_timer_handle = osTimerCreate(osTimer(vSettingsTimer), osTimerOnce, NULL); osTimerDef(vModbusTimer, modbus_port_timer); modbus_timer_handle = osTimerCreate(osTimer(vModbusTimer), osTimerOnce, NULL); #endif } // void modbus_task(void *params) { (void)params; for (;;) { eMBPoll(); } } // void modbus_params(void *params) { for (;;) { if (mb_action != MB_NO_ACTION) { switch (mb_action) { // Установка нового адреса case MB_CHANGE_ADDR : //settings.com_settings.mb_addr = new_slave_addr; eMBSetSlaveAddr(new_slave_addr); break; case MB_CHANGE_PORT_SETTINGS : #if 0 osDelay(200); eMBRTUStop(); settings_set_modbus_params(temp_modbus_port); settings_init_mb_port(settings.com_settings.mb_addr); MBDBG settings_print_modbus(); eMBRTUStart(); eMBEnable(); mb_package_flag = false; osTimerStart(modbus_timer_handle, 9800); #endif break; // Полное восстановление дефолтных настроек case MB_DEF_SETTINGS : #if 0 settings_set_default(true); settings_save(); #endif break; // Частичное восстановление дефолтных настроек case MB_PART_DEF_SETTINGS : #if 0 settings_set_default(false); settings_save(); #endif break; case MB_SAVE_SETTINGS : #if 0 settings_save(); #endif break; case MB_SAVE_SYS_SETTINGS : #if 0 if (set_sys_settings_flag) { memcpy(&sys_settings, &temp_sys_settings, sizeof(sys_settings)); sys_settings_save(); } #endif break; case MB_RESET : vTaskDelay(100); NVIC_SystemReset(); break; default : break; } mb_action = MB_NO_ACTION; } vTaskDelay(10); } } // Отложенная перезагрузка в Bootloader void modbus_reset(void const * params) { #if 0 MBDBG printf("Switch to bootloader!\r\n"); rtc_set_load_mode(1); HAL_NVIC_SystemReset(); #endif } // Запуск таймера на изменение системных настроек void settings_timer(void const * params) { #if 0 set_sys_settings_flag = false; psw_ok = false; #endif } // Запуск таймера для изменение настроек modbus void modbus_port_timer(void const * params) { #if 0 eMBRTUStop(); // Были транзакции по modbus с новыми настройками. // Нужно сохранить новые настройки. if (mb_package_flag) { settings.com_settings.mb_port = temp_modbus_port; settings_set_modbus_params(settings.com_settings.mb_port); settings_init_mb_port(settings.com_settings.mb_addr); settings_save(); } // Нужно вернуть старые настройки else { temp_modbus_port = settings.com_settings.mb_port; settings_set_modbus_params(settings.com_settings.mb_port); settings_init_mb_port(settings.com_settings.mb_addr); } MBDBG settings_print_modbus(); eMBRTUStart(); eMBEnable(); #endif } // ------------------------------------------------------------------- // // Modbus callback's // ------------------------------------------------------------------- // // // 65 (0x41) Read Input Registers eMBErrorCode eMBUpdateCB( UCHAR * pucFrame, USHORT * usLen) { eMBErrorCode eStatus = MB_ENOERR; mb_package_flag = true; // Команда перехода в bootloader. if (pucFrame[1] == 0x01) { update_tim_start(); } return eStatus; } eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) { return MB_ENOREG; } // 03 (0x03) Read Holding Registers // чтение N регистров управления и уставок // 16 (0x10) Write Multiple registers // запись N регистров управления и уставок (0x10) eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) { eMBErrorCode eStatus = MB_ENOERR; int iRegIndex; mb_delay_action_t mb_act = MB_NO_ACTION; uint16_t regs_cnt = usNRegs; uint16_t index_param; uint8_t *ptr_buf = pucRegBuffer; uint16_t size; /* printf("usAddress: 0x%X\r\n", usAddress); printf("usNRegs: %u\r\n", usNRegs); printf("eMode: %u\r\n", eMode); printf("pucRegBuffer :%X\r\n", pucRegBuffer[0]); */ save_mode_reset_cnt(); mb_package_flag = true; iRegIndex = (int)(usAddress - usRegHoldingStart); #if 1 switch (eMode) { case MB_REG_READ : while (regs_cnt) { // Поиск регистра if (!mb_find_param(iRegIndex, &index_param, &size)) { return MB_ENOREG; // нет запрашиваемого регистра } else { MBDBG printf("reg: %X, index: %u, size: %u\r\n", iRegIndex, index_param, size); MBDBG printf("reg: %X\r\n", iRegIndex); mb_get_param(ptr_buf, index_param); // Вызов функции записи iRegIndex += size; ptr_buf += 2*size; regs_cnt -= size; } } break; case MB_REG_WRITE : while (regs_cnt) { // Поиск регистра if (!mb_find_param(iRegIndex, &index_param, &size)) { return MB_ENOREG; // нет запрашиваемого регистра } else { MBDBG printf("reg: %X, index: %u, size: %u\r\n", iRegIndex, index_param, size); mb_act = mb_set_param(ptr_buf, index_param); // Вызов функции записи if (mb_act != MB_NO_ACTION) mb_action = mb_act; iRegIndex += size; ptr_buf += 2*size; regs_cnt -= size; if (mb_act == MB_PAS_ERR) return MB_EINVAL; } } break; } #endif return eStatus; } // 17 (0x11) Report Slave ID (Serial Line only) // чтение информации об устройстве (0x11) eMBException eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen ) { #if 1 mb_package_flag = true; //*usLen = mb_get_info(&pucFrame[1]) + 3; #endif return MB_EX_NONE; } // чтение/запись значений из нескольких регистров флагов (Coil Status). // чтения N регистров параметров eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) { return MB_ENOREG; } eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) { return MB_ENOREG; } // 0x42 // Запрос на изменение адреса // Если запрос широковещательный, то нужно проверить присланный ID. eMBException eMBSetAddrIdCB( UCHAR * pucFrame, USHORT * usLen ) { #if 0 mb_package_flag = true; if (rcvAddress == MB_ADDRESS_BROADCAST) { if (mb_set_addr_id(&pucFrame[1], &new_slave_addr)) mb_action = MB_CHANGE_ADDR; } // Адресный запрос. ID не проверяем else { if (mb_set_addr(&pucFrame[1], &new_slave_addr)) { pucFrame[1] = new_slave_addr; mb_action = MB_CHANGE_ADDR; } else pucFrame[1] = MB_BOOT_ERR_WRONG_CONTENT; } *usLen = 2; #endif return MB_EX_NONE; } // 0x43 eMBException eMBSetAddrSerialCB( UCHAR * pucFrame, USHORT * usLen ) { #if 0 mb_package_flag = true; if (rcvAddress == MB_ADDRESS_BROADCAST) { if (mb_set_addr_serial(&pucFrame[1], &new_slave_addr)) mb_action = MB_CHANGE_ADDR; } // Адресный запрос. ID не проверяем else { if (mb_set_addr(&pucFrame[1], &new_slave_addr)) { pucFrame[1] = new_slave_addr; mb_action = MB_CHANGE_ADDR; } else pucFrame[1] = MB_BOOT_ERR_WRONG_CONTENT; } *usLen = 2; #endif return MB_EX_NONE; }