#include "requester.h" static union Byte byte[2048][8]; #define byte_modbusadr(x) byte[x/64][(x%64)/8] #define _GET_MODBUS_BIT(x) byte[x/64][(x%64)/8].AllBit>>((x%64)%8) #define _GET_MODBUS_ADR(SensorId, RequestedBytePosition, RequestedBitPosition) SensorId*64 + RequestedBytePosition*8 + RequestedBitPosition uint16_t ModbusFilters[COUNT_OF_MODBUS_SECTIONS][2]; struct device CurrentDevice; struct device Device_on_the_Network[32]; struct data Data; struct controlflags ControlFlags; struct received_request ReceivedRequest; #define MAX_NUM_OF_DEVICES_PER_LINE 4 #define MAX_NUM_OF_REGISTERS_IN_DEVICE 255 //Регистр это слово (16 бит). uint16 uint16_t ModbusDemonstration[MAX_NUM_OF_DEVICES_PER_LINE][MAX_NUM_OF_REGISTERS_IN_DEVICE]; uint16_t ModbusAlternativeTable[MAX_NUM_OF_DEVICES_PER_LINE*MAX_NUM_OF_REGISTERS_IN_DEVICE]; _Bool IsLeapYear(uint8_t year) { year+=2000; return (year%400==0)||((year%4==0)&&(year%100!=0)); } /** * @brief Инициализация переферии * @details Инициализация HAL, CAN, TIM7, RTC. * @note Фильтры CAN описаны в разделе REQUESTER_CAN_FILTERS(). */ void REQUESTER_Init(void) { HAL_Init(); MX_CAN_Init(); HAL_CAN_Start(&hcan); REQUESTER_CAN_FILTERS(); HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING); ControlFlags.IsPulse = 1; MX_TIM7_Init(); MX_RTC_Init(); #ifdef _DEMO int Reg_AltModbusTable; //Тестовые значения регистров. Для отладки/демонстрации for(int x = 0; x < MAX_NUM_OF_DEVICES_PER_LINE; x++) { for(int y = 0; y < MAX_NUM_OF_REGISTERS_IN_DEVICE; y++) { ModbusDemonstration[x][y] = x<<8 | y; Reg_AltModbusTable = x*MAX_NUM_OF_REGISTERS_IN_DEVICE+y; ModbusAlternativeTable[Reg_AltModbusTable] = x<<8 | y; } } #endif } int ProverkaDefinaResult; int ProverkaDefinaItem = 0; int ProverkaArbitors = 0; /** * @brief Функция с обработкой полученных запросов * @details В бесконечном цикле функция ожидает выставление флага о полученном запросе. * Обработка запроса аналоговых значений - REQUESTER_AnalogProcessing(). * Обработка широковещательных запросов - REQUESTER_BroadcastProcessing(). * Обработка запроса дискретных значений - REQUESTER_DiscreticProcessing(). * Обработка Modbus - REQUESTER_ModbusProcessing(). * @note */ void REQUESTER_MainWhile(void) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; union ext_ID eID; eID.Fields.DeviceID = 16; eID.Fields.DataType = DATA_TYPE_ANALOG; eID.Fields.SensorType = 0x1F; eID.Fields.SensorID = 0; eID.Fields.Route = ROUTE_SLAVE; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; int TxTest = 0; HAL_TIM_Base_Start_IT(&htim7); while(1) { if(ReceivedRequest.AnalogFlags.AllFlags) { REQUESTER_AnalogProcessing(); } if(ReceivedRequest.BroadcastFlags.AllFlags) { REQUESTER_BroadcastProcessing(); } if(ReceivedRequest.DiscreticFlags.AllFlags) { REQUESTER_DiscreticProcessing(); } if(ReceivedRequest.ModbusFlags.AllFlags) { REQUESTER_ModbusProcessing(); } while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) == 0); TxHeader.ExtId = eID.BitAll; if(HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailBox)!= HAL_OK) { ProverkaArbitors++; } eID.Fields.SensorID++; if(eID.Fields.SensorID>100) { eID.Fields.SensorID = 0; } } } /** * @brief Функция обработки аналоговых запросов. * @details Функция, формирующая и отправляющая ответ на запросы. Типы запросов: Универсальный, Уставки, Напряжение, Ток, Температура */ void REQUESTER_AnalogProcessing() { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; if(ReceivedRequest.AnalogFlags.AnalogType.Request_Universal_Sens) { ReceivedRequest.AnalogFlags.AnalogType.Request_Universal_Sens = 0; } if(ReceivedRequest.AnalogFlags.AnalogType.Request_U_Sens) { //Запрос на данные датчика напряжения. //В дальнейшем реализовать отправку настоящих данных. //А пока - тестовое сообщение, нужное для отладки. //Расширенный ID TxHeader.IDE=CAN_ID_EXT; //Ответ на запрос осуществляется по тому-же ID, //с которым был отправлен запрос. union ext_ID eID; eID.BitAll = ReceivedRequest.RequestedExtID.BitAll; eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = eID.BitAll; //Выставляется количество передаваемых байтов. (Макс. 8) TxHeader.DLC = 6; data[0] = 'U'; data[1] = ' '; data[2] = 's'; data[3] = 'e'; data[4] = 'n'; data[5] = 's'; HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailBox); ReceivedRequest.AnalogFlags.AnalogType.Request_U_Sens=0; } if(ReceivedRequest.AnalogFlags.AnalogType.Request_I_Sens) { TxHeader.IDE=CAN_ID_EXT; union ext_ID eID; eID.BitAll = ReceivedRequest.RequestedExtID.BitAll; eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = eID.BitAll; TxHeader.DLC = 6; data[0] = 'I'; data[1] = ' '; data[2] = 's'; data[3] = 'e'; data[4] = 'n'; data[5] = 's'; HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailBox); ReceivedRequest.AnalogFlags.AnalogType.Request_I_Sens=0; } if(ReceivedRequest.AnalogFlags.AnalogType.Request_T_Sens) { TxHeader.IDE=CAN_ID_EXT; union ext_ID eID; eID.BitAll = ReceivedRequest.RequestedExtID.BitAll; eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = eID.BitAll; TxHeader.DLC = 6; data[0] = 'T'; data[1] = ' '; data[2] = 's'; data[3] = 'e'; data[4] = 'n'; data[5] = 's'; HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailBox); ReceivedRequest.AnalogFlags.AnalogType.Request_T_Sens=0; } } /** * @brief Функция обработки широковещательных запросов. * @details Функция, выполняющая команды, переданные в широковещательном формате с головного (master) устройства. Типы команд: Запрос статуса, запрос на включение или выключение, рестарт устройств, установка времени. */ void REQUESTER_BroadcastProcessing() { if(ReceivedRequest.BroadcastFlags.BroadcastType.Request_OnOff) { //Обработка запроса на вкл/выкл ControlFlags.IsPulse = !ControlFlags.IsPulse; ReceivedRequest.BroadcastFlags.BroadcastType.Request_OnOff = 0; } if(ReceivedRequest.BroadcastFlags.BroadcastType.Request_RTC_Setup) { //Обработка запроса на синхронизацию времени //С головным устройством if(ReceivedRequest.RequestedDLC > 7) { //ERROR } else { int DaysCount_Normal[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; if (ReceivedRequest.RxData[0]>23 || ReceivedRequest.RxData[1]>59 || ReceivedRequest.RxData[2]>59 || ReceivedRequest.RxData[3]>99 || ReceivedRequest.RxData[4]>12 || ReceivedRequest.RxData[5] > DaysCount_Normal[IsLeapYear(ReceivedRequest.RxData[3])][ReceivedRequest.RxData[4]] || ReceivedRequest.RxData[6]>6) { //ERROR } else { REQUESTER_RTC_SYNC(ReceivedRequest.RxData); } } ReceivedRequest.BroadcastFlags.BroadcastType.Request_RTC_Setup = 0; } if(ReceivedRequest.BroadcastFlags.BroadcastType.Request_Status) { //Обработка запроса статуса устройства RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef DateToUpdate = {0}; HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE=CAN_ID_EXT; union ext_ID eID; eID.BitAll = ReceivedRequest.RequestedExtID.BitAll; eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = eID.BitAll; TxHeader.DLC = 7; data[0] = sTime.Hours; data[1] = sTime.Minutes; data[2] = sTime.Seconds; HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN); data[3] = DateToUpdate.Year; data[4] = DateToUpdate.Month; data[5] = DateToUpdate.Date; data[6] = DateToUpdate.WeekDay; HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailBox); ReceivedRequest.AnalogFlags.AnalogType.Request_T_Sens=0; ReceivedRequest.BroadcastFlags.BroadcastType.Request_Status = 0; } } /** * @brief Функция обработки дискретных запросов. * @details Функция, формирующая и отправляющая ответ на запросы. Типы запросов: Аварии, Предупреждения, Управляющие сигналы, Флаги, Рестарт устройства, Изменение режима работы устройства, Запрос на устройство. * @note Запрос на устройство. Головное (master) устройство запрашивает некоторое колличество параметров. В Data - 64 битовых адресса параметров, тип которых задаётся в Sensor ID. Имеется возможность запрашивать непоследовательные параметры. */ void REQUESTER_DiscreticProcessing() { if(ReceivedRequest.DiscreticFlags.DiscreticType.Request_Accident) { ReceivedRequest.DiscreticFlags.DiscreticType.Request_Accident = 0; } if(ReceivedRequest.DiscreticFlags.DiscreticType.Request_Control_Signals) { ReceivedRequest.DiscreticFlags.DiscreticType.Request_Control_Signals = 0; } if(ReceivedRequest.DiscreticFlags.DiscreticType.Request_Flags) { ReceivedRequest.DiscreticFlags.DiscreticType.Request_Flags = 0; } if(ReceivedRequest.DiscreticFlags.DiscreticType.Request_Warning) { ReceivedRequest.DiscreticFlags.DiscreticType.Request_Warning = 0; } if(ReceivedRequest.DiscreticFlags.DiscreticType.Request_Reset) { ReceivedRequest.DiscreticFlags.DiscreticType.Request_Reset = 0; NVIC_SystemReset(); } if(ReceivedRequest.DiscreticFlags.DiscreticType.Request_List_of_Parameters) { ReceivedRequest.DiscreticFlags.DiscreticType.Request_List_of_Parameters = 0; for(int Current_byte = 0; Current_byte < 8; Current_byte++) { for(int Current_bit = 0; Current_bit < 8; Current_bit++) { if((ReceivedRequest.RxData[Current_byte]>>Current_bit)&0b1) { _GET_MODBUS_ADR(ReceivedRequest.RequestedExtID.Fields.SensorID, Current_byte, Current_bit); } } } } } /** * @brief Функция обработки Modbus запросов. * @details Функция, формирующая и отправляющая ответ на запросы. */ void REQUESTER_ModbusProcessing() { if((ReceivedRequest.SensorToModbus.Modbus.StrAdr>=0) && (ReceivedRequest.SensorToModbus.Modbus.StrAdr<=127)) { //Обращение к существующему в устройстве модбас регистру CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.DLC = 8; TxHeader.RTR = CAN_RTR_DATA; int RequestFromDLC; for(RequestFromDLC = ReceivedRequest.SensorToModbus.Modbus.StrAdr; (RequestFromDLC>11; eID.Fields.SensorID = RequestFromDLC; TxHeader.ExtId = eID.BitAll; for(int DataFor = 0; DataFor < 8; DataFor+=2) { data[DataFor] = HighByteOfWord(ModbusDemonstration[CURRENT_ID_DEVICE][RequestFromDLC]); data[DataFor+1] = LowByteOfWord(ModbusDemonstration[CURRENT_ID_DEVICE][RequestFromDLC]); RequestFromDLC++; TxHeader.DLC +=2; if(!((RequestFromDLC 0xFF) { PulseStage = 0; } data[0] = PulseStage++; HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailBox); } } void REQUESTER_RTC_SYNC(uint8_t *data) { __HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc); RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef DateToUpdate = {0}; sTime.Hours = data[0]; sTime.Minutes = data[1]; sTime.Seconds = data[2]; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } DateToUpdate.Year = data[3]; DateToUpdate.Month = data[4]; DateToUpdate.Date = data[5]; DateToUpdate.WeekDay = data[6]; if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } __HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc); } void REQUESTER_CAN_FILTERS() { //MAIN DEVICE CAN_FilterTypeDef canFilterConfig; canFilterConfig.FilterBank = 0; canFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; canFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; /*Для ID устройства используются восемь младших битов. Макс значение 0 устройство - 0x000, 1 - 0x002, 2 - 0x004, 3 - 0x006*/ canFilterConfig.FilterIdHigh = (uint16_t)(ID_MAIN_DEVICE>>13); canFilterConfig.FilterIdLow = (uint16_t)(ID_MAIN_DEVICE<<5) | CAN_IDE_32; /*Маска 1.1111.1110.<...>. Нули - любые символы. Единицы - точное соответствие фильтру выше.*/ canFilterConfig.FilterMaskIdHigh = (uint16_t)(CAN_DEVICE_ID_FILTER>>13); canFilterConfig.FilterMaskIdLow = (uint16_t)(CAN_DEVICE_ID_FILTER<<3) | CAN_IDE_32; canFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; canFilterConfig.FilterActivation = ENABLE; canFilterConfig.SlaveStartFilterBank = 14; if(HAL_CAN_ConfigFilter(&hcan, &canFilterConfig) != HAL_OK) { Error_Handler(); } //CURRENT DEVICE canFilterConfig.FilterBank = 1; /*Для ID устройства используются восемь младших битов. Макс значение 0 устройство - 0x000, 1 - 0x002, 2 - 0x004, 3 - 0x006*/ canFilterConfig.FilterIdHigh = (uint16_t)(CURRENT_ID_DEVICE>>13); canFilterConfig.FilterIdLow = (uint16_t)(CURRENT_ID_DEVICE<<5) | CAN_IDE_32; /*Маска 1.1111.1110.<...>. Нули - любые символы. Единицы - точное соответствие фильтру выше.*/ canFilterConfig.FilterMaskIdHigh = (uint16_t)(CAN_DEVICE_ID_FILTER>>13); canFilterConfig.FilterMaskIdLow = (uint16_t)(CAN_DEVICE_ID_FILTER<<3) | CAN_IDE_32; if(HAL_CAN_ConfigFilter(&hcan, &canFilterConfig) != HAL_OK) { Error_Handler(); } //MODBUS canFilterConfig.FilterBank = 2; canFilterConfig.FilterIdHigh = (uint16_t)(0x03000000>>13); canFilterConfig.FilterIdLow = (uint16_t)(0x03000000<<5) | CAN_IDE_32; canFilterConfig.FilterMaskIdHigh = (uint16_t)(CAN_DATA_TYPE_FILTER>>13); // we're checking only high 13 bits, that contained "key" canFilterConfig.FilterMaskIdLow = (uint16_t)(CAN_DATA_TYPE_FILTER<<3) | CAN_IDE_32; // 1<<2 - set IDE bit if(HAL_CAN_ConfigFilter(&hcan, &canFilterConfig) != HAL_OK) { Error_Handler(); } //PULSE canFilterConfig.FilterBank = 3; canFilterConfig.FilterIdHigh = (uint16_t)(HighIdFilter(DATA_TYPE_PULSE)>>13); //canFilterConfig.FilterIdHigh = (uint16_t)(0x1F000000>>13); canFilterConfig.FilterIdLow = (uint16_t)(HighIdFilter(DATA_TYPE_PULSE)<<5) | CAN_IDE_32; canFilterConfig.FilterMaskIdHigh = (uint16_t)(CAN_DATA_TYPE_FILTER>>13); // we're checking only high 13 bits, that contained "key" canFilterConfig.FilterMaskIdLow = (uint16_t)(CAN_DATA_TYPE_FILTER<<3) | CAN_IDE_32; // 1<<2 - set IDE bit if(HAL_CAN_ConfigFilter(&hcan, &canFilterConfig) != HAL_OK) { Error_Handler(); } }