5151
5252#include " debug.h"
5353
54+ constexpr auto dmxSlotsCompleteFlag = 0x8000U ;
55+ constexpr auto rdmSlotsCompleteFlag = 0x4000U ;
56+
5457extern struct HwTimersSeconds g_Seconds;
5558
5659namespace dmx {
@@ -91,16 +94,20 @@ struct RxDmxData {
9194 uint32_t nSlotsInPacket;
9295};
9396
97+ enum class ActiveBuffer { A, B };
98+
9499struct RxData {
95100 struct {
96- volatile RxDmxData current;
101+ volatile RxDmxData bufferA;
102+ volatile RxDmxData bufferB;
103+ ActiveBuffer active { ActiveBuffer::A }; // Active write buffer
97104 RxDmxData previous;
98105 } Dmx ALIGNED;
99106 struct {
100107 volatile uint8_t data[sizeof (struct TRdmMessage )] ALIGNED;
101108 volatile uint32_t nIndex;
102109 } Rdm ALIGNED;
103- volatile TxRxState State;
110+ volatile TxRxState State { TxRxState::IDLE } ;
104111} ALIGNED;
105112
106113struct DirGpio {
@@ -158,29 +165,62 @@ static RxData sv_RxBuffer[dmx::config::max::PORTS] ALIGNED;
158165static TxData s_TxBuffer[dmx::config::max::PORTS] ALIGNED SECTION_DMA_BUFFER;
159166static DmxTransmit s_nDmxTransmit;
160167
168+ // The active DMX data buffer for writes
169+ volatile RxDmxData& getWriteDmxDataBuffer (const uint32_t nPortIndex) {
170+ if (sv_RxBuffer[nPortIndex].Dmx .active == ActiveBuffer::A) {
171+ return sv_RxBuffer[nPortIndex].Dmx .bufferA ;
172+ }
173+ return sv_RxBuffer[nPortIndex].Dmx .bufferB ;
174+ }
175+
176+ // The non-active DMX data buffer for reads
177+ volatile RxDmxData& getReadDmxDataBuffer (const uint32_t nPortIndex) {
178+ if (sv_RxBuffer[nPortIndex].Dmx .active == ActiveBuffer::A) {
179+ return sv_RxBuffer[nPortIndex].Dmx .bufferB ;
180+ }
181+ return sv_RxBuffer[nPortIndex].Dmx .bufferA ;
182+ }
183+
184+ // Swap the active buffer for writing
185+ void swapActiveDmxDataBuffer (const uint32_t nPortIndex) {
186+ if (sv_RxBuffer[nPortIndex].Dmx .active == ActiveBuffer::A) {
187+ sv_RxBuffer[nPortIndex].Dmx .active = ActiveBuffer::B;
188+ }
189+ else
190+ {
191+ sv_RxBuffer[nPortIndex].Dmx .active = ActiveBuffer::A;
192+ }
193+ }
194+
161195template <uint32_t uart, uint32_t nPortIndex>
162196void irq_handler_dmx_rdm_input () {
197+ auto & dmxDataBuffer = getWriteDmxDataBuffer (nPortIndex);
163198 const auto isFlagIdleFrame = (USART_REG_VAL (uart, USART_FLAG_IDLE) & BIT (USART_BIT_POS (USART_FLAG_IDLE))) == BIT (USART_BIT_POS (USART_FLAG_IDLE));
164199 /*
165200 * Software can clear this bit by reading the USART_STAT and USART_DATA registers one by one.
166201 */
167202 if (isFlagIdleFrame) {
168203 static_cast <void >(GET_BITS (USART_RDATA (uart), 0U , 8U ));
169-
170- if (sv_RxBuffer[nPortIndex].State == TxRxState::DMXDATA) {
171- sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
172- sv_RxBuffer[nPortIndex].Dmx .current .nSlotsInPacket |= 0x8000 ;
173-
174- return ;
175- }
176-
177- if (sv_RxBuffer[0 ].State == TxRxState::RDMDISC) {
178- sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
179- sv_RxBuffer[nPortIndex].Rdm .nIndex |= 0x4000 ;
180-
181- return ;
204+ switch (sv_RxBuffer[nPortIndex].State )
205+ {
206+ case TxRxState::BREAK: break ;
207+ case TxRxState::DMXDATA:
208+ {
209+ dmxDataBuffer.nSlotsInPacket |= dmxSlotsCompleteFlag;
210+ break ;
211+ }
212+ case TxRxState::RDMDISC:
213+ {
214+ sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
215+ sv_RxBuffer[nPortIndex].Rdm .nIndex |= rdmSlotsCompleteFlag;
216+ break ;
217+ }
218+ default :
219+ {
220+ sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
221+ break ;
222+ }
182223 }
183-
184224 return ;
185225 }
186226
@@ -191,15 +231,41 @@ void irq_handler_dmx_rdm_input() {
191231 if (isFlagFrameError) {
192232 static_cast <void >(GET_BITS (USART_RDATA (uart), 0U , 8U ));
193233
194- if (sv_RxBuffer[nPortIndex].State == TxRxState::IDLE) {
195- sv_RxBuffer[nPortIndex].State = TxRxState::BREAK;
234+ switch (sv_RxBuffer[nPortIndex].State )
235+ {
236+ case TxRxState::RDMDISC:
237+ case TxRxState::IDLE:
238+ {
239+ break ;
240+ }
241+ case TxRxState::DMXDATA:
242+ {
243+ if (!(dmxDataBuffer.nSlotsInPacket & dmxSlotsCompleteFlag)) {
244+ return ;
245+ }
246+ break ;
247+ }
248+ case TxRxState::RDMDATA:
249+ {
250+ if (!(sv_RxBuffer[nPortIndex].Rdm .nIndex & rdmSlotsCompleteFlag)) {
251+ return ;
252+ }
253+ break ;
254+ }
255+ default :
256+ {
257+ sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
258+ return ;
259+ }
196260 }
197261
262+ sv_RxBuffer[nPortIndex].State = TxRxState::BREAK;
263+ swapActiveDmxDataBuffer (nPortIndex);
264+
198265 return ;
199266 }
200267
201268 const auto data = static_cast <uint8_t >(GET_BITS (USART_RDATA (uart), 0U , 8U ));
202-
203269 switch (sv_RxBuffer[nPortIndex].State ) {
204270 case TxRxState::IDLE:
205271 sv_RxBuffer[nPortIndex].State = TxRxState::RDMDISC;
@@ -209,8 +275,8 @@ void irq_handler_dmx_rdm_input() {
209275 case TxRxState::BREAK:
210276 switch (data) {
211277 case START_CODE:
212- sv_RxBuffer[nPortIndex]. Dmx . current .data [0 ] = START_CODE;
213- sv_RxBuffer[nPortIndex]. Dmx . current .nSlotsInPacket = 1 ;
278+ dmxDataBuffer .data [0 ] = START_CODE;
279+ dmxDataBuffer .nSlotsInPacket = 1 ;
214280 sv_nRxDmxPackets[nPortIndex].nCount ++;
215281 sv_RxBuffer[nPortIndex].State = TxRxState::DMXDATA;
216282 break ;
@@ -220,21 +286,18 @@ void irq_handler_dmx_rdm_input() {
220286 sv_RxBuffer[nPortIndex].State = TxRxState::RDMDATA;
221287 break ;
222288 default :
223- sv_RxBuffer[nPortIndex]. Dmx . current .nSlotsInPacket = 0 ;
289+ dmxDataBuffer .nSlotsInPacket = 0 ;
224290 sv_RxBuffer[nPortIndex].Rdm .nIndex = 0 ;
225291 sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
226292 break ;
227293 }
228294 break ;
229295 case TxRxState::DMXDATA: {
230- auto nIndex = sv_RxBuffer[nPortIndex].Dmx .current .nSlotsInPacket ;
231- sv_RxBuffer[nPortIndex].Dmx .current .data [nIndex] = data;
232- nIndex++;
233- sv_RxBuffer[nPortIndex].Dmx .current .nSlotsInPacket = nIndex;
296+ dmxDataBuffer.nSlotsInPacket &= ~dmxSlotsCompleteFlag;
297+ dmxDataBuffer.data [dmxDataBuffer.nSlotsInPacket ++] = data;
234298
235- if (nIndex > dmx::max::CHANNELS) {
236- nIndex |= 0x8000 ;
237- sv_RxBuffer[nPortIndex].Dmx .current .nSlotsInPacket = nIndex;
299+ if (dmxDataBuffer.nSlotsInPacket > dmx::max::CHANNELS) {
300+ dmxDataBuffer.nSlotsInPacket |= dmxSlotsCompleteFlag;
238301 sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
239302 break ;
240303 }
@@ -266,7 +329,7 @@ void irq_handler_dmx_rdm_input() {
266329 case TxRxState::CHECKSUML: {
267330 auto nIndex = sv_RxBuffer[nPortIndex].Rdm .nIndex ;
268331 sv_RxBuffer[nPortIndex].Rdm .data [nIndex] = data;
269- nIndex |= 0x4000 ;
332+ nIndex |= rdmSlotsCompleteFlag ;
270333 sv_RxBuffer[nPortIndex].Rdm .nIndex = nIndex;
271334 sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
272335 gsv_RdmDataReceiveEnd = DWT->CYCCNT ;
@@ -283,7 +346,7 @@ void irq_handler_dmx_rdm_input() {
283346 }
284347 break ;
285348 default :
286- sv_RxBuffer[nPortIndex]. Dmx . current .nSlotsInPacket = 0 ;
349+ dmxDataBuffer .nSlotsInPacket = 0 ;
287350 sv_RxBuffer[nPortIndex].Rdm .nIndex = 0 ;
288351 sv_RxBuffer[nPortIndex].State = TxRxState::IDLE;
289352 break ;
@@ -1960,11 +2023,12 @@ const uint8_t *Dmx::GetDmxChanged(const uint32_t nPortIndex) {
19602023 return nullptr ;
19612024 }
19622025
1963- const auto * __restrict__ pSrc32 = reinterpret_cast <const volatile uint32_t *>(sv_RxBuffer[nPortIndex].Dmx .current .data );
2026+ auto & dmxDataBuffer = getReadDmxDataBuffer (nPortIndex);
2027+ const auto * __restrict__ pSrc32 = reinterpret_cast <const volatile uint32_t *>(dmxDataBuffer.data );
19642028 auto * __restrict__ pDst32 = reinterpret_cast <uint32_t *>(sv_RxBuffer[nPortIndex].Dmx .previous .data );
19652029
1966- if (sv_RxBuffer[nPortIndex]. Dmx . current .nSlotsInPacket != sv_RxBuffer[nPortIndex].Dmx .previous .nSlotsInPacket ) {
1967- sv_RxBuffer[nPortIndex].Dmx .previous .nSlotsInPacket = sv_RxBuffer[nPortIndex]. Dmx . current .nSlotsInPacket ;
2030+ if (dmxDataBuffer .nSlotsInPacket != sv_RxBuffer[nPortIndex].Dmx .previous .nSlotsInPacket ) {
2031+ sv_RxBuffer[nPortIndex].Dmx .previous .nSlotsInPacket = dmxDataBuffer .nSlotsInPacket ;
19682032
19692033 for (size_t i = 0 ; i < buffer::SIZE / 4 ; ++i) {
19702034 pDst32[i] = pSrc32[i];
@@ -1994,24 +2058,23 @@ const uint8_t *Dmx::GetDmxChanged(const uint32_t nPortIndex) {
19942058const uint8_t *Dmx::GetDmxAvailable ([[maybe_unused]] const uint32_t nPortIndex) {
19952059 assert (nPortIndex < dmx::config::max::PORTS);
19962060#if !defined(CONFIG_DMX_TRANSMIT_ONLY)
1997- auto nSlotsInPacket = sv_RxBuffer[nPortIndex].Dmx .current .nSlotsInPacket ;
19982061
1999- if ((nSlotsInPacket & 0x8000 ) != 0x8000 ) {
2062+ auto & dmxDataBuffer = getReadDmxDataBuffer (nPortIndex);
2063+ if (!(dmxDataBuffer.nSlotsInPacket & dmxSlotsCompleteFlag)) {
20002064 return nullptr ;
20012065 }
20022066
2003- nSlotsInPacket &= ~0x8000 ;
2004- nSlotsInPacket--; // Remove SC from length
2005- sv_RxBuffer[nPortIndex].Dmx .current .nSlotsInPacket = nSlotsInPacket;
2067+ dmxDataBuffer.nSlotsInPacket &= ~dmxSlotsCompleteFlag;
2068+ dmxDataBuffer.nSlotsInPacket --; // Remove SC from length
20062069
2007- return const_cast <const uint8_t *>(sv_RxBuffer[nPortIndex]. Dmx . current .data );
2070+ return const_cast <const uint8_t *>(dmxDataBuffer .data );
20082071#else
20092072 return nullptr ;
20102073#endif
20112074}
20122075
20132076const uint8_t *Dmx::GetDmxCurrentData (const uint32_t nPortIndex) {
2014- return const_cast <const uint8_t *>(sv_RxBuffer[ nPortIndex]. Dmx . current .data );
2077+ return const_cast <const uint8_t *>(getReadDmxDataBuffer ( nPortIndex) .data );
20152078}
20162079
20172080uint32_t Dmx::GetDmxUpdatesPerSecond ([[maybe_unused]] uint32_t nPortIndex) {
@@ -2247,7 +2310,7 @@ void Dmx::RdmSendDiscoveryRespondMessage(uint32_t nPortIndex, const uint8_t *pRd
22472310const uint8_t *Dmx::RdmReceive (const uint32_t nPortIndex) {
22482311 assert (nPortIndex < dmx::config::max::PORTS);
22492312
2250- if ((sv_RxBuffer[nPortIndex].Rdm .nIndex & 0x4000 ) != 0x4000 ) {
2313+ if (! (sv_RxBuffer[nPortIndex].Rdm .nIndex & rdmSlotsCompleteFlag) ) {
22512314 return nullptr ;
22522315 }
22532316
0 commit comments