diff --git a/Documentation/DALI Commands.xlsx b/Documentation/DALI Commands.xlsx
new file mode 100644
index 0000000..617d160
--- /dev/null
+++ b/Documentation/DALI Commands.xlsx
diff --git a/Documentation/Renesas DALI Applicaton Note.pdf b/Documentation/Renesas DALI Applicaton Note.pdf
new file mode 100644
index 0000000..29cbaa4
--- /dev/null
+++ b/Documentation/Renesas DALI Applicaton Note.pdf
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.