Commit 1e9aafb0e7b5b118bc042269f1b4e7d0b290229f

Authored by qqqlab
Committed by GitHub
1 parent ed9f0a60

.

Examples/Commissioning/Commissioning.ino
@@ -28,9 +28,9 @@ Changelog: @@ -28,9 +28,9 @@ Changelog:
28 #define DALI_OUTPUT_PIN 3 28 #define DALI_OUTPUT_PIN 3
29 #define DALI_INPUT_PIN 4 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 void setup() { 35 void setup() {
36 Serial.begin(115200); 36 Serial.begin(115200);
@@ -50,42 +50,52 @@ void loop() { @@ -50,42 +50,52 @@ void loop() {
50 while (Serial.available() > 0) { 50 while (Serial.available() > 0) {
51 int incomingByte = Serial.read(); 51 int incomingByte = Serial.read();
52 switch(incomingByte) { 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 void menu() { 61 void menu() {
62 Serial.println("----------------------------"); 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 Serial.println("----------------------------"); 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 Serial.println("Running: Scan all short addresses"); 85 Serial.println("Running: Scan all short addresses");
80 uint8_t sa; 86 uint8_t sa;
  87 + uint8_t cnt = 0;
81 for(sa = 0; sa<64; sa++) { 88 for(sa = 0; sa<64; sa++) {
82 int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa); 89 int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
83 if(rv!=DALI_RESULT_NO_REPLY) { 90 if(rv!=DALI_RESULT_NO_REPLY) {
  91 + cnt++;
  92 + Serial.print("short address=");
84 Serial.print(sa); 93 Serial.print(sa);
85 Serial.print(" status=0x"); 94 Serial.print(" status=0x");
86 Serial.print(rv,HEX); 95 Serial.print(rv,HEX);
87 Serial.print(" minLevel="); 96 Serial.print(" minLevel=");
88 Serial.print(dali.cmd(DALI_QUERY_MIN_LEVEL,sa)); 97 Serial.print(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
  98 + Serial.print(" flashing");
89 for(uint8_t i=0;i<5;i++) { 99 for(uint8_t i=0;i<5;i++) {
90 dali.set_level(254,sa); 100 dali.set_level(254,sa);
91 Serial.print("."); 101 Serial.print(".");
@@ -102,28 +112,79 @@ void scan_short_addr() { @@ -102,28 +112,79 @@ void scan_short_addr() {
102 // dali.cmd(DALI_SET_SHORT_ADDRESS, sa); 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 //might need a couple of calls to find everything... 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,9 +28,9 @@ Changelog:
28 #define DALI_OUTPUT_PIN 3 28 #define DALI_OUTPUT_PIN 3
29 #define DALI_INPUT_PIN 4 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 void setup() { 35 void setup() {
36 Serial.begin(115200); 36 Serial.begin(115200);
qqqDali.cpp
@@ -16,39 +16,25 @@ @@ -16,39 +16,25 @@
16 16
17 ---------------------------------------------------------------------------- 17 ----------------------------------------------------------------------------
18 Changelog: 18 Changelog:
  19 +2020-11-10 Split off hardware specific code into separate class
19 2020-11-08 Created & tested on ATMega328 @ 8Mhz 20 2020-11-08 Created & tested on ATMega328 @ 8Mhz
20 ###########################################################################*/ 21 ###########################################################################*/
21 #include "qqqDali.h" 22 #include "qqqDali.h"
22 -#include "arduino.h"  
23 23
24 //########################################################################### 24 //###########################################################################
25 // Helpers 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 #define DALI_TE ((1000000+(DALI_BAUD))/(2*(DALI_BAUD))) //417us 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 #define DALI_IS_TE(x) ((DALI_TE_MIN)<=(x) && (x)<=(DALI_TE_MAX)) 31 #define DALI_IS_TE(x) ((DALI_TE_MIN)<=(x) && (x)<=(DALI_TE_MAX))
35 #define DALI_IS_2TE(x) ((2*(DALI_TE_MIN))<=(x) && (x)<=(2*(DALI_TE_MAX))) 32 #define DALI_IS_2TE(x) ((2*(DALI_TE_MIN))<=(x) && (x)<=(2*(DALI_TE_MAX)))
36 33
37 //########################################################################### 34 //###########################################################################
38 // Transmitter ISR 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 void Dali::ISR_timer() { 38 void Dali::ISR_timer() {
53 if(this->bus_idle_te_cnt<0xff) this->bus_idle_te_cnt++; 39 if(this->bus_idle_te_cnt<0xff) this->bus_idle_te_cnt++;
54 40
@@ -59,26 +45,29 @@ void Dali::ISR_timer() { @@ -59,26 +45,29 @@ void Dali::ISR_timer() {
59 case TX_START: 45 case TX_START:
60 //wait for timeslot, then send start bit 46 //wait for timeslot, then send start bit
61 if(this->bus_idle_te_cnt >= 22) { 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 this->tx_state = TX_START_X; 50 this->tx_state = TX_START_X;
64 } 51 }
65 break; 52 break;
66 case TX_START_X: 53 case TX_START_X:
67 - DALI_BUS_HIGH(); 54 + this->HAL_set_bus_high();
  55 + this->tx_bus_low=0;
68 this->tx_pos=0; 56 this->tx_pos=0;
69 this->tx_state = TX_BIT; 57 this->tx_state = TX_BIT;
70 break; 58 break;
71 case TX_BIT: 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 this->tx_state = TX_BIT_X; 61 this->tx_state = TX_BIT_X;
74 break; 62 break;
75 case TX_BIT_X: 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 this->tx_pos++; 65 this->tx_pos++;
78 if(this->tx_pos < this->tx_len) {this->tx_state = TX_BIT;} else {this->tx_state = TX_STOP1;} 66 if(this->tx_pos < this->tx_len) {this->tx_state = TX_BIT;} else {this->tx_state = TX_STOP1;}
79 break; 67 break;
80 case TX_STOP1: 68 case TX_STOP1:
81 - DALI_BUS_HIGH(); 69 + this->HAL_set_bus_high();
  70 + this->tx_bus_low=0;
82 this->tx_state = TX_STOP1_X; 71 this->tx_state = TX_STOP1_X;
83 break; 72 break;
84 case TX_STOP1_X: 73 case TX_STOP1_X:
@@ -105,7 +94,7 @@ void Dali::ISR_timer() { @@ -105,7 +94,7 @@ void Dali::ISR_timer() {
105 uint8_t bitlen = (this->rx_halfbitlen+1)>>1; 94 uint8_t bitlen = (this->rx_halfbitlen+1)>>1;
106 if((bitlen & 0x7) == 0) { 95 if((bitlen & 0x7) == 0) {
107 this->rx_len = bitlen>>3; 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 }else{ 98 }else{
110 //invalid bitlen 99 //invalid bitlen
111 //TODO handle this 100 //TODO handle this
@@ -116,29 +105,11 @@ void Dali::ISR_timer() { @@ -116,29 +105,11 @@ void Dali::ISR_timer() {
116 //########################################################################### 105 //###########################################################################
117 // Receiver ISR 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 void Dali::ISR_pinchange() { 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 this->bus_idle_te_cnt=0; //reset idle counter 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 //exit if transmitting 114 //exit if transmitting
144 if(this->tx_state != TX_IDLE) { 115 if(this->tx_state != TX_IDLE) {
@@ -206,63 +177,6 @@ void Dali::push_halfbit(uint8_t bit) { @@ -206,63 +177,6 @@ void Dali::push_halfbit(uint8_t bit) {
206 //########################################################################### 177 //###########################################################################
207 // Dali Class 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 uint8_t Dali::send(uint8_t* tx_msg, uint8_t tx_len_bytes) { 180 uint8_t Dali::send(uint8_t* tx_msg, uint8_t tx_len_bytes) {
267 if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG); 181 if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG);
268 if(this->tx_state != TX_IDLE) return -(DALI_RESULT_TIMEOUT); 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,41 +187,41 @@ uint8_t Dali::send(uint8_t* tx_msg, uint8_t tx_len_bytes) {
273 return 0; 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 if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG); 191 if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG);
278 - uint32_t ts = millis(); 192 + uint32_t ts = HAL_micros();
279 //wait for idle 193 //wait for idle
280 while(this->tx_state != TX_IDLE) { 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 //start transmit 197 //start transmit
284 uint8_t rv = this->send(tx_msg,tx_len_bytes); 198 uint8_t rv = this->send(tx_msg,tx_len_bytes);
285 if(rv) return rv; 199 if(rv) return rv;
286 //wait for completion 200 //wait for completion
287 while(this->tx_state != TX_IDLE) { 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 return 0; 204 return 0;
291 } 205 }
292 206
293 //transmit 2 byte command, receive 1 byte reply 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 uint8_t tx[2]; 209 uint8_t tx[2];
296 tx[0] = cmd0; 210 tx[0] = cmd0;
297 tx[1] = cmd1; 211 tx[1] = cmd1;
298 - int16_t rv = this->sendwait(tx,2); 212 + int16_t rv = this->sendwait(tx, 2, timeout_us);
299 this->rx_halfbitlen = 0; 213 this->rx_halfbitlen = 0;
300 if(rv) return -rv;; 214 if(rv) return -rv;;
301 215
302 //wait up to 10 ms for start of reply 216 //wait up to 10 ms for start of reply
303 - uint32_t ts = millis(); 217 + uint32_t ts = HAL_micros();
304 while(this->rx_state == RX_IDLE) { 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 //wait up to 15 ms for completion of reply 221 //wait up to 15 ms for completion of reply
308 - ts = millis(); 222 + ts = HAL_micros();
309 while(this->rx_len == 0) { 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 if(this->rx_len > 1) return DALI_RESULT_INVALID_REPLY; 226 if(this->rx_len > 1) return DALI_RESULT_INVALID_REPLY;
313 return this->rx_msg[0]; 227 return this->rx_msg[0];
@@ -464,41 +378,40 @@ uint32_t Dali::find_addr() { @@ -464,41 +378,40 @@ uint32_t Dali::find_addr() {
464 //init_arg=11111111 : all without short address 378 //init_arg=11111111 : all without short address
465 //init_arg=00000000 : all 379 //init_arg=00000000 : all
466 //init_arg=0AAAAAA1 : only for this shortadr 380 //init_arg=0AAAAAA1 : only for this shortadr
  381 +//returns number of new short addresses assigned
467 uint8_t Dali::commission(uint8_t init_arg) { 382 uint8_t Dali::commission(uint8_t init_arg) {
468 uint8_t cnt = 0; 383 uint8_t cnt = 0;
469 uint8_t arr[64]; 384 uint8_t arr[64];
470 uint8_t sa; 385 uint8_t sa;
471 for(sa=0; sa<64; sa++) arr[sa]=0; 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 for(sa = 0; sa<64; sa++) { 391 for(sa = 0; sa<64; sa++) {
477 int16_t rv = this->cmd(DALI_QUERY_STATUS,sa); 392 int16_t rv = this->cmd(DALI_QUERY_STATUS,sa);
478 if(rv!=DALI_RESULT_NO_REPLY) { 393 if(rv!=DALI_RESULT_NO_REPLY) {
479 arr[sa]=1; 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 this->cmd(DALI_INITIALISE,init_arg); 404 this->cmd(DALI_INITIALISE,init_arg);
491 this->cmd(DALI_RANDOMISE,0x00); 405 this->cmd(DALI_RANDOMISE,0x00);
492 - delay(100);  
493 406
494 - while(cnt<64) { 407 + while(1) {
495 //Serial.print("addr="); 408 //Serial.print("addr=");
496 //Serial.println(this->get_random_address(0xff),HEX); 409 //Serial.println(this->get_random_address(0xff),HEX);
497 410
498 uint32_t adr = this->find_addr(); 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 //Serial.print("short adr="); 416 //Serial.print("short adr=");
504 //Serial.println(dali_query_short_address()); 417 //Serial.println(dali_query_short_address());
@@ -507,17 +420,17 @@ uint8_t Dali::commission(uint8_t init_arg) { @@ -507,17 +420,17 @@ uint8_t Dali::commission(uint8_t init_arg) {
507 for(sa=0; sa<64; sa++) { 420 for(sa=0; sa<64; sa++) {
508 if(arr[sa]==0) break; 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 arr[sa] = 1; 424 arr[sa] = 1;
512 cnt++; 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 this->program_short_address(sa); 429 this->program_short_address(sa);
517 //dali_program_short_address(0xff); 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 this->cmd(DALI_WITHDRAW,0x00); 435 this->cmd(DALI_WITHDRAW,0x00);
523 } 436 }
qqqDali.h
@@ -16,14 +16,24 @@ @@ -16,14 +16,24 @@
16 16
17 ---------------------------------------------------------------------------- 17 ----------------------------------------------------------------------------
18 Changelog: 18 Changelog:
  19 +2020-11-10 Split off hardware specific code into separate class
19 2020-11-08 Created & tested on ATMega328 @ 8Mhz 20 2020-11-08 Created & tested on ATMega328 @ 8Mhz
20 ###########################################################################*/ 21 ###########################################################################*/
21 #include <inttypes.h> 22 #include <inttypes.h>
22 23
23 -  
24 class Dali { 24 class Dali {
25 public: 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 //high level functions 38 //high level functions
29 void set_level(uint8_t level, uint8_t adr=0xFF); //set arc level 39 void set_level(uint8_t level, uint8_t adr=0xFF); //set arc level
@@ -43,24 +53,17 @@ public: @@ -43,24 +53,17 @@ public:
43 uint8_t query_short_address(); 53 uint8_t query_short_address();
44 uint32_t find_addr(); 54 uint32_t find_addr();
45 55
46 -  
47 //low level functions 56 //low level functions
48 - typedef void (*EventHandlerReceivedDataFuncPtr)(Dali *sender, uint8_t *data, uint8_t len);  
49 - EventHandlerReceivedDataFuncPtr EventHandlerReceivedData;  
50 -  
51 uint8_t send(uint8_t* tx_msg, uint8_t tx_len_bytes); 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 //low level functions 65 //low level functions
62 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}; 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 uint8_t tx_msg[3]; //message to transmit 67 uint8_t tx_msg[3]; //message to transmit
65 uint8_t tx_len; //number of bits to transmit 68 uint8_t tx_len; //number of bits to transmit
66 volatile uint8_t tx_pos; //current bit transmit position 69 volatile uint8_t tx_pos; //current bit transmit position
@@ -69,7 +72,6 @@ private: @@ -69,7 +72,6 @@ private:
69 volatile uint8_t tx_bus_low; //bus is low according to transmitter? 72 volatile uint8_t tx_bus_low; //bus is low according to transmitter?
70 73
71 enum rx_stateEnum { RX_IDLE,RX_START,RX_BIT}; 74 enum rx_stateEnum { RX_IDLE,RX_START,RX_BIT};
72 - uint8_t rx_pin; //receiver pin  
73 volatile uint8_t rx_last_bus_low; //receiver as low at last pinchange 75 volatile uint8_t rx_last_bus_low; //receiver as low at last pinchange
74 volatile uint32_t rx_last_change_ts; //timestamp last pinchange 76 volatile uint32_t rx_last_change_ts; //timestamp last pinchange
75 volatile rx_stateEnum rx_state; //current state 77 volatile rx_stateEnum rx_state; //current state
@@ -88,6 +90,10 @@ private: @@ -88,6 +90,10 @@ private:
88 }; 90 };
89 91
90 92
  93 +
  94 +
  95 +#define DALI_BAUD 1200
  96 +
91 #define DALI_RESULT_TIMEOUT -1 //Timeout waiting for DALI bus 97 #define DALI_RESULT_TIMEOUT -1 //Timeout waiting for DALI bus
92 #define DALI_RESULT_INVALID_TOO_LONG -2 //Trying to send too many bytes (max 3) 98 #define DALI_RESULT_INVALID_TOO_LONG -2 //Trying to send too many bytes (max 3)
93 #define DALI_RESULT_TX_TIMEOUT -3 //Timeout during transmission 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 +}