/*###########################################################################
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 .
###########################################################################*/
#include "qqqDALI.h"
Dali dali;
//ATMEGA328 specific
#define TX_PIN 3
#define RX_PIN 4
//is bus asserted
uint8_t bus_is_high() {
return digitalRead(RX_PIN); //slow version
//return PIND & (1 << 4); //fast version
}
//assert bus
void bus_set_low() {
digitalWrite(TX_PIN,HIGH); //opto slow version
//PORTD |= (1 << 3); //opto fast version
//digitalWrite(TX_PIN,LOW); //diy slow version
//PORTD &= ~(1 << 3); //diy fast version
}
//release bus
void bus_set_high() {
digitalWrite(TX_PIN,LOW); //opto slow version
//PORTD &= ~(1 << 3); //opto fast version
//digitalWrite(TX_PIN,HIGH); //diy slow version
//PORTD |= (1 << 3); //diy fast version
}
void bus_init() {
//setup rx pin
pinMode(4, INPUT);
//setup tx pin
pinMode(3, OUTPUT);
//setup tx timer interrupt
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = (F_CPU + 8 * DALI_BAUD / 2) / (8 * DALI_BAUD); // compare match register at baud rate * 8
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS10); // 1:1 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
}
ISR(TIMER1_COMPA_vect) {
dali.timer();
}
void setup() {
Serial.begin(115200);
Serial.println("DALI Commissioning Demo");
dali.begin(bus_is_high, bus_set_high, bus_set_low);
bus_init();
menu();
}
void loop() {
while (Serial.available() > 0) {
int incomingByte = Serial.read();
switch(incomingByte) {
case '1': menu_blink(); menu(); break;
case '2': menu_scan_short_addr(); menu(); break;
case '3': menu_commission(); menu(); break;
case '4': menu_commission_debug(); menu(); break;
case '5': menu_delete_short_addr(); menu(); break;
case '6': menu_read_memory(); menu(); break;
}
}
}
void menu() {
Serial.println("----------------------------");
Serial.println("1 Blink all lamps");
Serial.println("2 Scan short addresses");
Serial.println("3 Commission short addresses");
Serial.println("4 Commission short addresses (VERBOSE)");
Serial.println("5 Delete short addresses");
Serial.println("6 Read memory bank");
Serial.println("----------------------------");
}
void menu_blink() {
Serial.println("Running: Blinking all lamps");
for(uint8_t i=0;i<5;i++) {
dali.set_level(254);
Serial.print(".");
delay(500);
dali.set_level(0);
Serial.print(".");
delay(500);
}
Serial.println();
}
void menu_scan_short_addr() {
Serial.println("Running: Scan all short addresses");
uint8_t sa;
uint8_t cnt = 0;
for(sa = 0; sa<64; sa++) {
int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
if(rv>=0) {
cnt++;
Serial.print("short address=");
Serial.print(sa);
Serial.print(" status=0x");
Serial.print(rv,HEX);
Serial.print(" minLevel=");
Serial.print(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
Serial.print(" flashing");
for(uint8_t i=0;i<5;i++) {
dali.set_level(254,sa);
Serial.print(".");
delay(500);
dali.set_level(0,sa);
Serial.print(".");
delay(500);
}
Serial.println();
}else if (-rv != DALI_RESULT_NO_REPLY) {
Serial.print("short address=");
Serial.print(sa);
Serial.print(" ERROR=");
Serial.println(-rv);
}
}
Serial.print("DONE, found ");Serial.print(cnt);Serial.println(" short addresses");
}
//might need a couple of calls to find everything...
void menu_commission(){
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");
}
void menu_delete_short_addr() {
Serial.println("Running: Delete all short addresses");
//remove all short addresses
dali.cmd(DALI_DATA_TRANSFER_REGISTER0,0xFF);
dali.cmd(DALI_SET_SHORT_ADDRESS, 0xFF);
Serial.println("DONE delete");
}
//init_arg=11111111 : all without short address
//init_arg=00000000 : all
//init_arg=0AAAAAA1 : only for this shortadr
//returns number of new short addresses assigned
uint8_t debug_commission(uint8_t init_arg) {
uint8_t cnt = 0;
uint8_t arr[64];
uint8_t sa;
for(sa=0; sa<64; sa++) arr[sa]=0;
dali.cmd(DALI_INITIALISE,init_arg);
dali.cmd(DALI_RANDOMISE,0x00);
//need 100ms pause after RANDOMISE, scan takes care of this...
//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>=0) {
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));
}
}
// dali.set_searchaddr(0x000000);
// dali.set_searchaddr(0xFFFFFF);
//while(1) {
// dali.compare();
// delay(200);
//}
Serial.println("Find random adr");
while(1) {
uint32_t adr = dali.find_addr();
if(adr>0xffffff) break;
Serial.print("found=");
Serial.println(adr,HEX);
//find available address
for(sa=0; sa<64; sa++) {
if(arr[sa]==0) break;
}
if(sa>=64) break;
arr[sa] = 1;
cnt++;
Serial.print("program short adr=");
Serial.println(sa);
dali.program_short_address(sa);
Serial.print("read short adr=");
Serial.println(dali.query_short_address());
dali.cmd(DALI_WITHDRAW,0x00);
}
dali.cmd(DALI_TERMINATE,0x00);
return cnt;
}
void menu_read_memory() {
/*
uint8_t v = 123;
uint8_t adr = 0xff;
while(1) {
int16_t rv = dali.cmd(DALI_DATA_TRANSFER_REGISTER0, v); //store value in DTR
Serial.print("rv=");
Serial.print(rv);
int16_t dtr = dali.cmd(DALI_QUERY_CONTENT_DTR0, adr); //get DTR value
Serial.print(" dtr=");
Serial.println(dtr);
delay(13);
}
*/
Serial.println("Running: Scan all short addresses");
uint8_t sa;
uint8_t cnt = 0;
for(sa = 0; sa<64; sa++) {
int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
if(rv>=0) {
cnt++;
Serial.print("\nshort address ");
Serial.println(sa);
Serial.print("status=0x");
Serial.println(rv,HEX);
Serial.print("minLevel=");
Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
dali_read_memory_bank_verbose(0,sa);
}else if (-rv != DALI_RESULT_NO_REPLY) {
Serial.print("short address=");
Serial.print(sa);
Serial.print(" ERROR=");
Serial.println(-rv);
}
}
Serial.print("DONE, found ");Serial.print(cnt);Serial.println(" short addresses");
}
uint8_t dali_read_memory_bank_verbose(uint8_t bank, uint8_t adr) {
uint16_t rv;
if(dali.set_dtr0(0, adr)) return 1;
if(dali.set_dtr1(bank, adr)) return 2;
//uint8_t data[255];
uint16_t len = dali.cmd(DALI_READ_MEMORY_LOCATION, adr);
Serial.print("memlen=");
Serial.println(len);
for(uint8_t i=0;i=0) {
//data[i] = mem;
Serial.print(i,HEX);
Serial.print(":");
Serial.print(mem);
Serial.print(" 0x");
Serial.print(mem,HEX);
Serial.print(" ");
if(mem>=32 && mem <127) Serial.print((char)mem);
Serial.println();
}else if(mem!=-DALI_RESULT_NO_REPLY) {
Serial.print(i,HEX);
Serial.print(":err=");
Serial.println(mem);
}
}
uint16_t dtr0 = dali.cmd(DALI_QUERY_CONTENT_DTR0,adr); //get DTR value
if(dtr0 != 255) return 4;
}