Commit 1e9aafb0e7b5b118bc042269f1b4e7d0b290229f

Authored by qqqlab
Committed by GitHub
1 parent ed9f0a60

.

Examples/Commissioning/Commissioning.ino
... ... @@ -28,9 +28,9 @@ Changelog:
28 28 #define DALI_OUTPUT_PIN 3
29 29 #define DALI_INPUT_PIN 4
30 30  
31   -#include "qqqDali.h"
  31 +#include "qqqDali_ATMega328.h"
32 32  
33   -Dali dali;
  33 +Dali_ATMega328 dali;
34 34  
35 35 void setup() {
36 36 Serial.begin(115200);
... ... @@ -50,42 +50,52 @@ void loop() {
50 50 while (Serial.available() > 0) {
51 51 int incomingByte = Serial.read();
52 52 switch(incomingByte) {
53   - case '1': scan_short_addr(); menu(); break;
54   - case '2': delete_short_addr(); menu(); break;
55   - case '3': commission_wo_short(); menu(); break;
56   - case '4': commission_all(); menu(); break;
57   - case '5': flash(); menu(); break; }
  53 + case '1': menu_flash(); menu(); break;
  54 + case '2': menu_scan_short_addr(); menu(); break;
  55 + case '3': menu_commission(); menu(); break;
  56 + case '4': menu_delete_short_addr(); menu(); break;
  57 + }
58 58 }
59 59 }
60 60  
61 61 void menu() {
62 62 Serial.println("----------------------------");
63   - Serial.println("1 Scan all short addresses");
64   - Serial.println("2 Dele1te all short addresses");
65   - Serial.println("3 Commission w/o short adr");
66   - Serial.println("4 Commission all short addresses");
67   - Serial.println("5 Flash all lights");
  63 + Serial.println("1 Flash all lights");
  64 + Serial.println("2 Scan short addresses");
  65 + Serial.println("3 Commission short addresses");
  66 + Serial.println("4 Delete short addresses");
68 67 Serial.println("----------------------------");
69 68 }
70 69  
71   -void delete_short_addr() {
72   - Serial.println("Running: Delete all short addresses");
73   - //remove all short addresses
74   - dali.cmd(DALI_DATA_TRANSFER_REGISTER0,0xFF);
75   - dali.cmd(DALI_SET_SHORT_ADDRESS, 0xFF);
  70 +
  71 +void menu_flash() {
  72 + Serial.println("Running: Flash all");
  73 + for(uint8_t i=0;i<5;i++) {
  74 + dali.set_level(254);
  75 + Serial.print(".");
  76 + delay(500);
  77 + dali.set_level(0);
  78 + Serial.print(".");
  79 + delay(500);
  80 + }
  81 + Serial.println();
76 82 }
77 83  
78   -void scan_short_addr() {
  84 +void menu_scan_short_addr() {
79 85 Serial.println("Running: Scan all short addresses");
80 86 uint8_t sa;
  87 + uint8_t cnt = 0;
81 88 for(sa = 0; sa<64; sa++) {
82 89 int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
83 90 if(rv!=DALI_RESULT_NO_REPLY) {
  91 + cnt++;
  92 + Serial.print("short address=");
84 93 Serial.print(sa);
85 94 Serial.print(" status=0x");
86 95 Serial.print(rv,HEX);
87 96 Serial.print(" minLevel=");
88 97 Serial.print(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
  98 + Serial.print(" flashing");
89 99 for(uint8_t i=0;i<5;i++) {
90 100 dali.set_level(254,sa);
91 101 Serial.print(".");
... ... @@ -102,28 +112,79 @@ void scan_short_addr() {
102 112 // dali.cmd(DALI_SET_SHORT_ADDRESS, sa);
103 113 // }
104 114 }
  115 + Serial.print("DONE, found ");Serial.print(cnt);Serial.println(" short addresses");
105 116 }
106 117  
107 118 //might need a couple of calls to find everything...
108   -void commission_wo_short(){
109   - Serial.println("Running: Commission w/o short adr");
110   - dali.commission(0xff); //init_arg=0b11111111 : all without short address
  119 +void menu_commission(){
  120 + Serial.println("Running: Commission - be patient, this takes a while ....");
  121 +// uint8_t cnt = dali.commission(0xff); //init_arg=0b11111111 : all without short address
  122 + uint8_t cnt = debug_commission(0xff); //init_arg=0b11111111 : all without short address
  123 + Serial.print("DONE, assigned ");Serial.print(cnt);Serial.println(" new short addresses");
111 124 }
112 125  
113   -void commission_all(){
114   - Serial.println("Running: Commission all");
115   - dali.commission(0x00); //init_arg=0b00000000 : all
  126 +void menu_delete_short_addr() {
  127 + Serial.println("Running: Delete all short addresses");
  128 + //remove all short addresses
  129 + dali.cmd(DALI_DATA_TRANSFER_REGISTER0,0xFF);
  130 + dali.cmd(DALI_SET_SHORT_ADDRESS, 0xFF);
  131 + Serial.println("DONE delete");
116 132 }
117 133  
118   -void flash() {
119   - Serial.println("Running: Flash all");
120   - for(uint8_t i=0;i<5;i++) {
121   - dali.set_level(254);
122   - Serial.print(".");
123   - delay(500);
124   - dali.set_level(0);
125   - Serial.print(".");
126   - delay(500);
  134 +//init_arg=11111111 : all without short address
  135 +//init_arg=00000000 : all
  136 +//init_arg=0AAAAAA1 : only for this shortadr
  137 +//returns number of new short addresses assigned
  138 +uint8_t debug_commission(uint8_t init_arg) {
  139 + uint8_t cnt = 0;
  140 + uint8_t arr[64];
  141 + uint8_t sa;
  142 + for(sa=0; sa<64; sa++) arr[sa]=0;
  143 +
  144 + //find existing short addresses when not assigning all
  145 + if(init_arg!=0b00000000) {
  146 + Serial.println("Find existing short adr");
  147 + for(sa = 0; sa<64; sa++) {
  148 + int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
  149 + if(rv!=DALI_RESULT_NO_REPLY) {
  150 + arr[sa]=1;
  151 + Serial.print("sortadr=");
  152 + Serial.print(sa);
  153 + Serial.print(" status=0x");
  154 + Serial.print(rv,HEX);
  155 + Serial.print(" minLevel=");
  156 + Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
  157 + }
  158 + }
127 159 }
128   - Serial.println();
  160 +
  161 + dali.cmd(DALI_INITIALISE,init_arg);
  162 + dali.cmd(DALI_RANDOMISE,0x00);
  163 +
  164 + Serial.println("Find random adr");
  165 + while(1) {
  166 + uint32_t adr = dali.find_addr();
  167 + if(adr>0xffffff) break;
  168 + Serial.print("found=");
  169 + Serial.println(adr,HEX);
  170 +
  171 + //find available address
  172 + for(sa=0; sa<64; sa++) {
  173 + if(arr[sa]==0) break;
  174 + }
  175 + if(sa>=64) break;
  176 + arr[sa] = 1;
  177 + cnt++;
  178 +
  179 + Serial.print("program short adr=");
  180 + Serial.println(sa);
  181 + dali.program_short_address(sa);
  182 + Serial.print("read short adr=");
  183 + Serial.println(dali.query_short_address());
  184 +
  185 + dali.cmd(DALI_WITHDRAW,0x00);
  186 + }
  187 +
  188 + dali.cmd(DALI_TERMINATE,0x00);
  189 + return cnt;
129 190 }
... ...
Examples/Dimmer/Dimmer.ino
... ... @@ -28,9 +28,9 @@ Changelog:
28 28 #define DALI_OUTPUT_PIN 3
29 29 #define DALI_INPUT_PIN 4
30 30  
31   -#include "qqqDali.h"
  31 +#include "qqqDali_ATMega328.h"
32 32  
33   -Dali dali;
  33 +Dali_ATMega328 dali;
34 34  
35 35 void setup() {
36 36 Serial.begin(115200);
... ...
qqqDali.cpp
... ... @@ -16,39 +16,25 @@
16 16  
17 17 ----------------------------------------------------------------------------
18 18 Changelog:
  19 +2020-11-10 Split off hardware specific code into separate class
19 20 2020-11-08 Created & tested on ATMega328 @ 8Mhz
20 21 ###########################################################################*/
21 22 #include "qqqDali.h"
22   -#include "arduino.h"
23 23  
24 24 //###########################################################################
25 25 // Helpers
26 26 //###########################################################################
27   -#define DALI_BUS_LOW() digitalWrite(this->tx_pin,LOW); this->tx_bus_low=1
28   -#define DALI_BUS_HIGH() digitalWrite(this->tx_pin,HIGH); this->tx_bus_low=0
29   -#define DALI_IS_BUS_LOW() (digitalRead(this->rx_pin)==LOW)
30   -#define DALI_BAUD 1200
  27 +#define DALI_TOL 15 //allow for 15% tolerance on timing (DALI spec calls for 10%, add 5% for uc clock tolerance)
31 28 #define DALI_TE ((1000000+(DALI_BAUD))/(2*(DALI_BAUD))) //417us
32   -#define DALI_TE_MIN (80*DALI_TE)/100
33   -#define DALI_TE_MAX (120*DALI_TE)/100
  29 +#define DALI_TE_MIN ((100-DALI_TOL)*DALI_TE)/100
  30 +#define DALI_TE_MAX ((100+DALI_TOL)*DALI_TE)/100
34 31 #define DALI_IS_TE(x) ((DALI_TE_MIN)<=(x) && (x)<=(DALI_TE_MAX))
35 32 #define DALI_IS_2TE(x) ((2*(DALI_TE_MIN))<=(x) && (x)<=(2*(DALI_TE_MAX)))
36 33  
37 34 //###########################################################################
38 35 // Transmitter ISR
39 36 //###########################################################################
40   -static Dali *IsrTimerHooks[DALI_HOOK_COUNT+1];
41   -
42   -// timer compare interrupt service routine
43   -ISR(TIMER1_COMPA_vect) {
44   -
45   - for(uint8_t i=0;i<DALI_HOOK_COUNT;i++) {
46   - if(IsrTimerHooks[i]==NULL) {return;}
47   - IsrTimerHooks[i]->ISR_timer();
48   - }
49   -}
50   -
51   -//called every Te period (417us)
  37 +//called by derived class every Te period (417us)
52 38 void Dali::ISR_timer() {
53 39 if(this->bus_idle_te_cnt<0xff) this->bus_idle_te_cnt++;
54 40  
... ... @@ -59,26 +45,29 @@ void Dali::ISR_timer() {
59 45 case TX_START:
60 46 //wait for timeslot, then send start bit
61 47 if(this->bus_idle_te_cnt >= 22) {
62   - DALI_BUS_LOW();
  48 + this->HAL_set_bus_low();
  49 + this->tx_bus_low=1;
63 50 this->tx_state = TX_START_X;
64 51 }
65 52 break;
66 53 case TX_START_X:
67   - DALI_BUS_HIGH();
  54 + this->HAL_set_bus_high();
  55 + this->tx_bus_low=0;
68 56 this->tx_pos=0;
69 57 this->tx_state = TX_BIT;
70 58 break;
71 59 case TX_BIT:
72   - if(this->tx_msg[this->tx_pos>>3] & 1<<(7-(this->tx_pos&0x7))) {DALI_BUS_LOW();} else {DALI_BUS_HIGH();}
  60 + if(this->tx_msg[this->tx_pos>>3] & 1<<(7-(this->tx_pos&0x7))) {this->HAL_set_bus_low();this->tx_bus_low=1;} else {this->HAL_set_bus_high();this->tx_bus_low=0;}
73 61 this->tx_state = TX_BIT_X;
74 62 break;
75 63 case TX_BIT_X:
76   - if(this->tx_msg[this->tx_pos>>3] & 1<<(7-(this->tx_pos&0x7))) {DALI_BUS_HIGH();} else {DALI_BUS_LOW();}
  64 + if(this->tx_msg[this->tx_pos>>3] & 1<<(7-(this->tx_pos&0x7))) {this->HAL_set_bus_high();this->tx_bus_low=0;} else {this->HAL_set_bus_low();this->tx_bus_low=1;}
77 65 this->tx_pos++;
78 66 if(this->tx_pos < this->tx_len) {this->tx_state = TX_BIT;} else {this->tx_state = TX_STOP1;}
79 67 break;
80 68 case TX_STOP1:
81   - DALI_BUS_HIGH();
  69 + this->HAL_set_bus_high();
  70 + this->tx_bus_low=0;
82 71 this->tx_state = TX_STOP1_X;
83 72 break;
84 73 case TX_STOP1_X:
... ... @@ -105,7 +94,7 @@ void Dali::ISR_timer() {
105 94 uint8_t bitlen = (this->rx_halfbitlen+1)>>1;
106 95 if((bitlen & 0x7) == 0) {
107 96 this->rx_len = bitlen>>3;
108   - if(this->EventHandlerReceivedData!=NULL) this->EventHandlerReceivedData(this, (uint8_t*)this->rx_msg, this->rx_len);
  97 + if(this->EventHandlerReceivedData) this->EventHandlerReceivedData(this, (uint8_t*)this->rx_msg, this->rx_len);
109 98 }else{
110 99 //invalid bitlen
111 100 //TODO handle this
... ... @@ -116,29 +105,11 @@ void Dali::ISR_timer() {
116 105 //###########################################################################
117 106 // Receiver ISR
118 107 //###########################################################################
119   -//pin PCINT
120   -//0-7 PCINT2_vect PCINT16-23
121   -//8-13 PCINT0_vect PCINT0-5
122   -//14-19 PCINT1_vect PCINT8-13
123   -static Dali *IsrPCINT0Hook;
124   -static Dali *IsrPCINT1Hook;
125   -static Dali *IsrPCINT2Hook;
126   -
127   -ISR(PCINT0_vect) {
128   - if(IsrPCINT0Hook!=NULL) IsrPCINT0Hook->ISR_pinchange();
129   -}
130   -ISR(PCINT1_vect) {
131   - if(IsrPCINT1Hook!=NULL) IsrPCINT1Hook->ISR_pinchange();
132   -}
133   -ISR(PCINT2_vect) {
134   - if(IsrPCINT2Hook!=NULL) IsrPCINT2Hook->ISR_pinchange();
135   -}
136   -
137   -
  108 +//called by derived class on bus state change
138 109 void Dali::ISR_pinchange() {
139   - uint32_t ts = micros(); //get timestamp of change
  110 + uint32_t ts = this->HAL_micros(); //get timestamp of change
140 111 this->bus_idle_te_cnt=0; //reset idle counter
141   - uint8_t bus_low = DALI_IS_BUS_LOW();
  112 + uint8_t bus_low = this->HAL_is_bus_low();
142 113  
143 114 //exit if transmitting
144 115 if(this->tx_state != TX_IDLE) {
... ... @@ -206,63 +177,6 @@ void Dali::push_halfbit(uint8_t bit) {
206 177 //###########################################################################
207 178 // Dali Class
208 179 //###########################################################################
209   -void Dali::begin(int8_t tx_pin, int8_t rx_pin) {
210   - this->tx_pin = tx_pin;
211   - this->rx_pin = rx_pin;
212   - this->tx_state = TX_IDLE;
213   - this->rx_state = RX_IDLE;
214   -
215   - //setup tx
216   - if(this->tx_pin>=0) {
217   - //setup tx pin
218   - pinMode(this->tx_pin, OUTPUT);
219   - DALI_BUS_HIGH();
220   -
221   - //setup tx timer interrupt
222   - TCCR1A = 0;
223   - TCCR1B = 0;
224   - TCNT1 = 0;
225   -
226   - OCR1A = (F_CPU+(DALI_BAUD))/(2*(DALI_BAUD)); // compare match register 16MHz/256/2Hz
227   - TCCR1B |= (1 << WGM12); // CTC mode
228   - TCCR1B |= (1 << CS10); // 1:1 prescaler
229   - TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
230   -
231   - //setup timer interrupt hooks
232   - for(uint8_t i=0;i<DALI_HOOK_COUNT;i++) {
233   - if(IsrTimerHooks[i] == NULL) {
234   - IsrTimerHooks[i] = this;
235   - break;
236   - }
237   - }
238   - }
239   -
240   - //setup rx
241   - if(this->rx_pin>=0) {
242   - //setup rx pin
243   - pinMode(this->rx_pin, INPUT);
244   -
245   - //setup rx pinchange interrupt
246   - // 0- 7 PCINT2_vect PCINT16-23
247   - // 8-13 PCINT0_vect PCINT0-5
248   - //14-19 PCINT1_vect PCINT8-13
249   - if(this->rx_pin<=7){
250   - PCICR |= (1<<PCIE2);
251   - PCMSK2 |= (1<< (this->rx_pin));
252   - IsrPCINT2Hook = this; //setup pinchange interrupt hook
253   - }else if(this->rx_pin<=13) {
254   - PCICR |= (1<<PCIE0);
255   - PCMSK0 |= (1<< (this->rx_pin-8));
256   - IsrPCINT0Hook = this; //setup pinchange interrupt hook
257   - }else if(this->rx_pin<=19) {
258   - PCICR |= (1<<PCIE1);
259   - PCMSK1 |= (1<< (this->rx_pin-14));
260   - IsrPCINT1Hook = this; //setup pinchange interrupt hook
261   - }
262   - }
263   -}
264   -
265   -
266 180 uint8_t Dali::send(uint8_t* tx_msg, uint8_t tx_len_bytes) {
267 181 if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG);
268 182 if(this->tx_state != TX_IDLE) return -(DALI_RESULT_TIMEOUT);
... ... @@ -273,41 +187,41 @@ uint8_t Dali::send(uint8_t* tx_msg, uint8_t tx_len_bytes) {
273 187 return 0;
274 188 }
275 189  
276   -uint8_t Dali::sendwait(uint8_t* tx_msg, uint8_t tx_len_bytes, uint32_t timeout_ms) {
  190 +uint8_t Dali::sendwait(uint8_t* tx_msg, uint8_t tx_len_bytes, uint32_t timeout_us) {
277 191 if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG);
278   - uint32_t ts = millis();
  192 + uint32_t ts = HAL_micros();
279 193 //wait for idle
280 194 while(this->tx_state != TX_IDLE) {
281   - if(millis() - ts > timeout_ms) return -(DALI_RESULT_TIMEOUT);
  195 + if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TIMEOUT);
282 196 }
283 197 //start transmit
284 198 uint8_t rv = this->send(tx_msg,tx_len_bytes);
285 199 if(rv) return rv;
286 200 //wait for completion
287 201 while(this->tx_state != TX_IDLE) {
288   - if(millis() - ts > timeout_ms) return -(DALI_RESULT_TX_TIMEOUT);
  202 + if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TX_TIMEOUT);
289 203 }
290 204 return 0;
291 205 }
292 206  
293 207 //transmit 2 byte command, receive 1 byte reply
294   -int16_t Dali::tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_ms) {
  208 +int16_t Dali::tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_us) {
295 209 uint8_t tx[2];
296 210 tx[0] = cmd0;
297 211 tx[1] = cmd1;
298   - int16_t rv = this->sendwait(tx,2);
  212 + int16_t rv = this->sendwait(tx, 2, timeout_us);
299 213 this->rx_halfbitlen = 0;
300 214 if(rv) return -rv;;
301 215  
302 216 //wait up to 10 ms for start of reply
303   - uint32_t ts = millis();
  217 + uint32_t ts = HAL_micros();
304 218 while(this->rx_state == RX_IDLE) {
305   - if(millis() - ts > 10) return DALI_RESULT_NO_REPLY;
  219 + if(HAL_micros() - ts > 10000) return DALI_RESULT_NO_REPLY;
306 220 }
307 221 //wait up to 15 ms for completion of reply
308   - ts = millis();
  222 + ts = HAL_micros();
309 223 while(this->rx_len == 0) {
310   - if(millis() - ts > 15) return DALI_RESULT_NO_REPLY;
  224 + if(HAL_micros() - ts > 15000) return DALI_RESULT_NO_REPLY;
311 225 }
312 226 if(this->rx_len > 1) return DALI_RESULT_INVALID_REPLY;
313 227 return this->rx_msg[0];
... ... @@ -464,41 +378,40 @@ uint32_t Dali::find_addr() {
464 378 //init_arg=11111111 : all without short address
465 379 //init_arg=00000000 : all
466 380 //init_arg=0AAAAAA1 : only for this shortadr
  381 +//returns number of new short addresses assigned
467 382 uint8_t Dali::commission(uint8_t init_arg) {
468 383 uint8_t cnt = 0;
469 384 uint8_t arr[64];
470 385 uint8_t sa;
471 386 for(sa=0; sa<64; sa++) arr[sa]=0;
472 387  
473   - //find existing short addresses
474   -// if(init_arg==0xff) {
475   - Serial.println("Short adr");
  388 + //find existing short addresses when not assigning all
  389 + if(init_arg!=0b00000000) {
  390 + //Serial.println("Short adr");
476 391 for(sa = 0; sa<64; sa++) {
477 392 int16_t rv = this->cmd(DALI_QUERY_STATUS,sa);
478 393 if(rv!=DALI_RESULT_NO_REPLY) {
479 394 arr[sa]=1;
480   - cnt++;
481   - Serial.print(sa);
482   - Serial.print(" status=0x");
483   - Serial.print(rv,HEX);
484   - Serial.print(" minLevel=");
485   - Serial.println(this->cmd(DALI_QUERY_MIN_LEVEL,sa));
  395 + //Serial.print(sa);
  396 + //Serial.print(" status=0x");
  397 + //Serial.print(rv,HEX);
  398 + //Serial.print(" minLevel=");
  399 + //Serial.println(this->cmd(DALI_QUERY_MIN_LEVEL,sa));
486 400 }
487 401 }
488   -// }
  402 + }
489 403  
490 404 this->cmd(DALI_INITIALISE,init_arg);
491 405 this->cmd(DALI_RANDOMISE,0x00);
492   - delay(100);
493 406  
494   - while(cnt<64) {
  407 + while(1) {
495 408 //Serial.print("addr=");
496 409 //Serial.println(this->get_random_address(0xff),HEX);
497 410  
498 411 uint32_t adr = this->find_addr();
499   - if(adr>0xffffff) break;
500   - Serial.print("found adr=");
501   - Serial.println(adr,HEX);
  412 + if(adr>0xffffff) break; //no more random addresses found -> exit
  413 + //Serial.print("found adr=");
  414 + //Serial.println(adr,HEX);
502 415  
503 416 //Serial.print("short adr=");
504 417 //Serial.println(dali_query_short_address());
... ... @@ -507,17 +420,17 @@ uint8_t Dali::commission(uint8_t init_arg) {
507 420 for(sa=0; sa<64; sa++) {
508 421 if(arr[sa]==0) break;
509 422 }
510   - if(sa>=64) break;
  423 + if(sa>=64) break; //all 64 short addresses assigned -> exit
511 424 arr[sa] = 1;
512 425 cnt++;
513 426  
514   - Serial.print("program short adr=");
515   - Serial.println(sa);
  427 + //Serial.print("program short adr=");
  428 + //Serial.println(sa);
516 429 this->program_short_address(sa);
517 430 //dali_program_short_address(0xff);
518 431  
519   - Serial.print("read short adr=");
520   - Serial.println(this->query_short_address());
  432 + //Serial.print("read short adr=");
  433 + //Serial.println(this->query_short_address()); //TODO check read adr, handle if not the same...
521 434  
522 435 this->cmd(DALI_WITHDRAW,0x00);
523 436 }
... ...
qqqDali.h
... ... @@ -16,14 +16,24 @@
16 16  
17 17 ----------------------------------------------------------------------------
18 18 Changelog:
  19 +2020-11-10 Split off hardware specific code into separate class
19 20 2020-11-08 Created & tested on ATMega328 @ 8Mhz
20 21 ###########################################################################*/
21 22 #include <inttypes.h>
22 23  
23   -
24 24 class Dali {
25 25 public:
26   - void begin(int8_t tx_pin, int8_t rx_pin);
  26 + //Hardware Abstraction Layer overrides
  27 + virtual void HAL_set_bus_low() const = 0; //set DALI bus to low state
  28 + virtual void HAL_set_bus_high() const = 0; //set DALI bus to high state
  29 + virtual uint8_t HAL_is_bus_low() const = 0; //is DALI bus in low state?
  30 + virtual uint32_t HAL_micros() const = 0; //get microsecond time stamp
  31 + void ISR_timer(); //call this function every 417us
  32 + void ISR_pinchange(); //call this function on change of DALI bus
  33 +
  34 + //callback on received data from DALI bus
  35 + typedef void (*EventHandlerReceivedDataFuncPtr)(Dali *sender, uint8_t *data, uint8_t len);
  36 + EventHandlerReceivedDataFuncPtr EventHandlerReceivedData;
27 37  
28 38 //high level functions
29 39 void set_level(uint8_t level, uint8_t adr=0xFF); //set arc level
... ... @@ -43,24 +53,17 @@ public:
43 53 uint8_t query_short_address();
44 54 uint32_t find_addr();
45 55  
46   -
47 56 //low level functions
48   - typedef void (*EventHandlerReceivedDataFuncPtr)(Dali *sender, uint8_t *data, uint8_t len);
49   - EventHandlerReceivedDataFuncPtr EventHandlerReceivedData;
50   -
51 57 uint8_t send(uint8_t* tx_msg, uint8_t tx_len_bytes);
52   - uint8_t sendwait(uint8_t* tx_msg, uint8_t tx_len_bytes, uint32_t timeout_ms=500);
53   - int16_t tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_ms=500);
54   - void ISR_timer();
55   - void ISR_pinchange();
  58 + uint8_t sendwait(uint8_t* tx_msg, uint8_t tx_len_bytes, uint32_t timeout_us=500000);
  59 + int16_t tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_us=500000);
56 60  
57   - #define DALI_HOOK_COUNT 3
58   -
59   -
60   -private:
  61 + //initialize variables
  62 + Dali() : tx_state(TX_IDLE), rx_state(RX_IDLE), tx_bus_low(0), tx_len(0), EventHandlerReceivedData(0) {};
  63 +
  64 +protected:
61 65 //low level functions
62 66 enum tx_stateEnum { TX_IDLE=0,TX_START,TX_START_X,TX_BIT,TX_BIT_X,TX_STOP1,TX_STOP1_X,TX_STOP2,TX_STOP2_X,TX_STOP3};
63   - uint8_t tx_pin; //transmitter pin
64 67 uint8_t tx_msg[3]; //message to transmit
65 68 uint8_t tx_len; //number of bits to transmit
66 69 volatile uint8_t tx_pos; //current bit transmit position
... ... @@ -69,7 +72,6 @@ private:
69 72 volatile uint8_t tx_bus_low; //bus is low according to transmitter?
70 73  
71 74 enum rx_stateEnum { RX_IDLE,RX_START,RX_BIT};
72   - uint8_t rx_pin; //receiver pin
73 75 volatile uint8_t rx_last_bus_low; //receiver as low at last pinchange
74 76 volatile uint32_t rx_last_change_ts; //timestamp last pinchange
75 77 volatile rx_stateEnum rx_state; //current state
... ... @@ -88,6 +90,10 @@ private:
88 90 };
89 91  
90 92  
  93 +
  94 +
  95 +#define DALI_BAUD 1200
  96 +
91 97 #define DALI_RESULT_TIMEOUT -1 //Timeout waiting for DALI bus
92 98 #define DALI_RESULT_INVALID_TOO_LONG -2 //Trying to send too many bytes (max 3)
93 99 #define DALI_RESULT_TX_TIMEOUT -3 //Timeout during transmission
... ...
qqqDali_ATMega328.h 0 โ†’ 100644
  1 +/*###########################################################################
  2 + qqqDali_ATMega328.h - copyright qqqlab.com / github.com/qqqlab
  3 +
  4 + This program is free software: you can redistribute it and/or modify
  5 + it under the terms of the GNU General Public License as published by
  6 + the Free Software Foundation, either version 3 of the License, or
  7 + (at your option) any later version.
  8 +
  9 + This program is distributed in the hope that it will be useful,
  10 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + GNU General Public License for more details.
  13 +
  14 + You should have received a copy of the GNU General Public License
  15 + along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +
  17 +----------------------------------------------------------------------------
  18 +Changelog:
  19 +2020-11-10 Created & tested on ATMega328 @ 8Mhz
  20 +###########################################################################*/
  21 +#include "arduino.h"
  22 +#include "qqqDali.h"
  23 +
  24 +#define DALI_HOOK_COUNT 3
  25 +
  26 +class Dali_ATMega328 : public Dali {
  27 +public:
  28 + void begin(int8_t tx_pin, int8_t rx_pin);
  29 + virtual void HAL_set_bus_low() const override;
  30 + virtual void HAL_set_bus_high() const override;
  31 + virtual uint8_t HAL_is_bus_low() const override;
  32 + virtual uint32_t HAL_micros() const override;
  33 +
  34 +private:
  35 + uint8_t tx_pin; //transmitter pin
  36 + uint8_t rx_pin; //receiver pin
  37 +};
  38 +
  39 +//-----------------------------------------
  40 +//Hardware Abstraction Layer
  41 +void Dali_ATMega328::HAL_set_bus_low() const {
  42 + digitalWrite(this->tx_pin,LOW);
  43 +}
  44 +
  45 +void Dali_ATMega328::HAL_set_bus_high() const {
  46 + digitalWrite(this->tx_pin,HIGH);
  47 +}
  48 +
  49 +uint8_t Dali_ATMega328::HAL_is_bus_low() const {
  50 + return (digitalRead(this->rx_pin) == LOW);
  51 +}
  52 +
  53 +uint32_t Dali_ATMega328::HAL_micros() const {
  54 + return micros();
  55 +}
  56 +
  57 +//-----------------------------------------
  58 +// Transmitter ISR
  59 +static Dali *IsrTimerHooks[DALI_HOOK_COUNT+1];
  60 +
  61 +// timer compare interrupt service routine
  62 +ISR(TIMER1_COMPA_vect) {
  63 +
  64 + for(uint8_t i=0;i<DALI_HOOK_COUNT;i++) {
  65 + if(IsrTimerHooks[i]==NULL) {return;}
  66 + IsrTimerHooks[i]->ISR_timer();
  67 + }
  68 +}
  69 +
  70 +//-----------------------------------------
  71 +// Receiver ISR
  72 +//pin PCINT
  73 +//0-7 PCINT2_vect PCINT16-23
  74 +//8-13 PCINT0_vect PCINT0-5
  75 +//14-19 PCINT1_vect PCINT8-13
  76 +static Dali *IsrPCINT0Hook;
  77 +static Dali *IsrPCINT1Hook;
  78 +static Dali *IsrPCINT2Hook;
  79 +
  80 +ISR(PCINT0_vect) {
  81 + if(IsrPCINT0Hook!=NULL) IsrPCINT0Hook->ISR_pinchange();
  82 +}
  83 +ISR(PCINT1_vect) {
  84 + if(IsrPCINT1Hook!=NULL) IsrPCINT1Hook->ISR_pinchange();
  85 +}
  86 +ISR(PCINT2_vect) {
  87 + if(IsrPCINT2Hook!=NULL) IsrPCINT2Hook->ISR_pinchange();
  88 +}
  89 +
  90 +
  91 +//-----------------------------------------
  92 +// begin
  93 +void Dali_ATMega328::begin(int8_t tx_pin, int8_t rx_pin) {
  94 + this->tx_pin = tx_pin;
  95 + this->rx_pin = rx_pin;
  96 +
  97 + //setup tx
  98 + if(this->tx_pin>=0) {
  99 + //setup tx pin
  100 + pinMode(this->tx_pin, OUTPUT);
  101 + this->HAL_set_bus_high();
  102 + this->tx_bus_low=0;
  103 +
  104 + //setup tx timer interrupt
  105 + TCCR1A = 0;
  106 + TCCR1B = 0;
  107 + TCNT1 = 0;
  108 + OCR1A = (F_CPU+(DALI_BAUD))/(2*(DALI_BAUD)); // compare match register at baud rate * 2
  109 + TCCR1B |= (1 << WGM12); // CTC mode
  110 + TCCR1B |= (1 << CS10); // 1:1 prescaler
  111 + TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  112 +
  113 + //setup timer interrupt hooks
  114 + for(uint8_t i=0;i<DALI_HOOK_COUNT;i++) {
  115 + if(IsrTimerHooks[i] == NULL) {
  116 + IsrTimerHooks[i] = this;
  117 + break;
  118 + }
  119 + }
  120 + }
  121 +
  122 + //setup rx
  123 + if(this->rx_pin>=0) {
  124 + //setup rx pin
  125 + pinMode(this->rx_pin, INPUT);
  126 +
  127 + //setup rx pinchange interrupt
  128 + // 0- 7 PCINT2_vect PCINT16-23
  129 + // 8-13 PCINT0_vect PCINT0-5
  130 + //14-19 PCINT1_vect PCINT8-13
  131 + if(this->rx_pin <= 7){
  132 + PCICR |= (1 << PCIE2);
  133 + PCMSK2 |= (1 << (this->rx_pin));
  134 + IsrPCINT2Hook = this; //setup pinchange interrupt hook
  135 + }else if(this->rx_pin <= 13) {
  136 + PCICR |= (1 << PCIE0);
  137 + PCMSK0 |= (1 << (this->rx_pin - 8));
  138 + IsrPCINT0Hook = this; //setup pinchange interrupt hook
  139 + }else if(this->rx_pin <= 19) {
  140 + PCICR |= (1 << PCIE1);
  141 + PCMSK1 |= (1 << (this->rx_pin - 14));
  142 + IsrPCINT1Hook = this; //setup pinchange interrupt hook
  143 + }
  144 + }
  145 +}
... ...