6565 --------------------------------------------------------------------------------------------
6666 Version yyyymmdd Action Description
6767 --------------------------------------------------------------------------------------------
68+ 1.3.0.4 20251123 update - Add send retry on collision detection
69+ - Prep DALI-2 24-bit transceive
6870 1.3.0.3 20251122 update - Remove sleep dependency from frame handling
6971 - Change receive timeout from 50 ms to 20 ms (DALI protocol is 9.2 ms)
7072 - Add DALI DT8 RGBWAF Control Gear (receive) for Tasmota color light control
139141#define DALI_DEBUG_PIN 4 // Debug GPIO
140142#endif
141143
144+ /* ********************************************************************************************/
145+
146+ #define DALI_COLLISION 0x10000000 // Collision data mask
147+ #define DALI_BACKWARD_FRAME 0x00000000 // Backward frame mask
148+ #define DALI_FORWARD_16BIT_FRAME 0x01000000 // DALI 16-bit forward frame mask
149+ #define DALI_FORWARD_24BIT_FRAME 0x02000000 // DALI-2 24-bit forward frame mask
150+ #define DALI_FORWARD_FRAME 0x03000000 // = DALI_FORWARD_16BIT_FRAME | DALI_FORWARD_24BIT_FRAME
151+
142152#include " include/xdrv_75_dali.h"
143153
144154#define DALI_MAX_STORED 17 // Store broadcast and group states
@@ -159,7 +169,6 @@ struct DALI {
159169 uint32_t bit_cycles;
160170 uint32_t last_activity;
161171 uint32_t received_dali_data; // Data received from DALI bus
162- uint32_t color_sequence;
163172 uint8_t pin_rx;
164173 uint8_t pin_tx;
165174 uint8_t max_short_address;
@@ -364,49 +373,61 @@ void DaliDisableRxInterrupt(void) {
364373void IRAM_ATTR DaliReceiveData (void ); // Fix ESP8266 ISR not in IRAM! exception
365374void DaliReceiveData (void ) {
366375 /*
376+ DALI-2 Forward frame (1 Start bit + 24 data bits) * 2 bits/bit (manchester encoding) + 2 * 2 Stop bits = 54 bits
377+ DALI data 0xFE6432 1 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 0 0 1 1 0 0 1 0 Forward frame - 23.2 ms
378+ Start and Stop bits 1 1 1
379+ Manchester data 01010101010101011010010110100110101010010110100110
380+ Stop bits 1111
381+
367382 Forward frame (1 Start bit + 16 data bits) * 2 bits/bit (manchester encoding) + 2 * 2 Stop bits = 38 bits
368- DALI data 0xFE64 1 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 Forward frame
383+ DALI data 0xFE64 1 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 Forward frame - 16.2 ms
369384 Start and Stop bits 1 1 1
370385 Manchester data 0101010101010101101001011010011010
371386 Stop bits 1111
372387
373388 Backward frame (1 Start bit + 8 data bits) * 2 bits/bit (manchester encoding) + 2 * 2 Stop bits = 22 bits
374- DALI data 0x64 0 1 1 0 0 1 0 0 Backward frame
389+ DALI data 0x64 0 1 1 0 0 1 0 0 Backward frame - 10 ms
375390 Start and Stop bits 1 1 1
376391 Manchester data 011001011010011010
377392 Stop bits 1111
378393
379- Bit number 01234567890123456789012345678901234567
380- 1 2 3
394+ Bit number 0123456789012345678901234567890123456789012345678901234
395+ 1 2 3 4 5
381396 */
382397 if (Dali->available ) { return ; } // Skip if last input is not yet handled
383398 uint32_t gap_time = millis () - Dali->last_activity ;
384399 uint32_t wait = ESP.getCycleCount () + (Dali->bit_cycles / 2 );
385400 int bit_state = 0 ;
386401 bool dali_read;
387- bool forward_frame = true ;
402+ uint32_t frame_type = 2 ; // 0 = 8-bit backward, 1 = 16-bit forward, 2 = 24-bit forward
388403 uint32_t received_dali_data = 0 ;
389404 uint32_t bit_number = 0 ;
390- while (bit_number < 38 ) {
405+ while (bit_number < 54 ) {
391406 while (ESP.getCycleCount () < wait);
392407 wait += Dali->bit_cycles ; // Auto roll-over +1Te
393408 dali_read = (digitalRead (Dali->pin_rx ) != Dali->invert_rx );
394409#ifdef DALI_DEBUG
395410 digitalWrite (DALI_DEBUG_PIN, bit_number&1 ); // Add LogicAnalyzer poll indication
396411#endif // DALI_DEBUG
397- if (bit_number < 34 ) { // 34 manchester encoded bits
412+ if (bit_number < 50 ) { // 50 manchester encoded bits
398413 bit_state += (dali_read) ? 1 : -1 ;
399414 if (0 == bit_state) { // Manchester encoding total 2 bits is always 0
400415 if (bit_number > 2 ) { // Skip start bit
401416 received_dali_data <<= 1 ;
402417 received_dali_data |= dali_read;
403418 }
404419 }
405- else if ((2 == bit_state) &&
420+ else if ((2 == bit_state) && // Invalid manchester data (might be stop bit)
406421 (bit_number == 19 )) { // Possible backward frame detected - Chk stop bits
407422 bit_state = 0 ;
408- bit_number = 35 ;
409- forward_frame = false ;
423+ bit_number = 51 ; // Continue receiving stop bits
424+ frame_type = 0 ; // 0 = 8-bit backward, 1 = 16-bit forward, 2 = 24-bit forward
425+ }
426+ else if ((2 == bit_state) && // Invalid manchester data (might be stop bit)
427+ (bit_number == 35 )) { // Possible 16-bit forward frame detected - Chk stop bits
428+ bit_state = 0 ;
429+ bit_number = 51 ; // Continue receiving stop bits
430+ frame_type = 1 ; // 0 = 8-bit backward, 1 = 16-bit forward, 2 = 24-bit forward
410431 }
411432 else if (abs (bit_state) > 1 ) { // Invalid manchester data (too many 0 or 1)
412433 break ;
@@ -424,11 +445,9 @@ void DaliReceiveData(void) {
424445 }
425446 Dali->last_activity = millis (); // Start Forward Frame delay time (>22Te)
426447
427- if (forward_frame) { // Forward frame received
428- received_dali_data |= 0x00020000 ; // Forward frame received
429- }
448+ received_dali_data |= (frame_type << 24 ); // 0 = 8-bit backward, 1 = 16-bit forward, 2 = 24-bit forward
430449 if (bit_state != 0 ) { // Invalid Manchester encoding including start and stop bits
431- received_dali_data |= 0x00010000 ; // Possible collision or invalid reply of repeated frame due to handling of first frame
450+ received_dali_data |= DALI_COLLISION; // Possible collision or invalid reply of repeated frame due to handling of first frame
432451 }
433452 if (Dali->response || // Response from last message send
434453 (Dali->received_dali_data != received_dali_data)) { // Skip duplicates
@@ -441,84 +460,103 @@ void DaliReceiveData(void) {
441460 * DALI send
442461\*-------------------------------------------------------------------------------------------*/
443462
444- void DaliSendDataOnce (uint16_t send_dali_data) {
463+ void DaliSendDataOnce (uint32_t send_dali_data) {
445464 /*
465+ DALI-2 protocol forward frame
466+ DALI data 0xFE6432 1 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 0 0 1 1 0 0 1 0
467+ Start and Stop bits 1 1 1
468+ Manchester data 01010101010101011010010110100110101010010110100110
469+ Stop bits 1111
470+
446471 DALI protocol forward frame
447472 DALI data 0xFE64 1 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0
448473 Start and Stop bits 1 1 1
449474 Manchester data 0101010101010101101001011010011010
450475 Stop bits 1111
451476
452- Bit number 01234567890123456789012345678901234567
453- 1 2 3
477+ Bit number 012345678901234567890123456789012345678901234567890123
478+ 1 2 3 4 5
454479 */
455- Dali->last_activity += 14 ; // As suggested by DALI protocol (>22Te = 9.17 ms) - We need to add 1.1 ms due to not waiting for stop bits
456- while (!TimeReached (Dali->last_activity )) {
457- delay (1 ); // Wait for bus to be free if needed
458- }
459480 bool bit_value;
460481 bool pin_value;
461482 bool dali_read;
462- bool collision = false ;
463- uint32_t bit_pos = 15 ;
464- uint32_t bit_number = 0 ;
483+ uint32_t retry = 2 ;
484+ bool collision;
485+ do {
486+ collision = false ;
487+ uint32_t send_data = send_dali_data;
488+ uint32_t bit_pos = 15 ; // 16-bit forward frame
489+ uint32_t max_bit_number = 34 ;
490+ if (send_data & DALI_FORWARD_24BIT_FRAME) {
491+ bit_pos = 23 ; // 24-bit forward frame
492+ max_bit_number = 50 ;
493+ }
494+ uint32_t bit_number = 0 ;
495+
496+ Dali->last_activity += 14 ; // As suggested by DALI protocol (>22Te = 9.17 ms) - We need to add 1.1 ms due to not waiting for stop bits
497+ while (!TimeReached (Dali->last_activity )) {
498+ delay (1 ); // Wait for bus to be free if needed
499+ }
465500
466501#ifdef ESP32
467- {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
468- portENTER_CRITICAL (&mux);
502+ {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
503+ portENTER_CRITICAL (&mux);
469504#endif
470505
471- uint32_t wait = ESP.getCycleCount ();
472- while (bit_number < 35 ) { // 417 * 35 = 35Te = 14.7 ms
473- if (!collision) {
474- if (0 == (bit_number &1 )) { // Even bit
475- // Start bit, Stop bit, Data bits
476- bit_value = (0 == bit_number) ? 1 : (34 == bit_number) ? 0 : (bool )((send_dali_data >> bit_pos--) &1 ); // MSB first
477- } else { // Odd bit
478- bit_value = !bit_value; // Complement bit
479- }
480- pin_value = bit_value ? LOW : HIGH; // Invert bit
481- } else {
482- if (34 == bit_number) {
483- pin_value = HIGH; // Set to idle
506+ uint32_t wait = ESP.getCycleCount ();
507+ while (bit_number <= max_bit_number) { // 417 * 35 = 35Te = 14.7 ms
508+ if (!collision) {
509+ if (0 == (bit_number &1 )) { // Even bit
510+ // Start bit, Stop bit, Data bits
511+ bit_value = (0 == bit_number) ? 1 : (max_bit_number == bit_number) ? 0 : (bool )((send_data >> bit_pos--) &1 ); // MSB first
512+ } else { // Odd bit
513+ bit_value = !bit_value; // Complement bit
514+ }
515+ pin_value = bit_value ? LOW : HIGH; // Invert bit
516+ } else {
517+ if (max_bit_number == bit_number) {
518+ pin_value = HIGH; // Set to idle
519+ }
484520 }
485- }
486521
487- digitalWrite (Dali->pin_tx , (Dali->invert_tx ) ? !pin_value : pin_value);
488- wait += Dali->bit_cycles ; // Auto roll-over
489- while (ESP.getCycleCount () < wait);
490-
491- if (!collision) {
492- dali_read = (digitalRead (Dali->pin_rx ) != Dali->invert_rx );
493- if ((HIGH == pin_value) && (LOW == dali_read)) { // Collision if write is 1 and bus is 0
494- collision = true ;
495- pin_value = LOW;
496- bit_number = 29 ; // Keep bus low for 4 bits
497- AddLog (LOG_LEVEL_DEBUG_MORE, PSTR (" DLI: Tx collision" ));
522+ digitalWrite (Dali->pin_tx , (Dali->invert_tx ) ? !pin_value : pin_value);
523+ wait += Dali->bit_cycles ; // Auto roll-over
524+ while (ESP.getCycleCount () < wait);
525+
526+ if (!collision) {
527+ dali_read = (digitalRead (Dali->pin_rx ) != Dali->invert_rx );
528+ if ((HIGH == pin_value) && (LOW == dali_read)) { // Collision if write is 1 and bus is 0
529+ collision = true ;
530+ pin_value = LOW;
531+ bit_number = max_bit_number -5 ; // Keep bus low for 4 bits - break sequence
532+ AddLog (LOG_LEVEL_DEBUG_MORE, PSTR (" DLI: Tx collision" ));
533+ }
498534 }
499- }
500535
501- bit_number++;
502- }
536+ bit_number++;
537+ }
503538
504539#ifdef ESP32
505- portEXIT_CRITICAL (&mux);}
540+ portEXIT_CRITICAL (&mux);}
506541#endif
507542
508- // delayMicroseconds(1100); // Wait 3Te as sending stop bits - adds to total 15.8 ms
509- Dali->last_activity = millis (); // Start Forward Frame delay time (>22Te)
510-
543+ // delayMicroseconds(1100); // Wait 3Te as sending stop bits - adds to total 15.8 ms
544+ Dali->last_activity = millis (); // Start Forward Frame delay time (>22Te)
545+ } while (retry-- && collision);
511546}
512547
513548/* -------------------------------------------------------------------------------------------*/
514549
515- void DaliSendData (uint32_t adr, uint32_t cmd) {
550+ void DaliSendData (uint32_t adr, uint32_t cmd, uint32_t opt = 0 );
551+ void DaliSendData (uint32_t adr, uint32_t cmd, uint32_t opt) {
516552 adr &= 0xFF ;
517553 cmd &= 0xFF ;
518554
519- Dali->address = adr;
520- Dali->command = cmd;
521- DaliSaveState (adr, cmd);
555+ if (!opt) { // No DALI-2 24-bit command
556+ Dali->address = adr;
557+ Dali->command = cmd;
558+ DaliSaveState (adr, cmd);
559+ }
522560
523561 bool send_twice = false ;
524562 if (adr & DALI_SELECTOR_BIT) { // Selector bit (command) or special command
@@ -547,12 +585,15 @@ void DaliSendData(uint32_t adr, uint32_t cmd) {
547585 }
548586 }
549587
588+ uint32_t send_dali_data = adr << 8 | cmd;
589+ if (opt & DALI_FORWARD_24BIT_FRAME) {
590+ send_dali_data = (send_dali_data << 8 ) | (opt & (DALI_FORWARD_24BIT_FRAME | 0xFF ));
591+ }
592+
550593#ifdef DALI_DEBUG
551- AddLog (Dali->log_level , PSTR (" DLI: Tx DT%d , Twice %d, Adr 0x%02X, Cmd 0x%02X " ), Dali-> device_type , send_twice, adr, cmd );
594+ AddLog (Dali->log_level , PSTR (" DLI: Tx 0x%08X , Twice %d, DT%d " ), send_dali_data , send_twice, Dali-> device_type );
552595#endif // DALI_DEBUG
553596
554- uint16_t send_dali_data = adr << 8 | cmd;
555-
556597 DaliDisableRxInterrupt ();
557598 DaliSendDataOnce (send_dali_data); // Takes 14.7 ms
558599 if (send_twice) {
@@ -578,16 +619,16 @@ int DaliSendWaitResponse(uint32_t adr, uint32_t cmd, uint32_t timeout) {
578619 int result = -1 ; // DALI NO or no response
579620 if (Dali->available ) {
580621 Dali->available = false ; // DALI collision (-2) or valid data (>=0)
581- bool collision = (Dali->received_dali_data &0x00010000 );
582- bool forward_frame = (Dali->received_dali_data &0x00020000 );
622+ bool collision = (Dali->received_dali_data & DALI_COLLISION );
623+ bool forward_frame = (Dali->received_dali_data & DALI_FORWARD_FRAME );
583624 if (!forward_frame) {
584625 result = (collision) ? -2 : (Dali->received_dali_data &0xFF );
585626 }
586627 }
587628 Dali->response = false ;
588629
589630#ifdef DALI_DEBUG
590- AddLog (Dali->log_level , PSTR (" DLI: Rx 0x%05X Response" ), result);
631+ AddLog (Dali->log_level , PSTR (" DLI: Rx 0x%08X Response" ), result);
591632#endif // DALI_DEBUG
592633
593634 return result;
@@ -883,13 +924,16 @@ void ResponseDali(uint32_t index) {
883924void DaliLoop (void ) {
884925 if (!Dali->available || Dali->response ) { return ; }
885926
886- bool collision = (Dali->received_dali_data &0x00010000 );
887- bool forward_frame = (Dali->received_dali_data &0x00020000 );
927+ bool collision = (Dali->received_dali_data & DALI_COLLISION);
928+ bool forward_frame = (Dali->received_dali_data & DALI_FORWARD_FRAME);
929+ bool forward_24bit_frame = (Dali->received_dali_data & DALI_FORWARD_24BIT_FRAME);
888930
889- AddLog ((1 == Dali->probe ) ? LOG_LEVEL_DEBUG : LOG_LEVEL_DEBUG_MORE, PSTR (" DLI: Rx 0x%05X%s" ), Dali->received_dali_data , (!forward_frame)?" backward" :" " );
931+ AddLog ((1 == Dali->probe ) ? LOG_LEVEL_DEBUG : LOG_LEVEL_DEBUG_MORE, PSTR (" DLI: Rx 0x%08X %s" ),
932+ Dali->received_dali_data , (collision)?" collision" :(forward_frame)?" " :" backward" );
890933
891934 if (collision || // Rx collision
892- !forward_frame || // We do not serve backward frames
935+ !forward_frame || // Skip backward frames
936+ forward_24bit_frame || // Currently no support for DALI-2 24-bit frame
893937 (1 == Dali->probe )) { // Probe only
894938 Dali->available = false ;
895939 return ;
@@ -900,10 +944,7 @@ void DaliLoop(void) {
900944
901945#ifdef USE_LIGHT
902946#ifdef DALI_LIGHT_COLOR_SUPPORT
903- if (DALI_209_SET_TEMPORARY_RGBWAF_CONTROL == Dali->command ) {
904- Dali->color_sequence = millis (); // Indicate start of color sequence - See DaliSetChannels()
905- }
906- else if (DALI_102_SET_DTR0 == Dali->address ) { Dali->dtr [0 ] = Dali->command ; } // Might be Red / White
947+ if (DALI_102_SET_DTR0 == Dali->address ) { Dali->dtr [0 ] = Dali->command ; } // Might be Red / White
907948 else if (DALI_102_SET_DTR1 == Dali->address ) { Dali->dtr [1 ] = Dali->command ; } // Might be Green / Amber
908949 else if (DALI_102_SET_DTR2 == Dali->address ) { Dali->dtr [2 ] = Dali->command ; } // Might be Blue
909950 else if (DALI_209_SET_TEMPORARY_RGB_DIMLEVEL == Dali->command ) {
@@ -916,7 +957,6 @@ void DaliLoop(void) {
916957 Dali->color [4 ] = Dali->dtr [0 ]; // Cold White
917958 }
918959 else if (DALI_209_ACTIVATE == Dali->command ) {
919- Dali->color_sequence = 0 ;
920960 uint32_t channels = Dali->Settings .light_type -8 ;
921961 if ((Dali->target_rgbwaf > 0 ) && (channels > 0 )) { // Color control
922962 Dali->address &= 0xFE ; // Reset DALI_SELECTOR_BIT set
@@ -943,7 +983,7 @@ void DaliLoop(void) {
943983 } else
944984#endif // DALI_LIGHT_COLOR_SUPPORT
945985#endif // USE_LIGHT
946- if (( !(Dali->address & DALI_SELECTOR_BIT)) && !Dali-> color_sequence ) { // Address
986+ if (!(Dali->address & DALI_SELECTOR_BIT)) { // Address
947987 uint32_t index = DaliSaveState (Dali->address , Dali->command ); // Update dimmer and power
948988 bool show_response = true ;
949989#ifdef USE_LIGHT
@@ -981,9 +1021,6 @@ void DaliEverySecond(void) {
9811021 if (5 == TasmotaGlobal.uptime ) {
9821022 DaliInitLight ();
9831023 }
984- if (Dali->color_sequence && TimeReached (Dali->color_sequence + 1000 )) {
985- Dali->color_sequence = 0 ; // Reset color sequence in case of incomplete DALI sequence
986- }
9871024}
9881025
9891026/* ********************************************************************************************\
@@ -1423,6 +1460,13 @@ void CmndDaliSend(void) {
14231460 AddLog (Dali->log_level , PSTR (" DLI: index %d, params %d, values %d,%d,%d,%d,%d" ), XdrvMailbox.index , params, values[0 ], values[1 ], values[2 ], values[3 ], values[4 ]);
14241461#endif // DALI_DEBUG
14251462
1463+ if (255 == XdrvMailbox.index ) { // DaliSend255 - Dali-2 24-bit frame
1464+ if (params >= 3 ) {
1465+ DaliSendData (values[0 ], values[1 ], values[2 ] | DALI_FORWARD_24BIT_FRAME);
1466+ ResponseCmndDone ();
1467+ return ;
1468+ }
1469+ }
14261470 if (DALI_207_DEVICE_TYPE == XdrvMailbox.index ) { // DaliSend6 - DT6 = 207 = Extended LED commands 224...236
14271471 /*
14281472 params 0 1 2
0 commit comments