From e44ea54cde229bd447cc03a99697a16bc2b32450 Mon Sep 17 00:00:00 2001 From: qqqlab <46283638+qqqlab@users.noreply.github.com> Date: Tue, 10 Nov 2020 21:09:12 +0100 Subject: [PATCH] . --- Documentation/DALI Commands.xlsx | Bin 0 -> 45316 bytes Documentation/Renesas DALI Applicaton Note.pdf | Bin 0 -> 1385478 bytes Examples/Commissioning/Commissioning.ino | 61 ++++++++++++++++++++++++++++++++++++------------------------- Examples/Monitor/Monitor.ino | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qqqDali.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------- qqqDali.h | 17 +++++++++-------- 6 files changed, 167 insertions(+), 86 deletions(-) create mode 100644 Documentation/DALI Commands.xlsx create mode 100644 Documentation/Renesas DALI Applicaton Note.pdf create mode 100644 Examples/Monitor/Monitor.ino diff --git a/Documentation/DALI Commands.xlsx b/Documentation/DALI Commands.xlsx new file mode 100644 index 0000000..617d160 Binary files /dev/null and b/Documentation/DALI Commands.xlsx differ diff --git a/Documentation/Renesas DALI Applicaton Note.pdf b/Documentation/Renesas DALI Applicaton Note.pdf new file mode 100644 index 0000000..29cbaa4 Binary files /dev/null and b/Documentation/Renesas DALI Applicaton Note.pdf differ diff --git a/Examples/Commissioning/Commissioning.ino b/Examples/Commissioning/Commissioning.ino index 07f5ee0..fe97002 100644 --- a/Examples/Commissioning/Commissioning.ino +++ b/Examples/Commissioning/Commissioning.ino @@ -50,26 +50,28 @@ void loop() { while (Serial.available() > 0) { int incomingByte = Serial.read(); switch(incomingByte) { - case '1': menu_flash(); menu(); break; + case '1': menu_blink(); menu(); break; case '2': menu_scan_short_addr(); menu(); break; case '3': menu_commission(); menu(); break; - case '4': menu_delete_short_addr(); menu(); break; + case '4': menu_commission_debug(); menu(); break; + case '5': menu_delete_short_addr(); menu(); break; } } } void menu() { Serial.println("----------------------------"); - Serial.println("1 Flash all lights"); + Serial.println("1 Blink all lamps"); Serial.println("2 Scan short addresses"); Serial.println("3 Commission short addresses"); - Serial.println("4 Delete short addresses"); + Serial.println("4 Commission short addresses (VERBOSE)"); + Serial.println("5 Delete short addresses"); Serial.println("----------------------------"); } -void menu_flash() { - Serial.println("Running: Flash all"); +void menu_blink() { + Serial.println("Running: Blinking all lamps"); for(uint8_t i=0;i<5;i++) { dali.set_level(254); Serial.print("."); @@ -117,8 +119,18 @@ void menu_scan_short_addr() { //might need a couple of calls to find everything... void menu_commission(){ - Serial.println("Running: Commission - be patient, this takes a while ...."); -// uint8_t cnt = dali.commission(0xff); //init_arg=0b11111111 : all without short address + Serial.println("Running: Commission"); + Serial.println("Might need a couple of runs to find all lamps ..."); + Serial.println("Be patient, this takes a while ..."); + uint8_t cnt = dali.commission(0xff); //init_arg=0b11111111 : all without short address + Serial.print("DONE, assigned ");Serial.print(cnt);Serial.println(" new short addresses"); +} + +//might need a couple of calls to find everything... +void menu_commission_debug(){ + Serial.println("Running: Commission (VERBOSE)"); + Serial.println("Might need a couple of runs to find all lamps ..."); + Serial.println("Be patient, this takes a while ..."); uint8_t cnt = debug_commission(0xff); //init_arg=0b11111111 : all without short address Serial.print("DONE, assigned ");Serial.print(cnt);Serial.println(" new short addresses"); } @@ -140,26 +152,25 @@ uint8_t debug_commission(uint8_t init_arg) { uint8_t arr[64]; uint8_t sa; for(sa=0; sa<64; sa++) arr[sa]=0; - - //find existing short addresses when not assigning all - if(init_arg!=0b00000000) { - Serial.println("Find existing short adr"); - for(sa = 0; sa<64; sa++) { - int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa); - if(rv!=DALI_RESULT_NO_REPLY) { - arr[sa]=1; - Serial.print("sortadr="); - Serial.print(sa); - Serial.print(" status=0x"); - Serial.print(rv,HEX); - Serial.print(" minLevel="); - Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa)); - } - } - } + dali.cmd(DALI_RESET,0x00); dali.cmd(DALI_INITIALISE,init_arg); dali.cmd(DALI_RANDOMISE,0x00); + + //find used short addresses (run always, seems to work better than without...) + Serial.println("Find existing short adr"); + for(sa = 0; sa<64; sa++) { + int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa); + if(rv!=DALI_RESULT_NO_REPLY) { + if(init_arg!=0b00000000) arr[sa]=1; //remove address from list if not in "all" mode + Serial.print("sortadr="); + Serial.print(sa); + Serial.print(" status=0x"); + Serial.print(rv,HEX); + Serial.print(" minLevel="); + Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa)); + } + } Serial.println("Find random adr"); while(1) { diff --git a/Examples/Monitor/Monitor.ino b/Examples/Monitor/Monitor.ino new file mode 100644 index 0000000..56df038 --- /dev/null +++ b/Examples/Monitor/Monitor.ino @@ -0,0 +1,77 @@ +/*########################################################################### +DALI Interface Demo + +Monitors all messages on the DALI bus + +---------------------------------------------------------------------------- +Changelog: +2020-11-10 Created & tested on ATMega328 @ 8Mhz +---------------------------------------------------------------------------- + Monitor.ino - copyright qqqlab.com / github.com/qqqlab + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +###########################################################################*/ + +#define DALI_OUTPUT_PIN 3 +#define DALI_INPUT_PIN 4 + +#include "qqqDali_ATMega328.h" + +Dali_ATMega328 dali; + +uint8_t rx_out=0; +volatile uint8_t rx_in=0; +uint8_t rx_data[256]; + +//callback to handle received data on dali2 interface - executes in interrupt context, store data in buffer and display in loop() +void dali_receiver(Dali *d, uint8_t *data, uint8_t len) { + //push data in buffer + int16_t freebuf = (int16_t)256 + rx_in - rx_out - len - 2; + if(freebuf<=1) return; //buffer full + uint8_t j = rx_in; + rx_data[j++] = len; //push length + for(uint8_t i=0;irx_state = RX_IDLE; //TODO rx error return; - } + } break; } } @@ -177,34 +177,42 @@ void Dali::push_halfbit(uint8_t bit) { //########################################################################### // Dali Class //########################################################################### + +//non blocking send - check tx_state for completion, check tx_collision for collision errors uint8_t Dali::send(uint8_t* tx_msg, uint8_t tx_len_bytes) { - if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG); + if(tx_len_bytes>3) return -(DALI_RESULT_DATA_TOO_LONG); if(this->tx_state != TX_IDLE) return -(DALI_RESULT_TIMEOUT); for(uint8_t i=0;itx_msg[i]=tx_msg[i]; this->tx_len = tx_len_bytes<<3; this->tx_collision=0; - this->tx_state = TX_START; + this->tx_state = TX_START; //start transmission return 0; } +//blocking send - wait until successful send or timeout uint8_t Dali::sendwait(uint8_t* tx_msg, uint8_t tx_len_bytes, uint32_t timeout_us) { - if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG); + if(tx_len_bytes>3) return -(DALI_RESULT_DATA_TOO_LONG); uint32_t ts = HAL_micros(); - //wait for idle - while(this->tx_state != TX_IDLE) { - if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TIMEOUT); - } - //start transmit - uint8_t rv = this->send(tx_msg,tx_len_bytes); - if(rv) return rv; - //wait for completion - while(this->tx_state != TX_IDLE) { - if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TX_TIMEOUT); + + while(1) { + //wait for idle + while(this->tx_state != TX_IDLE) { + if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TIMEOUT); + } + //start transmit + uint8_t rv = this->send(tx_msg,tx_len_bytes); + if(rv) return rv; + //wait for completion + while(this->tx_state != TX_IDLE) { + if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TX_TIMEOUT); + } + //check for collisions + if(this->tx_collision==0) return 0; } - return 0; + return -(DALI_RESULT_TIMEOUT); } -//transmit 2 byte command, receive 1 byte reply +//blocking transmit 2 byte command, receive 1 byte reply (if reply was sent) int16_t Dali::tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_us) { uint8_t tx[2]; tx[0] = cmd0; @@ -227,8 +235,6 @@ int16_t Dali::tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_us) { return this->rx_msg[0]; } - - //================================================================= // High level //================================================================= @@ -324,7 +330,7 @@ void Dali::set_searchaddr(uint32_t adr) { this->cmd(DALI_SEARCHADDRL,adr); } -//set search address, but set only changed bytes +//set search address, but set only changed bytes (takes less time) void Dali::set_searchaddr_diff(uint32_t adr_new,uint32_t adr_current) { if( (uint8_t)(adr_new>>16) != (uint8_t)(adr_current>>16) ) this->cmd(DALI_SEARCHADDRH,adr_new>>16); if( (uint8_t)(adr_new>>8) != (uint8_t)(adr_current>>8) ) this->cmd(DALI_SEARCHADDRM,adr_new>>8); @@ -336,8 +342,6 @@ uint8_t Dali::compare() { return (0xff == this->cmd(DALI_COMPARE,0x00)); } - - //The slave shall store the received 6-bit address (AAAAAA) as a short address if it is selected. void Dali::program_short_address(uint8_t shortadr) { this->cmd(DALI_PROGRAM_SHORT_ADDRESS, (shortadr << 1) | 0x01); @@ -384,57 +388,45 @@ uint8_t Dali::commission(uint8_t init_arg) { uint8_t arr[64]; uint8_t sa; for(sa=0; sa<64; sa++) arr[sa]=0; - - //find existing short addresses when not assigning all - if(init_arg!=0b00000000) { - //Serial.println("Short adr"); - for(sa = 0; sa<64; sa++) { - int16_t rv = this->cmd(DALI_QUERY_STATUS,sa); - if(rv!=DALI_RESULT_NO_REPLY) { - arr[sa]=1; - //Serial.print(sa); - //Serial.print(" status=0x"); - //Serial.print(rv,HEX); - //Serial.print(" minLevel="); - //Serial.println(this->cmd(DALI_QUERY_MIN_LEVEL,sa)); - } - } - } + //start commissioning + this->cmd(DALI_RESET,0x00); this->cmd(DALI_INITIALISE,init_arg); this->cmd(DALI_RANDOMISE,0x00); + + //find used short addresses (run always, seems to work better than without...) + for(sa = 0; sa<64; sa++) { + int16_t rv = this->cmd(DALI_QUERY_STATUS,sa); + if(rv!=DALI_RESULT_NO_REPLY) { + if(init_arg!=0b00000000) arr[sa]=1; //remove address from list if not in "all" mode + } + } + //find random addresses and assign unused short addresses while(1) { - //Serial.print("addr="); - //Serial.println(this->get_random_address(0xff),HEX); - uint32_t adr = this->find_addr(); if(adr>0xffffff) break; //no more random addresses found -> exit - //Serial.print("found adr="); - //Serial.println(adr,HEX); - //Serial.print("short adr="); - //Serial.println(dali_query_short_address()); - - //find available address + //find first unused short address for(sa=0; sa<64; sa++) { if(arr[sa]==0) break; } if(sa>=64) break; //all 64 short addresses assigned -> exit + + //mark short address as used arr[sa] = 1; cnt++; - //Serial.print("program short adr="); - //Serial.println(sa); + //assign short address this->program_short_address(sa); - //dali_program_short_address(0xff); - - //Serial.print("read short adr="); + //Serial.println(this->query_short_address()); //TODO check read adr, handle if not the same... + //remove the device from the search this->cmd(DALI_WITHDRAW,0x00); } - + + //terminate the DALI_INITIALISE command this->cmd(DALI_TERMINATE,0x00); return cnt; } diff --git a/qqqDali.h b/qqqDali.h index 3cfdc96..ee3efd6 100644 --- a/qqqDali.h +++ b/qqqDali.h @@ -60,7 +60,7 @@ public: //initialize variables Dali() : tx_state(TX_IDLE), rx_state(RX_IDLE), tx_bus_low(0), tx_len(0), EventHandlerReceivedData(0) {}; - + protected: //low level functions 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}; @@ -79,6 +79,8 @@ protected: volatile uint8_t rx_len; //number of bytes received volatile int8_t rx_halfbitlen; //number of half bits received volatile uint8_t rx_last_halfbit; //last halfbit received + + volatile uint8_t bus_idle_te_cnt; //number of Te since start of idle bus @@ -94,13 +96,12 @@ protected: #define DALI_BAUD 1200 -#define DALI_RESULT_TIMEOUT -1 //Timeout waiting for DALI bus -#define DALI_RESULT_INVALID_TOO_LONG -2 //Trying to send too many bytes (max 3) -#define DALI_RESULT_TX_TIMEOUT -3 //Timeout during transmission -#define DALI_RESULT_NO_REPLY -4 //cmd() did not receive a reply (i.e. received a 'NO' Backward Frame) -#define DALI_RESULT_INVALID_CMD -5 //The cmd argument in the call to cmd() was invalid -#define DALI_RESULT_INVALID_REPLY -6 //cmd() received an invalid reply (too long) - +#define DALI_RESULT_TIMEOUT -1 //Timeout waiting for DALI bus +#define DALI_RESULT_DATA_TOO_LONG -2 //Trying to send too many bytes (max 3) +#define DALI_RESULT_TX_TIMEOUT -3 //Timeout during transmission +#define DALI_RESULT_NO_REPLY -4 //cmd() did not receive a reply (i.e. received a 'NO' Backward Frame) +#define DALI_RESULT_INVALID_CMD -5 //The cmd argument in the call to cmd() was invalid +#define DALI_RESULT_INVALID_REPLY -6 //cmd() received an invalid reply (too long) //bit8=extended commands, bit9=repeat #define DALI_OFF 0 //0 - Turns off lighting. -- libgit2 0.21.4