Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

350 строки
9.2 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. static uint16_t ModbusDataSram[MODBUS_DATA_SRAM_WORD_COUNT];
  14. #if !defined(PLSR_HOST_TEST)
  15. #pragma location = ".ccmram"
  16. #pragma data_alignment = 4
  17. __root
  18. #endif
  19. static uint16_t ModbusDataCcm[MODBUS_DATA_CCM_WORD_COUNT];
  20. static volatile uint32_t ModbusDataWriteSequence;
  21. static volatile uint32_t ModbusDataWriteFirstAddress;
  22. static volatile uint32_t ModbusDataWriteWordCount;
  23. static volatile MODBUS_DATA_DEVICE ModbusDataWriteDevice;
  24. static uint32_t ModbusDataEnterShortCritical(void)
  25. {
  26. #if defined(PLSR_HOST_TEST)
  27. return 0UL;
  28. #else
  29. uint32_t interruptState;
  30. interruptState = __get_PRIMASK();
  31. __disable_irq();
  32. return interruptState;
  33. #endif
  34. }
  35. static void ModbusDataExitShortCritical(uint32_t interruptState)
  36. {
  37. #if defined(PLSR_HOST_TEST)
  38. (void)interruptState;
  39. #else
  40. if (interruptState == 0UL)
  41. {
  42. __enable_irq();
  43. }
  44. #endif
  45. }
  46. static uint8_t ModbusDataResolve(MODBUS_DATA_DEVICE device,
  47. uint32_t address,
  48. uint16_t **word)
  49. {
  50. if (word == NULL)
  51. {
  52. return 0U;
  53. }
  54. switch (device)
  55. {
  56. case MODBUS_DATA_DEVICE_D:
  57. if (address >= MODBUS_DATA_D_WORD_COUNT)
  58. {
  59. return 0U;
  60. }
  61. *word = &ModbusDataSram[address];
  62. return 1U;
  63. case MODBUS_DATA_DEVICE_HD:
  64. if (address >= MODBUS_DATA_HD_WORD_COUNT)
  65. {
  66. return 0U;
  67. }
  68. *word = &ModbusDataSram[MODBUS_DATA_HD_SRAM_OFFSET + address];
  69. return 1U;
  70. case MODBUS_DATA_DEVICE_FD:
  71. if (address >= MODBUS_DATA_FD_WORD_COUNT)
  72. {
  73. return 0U;
  74. }
  75. *word = &ModbusDataCcm[address];
  76. return 1U;
  77. default:
  78. return 0U;
  79. }
  80. }
  81. static uint32_t ModbusDataCapacity(MODBUS_DATA_DEVICE device)
  82. {
  83. switch (device)
  84. {
  85. case MODBUS_DATA_DEVICE_D:
  86. return MODBUS_DATA_D_WORD_COUNT;
  87. case MODBUS_DATA_DEVICE_HD:
  88. return MODBUS_DATA_HD_WORD_COUNT;
  89. case MODBUS_DATA_DEVICE_FD:
  90. return MODBUS_DATA_FD_WORD_COUNT;
  91. default:
  92. return 0UL;
  93. }
  94. }
  95. static uint8_t ModbusDataWriteOverlaps(MODBUS_DATA_DEVICE device,
  96. uint32_t firstAddress,
  97. uint32_t wordCount)
  98. {
  99. uint32_t activeFirst;
  100. uint32_t activeCount;
  101. if (device != ModbusDataWriteDevice)
  102. {
  103. return 0U;
  104. }
  105. activeFirst = ModbusDataWriteFirstAddress;
  106. activeCount = ModbusDataWriteWordCount;
  107. if ((activeCount == 0UL) || (wordCount == 0UL))
  108. {
  109. return 0U;
  110. }
  111. return ((firstAddress < (activeFirst + activeCount))
  112. && (activeFirst < (firstAddress + wordCount)))
  113. ? 1U
  114. : 0U;
  115. }
  116. static void ModbusDataWriteBegin(MODBUS_DATA_DEVICE device,
  117. uint32_t firstAddress,
  118. uint32_t wordCount)
  119. {
  120. ModbusDataWriteDevice = device;
  121. ModbusDataWriteFirstAddress = firstAddress;
  122. ModbusDataWriteWordCount = wordCount;
  123. MODBUS_DATA_BARRIER();
  124. ModbusDataWriteSequence++;
  125. MODBUS_DATA_BARRIER();
  126. }
  127. static void ModbusDataWriteEnd(void)
  128. {
  129. MODBUS_DATA_BARRIER();
  130. ModbusDataWriteSequence++;
  131. }
  132. uint8_t ModbusDataValidateWords(MODBUS_DATA_DEVICE device,
  133. uint32_t firstAddress,
  134. uint32_t wordCount)
  135. {
  136. uint32_t capacity;
  137. capacity = ModbusDataCapacity(device);
  138. if ((capacity == 0UL) || (wordCount == 0UL)
  139. || (firstAddress >= capacity))
  140. {
  141. return 0U;
  142. }
  143. return (wordCount <= (capacity - firstAddress)) ? 1U : 0U;
  144. }
  145. uint8_t ModbusDataReadWord(MODBUS_DATA_DEVICE device,
  146. uint32_t address,
  147. uint16_t *value)
  148. {
  149. uint16_t *word;
  150. uint32_t before;
  151. uint32_t after;
  152. uint16_t snapshot;
  153. if ((value == NULL) || (ModbusDataResolve(device, address, &word) == 0U))
  154. {
  155. return 0U;
  156. }
  157. before = ModbusDataWriteSequence;
  158. if (((before & 1UL) != 0UL)
  159. && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
  160. {
  161. return 0U;
  162. }
  163. MODBUS_DATA_BARRIER();
  164. snapshot = *word;
  165. MODBUS_DATA_BARRIER();
  166. after = ModbusDataWriteSequence;
  167. if ((before != after)
  168. && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
  169. {
  170. return 0U;
  171. }
  172. if (((after & 1UL) != 0UL)
  173. && (ModbusDataWriteOverlaps(device, address, 1UL) != 0U))
  174. {
  175. return 0U;
  176. }
  177. *value = snapshot;
  178. return 1U;
  179. }
  180. uint8_t ModbusDataReadDword(MODBUS_DATA_DEVICE device,
  181. uint32_t lowAddress,
  182. int32_t *value)
  183. {
  184. uint16_t *lowWord;
  185. uint16_t *highWord;
  186. uint16_t lowSnapshot;
  187. uint16_t highSnapshot;
  188. uint32_t before;
  189. uint32_t after;
  190. if ((value == NULL)
  191. || (ModbusDataValidateWords(device, lowAddress, 2UL) == 0U)
  192. || (ModbusDataResolve(device, lowAddress, &lowWord) == 0U)
  193. || (ModbusDataResolve(device, lowAddress + 1UL, &highWord) == 0U))
  194. {
  195. return 0U;
  196. }
  197. before = ModbusDataWriteSequence;
  198. if (((before & 1UL) != 0UL)
  199. && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
  200. {
  201. return 0U;
  202. }
  203. MODBUS_DATA_BARRIER();
  204. lowSnapshot = *lowWord;
  205. highSnapshot = *highWord;
  206. MODBUS_DATA_BARRIER();
  207. after = ModbusDataWriteSequence;
  208. if ((before != after)
  209. && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
  210. {
  211. return 0U;
  212. }
  213. if (((after & 1UL) != 0UL)
  214. && (ModbusDataWriteOverlaps(device, lowAddress, 2UL) != 0U))
  215. {
  216. return 0U;
  217. }
  218. *value = (int32_t)(((uint32_t)highSnapshot << 16U) | lowSnapshot);
  219. return 1U;
  220. }
  221. uint8_t ModbusDataWriteWord(MODBUS_DATA_DEVICE device,
  222. uint32_t address,
  223. uint16_t value)
  224. {
  225. uint16_t *word;
  226. uint32_t interruptState;
  227. if (ModbusDataResolve(device, address, &word) == 0U)
  228. {
  229. return 0U;
  230. }
  231. interruptState = ModbusDataEnterShortCritical();
  232. ModbusDataWriteBegin(device, address, 1UL);
  233. *word = value;
  234. ModbusDataWriteEnd();
  235. ModbusDataExitShortCritical(interruptState);
  236. return 1U;
  237. }
  238. uint8_t ModbusDataWriteWords(MODBUS_DATA_DEVICE device,
  239. uint32_t firstAddress,
  240. const uint16_t *values,
  241. uint32_t wordCount)
  242. {
  243. uint16_t *firstWord;
  244. uint32_t index;
  245. uint32_t interruptState = 1UL;
  246. if ((values == NULL)
  247. || (ModbusDataValidateWords(device, firstAddress, wordCount) == 0U)
  248. || (ModbusDataResolve(device, firstAddress, &firstWord) == 0U))
  249. {
  250. return 0U;
  251. }
  252. /* A live INT32 update is only two words. Keep that very short commit
  253. * indivisible to the 100us ISR, so it sees either the old or new value.
  254. * Larger block writes use the non-blocking sequence protocol instead of
  255. * delaying pulse-related interrupts for an unbounded block copy. */
  256. if (wordCount <= 2UL)
  257. {
  258. interruptState = ModbusDataEnterShortCritical();
  259. }
  260. ModbusDataWriteBegin(device, firstAddress, wordCount);
  261. for (index = 0UL; index < wordCount; index++)
  262. {
  263. firstWord[index] = values[index];
  264. }
  265. ModbusDataWriteEnd();
  266. if (wordCount <= 2UL)
  267. {
  268. ModbusDataExitShortCritical(interruptState);
  269. }
  270. return 1U;
  271. }
  272. uint8_t ModbusDataReadLinear(uint32_t address, uint16_t *value)
  273. {
  274. if (address < MODBUS_DATA_SRAM_WORD_COUNT)
  275. {
  276. return ModbusDataReadWord((address < MODBUS_DATA_D_WORD_COUNT)
  277. ? MODBUS_DATA_DEVICE_D
  278. : MODBUS_DATA_DEVICE_HD,
  279. (address < MODBUS_DATA_D_WORD_COUNT)
  280. ? address
  281. : address - MODBUS_DATA_HD_SRAM_OFFSET,
  282. value);
  283. }
  284. if ((address >= MODBUS_DATA_LINEAR_CCM_BASE)
  285. && ((address - MODBUS_DATA_LINEAR_CCM_BASE)
  286. < MODBUS_DATA_CCM_WORD_COUNT))
  287. {
  288. uint32_t before;
  289. uint32_t after;
  290. uint16_t snapshot;
  291. if (value == NULL)
  292. {
  293. return 0U;
  294. }
  295. before = ModbusDataWriteSequence;
  296. if ((before & 1UL) != 0UL)
  297. {
  298. return 0U;
  299. }
  300. MODBUS_DATA_BARRIER();
  301. snapshot = ModbusDataCcm[address - MODBUS_DATA_LINEAR_CCM_BASE];
  302. MODBUS_DATA_BARRIER();
  303. after = ModbusDataWriteSequence;
  304. if ((before != after) || ((after & 1UL) != 0UL))
  305. {
  306. return 0U;
  307. }
  308. *value = snapshot;
  309. return 1U;
  310. }
  311. return 0U;
  312. }
  313. uint32_t ModbusDataGetWriteSequence(void)
  314. {
  315. return ModbusDataWriteSequence;
  316. }