diff --git a/Core/Inc/protocan.h b/Core/Inc/protocan.h index 01aa8fc..114ad90 100644 --- a/Core/Inc/protocan.h +++ b/Core/Inc/protocan.h @@ -255,6 +255,7 @@ PROTOCAN_INIT_StatusTypeDef PROTOCAN_INIT(CAN_HandleTypeDef *tmp_hcan, void PROTOCAN_DEINIT(uint8_t stage); void PROTOCAN_FILTERS(void); void PROTOCAN_LOOP(void); +PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data); void ProtoCanPulseCallback(TIM_HandleTypeDef *htim); void ProtoCanRxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan); diff --git a/Core/Src/protocan.c b/Core/Src/protocan.c index 50554ce..de1bac8 100644 --- a/Core/Src/protocan.c +++ b/Core/Src/protocan.c @@ -111,6 +111,19 @@ PROTOCAN_INIT_StatusTypeDef PROTOCAN_INIT(CAN_HandleTypeDef *tmp_hcan, RTC_Handl */ void PROTOCAN_LOOP(void) { + ProtoCanId_t testId; + testId.BitAll = 0; + testId.Fields.Priority = PROTOCAN_PRIORITY_STANDARD; + testId.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; + testId.Fields.DeviceType = CURRENT_TYPE_DEVICE; + testId.Fields.DeviceID = CURRENT_ID_DEVICE; + testId.Fields.MsgType = PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE; + + ProtoCanData_t testData; + uint16_t massiv[] = {0xABCD, 0x1234, 0xAFBF, 0x5678, 0x9AF1}; + testData.GeneralAddressSpaceData.Data = massiv; + testData.GeneralAddressSpaceData.RegCount = 5; + testData.GeneralAddressSpaceData.RegStartAdr = 0xFA; while(1) { if(AvailableCanRxMsg()) @@ -144,6 +157,7 @@ void PROTOCAN_LOOP(void) } CurrentStep = (uint16_t)(CurrentStep + 1) % PROTOCAN_RX_BUFFER_SIZE; } + PROTOCAN_SEND(testId, testData); } } @@ -659,6 +673,60 @@ __weak PROTOCAN_StatusTypeDef ProtoCanMsgToGeneralAddressSpace(struct RXMsg _rxM return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); } +/** + * @brief Отправляет произвольный диапазон регистров в пакетах по, максимум, 4 регистра за раз через CAN. + * + * Функция разбивает передаваемый массив регистров на пакеты по 4 или меньше и отправляет их по отдельности. + * Для каждого пакета формируется уникальный MsgBody, равный адресу первого регистра в пакете. + * + * @param priority Приоритет сообщения CAN. ProtoCan_Priority_TypeDef + * @param regStartAdr Адрес первого регистра из всего массива. + * @param data Указатель на массив регистров для отправки. + * @param regCount Общее количество регистров для отправки. + * + * @return Возвращает статус отправки: HAL_OK при успехе, или код ошибки HAL_StatusTypeDef при сбое. + */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_GENERAL_ADDRESS_SPACE(ProtoCanId_t id, uint16_t regStartAdr, uint16_t *data, uint8_t regCount) +{ + CAN_TxHeaderTypeDef TxHeader; + uint32_t TxMailBox = 0; + uint8_t canData[8]; + + TxHeader.IDE = CAN_ID_EXT; + TxHeader.TransmitGlobalTime = DISABLE; + TxHeader.RTR = CAN_RTR_DATA; + + ProtoCanId_t tmp_eID; + tmp_eID.BitAll = id.BitAll; + + uint8_t regsRemaining = regCount; + uint8_t currentIndex = 0; + + while(regsRemaining > 0) + { + uint8_t regsInPacket = (regsRemaining > 4) ? 4 : regsRemaining; + + tmp_eID.Fields.MsgBody = regStartAdr + currentIndex; + TxHeader.ExtId = tmp_eID.BitAll; + TxHeader.DLC = regsInPacket*2; + + for(int i = 0; i < regsInPacket; i++) + { + canData[(i*2)+1] = LowByteOfWord(data[currentIndex+i]); + canData[(i*2)] = HighByteOfWord(data[currentIndex+i]); + } + + HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox); + + if(status != HAL_OK) + { + return (PROTOCAN_StatusTypeDef)status; + } + + regsRemaining -= regsInPacket; + currentIndex += regsInPacket; + } + return (PROTOCAN_StatusTypeDef)HAL_OK; } /** @@ -1044,3 +1112,38 @@ void PROTOCAN_FILTERS() // Третий фильтр: проверяем 16-19 биты, равны PROTOCAN_MSGTYPE_PULSE PROTOCAN_CONFIG_FILTER(2, filter3_id, filter3_mask); } + +/** + * @brief Отправляет CAN-сообщение в зависимости от типа сообщения. + * + * Эта функция анализирует тип сообщения в идентификаторе и вызывает + * соответствующую функцию отправки. В текущей реализации поддерживается только + * тип PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE. + * + * @param id Идентификатор CAN-сообщения, содержащий информацию о типе. + * @param data Структура с данными, которые необходимо отправить. Зависит от типа сообщения. + * + * @return Статус выполнения операции: + * - PROTOCAN_OK при успешной отправке, + * - PROTOCAN_ERROR, если тип сообщения не поддерживается или произошла ошибка. + */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data) +{ + switch (id.Fields.MsgType) + { + case PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE: + { + /* Если есть регистры для отправки, указатель data должен быть валиден. */ + if((data.GeneralAddressSpaceData.RegCount > 0U) && data.GeneralAddressSpaceData.Data == 0) + { + return PROTOCAN_ERROR; + } + return PROTOCAN_SEND_GENERAL_ADDRESS_SPACE(id, data.GeneralAddressSpaceData.RegStartAdr, + data.GeneralAddressSpaceData.Data, + data.GeneralAddressSpaceData.RegCount); + } + default: + return PROTOCAN_ERROR; + } + return PROTOCAN_ERROR; +} \ No newline at end of file