25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

437 lines
11 KiB

  1. #include "modbus_data_store.h"
  2. #include <stddef.h>
  3. #if defined(PLSR_HOST_TEST)
  4. #define MODBUS_DATA_BARRIER() __sync_synchronize()
  5. #else
  6. #include "stm32f4xx.h"
  7. #define MODBUS_DATA_BARRIER() __DMB()
  8. #endif
  9. #define MODBUS_DATA_SRAM_WORD_COUNT (20000UL)
  10. #define MODBUS_DATA_CCM_WORD_COUNT (29999UL)
  11. #define MODBUS_DATA_HD_SRAM_OFFSET (10000UL)
  12. #define MODBUS_DATA_LINEAR_CCM_BASE (40000UL)
  13. #if (MODBUS_DATA_X_BIT_COUNT != MODBUS_DATA_M_BIT_COUNT) \
  14. || (MODBUS_DATA_X_BIT_COUNT != MODBUS_DATA_HM_BIT_COUNT)
  15. #error "Packed X/M/HM images require equal configured capacities"
  16. #endif
  17. #define MODBUS_DATA_BIT_BYTES ((MODBUS_DATA_X_BIT_COUNT + 7UL) / 8UL)
  18. static uint16_t ModbusDataSram[MODBUS_DATA_SRAM_WORD_COUNT];
  19. #if !defined(PLSR_HOST_TEST)
  20. #pragma location = ".ccmram"
  21. #pragma data_alignment = 4
  22. __root
  23. #endif
  24. static uint16_t ModbusDataCcm[MODBUS_DATA_CCM_WORD_COUNT];
  25. static uint8_t ModbusBitImages[3U][MODBUS_DATA_BIT_BYTES];
  26. static volatile uint32_t ModbusDataWriteSequence;
  27. static volatile uint32_t ModbusDataWriteFirstAddress;
  28. static volatile uint32_t ModbusDataWriteWordCount;
  29. static volatile MODBUS_DATA_DEVICE ModbusDataWriteDevice;
  30. static uint32_t ModbusDataEnterShortCritical(void)
  31. {
  32. #if defined(PLSR_HOST_TEST)
  33. return 0UL;
  34. #else
  35. uint32_t interruptState;
  36. interruptState = __get_PRIMASK();
  37. __disable_irq();
  38. return interruptState;
  39. #endif
  40. }
  41. static void ModbusDataExitShortCritical(uint32_t interruptState)
  42. {
  43. #if defined(PLSR_HOST_TEST)
  44. (void)interruptState;
  45. #else
  46. if (interruptState == 0UL)
  47. {
  48. __enable_irq();
  49. }
  50. #endif
  51. }
  52. static uint8_t ModbusDataResolve(MODBUS_DATA_DEVICE device,
  53. uint32_t address,
  54. uint16_t **word)
  55. {
  56. if (word == NULL)
  57. {
  58. return 0U;
  59. }
  60. switch (device)
  61. {
  62. case MODBUS_DATA_DEVICE_D:
  63. if (address >= MODBUS_DATA_D_WORD_COUNT)
  64. {
  65. return 0U;
  66. }
  67. *word = &ModbusDataSram[address];
  68. return 1U;
  69. case MODBUS_DATA_DEVICE_HD:
  70. if (address >= MODBUS_DATA_HD_WORD_COUNT)
  71. {
  72. return 0U;
  73. }
  74. *word = &ModbusDataSram[MODBUS_DATA_HD_SRAM_OFFSET + address];
  75. return 1U;
  76. case MODBUS_DATA_DEVICE_FD:
  77. if (address >= MODBUS_DATA_FD_WORD_COUNT)
  78. {
  79. return 0U;
  80. }
  81. *word = &ModbusDataCcm[address];
  82. return 1U;
  83. default:
  84. return 0U;
  85. }
  86. }
  87. static uint32_t ModbusDataCapacity(MODBUS_DATA_DEVICE device)
  88. {
  89. switch (device)
  90. {
  91. case MODBUS_DATA_DEVICE_D:
  92. return MODBUS_DATA_D_WORD_COUNT;
  93. case MODBUS_DATA_DEVICE_HD:
  94. return MODBUS_DATA_HD_WORD_COUNT;
  95. case MODBUS_DATA_DEVICE_FD:
  96. return MODBUS_DATA_FD_WORD_COUNT;
  97. default:
  98. return 0UL;
  99. }
  100. }
  101. static uint8_t ModbusDataWriteOverlaps(MODBUS_DATA_DEVICE device,
  102. uint32_t firstAddress,
  103. uint32_t wordCount)
  104. {
  105. uint32_t activeFirst;
  106. uint32_t activeCount;
  107. if (device != ModbusDataWriteDevice)
  108. {
  109. return 0U;
  110. }
  111. activeFirst = ModbusDataWriteFirstAddress;
  112. activeCount = ModbusDataWriteWordCount;
  113. if ((activeCount == 0UL) || (wordCount == 0UL))
  114. {
  115. return 0U;
  116. }
  117. return ((firstAddress < (activeFirst + activeCount))
  118. && (activeFirst < (firstAddress + wordCount)))
  119. ? 1U
  120. : 0U;
  121. }
  122. static void ModbusDataWriteBegin(MODBUS_DATA_DEVICE device,
  123. uint32_t firstAddress,
  124. uint32_t wordCount)
  125. {
  126. ModbusDataWriteDevice = device;
  127. ModbusDataWriteFirstAddress = firstAddress;
  128. ModbusDataWriteWordCount = wordCount;
  129. MODBUS_DATA_BARRIER();
  130. ModbusDataWriteSequence++;
  131. MODBUS_DATA_BARRIER();
  132. }
  133. static void ModbusDataWriteEnd(void)
  134. {
  135. MODBUS_DATA_BARRIER();
  136. ModbusDataWriteSequence++;
  137. }
  138. uint8_t ModbusDataValidateWords(MODBUS_DATA_DEVICE device,
  139. uint32_t firstAddress,
  140. uint32_t wordCount)
  141. {
  142. uint32_t capacity;
  143. capacity = ModbusDataCapacity(device);
  144. if ((capacity == 0UL) || (wordCount == 0UL)
  145. || (firstAddress >= capacity))
  146. {
  147. return 0U;
  148. }
  149. return (wordCount <= (capacity - firstAddress)) ? 1U : 0U;
  150. }
  151. uint8_t ModbusDataReadWord(MODBUS_DATA_DEVICE device,
  152. uint32_t address,
  153. uint16_t *value)
  154. {
  155. uint16_t *word;
  156. uint32_t before;
  157. uint32_t after;
  158. uint16_t snapshot;
  159. if ((value == NULL) || (ModbusDataResolve(device, address, &word) == 0U))
  160. {
  161. return 0U;
  162. }
  163. before = ModbusDataWriteSequence;
  164. if (((before & 1UL) != 0UL)
  165. && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
  166. {
  167. return 0U;
  168. }
  169. MODBUS_DATA_BARRIER();
  170. snapshot = *word;
  171. MODBUS_DATA_BARRIER();
  172. after = ModbusDataWriteSequence;
  173. if ((before != after)
  174. && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
  175. {
  176. return 0U;
  177. }
  178. if (((after & 1UL) != 0UL)
  179. && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
  180. {
  181. return 0U;
  182. }
  183. *value = snapshot;
  184. return 1U;
  185. }
  186. uint8_t ModbusDataReadDword(MODBUS_DATA_DEVICE device,
  187. uint32_t lowAddress,
  188. int32_t *value)
  189. {
  190. uint16_t *lowWord;
  191. uint16_t *highWord;
  192. uint16_t lowSnapshot;
  193. uint16_t highSnapshot;
  194. uint32_t before;
  195. uint32_t after;
  196. if ((value == NULL)
  197. || (ModbusDataValidateWords(device, lowAddress, 2UL) == 0U)
  198. || (ModbusDataResolve(device, lowAddress, &lowWord) == 0U)
  199. || (ModbusDataResolve(device, lowAddress + 1UL, &highWord) == 0U))
  200. {
  201. return 0U;
  202. }
  203. before = ModbusDataWriteSequence;
  204. if (((before & 1UL) != 0UL)
  205. && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
  206. {
  207. return 0U;
  208. }
  209. MODBUS_DATA_BARRIER();
  210. lowSnapshot = *lowWord;
  211. highSnapshot = *highWord;
  212. MODBUS_DATA_BARRIER();
  213. after = ModbusDataWriteSequence;
  214. if ((before != after)
  215. && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
  216. {
  217. return 0U;
  218. }
  219. if (((after & 1UL) != 0UL)
  220. && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
  221. {
  222. return 0U;
  223. }
  224. *value = (int32_t)(((uint32_t)highSnapshot << 16U) | lowSnapshot);
  225. return 1U;
  226. }
  227. uint8_t ModbusDataWriteWord(MODBUS_DATA_DEVICE device,
  228. uint32_t address,
  229. uint16_t value)
  230. {
  231. uint16_t *word;
  232. uint32_t interruptState;
  233. if (ModbusDataResolve(device, address, &word) == 0U)
  234. {
  235. return 0U;
  236. }
  237. interruptState = ModbusDataEnterShortCritical();
  238. ModbusDataWriteBegin(device, address, 1UL);
  239. *word = value;
  240. ModbusDataWriteEnd();
  241. ModbusDataExitShortCritical(interruptState);
  242. return 1U;
  243. }
  244. uint8_t ModbusDataWriteWords(MODBUS_DATA_DEVICE device,
  245. uint32_t firstAddress,
  246. const uint16_t *values,
  247. uint32_t wordCount)
  248. {
  249. uint16_t *firstWord;
  250. uint32_t index;
  251. uint32_t interruptState = 1UL;
  252. if ((values == NULL)
  253. || (ModbusDataValidateWords(device, firstAddress, wordCount) == 0U)
  254. || (ModbusDataResolve(device, firstAddress, &firstWord) == 0U))
  255. {
  256. return 0U;
  257. }
  258. /* A live INT32 update is only two words. Keep that very short commit
  259. * indivisible to the 100us ISR, so it sees either the old or new value.
  260. * Larger block writes use the non-blocking sequence protocol instead of
  261. * delaying pulse-related interrupts for an unbounded block copy. */
  262. if (wordCount <= 2UL)
  263. {
  264. interruptState = ModbusDataEnterShortCritical();
  265. }
  266. ModbusDataWriteBegin(device, firstAddress, wordCount);
  267. for (index = 0UL; index < wordCount; index++)
  268. {
  269. firstWord[index] = values[index];
  270. }
  271. ModbusDataWriteEnd();
  272. if (wordCount <= 2UL)
  273. {
  274. ModbusDataExitShortCritical(interruptState);
  275. }
  276. return 1U;
  277. }
  278. uint8_t ModbusDataReadLinear(uint32_t address, uint16_t *value)
  279. {
  280. if (address < MODBUS_DATA_SRAM_WORD_COUNT)
  281. {
  282. return ModbusDataReadWord((address < MODBUS_DATA_D_WORD_COUNT)
  283. ? MODBUS_DATA_DEVICE_D
  284. : MODBUS_DATA_DEVICE_HD,
  285. (address < MODBUS_DATA_D_WORD_COUNT)
  286. ? address
  287. : address - MODBUS_DATA_HD_SRAM_OFFSET,
  288. value);
  289. }
  290. if ((address >= MODBUS_DATA_LINEAR_CCM_BASE)
  291. && ((address - MODBUS_DATA_LINEAR_CCM_BASE)
  292. < MODBUS_DATA_CCM_WORD_COUNT))
  293. {
  294. uint32_t before;
  295. uint32_t after;
  296. uint16_t snapshot;
  297. if (value == NULL)
  298. {
  299. return 0U;
  300. }
  301. before = ModbusDataWriteSequence;
  302. if ((before & 1UL) != 0UL)
  303. {
  304. return 0U;
  305. }
  306. MODBUS_DATA_BARRIER();
  307. snapshot = ModbusDataCcm[address - MODBUS_DATA_LINEAR_CCM_BASE];
  308. MODBUS_DATA_BARRIER();
  309. after = ModbusDataWriteSequence;
  310. if ((before != after) || ((after & 1UL) != 0UL))
  311. {
  312. return 0U;
  313. }
  314. *value = snapshot;
  315. return 1U;
  316. }
  317. return 0U;
  318. }
  319. uint32_t ModbusDataGetWriteSequence(void)
  320. {
  321. return ModbusDataWriteSequence;
  322. }
  323. static uint32_t ModbusDataBitCapacity(MODBUS_BIT_DEVICE device)
  324. {
  325. switch (device)
  326. {
  327. case MODBUS_BIT_DEVICE_X:
  328. return MODBUS_DATA_X_BIT_COUNT;
  329. case MODBUS_BIT_DEVICE_M:
  330. return MODBUS_DATA_M_BIT_COUNT;
  331. case MODBUS_BIT_DEVICE_HM:
  332. return MODBUS_DATA_HM_BIT_COUNT;
  333. default:
  334. return 0UL;
  335. }
  336. }
  337. uint8_t ModbusDataValidateBits(MODBUS_BIT_DEVICE device,
  338. uint32_t firstAddress,
  339. uint32_t bitCount)
  340. {
  341. uint32_t capacity = ModbusDataBitCapacity(device);
  342. if ((capacity == 0UL) || (bitCount == 0UL)
  343. || (firstAddress >= capacity))
  344. {
  345. return 0U;
  346. }
  347. return (bitCount <= (capacity - firstAddress)) ? 1U : 0U;
  348. }
  349. uint8_t ModbusDataReadBit(MODBUS_BIT_DEVICE device,
  350. uint32_t address,
  351. uint8_t *value)
  352. {
  353. uint8_t mask;
  354. if ((value == NULL)
  355. || (ModbusDataValidateBits(device, address, 1UL) == 0U))
  356. {
  357. return 0U;
  358. }
  359. mask = (uint8_t)(1U << (address & 7UL));
  360. MODBUS_DATA_BARRIER();
  361. *value = ((ModbusBitImages[(uint32_t)device][address >> 3U] & mask) != 0U)
  362. ? 1U
  363. : 0U;
  364. MODBUS_DATA_BARRIER();
  365. return 1U;
  366. }
  367. uint8_t ModbusDataWriteBit(MODBUS_BIT_DEVICE device,
  368. uint32_t address,
  369. uint8_t value)
  370. {
  371. uint8_t *byte;
  372. uint8_t mask;
  373. uint32_t interruptState;
  374. if (ModbusDataValidateBits(device, address, 1UL) == 0U)
  375. {
  376. return 0U;
  377. }
  378. byte = &ModbusBitImages[(uint32_t)device][address >> 3U];
  379. mask = (uint8_t)(1U << (address & 7UL));
  380. interruptState = ModbusDataEnterShortCritical();
  381. if (value != 0U)
  382. {
  383. *byte |= mask;
  384. }
  385. else
  386. {
  387. *byte &= (uint8_t)(~mask);
  388. }
  389. MODBUS_DATA_BARRIER();
  390. ModbusDataExitShortCritical(interruptState);
  391. return 1U;
  392. }