#include "at32f403a_407.h" #include "common_config.h" #include "modbus.h" #include "update.h" #include "FreeRTOS.h" #include "task.h" #include "fr_timers.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 "log.h" #include "log_api.h" #include "settings_api.h" #include #include #include #define REG_HOLDING_START ( 1 ) #define REG_HOLDING_NREGS ( 5 ) #undef DBG #define DBG if(1) //UCHAR uint8_t mb_addr = 0; static USHORT usRegHoldingStart = REG_HOLDING_START; extern UCHAR rcvAddress; extern bool psw_ok; extern uint8_t arch_channel; //osThreadId modbus_task_handle; static void modbus_task(void *params); //osThreadId modbus_params_handle; static void modbus_params(void *params); TimerHandle_t settings_timer_handle; //osTimerId reset_timer_handle; //osTimerId settings_timer_handle; //osTimerId modbus_timer_handle; void cb_settings_timer(TimerHandle_t timer); 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; const UCHAR ucSlaveID[] = {0xAA, 0xBB, 0xCC}; gpio_mbaddr_init(); mb_addr = gpio_get_mbaddr(); mb_init_params(); mb_helper_tim_init(baud); settings_init_mb_port(mb_addr); 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(); settings_timer_handle = xTimerCreate("reset_timer", 10000, pdFALSE, (void *)0, cb_settings_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; uint8_t new_addr = 0; for (;;) { if (gpio_check_mbaddr(mb_addr, &new_addr)) { eMBSetSlaveAddr((UCHAR)new_addr); } 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_PAS_OK : //set_sys_settings_flag = true; //osTimerStart(settings_timer_handle, 30000); xTimerStart(settings_timer_handle, 0); 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 : settings_save_with_log(); break; case MB_SAVE_SYS_SETTINGS : if (save_sys_cmd) { save_sys_cmd = 0; memcpy(&sys_settings, &temp_sys_settings, sizeof(sys_settings)); sys_save(&sys_settings); } break; case MB_LOG_CLEAR : log_format(0, 0); // -------------------------------------------------------------------------- // // EVENT. Очиста журнала. log_add_entry(LOG_CLEAR, (log_event_state_t)LOG_EVENT_STATE_OK, 0, 0.0); break; case MB_ARCHIVE_CLEAR : log_format(1, arch_channel); // -------------------------------------------------------------------------- // // EVENT. Очиста архива. log_add_entry(LOG_CLEAR, (log_event_state_t)LOG_EVENT_STATE_OK, 0, 1.0); 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 } // Запуск таймера для изменение настроек 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; } eMBException eMBFuncReadFileRecordCB( UCHAR * pucFrame, USHORT * usLen ) { uint8_t byte_count; uint8_t reference_type; uint8_t archive_channel; uint16_t record_index = 0; uint16_t record_num = 0; #if 0 DBG printf("Recived: "); for (int i = 0; i < *usLen; i++) { DBG printf("%X ", pucFrame[i]); } DBG printf("\r\n"); #endif byte_count = pucFrame[1]; reference_type = pucFrame[2]; record_index = pucFrame[3] << 8; record_index |= pucFrame[4]; archive_channel = pucFrame[5] << 8; archive_channel |= pucFrame[6]; record_num = pucFrame[7] << 8; record_num |= pucFrame[8]; #if 0 DBG printf("Byte count: %u, reference_type: %u, \r\n", byte_count, reference_type); DBG printf("Record index: %u, channel: %u, record num: %u\r\n", record_index, archive_channel, record_num); #endif #if 1 if (reference_type == MB_ARCHIVE_ENTRY) { *usLen = 1 + mb_archive_get_entry((uint8_t*)&pucFrame[1], archive_channel, record_index); } else if (reference_type == MB_LOG_ENTRY) { *usLen = 1 + mb_log_get_entry((uint8_t*)&pucFrame[1], record_index); } #endif return MB_EX_NONE; } // void cb_settings_timer(TimerHandle_t timer) { DBG printf("Settings timer callback\r\n"); psw_ok = false; }