|
- #include "modbus_rtu_slave.h"
- #include "plsr.h"
- #include <string.h>
-
- #define MODBUS_RTU_ADU_SIZE_MAX (256U)
- #define MODBUS_RTU_BITS_PER_CHAR (11UL)
- #define MODBUS_RTU_HIGH_BAUD_LIMIT (19200UL)
- #define MODBUS_RTU_T15_US (750UL)
- #define MODBUS_RTU_T35_US (1750UL)
-
- #define MODBUS_BROADCAST_ADDRESS (0U)
- #define MODBUS_SLAVE_ADDRESS_MAX (247U)
-
- #define MODBUS_FC_READ_HOLDING (0x03U)
- #define MODBUS_FC_WRITE_SINGLE (0x06U)
- #define MODBUS_FC_WRITE_MULTIPLE (0x10U)
-
- #define MODBUS_EX_ILLEGAL_FUNCTION (0x01U)
- #define MODBUS_EX_ILLEGAL_ADDRESS (0x02U)
- #define MODBUS_EX_ILLEGAL_VALUE (0x03U)
- #define MODBUS_EX_SERVER_FAILURE (0x04U)
- #define MODBUS_EX_SERVER_BUSY (0x06U)
-
- #define MODBUS_READ_REGISTERS_MAX (125U)
- #define MODBUS_WRITE_REGISTERS_MAX (123U)
-
- static UART_HandleTypeDef *ModbusUart;
- static uint8_t ModbusSlaveAddress;
-
- static uint8_t ModbusRxDmaBuffer[MODBUS_RTU_ADU_SIZE_MAX];
- static uint8_t ModbusRxAssemblyBuffer[MODBUS_RTU_ADU_SIZE_MAX];
- static uint8_t ModbusRxFrame[MODBUS_RTU_ADU_SIZE_MAX];
- static uint8_t ModbusTxFrame[MODBUS_RTU_ADU_SIZE_MAX];
- static uint16_t ModbusRegisterScratch[MODBUS_READ_REGISTERS_MAX];
-
- static volatile uint16_t ModbusRxAssemblyLength;
- static volatile uint8_t ModbusRxAssemblyInvalid;
- static volatile uint32_t ModbusRxLastByteCycle;
- static volatile uint16_t ModbusRxFrameLength;
- static volatile uint8_t ModbusRxFrameReady;
- static volatile uint8_t ModbusTxBusy;
- static volatile uint32_t ModbusLastActivityCycle;
-
- static uint32_t ModbusRtuCharCycles;
- static uint32_t ModbusRtuT15Cycles;
- static uint32_t ModbusRtuT35Cycles;
-
- static HAL_StatusTypeDef ModbusStartReceive(void);
-
- static uint32_t ModbusEnterCritical(void)
- {
- uint32_t primask = __get_PRIMASK();
-
- __disable_irq();
- __DMB();
- return primask;
- }
-
- static void ModbusExitCritical(uint32_t primask)
- {
- __DMB();
- __set_PRIMASK(primask);
- }
-
- static uint16_t ModbusCrc16(const uint8_t *data, uint16_t length)
- {
- uint16_t crc = 0xFFFFU;
- uint16_t index;
- uint8_t bit;
-
- for (index = 0U; index < length; index++)
- {
- crc ^= data[index];
- for (bit = 0U; bit < 8U; bit++)
- {
- if ((crc & 1U) != 0U)
- {
- crc = (uint16_t)((crc >> 1U) ^ 0xA001U);
- }
- else
- {
- crc >>= 1U;
- }
- }
- }
- return crc;
- }
-
- static uint16_t ModbusGetU16Be(const uint8_t *data)
- {
- return (uint16_t)(((uint16_t)data[0] << 8U) | data[1]);
- }
-
- static void ModbusRtuTimingInit(uint32_t baudRate)
- {
- uint64_t coreClock = SystemCoreClock;
- uint64_t charCycleNumerator = coreClock * MODBUS_RTU_BITS_PER_CHAR;
-
- CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
- DWT->CYCCNT = 0U;
- DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
-
- ModbusRtuCharCycles =
- (uint32_t)((charCycleNumerator + baudRate - 1UL) / baudRate);
- if (ModbusRtuCharCycles == 0UL)
- {
- ModbusRtuCharCycles = 1UL;
- }
-
- if (baudRate > MODBUS_RTU_HIGH_BAUD_LIMIT)
- {
- ModbusRtuT15Cycles = (uint32_t)(
- (coreClock * MODBUS_RTU_T15_US + 999999UL) / 1000000UL);
- ModbusRtuT35Cycles = (uint32_t)(
- (coreClock * MODBUS_RTU_T35_US + 999999UL) / 1000000UL);
- }
- else
- {
- ModbusRtuT15Cycles =
- (uint32_t)(((uint64_t)ModbusRtuCharCycles * 3UL + 1UL) / 2UL);
- ModbusRtuT35Cycles =
- (uint32_t)(((uint64_t)ModbusRtuCharCycles * 7UL + 1UL) / 2UL);
- }
- }
-
- static void ModbusRxAssemblyFinalize(void)
- {
- uint16_t length = ModbusRxAssemblyLength;
-
- if (length == 0U)
- {
- return;
- }
-
- if ((ModbusRxAssemblyInvalid == 0U) && (ModbusRxFrameReady == 0U))
- {
- (void)memcpy(ModbusRxFrame, ModbusRxAssemblyBuffer, length);
- ModbusRxFrameLength = length;
- ModbusRxFrameReady = 1U;
- }
-
- ModbusRxAssemblyLength = 0U;
- ModbusRxAssemblyInvalid = 0U;
- }
-
- static HAL_StatusTypeDef ModbusStartReceive(void)
- {
- HAL_StatusTypeDef status;
-
- if ((ModbusUart == NULL) || (ModbusTxBusy != 0U))
- {
- return HAL_BUSY;
- }
-
- status = HAL_UARTEx_ReceiveToIdle_DMA(ModbusUart,
- ModbusRxDmaBuffer,
- sizeof(ModbusRxDmaBuffer));
- if (status == HAL_OK)
- {
- __HAL_DMA_DISABLE_IT(ModbusUart->hdmarx, DMA_IT_HT);
- }
- return status;
- }
-
- static void ModbusTryFinalizeReceive(void)
- {
- uint32_t now;
- uint32_t primask;
- uint8_t restartReceive;
-
- if ((ModbusUart == NULL) || (ModbusRxAssemblyLength == 0U))
- {
- return;
- }
-
- if (((ModbusUart->Instance->CR3 & USART_CR3_DMAR) != 0U)
- && (__HAL_DMA_GET_COUNTER(ModbusUart->hdmarx)
- < MODBUS_RTU_ADU_SIZE_MAX))
- {
- return;
- }
-
- now = DWT->CYCCNT;
- if ((uint32_t)(now - ModbusRxLastByteCycle) < ModbusRtuT35Cycles)
- {
- return;
- }
-
- if (HAL_UART_AbortReceive(ModbusUart) != HAL_OK)
- {
- primask = ModbusEnterCritical();
- ModbusRxAssemblyLength = 0U;
- ModbusRxAssemblyInvalid = 0U;
- ModbusExitCritical(primask);
- (void)HAL_UART_Abort(ModbusUart);
- (void)ModbusStartReceive();
- return;
- }
-
- primask = ModbusEnterCritical();
- ModbusRxAssemblyFinalize();
- restartReceive = (ModbusRxFrameReady == 0U) ? 1U : 0U;
- ModbusExitCritical(primask);
-
- if (restartReceive != 0U)
- {
- (void)ModbusStartReceive();
- }
- }
-
- static void ModbusAppendCrc(uint8_t *frame, uint16_t payloadLength)
- {
- uint16_t crc = ModbusCrc16(frame, payloadLength);
-
- frame[payloadLength] = (uint8_t)(crc & 0x00FFU);
- frame[payloadLength + 1U] = (uint8_t)(crc >> 8U);
- }
-
- static uint16_t ModbusBuildException(uint8_t function, uint8_t exception)
- {
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = (uint8_t)(function | 0x80U);
- ModbusTxFrame[2] = exception;
- ModbusAppendCrc(ModbusTxFrame, 3U);
- return 5U;
- }
-
- static uint16_t ModbusBuildPlsrException(uint8_t function,
- PLSR_MB_RESULT result,
- uint8_t isBroadcast)
- {
- uint8_t exception;
-
- if (isBroadcast != 0U)
- {
- return 0U;
- }
-
- switch (result)
- {
- case PLSR_MB_NOT_HANDLED:
- case PLSR_MB_ILLEGAL_ADDRESS:
- exception = MODBUS_EX_ILLEGAL_ADDRESS;
- break;
- case PLSR_MB_ILLEGAL_VALUE:
- exception = MODBUS_EX_ILLEGAL_VALUE;
- break;
- case PLSR_MB_DEVICE_BUSY:
- exception = MODBUS_EX_SERVER_BUSY;
- break;
- case PLSR_MB_SERVER_FAILURE:
- default:
- exception = MODBUS_EX_SERVER_FAILURE;
- break;
- }
- return ModbusBuildException(function, exception);
- }
-
- static uint16_t ModbusProcessReadHolding(const uint8_t *request,
- uint16_t requestLength)
- {
- uint16_t start;
- uint16_t quantity;
- uint16_t index;
- PLSR_MB_RESULT result;
-
- if (requestLength != 8U)
- {
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- start = ModbusGetU16Be(&request[2]);
- quantity = ModbusGetU16Be(&request[4]);
- if ((quantity == 0U) || (quantity > MODBUS_READ_REGISTERS_MAX))
- {
- return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- result = PlsrModbusReadHolding(start, quantity, ModbusRegisterScratch);
- if (result != PLSR_MB_OK)
- {
- return ModbusBuildPlsrException(request[1], result, 0U);
- }
-
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = MODBUS_FC_READ_HOLDING;
- ModbusTxFrame[2] = (uint8_t)(quantity * 2U);
- for (index = 0U; index < quantity; index++)
- {
- ModbusTxFrame[3U + index * 2U] =
- (uint8_t)(ModbusRegisterScratch[index] >> 8U);
- ModbusTxFrame[4U + index * 2U] =
- (uint8_t)(ModbusRegisterScratch[index] & 0x00FFU);
- }
- ModbusAppendCrc(ModbusTxFrame, (uint16_t)(3U + quantity * 2U));
- return (uint16_t)(5U + quantity * 2U);
- }
-
- static uint16_t ModbusProcessWriteSingle(const uint8_t *request,
- uint16_t requestLength,
- uint8_t isBroadcast)
- {
- uint16_t address;
- uint16_t value;
- PLSR_MB_RESULT result;
-
- if (requestLength != 8U)
- {
- return (isBroadcast != 0U)
- ? 0U
- : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- address = ModbusGetU16Be(&request[2]);
- value = ModbusGetU16Be(&request[4]);
- result = PlsrModbusWriteHolding(address, 1U, &value);
- if (result != PLSR_MB_OK)
- {
- return ModbusBuildPlsrException(request[1], result, isBroadcast);
- }
-
- if (isBroadcast != 0U)
- {
- return 0U;
- }
-
- (void)memcpy(ModbusTxFrame, request, 6U);
- ModbusAppendCrc(ModbusTxFrame, 6U);
- return 8U;
- }
-
- static uint16_t ModbusProcessWriteMultiple(const uint8_t *request,
- uint16_t requestLength,
- uint8_t isBroadcast)
- {
- uint16_t start;
- uint16_t quantity;
- uint16_t byteCount;
- uint16_t index;
- PLSR_MB_RESULT result;
-
- if (requestLength < 9U)
- {
- return (isBroadcast != 0U)
- ? 0U
- : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- start = ModbusGetU16Be(&request[2]);
- quantity = ModbusGetU16Be(&request[4]);
- byteCount = request[6];
- if ((quantity == 0U)
- || (quantity > MODBUS_WRITE_REGISTERS_MAX)
- || (byteCount != (uint16_t)(quantity * 2U))
- || (requestLength != (uint16_t)(9U + byteCount)))
- {
- return (isBroadcast != 0U)
- ? 0U
- : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
- }
-
- for (index = 0U; index < quantity; index++)
- {
- ModbusRegisterScratch[index] =
- ModbusGetU16Be(&request[7U + index * 2U]);
- }
- result = PlsrModbusWriteHolding(start, quantity, ModbusRegisterScratch);
- if (result != PLSR_MB_OK)
- {
- return ModbusBuildPlsrException(request[1], result, isBroadcast);
- }
-
- if (isBroadcast != 0U)
- {
- return 0U;
- }
-
- ModbusTxFrame[0] = ModbusSlaveAddress;
- ModbusTxFrame[1] = MODBUS_FC_WRITE_MULTIPLE;
- (void)memcpy(&ModbusTxFrame[2], &request[2], 4U);
- ModbusAppendCrc(ModbusTxFrame, 6U);
- return 8U;
- }
-
- static uint16_t ModbusProcessRequest(const uint8_t *request,
- uint16_t requestLength)
- {
- uint16_t receivedCrc;
- uint8_t isBroadcast;
-
- if (requestLength < 4U)
- {
- return 0U;
- }
-
- receivedCrc = (uint16_t)(request[requestLength - 2U]
- | ((uint16_t)request[requestLength - 1U] << 8U));
- if (ModbusCrc16(request, (uint16_t)(requestLength - 2U)) != receivedCrc)
- {
- return 0U;
- }
-
- if ((request[0] != ModbusSlaveAddress)
- && (request[0] != MODBUS_BROADCAST_ADDRESS))
- {
- return 0U;
- }
-
- isBroadcast = (request[0] == MODBUS_BROADCAST_ADDRESS) ? 1U : 0U;
- switch (request[1])
- {
- case MODBUS_FC_READ_HOLDING:
- return (isBroadcast != 0U)
- ? 0U
- : ModbusProcessReadHolding(request, requestLength);
- case MODBUS_FC_WRITE_SINGLE:
- return ModbusProcessWriteSingle(request,
- requestLength,
- isBroadcast);
- case MODBUS_FC_WRITE_MULTIPLE:
- return ModbusProcessWriteMultiple(request,
- requestLength,
- isBroadcast);
- default:
- return (isBroadcast != 0U)
- ? 0U
- : ModbusBuildException(request[1],
- MODBUS_EX_ILLEGAL_FUNCTION);
- }
- }
-
- HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart,
- uint8_t slaveAddress)
- {
- if ((huart == NULL)
- || (huart->Instance == NULL)
- || (huart->hdmarx == NULL)
- || (huart->hdmatx == NULL)
- || (huart->Init.BaudRate == 0UL)
- || (slaveAddress == MODBUS_BROADCAST_ADDRESS)
- || (slaveAddress > MODBUS_SLAVE_ADDRESS_MAX))
- {
- return HAL_ERROR;
- }
-
- ModbusUart = huart;
- ModbusSlaveAddress = slaveAddress;
- ModbusRxAssemblyLength = 0U;
- ModbusRxAssemblyInvalid = 0U;
- ModbusRxLastByteCycle = 0UL;
- ModbusRxFrameLength = 0U;
- ModbusRxFrameReady = 0U;
- ModbusTxBusy = 0U;
- ModbusRtuTimingInit(huart->Init.BaudRate);
- ModbusLastActivityCycle = DWT->CYCCNT;
-
- return ModbusStartReceive();
- }
-
- void ModbusSlavePoll(void)
- {
- uint16_t responseLength;
- uint32_t primask;
- HAL_StatusTypeDef txStatus = HAL_OK;
-
- if (ModbusUart == NULL)
- {
- return;
- }
-
- ModbusTryFinalizeReceive();
- if ((ModbusRxFrameReady == 0U) || (ModbusTxBusy != 0U))
- {
- return;
- }
-
- responseLength = ModbusProcessRequest(ModbusRxFrame,
- ModbusRxFrameLength);
-
- primask = ModbusEnterCritical();
- ModbusRxFrameReady = 0U;
- if (responseLength > 0U)
- {
- ModbusTxBusy = 1U;
- txStatus = HAL_UART_Transmit_DMA(ModbusUart,
- ModbusTxFrame,
- responseLength);
- if (txStatus != HAL_OK)
- {
- ModbusTxBusy = 0U;
- }
- }
- ModbusExitCritical(primask);
-
- if ((responseLength == 0U) || (txStatus != HAL_OK))
- {
- (void)ModbusStartReceive();
- }
- }
-
- uint8_t ModbusSlaveIsIdle(void)
- {
- uint32_t primask;
- uint32_t now;
- uint8_t isIdle = 0U;
-
- if ((ModbusUart == NULL) || (ModbusUart->hdmarx == NULL))
- {
- return 0U;
- }
-
- primask = ModbusEnterCritical();
- if ((ModbusRxAssemblyLength == 0U)
- && (ModbusRxAssemblyInvalid == 0U)
- && (ModbusRxFrameReady == 0U)
- && (ModbusTxBusy == 0U)
- && (ModbusUart->RxState == HAL_UART_STATE_BUSY_RX)
- && ((ModbusUart->Instance->CR3 & USART_CR3_DMAR) != 0U)
- && ((ModbusUart->hdmarx->Instance->CR & DMA_SxCR_EN) != 0U)
- && (__HAL_DMA_GET_COUNTER(ModbusUart->hdmarx)
- == MODBUS_RTU_ADU_SIZE_MAX)
- && ((ModbusUart->Instance->SR
- & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE
- | USART_SR_IDLE | USART_SR_RXNE)) == 0U))
- {
- now = DWT->CYCCNT;
- if ((uint32_t)(now - ModbusLastActivityCycle)
- >= ModbusRtuT35Cycles)
- {
- isIdle = 1U;
- }
- }
- ModbusExitCritical(primask);
- return isIdle;
- }
-
- void ModbusSlaveOnRxEvent(UART_HandleTypeDef *huart, uint16_t size)
- {
- HAL_UART_RxEventTypeTypeDef eventType;
- uint32_t now;
- uint32_t lastByteCycle;
- uint32_t firstByteCycle;
- uint32_t chunkCycles;
- uint32_t interChunkGap;
-
- if ((ModbusUart == NULL) || (huart != ModbusUart))
- {
- return;
- }
-
- now = DWT->CYCCNT;
- ModbusLastActivityCycle = now;
- eventType = HAL_UARTEx_GetRxEventType(huart);
- if (eventType == HAL_UART_RXEVENT_HT)
- {
- return;
- }
-
- if ((size == 0U) || (size > MODBUS_RTU_ADU_SIZE_MAX))
- {
- ModbusRxAssemblyLength = 0U;
- ModbusRxAssemblyInvalid = 0U;
- (void)ModbusStartReceive();
- return;
- }
-
- lastByteCycle = now;
- if (eventType == HAL_UART_RXEVENT_IDLE)
- {
- lastByteCycle -= ModbusRtuCharCycles;
- }
- chunkCycles = (uint32_t)((uint64_t)size * ModbusRtuCharCycles);
- firstByteCycle = lastByteCycle - chunkCycles;
-
- if (ModbusRxAssemblyLength > 0U)
- {
- interChunkGap = (uint32_t)(firstByteCycle
- - ModbusRxLastByteCycle);
- if (interChunkGap >= ModbusRtuT35Cycles)
- {
- ModbusRxAssemblyFinalize();
- }
- else if (interChunkGap > ModbusRtuT15Cycles)
- {
- ModbusRxAssemblyInvalid = 1U;
- }
- }
-
- if (size <= (uint16_t)(MODBUS_RTU_ADU_SIZE_MAX
- - ModbusRxAssemblyLength))
- {
- (void)memcpy(&ModbusRxAssemblyBuffer[ModbusRxAssemblyLength],
- ModbusRxDmaBuffer,
- size);
- ModbusRxAssemblyLength += size;
- }
- else
- {
- ModbusRxAssemblyInvalid = 1U;
- }
-
- ModbusRxLastByteCycle = lastByteCycle;
- (void)ModbusStartReceive();
- }
-
- void ModbusSlaveOnTxComplete(UART_HandleTypeDef *huart)
- {
- if ((ModbusUart == NULL) || (huart != ModbusUart))
- {
- return;
- }
-
- ModbusLastActivityCycle = DWT->CYCCNT;
- ModbusTxBusy = 0U;
- (void)ModbusStartReceive();
- }
-
- void ModbusSlaveOnUartError(UART_HandleTypeDef *huart)
- {
- if ((ModbusUart == NULL) || (huart != ModbusUart))
- {
- return;
- }
-
- ModbusLastActivityCycle = DWT->CYCCNT;
- ModbusTxBusy = 0U;
- ModbusRxAssemblyLength = 0U;
- ModbusRxAssemblyInvalid = 0U;
- ModbusRxFrameLength = 0U;
- ModbusRxFrameReady = 0U;
- (void)HAL_UART_Abort(huart);
- (void)ModbusStartReceive();
- }
|