Commit d12c5238758a004eb7be70800dc413291d65a75f
Committed by
GitHub
1 parent
7c023deb
.
Showing
3 changed files
with
276 additions
and
19 deletions
Examples/Commissioning/Commissioning.ino
0 → 100644
| 1 | +/*########################################################################### | |
| 2 | +DALI Interface Demo | |
| 3 | + | |
| 4 | +Commissioning demo - assign short addresses to all LED Drivers on the DALI bus | |
| 5 | + | |
| 6 | +Works with Arduino ATMEGA328 + Mikroe DALI Click | |
| 7 | + | |
| 8 | +---------------------------------------------------------------------------- | |
| 9 | +Changelog: | |
| 10 | +2020-11-08 Created & tested on ATMega328 @ 8Mhz | |
| 11 | +---------------------------------------------------------------------------- | |
| 12 | + Commisioning.ino - copyright qqqlab.com / github.com/qqqlab | |
| 13 | + | |
| 14 | + This program is free software: you can redistribute it and/or modify | |
| 15 | + it under the terms of the GNU General Public License as published by | |
| 16 | + the Free Software Foundation, either version 3 of the License, or | |
| 17 | + (at your option) any later version. | |
| 18 | + | |
| 19 | + This program is distributed in the hope that it will be useful, | |
| 20 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 21 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 22 | + GNU General Public License for more details. | |
| 23 | + | |
| 24 | + You should have received a copy of the GNU General Public License | |
| 25 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 26 | +###########################################################################*/ | |
| 27 | + | |
| 28 | +#define DALI_OUTPUT_PIN 3 | |
| 29 | +#define DALI_INPUT_PIN 4 | |
| 30 | + | |
| 31 | +#include "qqqDali.h" | |
| 32 | + | |
| 33 | +Dali dali; | |
| 34 | + | |
| 35 | +void setup() { | |
| 36 | + Serial.begin(115200); | |
| 37 | + Serial.println("DALI Commisioning Demo"); | |
| 38 | + | |
| 39 | + //start the DALI interfaces | |
| 40 | + //arguments: tx_pin, rx_pin (negative values disable transmitter / receiver) | |
| 41 | + //Note: the receiver pins should be on different PCINT groups, e.g one | |
| 42 | + //receiver on pin0-7 (PCINT2) one on pin8-13 (PCINT0) and one on pin14-19 (PCINT1) | |
| 43 | + dali.begin(DALI_OUTPUT_PIN, DALI_INPUT_PIN); | |
| 44 | + | |
| 45 | + menu(); | |
| 46 | +} | |
| 47 | + | |
| 48 | + | |
| 49 | +void loop() { | |
| 50 | + while (Serial.available() > 0) { | |
| 51 | + int incomingByte = Serial.read(); | |
| 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 | + } | |
| 58 | + } | |
| 59 | +} | |
| 60 | + | |
| 61 | +void menu() { | |
| 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("----------------------------"); | |
| 68 | +} | |
| 69 | + | |
| 70 | +void delete_short_addr() { | |
| 71 | + Serial.println("Running: Delete all short addresses"); | |
| 72 | + //remove all short addresses | |
| 73 | + dali.cmd(DALI_DATA_TRANSFER_REGISTER0,0xFF); | |
| 74 | + dali.cmd(DALI_SET_SHORT_ADDRESS, 0xFF); | |
| 75 | +} | |
| 76 | + | |
| 77 | +void scan_short_addr() { | |
| 78 | + Serial.println("Running: Scan all short addresses"); | |
| 79 | + uint8_t sa; | |
| 80 | + for(sa = 0; sa<64; sa++) { | |
| 81 | + int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa); | |
| 82 | + if(rv!=DALI_RESULT_NO_REPLY) { | |
| 83 | + Serial.print(sa); | |
| 84 | + Serial.print(" status=0x"); | |
| 85 | + Serial.print(rv,HEX); | |
| 86 | + Serial.print(" minLevel="); | |
| 87 | + Serial.print(dali.cmd(DALI_QUERY_MIN_LEVEL,sa)); | |
| 88 | + for(uint8_t i=0;i<5;i++) { | |
| 89 | + dali.set_level(254,sa); | |
| 90 | + Serial.print("."); | |
| 91 | + delay(500); | |
| 92 | + dali.set_level(0,sa); | |
| 93 | + Serial.print("."); | |
| 94 | + delay(500); | |
| 95 | + } | |
| 96 | + Serial.println(); | |
| 97 | + } | |
| 98 | +// }else{ | |
| 99 | +// //remove all short addres for this sa | |
| 100 | +// dali.cmd(DALI_DATA_TRANSFER_REGISTER0,0xFF); | |
| 101 | +// dali.cmd(DALI_SET_SHORT_ADDRESS, sa); | |
| 102 | +// } | |
| 103 | + } | |
| 104 | +} | |
| 105 | + | |
| 106 | +//might need a couple of calls to find everything... | |
| 107 | +void commission_wo_short(){ | |
| 108 | + Serial.println("Running: Commission w/o short adr"); | |
| 109 | + dali.commission(0xff); //init_arg=0b11111111 : all without short address | |
| 110 | +} | |
| 111 | + | |
| 112 | +void commission_all(){ | |
| 113 | + Serial.println("Running: Commission all"); | |
| 114 | + dali.commission(0x00); //init_arg=0b00000000 : all | |
| 115 | +} | ... | ... |
qqqDali.cpp
| ... | ... | @@ -394,4 +394,138 @@ uint8_t Dali::set_value(uint16_t setcmd, uint16_t getcmd, uint8_t v, uint8_t adr |
| 394 | 394 | return 0; |
| 395 | 395 | } |
| 396 | 396 | |
| 397 | - | |
| 397 | + | |
| 398 | +//====================================================================== | |
| 399 | +// Commissioning short addresses | |
| 400 | +//====================================================================== | |
| 401 | + | |
| 402 | +//Sets the slave Note 1 to the INITIALISE status for15 minutes. | |
| 403 | +//Commands 259 to 270 are enabled only for a slave in this | |
| 404 | +//status. | |
| 405 | + | |
| 406 | +//set search address | |
| 407 | +void Dali::set_searchaddr(uint32_t adr) { | |
| 408 | + this->cmd(DALI_SEARCHADDRH,adr>>16); | |
| 409 | + this->cmd(DALI_SEARCHADDRM,adr>>8); | |
| 410 | + this->cmd(DALI_SEARCHADDRL,adr); | |
| 411 | +} | |
| 412 | + | |
| 413 | +//set search address, but set only changed bytes | |
| 414 | +void Dali::set_searchaddr_diff(uint32_t adr_new,uint32_t adr_current) { | |
| 415 | + if( (uint8_t)(adr_new>>16) != (uint8_t)(adr_current>>16) ) this->cmd(DALI_SEARCHADDRH,adr_new>>16); | |
| 416 | + if( (uint8_t)(adr_new>>8) != (uint8_t)(adr_current>>8) ) this->cmd(DALI_SEARCHADDRM,adr_new>>8); | |
| 417 | + if( (uint8_t)(adr_new) != (uint8_t)(adr_current) ) this->cmd(DALI_SEARCHADDRL,adr_new); | |
| 418 | +} | |
| 419 | + | |
| 420 | +//Is the random address smaller or equal to the search address? | |
| 421 | +uint8_t Dali::compare() { | |
| 422 | + return (0xff == this->cmd(DALI_COMPARE,0x00)); | |
| 423 | +} | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | +//The slave shall store the received 6-bit address (AAAAAA) as a short address if it is selected. | |
| 428 | +void Dali::program_short_address(uint8_t shortadr) { | |
| 429 | + this->cmd(DALI_PROGRAM_SHORT_ADDRESS, (shortadr << 1) | 0x01); | |
| 430 | +} | |
| 431 | + | |
| 432 | +//What is the short address of the slave being selected? | |
| 433 | +uint8_t Dali::query_short_address() { | |
| 434 | + return this->cmd(DALI_QUERY_SHORT_ADDRESS, 0x00) >> 1; | |
| 435 | +} | |
| 436 | + | |
| 437 | +//find addr with binary search | |
| 438 | +uint32_t Dali::find_addr() { | |
| 439 | + uint32_t adr = 0x800000; | |
| 440 | + uint32_t addsub = 0x400000; | |
| 441 | + uint32_t adr_last = adr; | |
| 442 | + this->set_searchaddr(adr); | |
| 443 | + | |
| 444 | + while(addsub) { | |
| 445 | + this->set_searchaddr_diff(adr,adr_last); | |
| 446 | + adr_last = adr; | |
| 447 | + uint8_t cmp = this->compare(); | |
| 448 | + //Serial.print("cmp "); | |
| 449 | + //Serial.print(adr,HEX); | |
| 450 | + //Serial.print(" = "); | |
| 451 | + //Serial.println(cmp); | |
| 452 | + if(cmp) adr-=addsub; else adr+=addsub; | |
| 453 | + addsub >>= 1; | |
| 454 | + } | |
| 455 | + this->set_searchaddr_diff(adr,adr_last); | |
| 456 | + adr_last = adr; | |
| 457 | + if(!this->compare()) { | |
| 458 | + adr++; | |
| 459 | + this->set_searchaddr_diff(adr,adr_last); | |
| 460 | + } | |
| 461 | + return adr; | |
| 462 | +} | |
| 463 | + | |
| 464 | +//init_arg=11111111 : all without short address | |
| 465 | +//init_arg=00000000 : all | |
| 466 | +//init_arg=0AAAAAA1 : only for this shortadr | |
| 467 | +uint8_t Dali::commission(uint8_t init_arg) { | |
| 468 | + uint8_t cnt = 0; | |
| 469 | + uint8_t arr[64]; | |
| 470 | + uint8_t sa; | |
| 471 | + for(sa=0; sa<64; sa++) arr[sa]=0; | |
| 472 | + | |
| 473 | + //find existing short addresses | |
| 474 | +// if(init_arg==0xff) { | |
| 475 | + Serial.println("Short adr"); | |
| 476 | + for(sa = 0; sa<64; sa++) { | |
| 477 | + int16_t rv = this->cmd(DALI_QUERY_STATUS,sa); | |
| 478 | + if(rv!=DALI_RESULT_NO_REPLY) { | |
| 479 | + 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)); | |
| 486 | + } | |
| 487 | + } | |
| 488 | +// } | |
| 489 | + | |
| 490 | + this->cmd(DALI_INITIALISE,init_arg); | |
| 491 | + this->cmd(DALI_RANDOMISE,0x00); | |
| 492 | + delay(100); | |
| 493 | + | |
| 494 | + while(cnt<64) { | |
| 495 | + //Serial.print("addr="); | |
| 496 | + //Serial.println(this->get_random_address(0xff),HEX); | |
| 497 | + | |
| 498 | + uint32_t adr = this->find_addr(); | |
| 499 | + if(adr>0xffffff) break; | |
| 500 | + Serial.print("found adr="); | |
| 501 | + Serial.println(adr,HEX); | |
| 502 | + | |
| 503 | + //Serial.print("short adr="); | |
| 504 | + //Serial.println(dali_query_short_address()); | |
| 505 | + | |
| 506 | + //find available address | |
| 507 | + for(sa=0; sa<64; sa++) { | |
| 508 | + if(arr[sa]==0) break; | |
| 509 | + } | |
| 510 | + if(sa>=64) break; | |
| 511 | + arr[sa] = 1; | |
| 512 | + cnt++; | |
| 513 | + | |
| 514 | + Serial.print("program short adr="); | |
| 515 | + Serial.println(sa); | |
| 516 | + this->program_short_address(sa); | |
| 517 | + //dali_program_short_address(0xff); | |
| 518 | + | |
| 519 | + Serial.print("read short adr="); | |
| 520 | + Serial.println(this->query_short_address()); | |
| 521 | + | |
| 522 | + this->cmd(DALI_WITHDRAW,0x00); | |
| 523 | + } | |
| 524 | + | |
| 525 | + this->cmd(DALI_TERMINATE,0x00); | |
| 526 | + return cnt; | |
| 527 | +} | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | +//====================================================================== | ... | ... |
qqqDali.h
| ... | ... | @@ -23,28 +23,36 @@ Changelog: |
| 23 | 23 | |
| 24 | 24 | class Dali { |
| 25 | 25 | public: |
| 26 | - void begin(int8_t tx_pin, int8_t rx_pin); | |
| 26 | + void begin(int8_t tx_pin, int8_t rx_pin); | |
| 27 | 27 | |
| 28 | 28 | //high level functions |
| 29 | - void set_level(uint8_t level, uint8_t adr=0xFF); //set arc level | |
| 30 | - int16_t cmd(uint16_t cmd, uint8_t arg); //execute DALI command, use a DALI_xxx command define as cmd argument, returns negative DALI_RESULT_xxx or reply byte | |
| 31 | - uint8_t set_operating_mode(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 32 | - uint8_t set_max_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 33 | - uint8_t set_min_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 34 | - uint8_t set_system_failure_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 35 | - uint8_t set_power_on_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 36 | - | |
| 29 | + void set_level(uint8_t level, uint8_t adr=0xFF); //set arc level | |
| 30 | + int16_t cmd(uint16_t cmd, uint8_t arg); //execute DALI command, use a DALI_xxx command define as cmd argument, returns negative DALI_RESULT_xxx or reply byte | |
| 31 | + uint8_t set_operating_mode(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 32 | + uint8_t set_max_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 33 | + uint8_t set_min_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 34 | + uint8_t set_system_failure_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 35 | + uint8_t set_power_on_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success | |
| 37 | 36 | |
| 37 | + //commissioning | |
| 38 | + uint8_t commission(uint8_t init_arg=0xff); | |
| 39 | + void set_searchaddr(uint32_t adr); | |
| 40 | + void set_searchaddr_diff(uint32_t adr_new,uint32_t adr_current); | |
| 41 | + uint8_t compare(); | |
| 42 | + void program_short_address(uint8_t shortadr); | |
| 43 | + uint8_t query_short_address(); | |
| 44 | + uint32_t find_addr(); | |
| 45 | + | |
| 38 | 46 | |
| 39 | 47 | //low level functions |
| 40 | 48 | typedef void (*EventHandlerReceivedDataFuncPtr)(Dali *sender, uint8_t *data, uint8_t len); |
| 41 | 49 | EventHandlerReceivedDataFuncPtr EventHandlerReceivedData; |
| 42 | 50 | |
| 43 | - uint8_t send(uint8_t* tx_msg, uint8_t tx_len_bytes); | |
| 44 | - uint8_t sendwait(uint8_t* tx_msg, uint8_t tx_len_bytes, uint32_t timeout_ms=500); | |
| 45 | - int16_t tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_ms=500); | |
| 46 | - void ISR_timer(); | |
| 47 | - void ISR_pinchange(); | |
| 51 | + 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(); | |
| 48 | 56 | |
| 49 | 57 | #define DALI_HOOK_COUNT 3 |
| 50 | 58 | |
| ... | ... | @@ -52,16 +60,16 @@ public: |
| 52 | 60 | private: |
| 53 | 61 | //low level functions |
| 54 | 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}; |
| 55 | - uint8_t tx_pin; //transmitter pin | |
| 56 | - uint8_t tx_msg[3]; //message to transmit | |
| 57 | - uint8_t tx_len; //number of bits to transmit | |
| 63 | + uint8_t tx_pin; //transmitter pin | |
| 64 | + uint8_t tx_msg[3]; //message to transmit | |
| 65 | + uint8_t tx_len; //number of bits to transmit | |
| 58 | 66 | volatile uint8_t tx_pos; //current bit transmit position |
| 59 | 67 | volatile tx_stateEnum tx_state; //current state |
| 60 | 68 | volatile uint8_t tx_collision; //collistion occured |
| 61 | 69 | volatile uint8_t tx_bus_low; //bus is low according to transmitter? |
| 62 | 70 | |
| 63 | 71 | enum rx_stateEnum { RX_IDLE,RX_START,RX_BIT}; |
| 64 | - uint8_t rx_pin; //receiver pin | |
| 72 | + uint8_t rx_pin; //receiver pin | |
| 65 | 73 | volatile uint8_t rx_last_bus_low; //receiver as low at last pinchange |
| 66 | 74 | volatile uint32_t rx_last_change_ts; //timestamp last pinchange |
| 67 | 75 | volatile rx_stateEnum rx_state; //current state | ... | ... |