#include "requester.h" struct device CurrentDevice; struct device Device_on_the_Network[8][16]; struct controlflags ControlFlags; uint8_t CurrentStep = 1; uint8_t LastStep = 0; struct RXMsg rxMsg[CAN_RX_BUFFER_SIZE]; _Bool IsLeapYear(uint8_t year) { year+=2000; return (year%400==0)||((year%4==0)&&(year%100!=0)); } uint16_t AvailableCanRxMsg(void) { return ((uint16_t)(CAN_RX_BUFFER_SIZE + (LastStep - CurrentStep + 1)))%CAN_RX_BUFFER_SIZE; } /** * @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); HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_ERROR | CAN_IT_BUSOFF | CAN_IT_LAST_ERROR_CODE); ControlFlags.IsPulse = 1; MX_TIM4_Init(); MX_RTC_Init(); } /** * @brief Функция с обработкой полученных запросов * @details В бесконечном цикле функция ожидает приёма сообщения. После этого сообщение распределяется в зависимости от DataType. * Обработка запроса аналоговых значений - REQUESTER_AnalogProcessing(). * Обработка широковещательных запросов - REQUESTER_BroadcastProcessing(). * Обработка запроса дискретных значений - REQUESTER_DiscreticProcessing(). * Обработка Modbus - REQUESTER_ModbusProcessing(). */ void REQUESTER_MainWhile(void) { HAL_TIM_Base_Start_IT(&htim4); unsigned currentAttemptCount; while(1) { if(AvailableCanRxMsg()) { currentAttemptCount = 0; if(rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_ANALOG) { REQUESTER_AnalogProcessing(rxMsg[CurrentStep]); } else if(rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_BROADCAST) { REQUESTER_BroadcastProcessing(rxMsg[CurrentStep]); } else if(rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_DISCRETE) { REQUESTER_DiscreticProcessing(rxMsg[CurrentStep]); } else if(rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_GENERAL_ADDRESS_SPACE) { REQUESTER_GeneralAddressSpace_Answer(rxMsg[CurrentStep]); } else if(rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_MODBUS_COIL || rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_MODBUS_DISCRETE || rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_MODBUS_HOLDING || rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_MODBUS_INPUT) { REQUESTER_ModbusProcessing(rxMsg[CurrentStep]); } else if(rxMsg[CurrentStep].eID.Fields.MsgType == DATA_TYPE_ERROR) { CanRequestError(rxMsg[CurrentStep]); } CurrentStep = (uint16_t)(CurrentStep + 1) % CAN_RX_BUFFER_SIZE; } } } /** * @brief Функция обработки аналоговых запросов. * @param struct RXMsg _rxMsg - структура для полученного сообщения. * @details Функция, формирующая и отправляющая ответ на запросы. Типы запросов: Универсальный, Уставки, Напряжение, Ток, Температура. */ CRR_Status REQUESTER_AnalogProcessing(struct RXMsg _rxMsg) { msgAnalogType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; switch (msg.Fields.SensorType) { case SENSOR_TYPE_ANALOG_UNIVERSAL: { return (CRR_Status)CanRequestToAnalogUniversal(_rxMsg); break; } case SENSOR_TYPE_ANALOG_USTAVKI: { return (CRR_Status)CanRequestToAnalogUSTAVKI(_rxMsg); break; } case SENSOR_TYPE_ANALOG_U: { return (CRR_Status)CanRequestToAnalogUSens(_rxMsg); break; } case SENSOR_TYPE_ANALOG_I: { return (CRR_Status)CanRequestToAnalogISens(_rxMsg); break; } case SENSOR_TYPE_ANALOG_T: { return (CRR_Status)CanRequestToAnalogTSens(_rxMsg); break; } default: //RESERVE SENSOR TYPE return CRR_ERROR; break; } return CRR_ERROR; } __weak HAL_StatusTypeDef CanRequestToAnalogUniversal(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 6; data[0] = 'U'; data[1] = 'N'; data[2] = 'I'; data[3] = 'V'; data[4] = 'E'; data[5] = 'R'; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestToAnalogUSTAVKI(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 7; data[0] = 'U'; data[1] = 'S'; data[2] = 'T'; data[3] = 'A'; data[4] = 'V'; data[5] = 'K'; data[6] = 'I'; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestToAnalogUSens(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 6; msgAnalogType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; data[0] = 'U'; data[1] = 'S'; data[2] = 47 + msg.Fields.SensorID / 1000; data[3] = 47 + msg.Fields.SensorID / 100 % 10; data[4] = 47 + msg.Fields.SensorID / 10 % 10; data[5] = 47 + msg.Fields.SensorID % 10; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestToAnalogISens(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 6; msgAnalogType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; data[0] = 'I'; data[1] = 'S'; data[2] = 47 + msg.Fields.SensorID / 1000; data[3] = 47 + msg.Fields.SensorID / 100 % 10; data[4] = 47 + msg.Fields.SensorID / 10 % 10; data[5] = 47 + msg.Fields.SensorID % 10; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestToAnalogTSens(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 6; msgAnalogType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; data[0] = 'T'; data[1] = 'S'; data[2] = 47 + msg.Fields.SensorID / 1000; data[3] = 47 + msg.Fields.SensorID / 100 % 10; data[4] = 47 + msg.Fields.SensorID / 10 % 10; data[5] = 47 + msg.Fields.SensorID % 10; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } /** * @brief Функция обработки широковещательных запросов. * @param struct RXMsg _rxMsg - структура для полученного сообщения. * @details Функция, выполняющая команды, переданные в широковещательном формате с головного (master) устройства. Типы команд: Запрос статуса, запрос на включение или выключение, рестарт устройств, установка времени. */ CRR_Status REQUESTER_BroadcastProcessing(struct RXMsg _rxMsg) { msgBroadcastType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; switch(msg.Fields.BroadcastType) { case SENSOR_TYPE_BROADCAST_STATUS: { //Обработка запроса статуса устройства if(CanRequestToBroadcastStatus(_rxMsg)!=HAL_OK) { return CRR_ERROR; } break; } case SENSOR_TYPE_BROADCAST_ONOFF: { //Обработка запроса на вкл/выкл CanRequestToBroadcastOnOff(_rxMsg); break; } case SENSOR_TYPE_BROADCAST_RESTARTDEVICE: { CanRequestToBroadcastRestart(_rxMsg); break; } case SENSOR_TYPE_BROADCAST_RTCSETUP: { //Обработка запроса на синхронизацию времени //С головным устройством CanRequestToBroadcastRtcSetup(_rxMsg); break;; } default: //RESERVE SENSOR TYPE. return CRR_ERROR; break; } return CRR_OK; } __weak HAL_StatusTypeDef CanRequestToBroadcastStatus(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.DLC = 7; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; tmp_eID.Fields.DeviceType = CURRENT_TYPE_DEVICE; tmp_eID.Fields.DeviceID = CURRENT_ID_DEVICE; TxHeader.ExtId = tmp_eID.BitAll; RTC_TimeTypeDef sTime = {0}; HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); data[0] = sTime.Hours; data[1] = sTime.Minutes; data[2] = sTime.Seconds; RTC_DateTypeDef DateToUpdate = {0}; HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN); data[3] = DateToUpdate.Year; data[4] = DateToUpdate.Month; data[5] = DateToUpdate.Date; data[6] = DateToUpdate.WeekDay; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak void CanRequestToBroadcastOnOff(struct RXMsg _rxMsg) { ControlFlags.IsPulse = !ControlFlags.IsPulse; } __weak void CanRequestToBroadcastRestart(struct RXMsg _rxMsg) { if(_rxMsg.DLC == 0) { return; } msgBroadcastType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; if(msg.Fields.Page == (CURRENT_ID_DEVICE / (_rxMsg.DLC*8))) { uint64_t page = 0; for(int i = 0; i < _rxMsg.DLC; i++) { page+=(_rxMsg.Data[i]<<(i*8)); } if((page>>CURRENT_ID_DEVICE)&0b1) { NVIC_SystemReset(); } } return; } __weak void CanRequestToBroadcastRtcSetup(struct RXMsg _rxMsg) { if(_rxMsg.DLC > 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(_rxMsg.Data[0]>23 || _rxMsg.Data[1]>59 || _rxMsg.Data[2]>59 || _rxMsg.Data[3]>99 || _rxMsg.Data[4]>12 || _rxMsg.Data[5] > DaysCount_Normal[IsLeapYear(_rxMsg.Data[3])][_rxMsg.Data[4]] || _rxMsg.Data[6]>6) { //ERROR } else { REQUESTER_RTC_SYNC(_rxMsg.Data); } } } /** * @brief Функция обработки дискретных запросов. * @param struct RXMsg _rxMsg - структура для полученного сообщения. * @details Функция, формирующая и отправляющая ответ на запросы. Типы запросов: Аварии, Предупреждения, Управляющие сигналы, Флаги, Рестарт устройства, Изменение режима работы устройства, Запрос на устройство. * @note Запрос на устройство. Головное (master) устройство запрашивает некоторое колличество параметров. В Data - 64 битовых адресса параметров, тип которых задаётся в Sensor ID. Имеется возможность запрашивать непоследовательные параметры. */ CRR_Status REQUESTER_DiscreticProcessing(struct RXMsg _rxMsg) { msgDiscreteType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; switch(msg.Fields.Type){ case SENSOR_TYPE_DISCRETE_ACCIDENT: { CanRequestToDiscreteAccident(_rxMsg); break; } case SENSOR_TYPE_DISCRETE_WARNING: { CanRequestToDiscreteWarning(_rxMsg); break; } case SENSOR_TYPE_DISCRETE_CONTROL_SIGNALS: { CanRequestToDiscreteControlSignals(_rxMsg); break; } case SENSOR_TYPE_DISCRETE_FLAGS: { CanRequestToDiscreteFlags(_rxMsg); break; } case SENSOR_TYPE_DISCRETE_RESET: { CanRequestToDiscreteReset(_rxMsg); break; } case SENSOR_TYPE_DISCRETE_CHANGE_MODE: { CanRequestToDiscreteChangeMode(_rxMsg); break; } case SENSOR_TYPE_DISCRETE_REQUEST_LIST_OF_PARAMETERS: { CanRequestToDiscreteRequestListOfParameters(_rxMsg); break; } default: //RESERVE SENSOR TYPE. return CRR_ERROR; break; } return CRR_OK; } __weak void CanRequestToDiscreteAccident(struct RXMsg _rxMsg) { return; } __weak void CanRequestToDiscreteWarning(struct RXMsg _rxMsg) { return; } __weak void CanRequestToDiscreteControlSignals(struct RXMsg _rxMsg) { return; } __weak void CanRequestToDiscreteFlags(struct RXMsg _rxMsg) { return; } __weak void CanRequestToDiscreteReset(struct RXMsg _rxMsg) { NVIC_SystemReset(); } __weak void CanRequestToDiscreteChangeMode(struct RXMsg _rxMsg) { return; } __weak void CanRequestToDiscreteRequestListOfParameters(struct RXMsg _rxMsg) { return; } void REQUESTER_GeneralAddressSpace_Answer(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 8; data[0] = 'G'; data[1] = 'A'; data[2] = 'S'; data[3] = '-'; for(int i = 0; i < 4; i++) { unsigned sym = (_rxMsg.eID.Fields.MsgBody>>(12-(i*4)))&0xF; if(sym >= 10) data[4+i] = sym%10+'A'; else data[4+i] = sym+'0'; } HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } /** * @brief Функция обработки Modbus запросов. * @param struct RXMsg _rxMsg - структура для полученного сообщения. * @details Функция, формирующая и отправляющая ответ на запросы. */ CRR_Status REQUESTER_ModbusProcessing(struct RXMsg _rxMsg) { switch(_rxMsg.eID.Fields.MsgType) { case DATA_TYPE_MODBUS_COIL: { return (CRR_Status)CanRequestToModbusCoil(_rxMsg); break; } case DATA_TYPE_MODBUS_DISCRETE: { return (CRR_Status)CanRequestToModbusDiscrete(_rxMsg); break; } case DATA_TYPE_MODBUS_HOLDING: { return (CRR_Status)CanRequestToModbusHolding(_rxMsg); break; } case DATA_TYPE_MODBUS_INPUT: { return (CRR_Status)CanRequestToModbusInput(_rxMsg); break; } default: //ERROR return CRR_ERROR; break; } return CRR_ERROR; } __weak HAL_StatusTypeDef CanRequestToModbusCoil(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 8; msgModbusType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; data[0] = 'M'; data[1] = 'C'; data[2] = ' '; data[3] = 'S'; data[4] = msg.Fields.StrAdr; data[5] = ' '; data[6] = 'C'; data[7] = msg.Fields.RegCount; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestToModbusDiscrete(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 8; msgModbusType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; data[0] = 'M'; data[1] = 'D'; data[2] = ' '; data[3] = 'S'; data[4] = msg.Fields.StrAdr; data[5] = ' '; data[6] = 'C'; data[7] = msg.Fields.RegCount; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestToModbusHolding(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 8; msgModbusType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; data[0] = 'M'; data[1] = 'H'; data[2] = ' '; data[3] = 'S'; data[4] = msg.Fields.StrAdr; data[5] = ' '; data[6] = 'C'; data[7] = msg.Fields.RegCount; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestToModbusInput(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 8; msgModbusType msg; msg.Body = _rxMsg.eID.Fields.MsgBody; data[0] = 'M'; data[1] = 'I'; data[2] = ' '; data[3] = 'S'; data[4] = msg.Fields.StrAdr; data[5] = ' '; data[6] = 'C'; data[7] = msg.Fields.RegCount; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } __weak HAL_StatusTypeDef CanRequestError(struct RXMsg _rxMsg) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; extID tmp_eID; tmp_eID.BitAll = _rxMsg.eID.BitAll; tmp_eID.Fields.Route = ROUTE_SLAVE; tmp_eID.Fields.MsgType = DATA_TYPE_ERROR; msgErrorType msg; msg.Fields.ErrorCode = 0xFF; msg.Fields.Info = 0; tmp_eID.Fields.MsgBody = msg.Body; TxHeader.ExtId = tmp_eID.BitAll; TxHeader.DLC = 0; return HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } /** * @brief * @param extID tmp_eID * @param uint32_t tmp_IDE * @param uint32_t tmp_RTR * @param uint32_t tmp_DLC * @param uint8_t *tmp_DATA * @param uint16_t tmp_LastStep * @details */ void TakeRxMsgToBuffer(extID tmp_eID, uint32_t tmp_IDE, uint32_t tmp_RTR, uint32_t tmp_DLC, uint8_t *tmp_DATA, uint16_t tmp_LastStep) { rxMsg[tmp_LastStep].eID.BitAll = tmp_eID.BitAll; rxMsg[tmp_LastStep].info.EXT = tmp_IDE; rxMsg[tmp_LastStep].info.RTR = tmp_RTR; rxMsg[tmp_LastStep].DLC = tmp_DLC; for(int i = 0; i < tmp_DLC; i++) { rxMsg[tmp_LastStep].Data[i] = tmp_DATA[i]; } LastStep = tmp_LastStep; } /** * @brief Callback-Функция обработки приёма. * @details Функция, сигнализирующая через флаги в бесконечный цикл REQUESTER_MainWhile о приёме запроса. */ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { // Обработка всех сообщений в FIFO CAN_RxHeaderTypeDef RxHeader; uint8_t RCAN_Data[8]; while(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RCAN_Data) == HAL_OK) { //Расширенный ID if(RxHeader.IDE == CAN_ID_EXT) { if(!((CAN_RX_BUFFER_SIZE + LastStep - (CurrentStep-1))&CAN_RX_BUFFER_SIZE)) { //Буффер переполнен return; } uint16_t tmp_LastStep = (uint16_t)(LastStep + 1) % CAN_RX_BUFFER_SIZE; extID ExtID_Of_RX_MSG; ExtID_Of_RX_MSG.BitAll = RxHeader.ExtId; //Полученное сообщение - пульс устройств в сети if(ExtID_Of_RX_MSG.Fields.MsgType == DATA_TYPE_PULSE) { Device_on_the_Network[ExtID_Of_RX_MSG.Fields.DeviceType][ExtID_Of_RX_MSG.Fields.DeviceID].Status = ONLINE; Device_on_the_Network[ExtID_Of_RX_MSG.Fields.DeviceType][ExtID_Of_RX_MSG.Fields.DeviceID].TimeFromLastPulse = 0; return; } TakeRxMsgToBuffer(ExtID_Of_RX_MSG, RxHeader.IDE, RxHeader.RTR, RxHeader.DLC, RCAN_Data, tmp_LastStep); } } } /** * @brief Функция отправки пульса устройства. * @details Пульс устройства. Есть возможность отключить пульс по запросу. */ void REQUESTER_Pulse_TIM_Handler() { if(ControlFlags.IsPulse) { static unsigned PulseStage = 0; CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; extID currentID; currentID.BitAll = 0; currentID.Fields.MsgBody = 0; currentID.Fields.DeviceID = CURRENT_ID_DEVICE; currentID.Fields.DeviceType = CURRENT_TYPE_DEVICE; currentID.Fields.MsgType = DATA_TYPE_PULSE; currentID.Fields.Route = ROUTE_SLAVE; currentID.Fields.Priority = PRIORITY_STANDARD; TxHeader.ExtId = currentID.BitAll; uint8_t data[8]; TxHeader.IDE = CAN_ID_EXT; TxHeader.TransmitGlobalTime = DISABLE; TxHeader.RTR = CAN_RTR_DATA; TxHeader.DLC = 1; PulseStage++; unsigned int debugID; debugID = currentID.BitAll; if(PulseStage > 0xFF){ PulseStage = 0; } data[0] = PulseStage; HAL_CAN_AddTxMessage(&_HCAN, &TxHeader, data, &TxMailBox); } } /** * @brief Функция установки в RTC полученной даты/время из запроса. * @param uint8_t *data - Байтовый массив, 7 элементов. [0] - Часы. [1] - Минуты. [2] - Секунды. [3] - Год. [4] - Месяц. [5] - Дата. [6] - День недели. */ 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); } /** * @brief Функция настройки фильтров CAN. * @details Настройка фильтров. Фильр для приёма сообщений с главного устройства. Фильтр для приёма на текущее устройство. Фильтр для приёма пульса других устройств в сети. */ void CONFIG_CAN_FILTER(uint8_t filterBank, uint32_t idFilter, uint32_t idMask) { CAN_FilterTypeDef canFilterConfig; canFilterConfig.FilterBank = filterBank; canFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; canFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; canFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; canFilterConfig.FilterActivation = ENABLE; canFilterConfig.SlaveStartFilterBank = 14; // Разбиваем 32-битный ID и маску для фильтрации на High и Low 16 бит canFilterConfig.FilterIdHigh = (uint16_t)( ((idFilter) >> 13) ); // верхние 16 бит canFilterConfig.FilterIdLow = (uint16_t)( (((idFilter) << 3) ) | CAN_IDE_32 ); // низкие 16 бит, canFilterConfig.FilterMaskIdHigh = (uint16_t)(((idMask) >> 13) ); canFilterConfig.FilterMaskIdLow = (uint16_t)( (((idMask) << 3) ) | CAN_IDE_32 ); if(HAL_CAN_ConfigFilter(&_HCAN, &canFilterConfig) != HAL_OK) { Error_Handler(); } } #define BIT27 (1UL << 27) #define BITS_20_23_MASK (0xFUL << 20) // 4 бита (20..23) #define BITS_24_26_MASK (0x7UL << 24) // 3 бита (24..26) uint32_t filter1_id = BIT27 | (CURRENT_TYPE_DEVICE << 24) | (CURRENT_ID_DEVICE << 20); uint32_t filter1_mask = BIT27 | BITS_24_26_MASK | BITS_20_23_MASK; // все проверяемые биты #define BITS_16_19_MASK (0xFUL << 16) uint32_t filter2_id = DATA_TYPE_BROADCAST << 16; uint32_t filter2_mask = BITS_16_19_MASK; uint32_t filter3_id = DATA_TYPE_PULSE << 16; uint32_t filter3_mask = BITS_16_19_MASK; void REQUESTER_CAN_FILTERS() { // Первый фильтр: проверяем 20-27 биты, где 27-й всегда 1 CONFIG_CAN_FILTER(0, filter1_id, filter1_mask); // Второй фильтр: проверяем 16-19 биты, равны DATA_TYPE_BROADCASTE CONFIG_CAN_FILTER(1, filter2_id, filter2_mask); // Третий фильтр: проверяем 16-19 биты, равны DATA_TYPE_PULSE CONFIG_CAN_FILTER(2, filter3_id, filter3_mask); //CONFIG_CAN_FILTER(3, 0, 0); }