|
- #include "modbus_data_store.h"
- #include <stddef.h>
-
- #if defined(PLSR_HOST_TEST)
- #define MODBUS_DATA_BARRIER() __sync_synchronize()
- #else
- #include "stm32f4xx.h"
- #define MODBUS_DATA_BARRIER() __DMB()
- #endif
-
- #define MODBUS_DATA_SRAM_WORD_COUNT (20000UL)
- #define MODBUS_DATA_CCM_WORD_COUNT (29999UL)
- #define MODBUS_DATA_HD_SRAM_OFFSET (10000UL)
- #define MODBUS_DATA_LINEAR_CCM_BASE (40000UL)
- #if (MODBUS_DATA_X_BIT_COUNT != MODBUS_DATA_M_BIT_COUNT) \
- || (MODBUS_DATA_X_BIT_COUNT != MODBUS_DATA_HM_BIT_COUNT)
- #error "Packed X/M/HM images require equal configured capacities"
- #endif
- #define MODBUS_DATA_BIT_BYTES ((MODBUS_DATA_X_BIT_COUNT + 7UL) / 8UL)
-
- static uint16_t ModbusDataSram[MODBUS_DATA_SRAM_WORD_COUNT];
-
- #if !defined(PLSR_HOST_TEST)
- #pragma location = ".ccmram"
- #pragma data_alignment = 4
- __root
- #endif
- static uint16_t ModbusDataCcm[MODBUS_DATA_CCM_WORD_COUNT];
-
- static uint8_t ModbusBitImages[3U][MODBUS_DATA_BIT_BYTES];
-
- static volatile uint32_t ModbusDataWriteSequence;
- static volatile uint32_t ModbusDataWriteFirstAddress;
- static volatile uint32_t ModbusDataWriteWordCount;
- static volatile MODBUS_DATA_DEVICE ModbusDataWriteDevice;
-
- static uint32_t ModbusDataEnterShortCritical(void)
- {
- #if defined(PLSR_HOST_TEST)
- return 0UL;
- #else
- uint32_t interruptState;
-
- interruptState = __get_PRIMASK();
- __disable_irq();
- return interruptState;
- #endif
- }
-
- static void ModbusDataExitShortCritical(uint32_t interruptState)
- {
- #if defined(PLSR_HOST_TEST)
- (void)interruptState;
- #else
- if (interruptState == 0UL)
- {
- __enable_irq();
- }
- #endif
- }
-
- static uint8_t ModbusDataResolve(MODBUS_DATA_DEVICE device,
- uint32_t address,
- uint16_t **word)
- {
- if (word == NULL)
- {
- return 0U;
- }
- switch (device)
- {
- case MODBUS_DATA_DEVICE_D:
- if (address >= MODBUS_DATA_D_WORD_COUNT)
- {
- return 0U;
- }
- *word = &ModbusDataSram[address];
- return 1U;
-
- case MODBUS_DATA_DEVICE_HD:
- if (address >= MODBUS_DATA_HD_WORD_COUNT)
- {
- return 0U;
- }
- *word = &ModbusDataSram[MODBUS_DATA_HD_SRAM_OFFSET + address];
- return 1U;
-
- case MODBUS_DATA_DEVICE_FD:
- if (address >= MODBUS_DATA_FD_WORD_COUNT)
- {
- return 0U;
- }
- *word = &ModbusDataCcm[address];
- return 1U;
-
- default:
- return 0U;
- }
- }
-
- static uint32_t ModbusDataCapacity(MODBUS_DATA_DEVICE device)
- {
- switch (device)
- {
- case MODBUS_DATA_DEVICE_D:
- return MODBUS_DATA_D_WORD_COUNT;
-
- case MODBUS_DATA_DEVICE_HD:
- return MODBUS_DATA_HD_WORD_COUNT;
-
- case MODBUS_DATA_DEVICE_FD:
- return MODBUS_DATA_FD_WORD_COUNT;
-
- default:
- return 0UL;
- }
- }
-
- static uint8_t ModbusDataWriteOverlaps(MODBUS_DATA_DEVICE device,
- uint32_t firstAddress,
- uint32_t wordCount)
- {
- uint32_t activeFirst;
- uint32_t activeCount;
-
- if (device != ModbusDataWriteDevice)
- {
- return 0U;
- }
- activeFirst = ModbusDataWriteFirstAddress;
- activeCount = ModbusDataWriteWordCount;
- if ((activeCount == 0UL) || (wordCount == 0UL))
- {
- return 0U;
- }
- return ((firstAddress < (activeFirst + activeCount))
- && (activeFirst < (firstAddress + wordCount)))
- ? 1U
- : 0U;
- }
-
- static void ModbusDataWriteBegin(MODBUS_DATA_DEVICE device,
- uint32_t firstAddress,
- uint32_t wordCount)
- {
- ModbusDataWriteDevice = device;
- ModbusDataWriteFirstAddress = firstAddress;
- ModbusDataWriteWordCount = wordCount;
- MODBUS_DATA_BARRIER();
- ModbusDataWriteSequence++;
- MODBUS_DATA_BARRIER();
- }
-
- static void ModbusDataWriteEnd(void)
- {
- MODBUS_DATA_BARRIER();
- ModbusDataWriteSequence++;
- }
-
- uint8_t ModbusDataValidateWords(MODBUS_DATA_DEVICE device,
- uint32_t firstAddress,
- uint32_t wordCount)
- {
- uint32_t capacity;
-
- capacity = ModbusDataCapacity(device);
- if ((capacity == 0UL) || (wordCount == 0UL)
- || (firstAddress >= capacity))
- {
- return 0U;
- }
- return (wordCount <= (capacity - firstAddress)) ? 1U : 0U;
- }
-
- uint8_t ModbusDataReadWord(MODBUS_DATA_DEVICE device,
- uint32_t address,
- uint16_t *value)
- {
- uint16_t *word;
- uint32_t before;
- uint32_t after;
- uint16_t snapshot;
-
- if ((value == NULL) || (ModbusDataResolve(device, address, &word) == 0U))
- {
- return 0U;
- }
- before = ModbusDataWriteSequence;
- if (((before & 1UL) != 0UL)
- && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
- {
- return 0U;
- }
- MODBUS_DATA_BARRIER();
- snapshot = *word;
- MODBUS_DATA_BARRIER();
- after = ModbusDataWriteSequence;
- if ((before != after)
- && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
- {
- return 0U;
- }
- if (((after & 1UL) != 0UL)
- && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
- {
- return 0U;
- }
- *value = snapshot;
- return 1U;
- }
-
- uint8_t ModbusDataReadDword(MODBUS_DATA_DEVICE device,
- uint32_t lowAddress,
- int32_t *value)
- {
- uint16_t *lowWord;
- uint16_t *highWord;
- uint16_t lowSnapshot;
- uint16_t highSnapshot;
- uint32_t before;
- uint32_t after;
-
- if ((value == NULL)
- || (ModbusDataValidateWords(device, lowAddress, 2UL) == 0U)
- || (ModbusDataResolve(device, lowAddress, &lowWord) == 0U)
- || (ModbusDataResolve(device, lowAddress + 1UL, &highWord) == 0U))
- {
- return 0U;
- }
- before = ModbusDataWriteSequence;
- if (((before & 1UL) != 0UL)
- && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
- {
- return 0U;
- }
- MODBUS_DATA_BARRIER();
- lowSnapshot = *lowWord;
- highSnapshot = *highWord;
- MODBUS_DATA_BARRIER();
- after = ModbusDataWriteSequence;
- if ((before != after)
- && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
- {
- return 0U;
- }
- if (((after & 1UL) != 0UL)
- && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
- {
- return 0U;
- }
- *value = (int32_t)(((uint32_t)highSnapshot << 16U) | lowSnapshot);
- return 1U;
- }
-
- uint8_t ModbusDataWriteWord(MODBUS_DATA_DEVICE device,
- uint32_t address,
- uint16_t value)
- {
- uint16_t *word;
- uint32_t interruptState;
-
- if (ModbusDataResolve(device, address, &word) == 0U)
- {
- return 0U;
- }
- interruptState = ModbusDataEnterShortCritical();
- ModbusDataWriteBegin(device, address, 1UL);
- *word = value;
- ModbusDataWriteEnd();
- ModbusDataExitShortCritical(interruptState);
- return 1U;
- }
-
- uint8_t ModbusDataWriteWords(MODBUS_DATA_DEVICE device,
- uint32_t firstAddress,
- const uint16_t *values,
- uint32_t wordCount)
- {
- uint16_t *firstWord;
- uint32_t index;
- uint32_t interruptState = 1UL;
-
- if ((values == NULL)
- || (ModbusDataValidateWords(device, firstAddress, wordCount) == 0U)
- || (ModbusDataResolve(device, firstAddress, &firstWord) == 0U))
- {
- return 0U;
- }
- /* A live INT32 update is only two words. Keep that very short commit
- * indivisible to the 100us ISR, so it sees either the old or new value.
- * Larger block writes use the non-blocking sequence protocol instead of
- * delaying pulse-related interrupts for an unbounded block copy. */
- if (wordCount <= 2UL)
- {
- interruptState = ModbusDataEnterShortCritical();
- }
- ModbusDataWriteBegin(device, firstAddress, wordCount);
- for (index = 0UL; index < wordCount; index++)
- {
- firstWord[index] = values[index];
- }
- ModbusDataWriteEnd();
- if (wordCount <= 2UL)
- {
- ModbusDataExitShortCritical(interruptState);
- }
- return 1U;
- }
-
- uint8_t ModbusDataReadLinear(uint32_t address, uint16_t *value)
- {
- if (address < MODBUS_DATA_SRAM_WORD_COUNT)
- {
- return ModbusDataReadWord((address < MODBUS_DATA_D_WORD_COUNT)
- ? MODBUS_DATA_DEVICE_D
- : MODBUS_DATA_DEVICE_HD,
- (address < MODBUS_DATA_D_WORD_COUNT)
- ? address
- : address - MODBUS_DATA_HD_SRAM_OFFSET,
- value);
- }
- if ((address >= MODBUS_DATA_LINEAR_CCM_BASE)
- && ((address - MODBUS_DATA_LINEAR_CCM_BASE)
- < MODBUS_DATA_CCM_WORD_COUNT))
- {
- uint32_t before;
- uint32_t after;
- uint16_t snapshot;
-
- if (value == NULL)
- {
- return 0U;
- }
- before = ModbusDataWriteSequence;
- if ((before & 1UL) != 0UL)
- {
- return 0U;
- }
- MODBUS_DATA_BARRIER();
- snapshot = ModbusDataCcm[address - MODBUS_DATA_LINEAR_CCM_BASE];
- MODBUS_DATA_BARRIER();
- after = ModbusDataWriteSequence;
- if ((before != after) || ((after & 1UL) != 0UL))
- {
- return 0U;
- }
- *value = snapshot;
- return 1U;
- }
- return 0U;
- }
-
- uint32_t ModbusDataGetWriteSequence(void)
- {
- return ModbusDataWriteSequence;
- }
-
- static uint32_t ModbusDataBitCapacity(MODBUS_BIT_DEVICE device)
- {
- switch (device)
- {
- case MODBUS_BIT_DEVICE_X:
- return MODBUS_DATA_X_BIT_COUNT;
-
- case MODBUS_BIT_DEVICE_M:
- return MODBUS_DATA_M_BIT_COUNT;
-
- case MODBUS_BIT_DEVICE_HM:
- return MODBUS_DATA_HM_BIT_COUNT;
-
- default:
- return 0UL;
- }
- }
-
- uint8_t ModbusDataValidateBits(MODBUS_BIT_DEVICE device,
- uint32_t firstAddress,
- uint32_t bitCount)
- {
- uint32_t capacity = ModbusDataBitCapacity(device);
-
- if ((capacity == 0UL) || (bitCount == 0UL)
- || (firstAddress >= capacity))
- {
- return 0U;
- }
- return (bitCount <= (capacity - firstAddress)) ? 1U : 0U;
- }
-
- uint8_t ModbusDataReadBit(MODBUS_BIT_DEVICE device,
- uint32_t address,
- uint8_t *value)
- {
- uint8_t mask;
-
- if ((value == NULL)
- || (ModbusDataValidateBits(device, address, 1UL) == 0U))
- {
- return 0U;
- }
- mask = (uint8_t)(1U << (address & 7UL));
- MODBUS_DATA_BARRIER();
- *value = ((ModbusBitImages[(uint32_t)device][address >> 3U] & mask) != 0U)
- ? 1U
- : 0U;
- MODBUS_DATA_BARRIER();
- return 1U;
- }
-
- uint8_t ModbusDataWriteBit(MODBUS_BIT_DEVICE device,
- uint32_t address,
- uint8_t value)
- {
- uint8_t *byte;
- uint8_t mask;
- uint32_t interruptState;
-
- if (ModbusDataValidateBits(device, address, 1UL) == 0U)
- {
- return 0U;
- }
- byte = &ModbusBitImages[(uint32_t)device][address >> 3U];
- mask = (uint8_t)(1U << (address & 7UL));
- interruptState = ModbusDataEnterShortCritical();
- if (value != 0U)
- {
- *byte |= mask;
- }
- else
- {
- *byte &= (uint8_t)(~mask);
- }
- MODBUS_DATA_BARRIER();
- ModbusDataExitShortCritical(interruptState);
- return 1U;
- }
|