Commit ae5cef79cc8d9f42bef16f29a47d59027cf7f244

Authored by qqqlab
Committed by GitHub
1 parent 81a81f13

.

examples/Commissioning/Commissioning.ino 0 → 100644
  1 +/*###########################################################################
  2 + 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 +#include "qqqDALI.h"
  18 +
  19 +Dali dali;
  20 +
  21 +//ATMEGA328 specific
  22 +#define TX_PIN 3
  23 +#define RX_PIN 4
  24 +
  25 +//is bus asserted
  26 +uint8_t bus_is_high() {
  27 + return digitalRead(RX_PIN); //slow version
  28 + //return PIND & (1 << 4); //fast version
  29 +}
  30 +
  31 +//assert bus
  32 +void bus_set_low() {
  33 + digitalWrite(TX_PIN,HIGH); //opto slow version
  34 + //PORTD |= (1 << 3); //opto fast version
  35 +
  36 + //digitalWrite(TX_PIN,LOW); //diy slow version
  37 + //PORTD &= ~(1 << 3); //diy fast version
  38 +}
  39 +
  40 +//release bus
  41 +void bus_set_high() {
  42 + digitalWrite(TX_PIN,LOW); //opto slow version
  43 + //PORTD &= ~(1 << 3); //opto fast version
  44 +
  45 + //digitalWrite(TX_PIN,HIGH); //diy slow version
  46 + //PORTD |= (1 << 3); //diy fast version
  47 +}
  48 +
  49 +void bus_init() {
  50 + //setup rx pin
  51 + pinMode(4, INPUT);
  52 +
  53 + //setup tx pin
  54 + pinMode(3, OUTPUT);
  55 +
  56 + //setup tx timer interrupt
  57 + TCCR1A = 0;
  58 + TCCR1B = 0;
  59 + TCNT1 = 0;
  60 + OCR1A = (F_CPU + 8 * DALI_BAUD / 2) / (8 * DALI_BAUD); // compare match register at baud rate * 8
  61 + TCCR1B |= (1 << WGM12); // CTC mode
  62 + TCCR1B |= (1 << CS10); // 1:1 prescaler
  63 + TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  64 +}
  65 +
  66 +ISR(TIMER1_COMPA_vect) {
  67 + dali.timer();
  68 +}
  69 +
  70 +void setup() {
  71 + Serial.begin(115200);
  72 + Serial.println("DALI Commissioning Demo");
  73 +
  74 + dali.begin(bus_is_high, bus_set_high, bus_set_low);
  75 + bus_init();
  76 +
  77 + menu();
  78 +}
  79 +
  80 +void loop() {
  81 + while (Serial.available() > 0) {
  82 + int incomingByte = Serial.read();
  83 + switch(incomingByte) {
  84 + case '1': menu_blink(); menu(); break;
  85 + case '2': menu_scan_short_addr(); menu(); break;
  86 + case '3': menu_commission(); menu(); break;
  87 + case '4': menu_commission_debug(); menu(); break;
  88 + case '5': menu_delete_short_addr(); menu(); break;
  89 + case '6': menu_read_memory(); menu(); break;
  90 + }
  91 + }
  92 +}
  93 +
  94 +void menu() {
  95 + Serial.println("----------------------------");
  96 + Serial.println("1 Blink all lamps");
  97 + Serial.println("2 Scan short addresses");
  98 + Serial.println("3 Commission short addresses");
  99 + Serial.println("4 Commission short addresses (VERBOSE)");
  100 + Serial.println("5 Delete short addresses");
  101 + Serial.println("6 Read memory bank");
  102 + Serial.println("----------------------------");
  103 +}
  104 +
  105 +void menu_blink() {
  106 + Serial.println("Running: Blinking all lamps");
  107 + for(uint8_t i=0;i<5;i++) {
  108 + dali.set_level(254);
  109 + Serial.print(".");
  110 + delay(500);
  111 + dali.set_level(0);
  112 + Serial.print(".");
  113 + delay(500);
  114 + }
  115 + Serial.println();
  116 +}
  117 +
  118 +void menu_scan_short_addr() {
  119 + Serial.println("Running: Scan all short addresses");
  120 + uint8_t sa;
  121 + uint8_t cnt = 0;
  122 + for(sa = 0; sa<64; sa++) {
  123 + int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
  124 + if(rv>=0) {
  125 + cnt++;
  126 + Serial.print("short address=");
  127 + Serial.print(sa);
  128 + Serial.print(" status=0x");
  129 + Serial.print(rv,HEX);
  130 + Serial.print(" minLevel=");
  131 + Serial.print(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
  132 + Serial.print(" flashing");
  133 + for(uint8_t i=0;i<5;i++) {
  134 + dali.set_level(254,sa);
  135 + Serial.print(".");
  136 + delay(500);
  137 + dali.set_level(0,sa);
  138 + Serial.print(".");
  139 + delay(500);
  140 + }
  141 + Serial.println();
  142 + }else if (-rv != DALI_RESULT_NO_REPLY) {
  143 + Serial.print("short address=");
  144 + Serial.print(sa);
  145 + Serial.print(" ERROR=");
  146 + Serial.println(-rv);
  147 + }
  148 + }
  149 + Serial.print("DONE, found ");Serial.print(cnt);Serial.println(" short addresses");
  150 +}
  151 +
  152 +//might need a couple of calls to find everything...
  153 +void menu_commission(){
  154 + Serial.println("Running: Commission");
  155 + Serial.println("Might need a couple of runs to find all lamps ...");
  156 + Serial.println("Be patient, this takes a while ...");
  157 + uint8_t cnt = dali.commission(0xff); //init_arg=0b11111111 : all without short address
  158 + Serial.print("DONE, assigned ");Serial.print(cnt);Serial.println(" new short addresses");
  159 +}
  160 +
  161 +//might need a couple of calls to find everything...
  162 +void menu_commission_debug(){
  163 + Serial.println("Running: Commission (VERBOSE)");
  164 + Serial.println("Might need a couple of runs to find all lamps ...");
  165 + Serial.println("Be patient, this takes a while ...");
  166 + uint8_t cnt = debug_commission(0xff); //init_arg=0b11111111 : all without short address
  167 + Serial.print("DONE, assigned ");Serial.print(cnt);Serial.println(" new short addresses");
  168 +}
  169 +
  170 +void menu_delete_short_addr() {
  171 + Serial.println("Running: Delete all short addresses");
  172 + //remove all short addresses
  173 + dali.cmd(DALI_DATA_TRANSFER_REGISTER0,0xFF);
  174 + dali.cmd(DALI_SET_SHORT_ADDRESS, 0xFF);
  175 + Serial.println("DONE delete");
  176 +}
  177 +
  178 +//init_arg=11111111 : all without short address
  179 +//init_arg=00000000 : all
  180 +//init_arg=0AAAAAA1 : only for this shortadr
  181 +//returns number of new short addresses assigned
  182 +uint8_t debug_commission(uint8_t init_arg) {
  183 + uint8_t cnt = 0;
  184 + uint8_t arr[64];
  185 + uint8_t sa;
  186 + for(sa=0; sa<64; sa++) arr[sa]=0;
  187 +
  188 + dali.cmd(DALI_INITIALISE,init_arg);
  189 + dali.cmd(DALI_RANDOMISE,0x00);
  190 + //need 100ms pause after RANDOMISE, scan takes care of this...
  191 +
  192 + //find used short addresses (run always, seems to work better than without...)
  193 + Serial.println("Find existing short adr");
  194 + for(sa = 0; sa<64; sa++) {
  195 + int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
  196 + if(rv>=0) {
  197 + if(init_arg!=0b00000000) arr[sa]=1; //remove address from list if not in "all" mode
  198 + Serial.print("sortadr=");
  199 + Serial.print(sa);
  200 + Serial.print(" status=0x");
  201 + Serial.print(rv,HEX);
  202 + Serial.print(" minLevel=");
  203 + Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
  204 + }
  205 + }
  206 +
  207 +// dali.set_searchaddr(0x000000);
  208 +// dali.set_searchaddr(0xFFFFFF);
  209 +//while(1) {
  210 +// dali.compare();
  211 +// delay(200);
  212 +//}
  213 +
  214 +
  215 +
  216 + Serial.println("Find random adr");
  217 + while(1) {
  218 + uint32_t adr = dali.find_addr();
  219 + if(adr>0xffffff) break;
  220 + Serial.print("found=");
  221 + Serial.println(adr,HEX);
  222 +
  223 + //find available address
  224 + for(sa=0; sa<64; sa++) {
  225 + if(arr[sa]==0) break;
  226 + }
  227 + if(sa>=64) break;
  228 + arr[sa] = 1;
  229 + cnt++;
  230 +
  231 + Serial.print("program short adr=");
  232 + Serial.println(sa);
  233 + dali.program_short_address(sa);
  234 + Serial.print("read short adr=");
  235 + Serial.println(dali.query_short_address());
  236 +
  237 + dali.cmd(DALI_WITHDRAW,0x00);
  238 + }
  239 +
  240 + dali.cmd(DALI_TERMINATE,0x00);
  241 + return cnt;
  242 +}
  243 +
  244 +void menu_read_memory() {
  245 +/*
  246 + uint8_t v = 123;
  247 + uint8_t adr = 0xff;
  248 +
  249 + while(1) {
  250 + int16_t rv = dali.cmd(DALI_DATA_TRANSFER_REGISTER0, v); //store value in DTR
  251 + Serial.print("rv=");
  252 + Serial.print(rv);
  253 +
  254 + int16_t dtr = dali.cmd(DALI_QUERY_CONTENT_DTR0, adr); //get DTR value
  255 + Serial.print(" dtr=");
  256 + Serial.println(dtr);
  257 + delay(13);
  258 + }
  259 +*/
  260 +
  261 + Serial.println("Running: Scan all short addresses");
  262 + uint8_t sa;
  263 + uint8_t cnt = 0;
  264 + for(sa = 0; sa<64; sa++) {
  265 + int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
  266 + if(rv>=0) {
  267 + cnt++;
  268 + Serial.print("\nshort address ");
  269 + Serial.println(sa);
  270 + Serial.print("status=0x");
  271 + Serial.println(rv,HEX);
  272 + Serial.print("minLevel=");
  273 + Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
  274 +
  275 + dali_read_memory_bank_verbose(0,sa);
  276 +
  277 + }else if (-rv != DALI_RESULT_NO_REPLY) {
  278 + Serial.print("short address=");
  279 + Serial.print(sa);
  280 + Serial.print(" ERROR=");
  281 + Serial.println(-rv);
  282 + }
  283 + }
  284 + Serial.print("DONE, found ");Serial.print(cnt);Serial.println(" short addresses");
  285 +}
  286 +
  287 +uint8_t dali_read_memory_bank_verbose(uint8_t bank, uint8_t adr) {
  288 + uint16_t rv;
  289 +
  290 + if(dali.set_dtr0(0, adr)) return 1;
  291 + if(dali.set_dtr1(bank, adr)) return 2;
  292 +
  293 + //uint8_t data[255];
  294 + uint16_t len = dali.cmd(DALI_READ_MEMORY_LOCATION, adr);
  295 + Serial.print("memlen=");
  296 + Serial.println(len);
  297 + for(uint8_t i=0;i<len;i++) {
  298 + int16_t mem = dali.cmd(DALI_READ_MEMORY_LOCATION, adr);
  299 + if(mem>=0) {
  300 + //data[i] = mem;
  301 + Serial.print(i,HEX);
  302 + Serial.print(":");
  303 + Serial.print(mem);
  304 + Serial.print(" 0x");
  305 + Serial.print(mem,HEX);
  306 + Serial.print(" ");
  307 + if(mem>=32 && mem <127) Serial.print((char)mem);
  308 + Serial.println();
  309 + }else if(mem!=-DALI_RESULT_NO_REPLY) {
  310 + Serial.print(i,HEX);
  311 + Serial.print(":err=");
  312 + Serial.println(mem);
  313 + }
  314 + }
  315 +
  316 + uint16_t dtr0 = dali.cmd(DALI_QUERY_CONTENT_DTR0,adr); //get DTR value
  317 + if(dtr0 != 255) return 4;
  318 +}
0 319 \ No newline at end of file
... ...
examples/Dimmer/Dimmer.ino 0 → 100644
  1 +/*###########################################################################
  2 + 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 +#include "qqqDALI.h"
  18 +
  19 +Dali dali;
  20 +
  21 +//ATMEGA328 specific
  22 +#define TX_PIN 3
  23 +#define RX_PIN 4
  24 +
  25 +//is bus asserted
  26 +uint8_t bus_is_high() {
  27 + return digitalRead(RX_PIN); //slow version
  28 + //return PIND & (1 << 4); //fast version
  29 +}
  30 +
  31 +//assert bus
  32 +void bus_set_low() {
  33 + digitalWrite(TX_PIN,HIGH); //opto slow version
  34 + //PORTD |= (1 << 3); //opto fast version
  35 +
  36 + //digitalWrite(TX_PIN,LOW); //diy slow version
  37 + //PORTD &= ~(1 << 3); //diy fast version
  38 +}
  39 +
  40 +//release bus
  41 +void bus_set_high() {
  42 + digitalWrite(TX_PIN,LOW); //opto slow version
  43 + //PORTD &= ~(1 << 3); //opto fast version
  44 +
  45 + //digitalWrite(TX_PIN,HIGH); //diy slow version
  46 + //PORTD |= (1 << 3); //diy fast version
  47 +}
  48 +
  49 +void bus_init() {
  50 + //setup rx pin
  51 + pinMode(4, INPUT);
  52 +
  53 + //setup tx pin
  54 + pinMode(3, OUTPUT);
  55 +
  56 + //setup tx timer interrupt
  57 + TCCR1A = 0;
  58 + TCCR1B = 0;
  59 + TCNT1 = 0;
  60 + OCR1A = (F_CPU + 8 * DALI_BAUD / 2) / (8 * DALI_BAUD); // compare match register at baud rate * 8
  61 + TCCR1B |= (1 << WGM12); // CTC mode
  62 + TCCR1B |= (1 << CS10); // 1:1 prescaler
  63 + TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  64 +}
  65 +
  66 +ISR(TIMER1_COMPA_vect) {
  67 + dali.timer();
  68 +}
  69 +
  70 +void setup() {
  71 + Serial.begin(115200);
  72 + Serial.println("DALI Dimmer Demo");
  73 +
  74 + dali.begin(bus_is_high, bus_set_high, bus_set_low);
  75 + bus_init();
  76 +}
  77 +
  78 +#define MIN_LEVEL 100 //most LED Drivers do not get much lower than this
  79 +int16_t level = 254; //254 is max level, 1 is min level (if driver supports it), 0 is off
  80 +int8_t level_step = 4;
  81 +
  82 +void loop() {
  83 + Serial.print("set level: ");
  84 + Serial.println(level);
  85 + dali.set_level(level);
  86 +
  87 + level+=level_step;
  88 + if(level>=254) {
  89 + level = 254;
  90 + level_step = -level_step;
  91 + }
  92 + if(level<MIN_LEVEL) {
  93 + level = MIN_LEVEL;
  94 + level_step = -level_step;
  95 + }
  96 +}
0 97 \ No newline at end of file
... ...
examples/Monitor/Monitor.ino 0 → 100644
  1 +/*###########################################################################
  2 + 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 +#include "qqqDALI.h"
  18 +
  19 +Dali dali;
  20 +
  21 +//ATMEGA328 specific
  22 +#define TX_PIN 3
  23 +#define RX_PIN 4
  24 +
  25 +//is bus asserted
  26 +uint8_t bus_is_high() {
  27 + return digitalRead(RX_PIN); //slow version
  28 + //return PIND & (1 << 4); //fast version
  29 +}
  30 +
  31 +//assert bus
  32 +void bus_set_low() {
  33 + digitalWrite(TX_PIN,HIGH); //opto slow version
  34 + //PORTD |= (1 << 3); //opto fast version
  35 +
  36 + //digitalWrite(TX_PIN,LOW); //diy slow version
  37 + //PORTD &= ~(1 << 3); //diy fast version
  38 +}
  39 +
  40 +//release bus
  41 +void bus_set_high() {
  42 + digitalWrite(TX_PIN,LOW); //opto slow version
  43 + //PORTD &= ~(1 << 3); //opto fast version
  44 +
  45 + //digitalWrite(TX_PIN,HIGH); //diy slow version
  46 + //PORTD |= (1 << 3); //diy fast version
  47 +}
  48 +
  49 +void bus_init() {
  50 + //setup rx pin
  51 + pinMode(4, INPUT);
  52 +
  53 + //setup tx pin
  54 + pinMode(3, OUTPUT);
  55 +
  56 + //setup tx timer interrupt
  57 + TCCR1A = 0;
  58 + TCCR1B = 0;
  59 + TCNT1 = 0;
  60 + OCR1A = (F_CPU + 8 * DALI_BAUD / 2) / (8 * DALI_BAUD); // compare match register at baud rate * 8
  61 + TCCR1B |= (1 << WGM12); // CTC mode
  62 + TCCR1B |= (1 << CS10); // 1:1 prescaler
  63 + TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  64 +}
  65 +
  66 +ISR(TIMER1_COMPA_vect) {
  67 + dali.timer();
  68 +}
  69 +
  70 +void setup() {
  71 + Serial.begin(115200);
  72 + Serial.println("DALI Monitor Demo");
  73 +
  74 + dali.begin(bus_is_high, bus_set_high, bus_set_low);
  75 + bus_init();
  76 +}
  77 +
  78 +void loop() {
  79 + uint8_t data[4];
  80 + uint8_t bitcnt = dali.rx(data);
  81 + if(bitcnt>=8) {
  82 + for(uint8_t i=0;i<=(bitcnt-1)>>3;i++) {
  83 + Serial.print(data[i],HEX);
  84 + Serial.print(' ');
  85 + }
  86 + Serial.println();
  87 + }
  88 +}
0 89 \ No newline at end of file
... ...
qqqDALI.cpp 0 → 100644
  1 +/*###########################################################################
  2 + 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-14 Rewrite with sampling instead of pinchange
  20 +2020-11-10 Split off hardware specific code into separate class
  21 +2020-11-08 Created & tested on ATMega328 @ 8Mhz
  22 +###########################################################################*/
  23 +
  24 +//#define DALI_DEBUG
  25 +
  26 +//=================================================================
  27 +// LOW LEVEL DRIVER
  28 +//=================================================================
  29 +#include "qqqDALI.h"
  30 +
  31 +#ifdef DALI_DEBUG
  32 +#include "arduino.h"
  33 +#endif
  34 +
  35 +//timing
  36 +#define BEFORE_CMD_IDLE_MS 13 //require 13ms idle time before sending a cmd()
  37 +
  38 +//busstate
  39 +#define IDLE 0
  40 +#define RX 1
  41 +#define COLLISION_RX 2
  42 +#define TX 3
  43 +#define COLLISION_TX 4
  44 +
  45 +void Dali::begin(uint8_t (*bus_is_high)(), void (*bus_set_low)(), void (*bus_set_high)())
  46 +{
  47 + this->bus_is_high = bus_is_high;
  48 + this->bus_set_low = bus_set_low;
  49 + this->bus_set_high = bus_set_high;
  50 + _init();
  51 +}
  52 +
  53 +void Dali::_set_busstate_idle() {
  54 + bus_set_high();
  55 + idlecnt = 0;
  56 + busstate = IDLE;
  57 +}
  58 +
  59 +void Dali::_init() {
  60 + _set_busstate_idle();
  61 + rxstate = EMPTY;
  62 + txcollision = 0;
  63 +}
  64 +
  65 +uint16_t Dali::milli() {
  66 + while(ticks==0xFF); //wait for _millis update to finish
  67 + return _milli;
  68 +}
  69 +
  70 +// timer interrupt service routine, called 9600 times per second
  71 +void Dali::timer() {
  72 + //get bus sample
  73 + uint8_t busishigh = (bus_is_high() ? 1 : 0); //bus_high is 1 on high (non-asserted), 0 on low (asserted)
  74 +
  75 + //millis update
  76 + ticks++;
  77 + if(ticks==10) {
  78 + ticks = 0xff; //signal _millis is updating
  79 + _milli++;
  80 + ticks = 0;
  81 + }
  82 +
  83 + switch(busstate) {
  84 + case IDLE:
  85 + if(busishigh) {
  86 + if(idlecnt != 0xff) idlecnt++;
  87 + break;
  88 + }
  89 + //set busstate = RX
  90 + rxpos = 0;
  91 + rxbitcnt = 0;
  92 + rxidle = 0;
  93 + rxstate = RECEIVING;
  94 + busstate = RX;
  95 + //fall-thru to RX
  96 + case RX:
  97 + //store sample
  98 + rxbyte = (rxbyte << 1) | busishigh;
  99 + rxbitcnt++;
  100 + if(rxbitcnt == 8) {
  101 + rxdata[rxpos] = rxbyte;
  102 + rxpos++;
  103 + if(rxpos > DALI_RX_BUF_SIZE - 1) rxpos = DALI_RX_BUF_SIZE - 1;
  104 + rxbitcnt = 0;
  105 + }
  106 + //check for reception of 2 stop bits
  107 + if(busishigh) {
  108 + rxidle++;
  109 + if(rxidle >= 16) {
  110 + rxdata[rxpos] = 0xFF;
  111 + rxpos++;
  112 + rxstate = COMPLETED;
  113 + _set_busstate_idle();
  114 + break;
  115 + }
  116 + }else{
  117 + rxidle = 0;
  118 + }
  119 + break;
  120 + case TX:
  121 + if(txhbcnt >= txhblen) {
  122 + //all bits transmitted, go back to IDLE
  123 + _set_busstate_idle();
  124 + }else{
  125 + //check for collisions (transmitting high but bus is low)
  126 + if( (
  127 + txcollisionhandling == DALI_TX_COLLISSION_ON //handle all
  128 + || (txcollisionhandling == DALI_TX_COLLISSION_AUTO && txhblen != 2+8+4) //handle only if not transmitting 8 bits (2+8+4 half bits)
  129 + ) && (txhigh && !busishigh) //transmitting high, but bus is low
  130 + && (txspcnt==1 || txspcnt==2) ) // in middle of transmitting low period
  131 + {
  132 + if(txcollision != 0xFF) txcollision++;
  133 + txspcnt = 0;
  134 + busstate = COLLISION_TX;
  135 + return;
  136 + }
  137 +
  138 + //send data bits (MSB first) to bus every 4th sample time
  139 + if(txspcnt == 0) {
  140 + //send bit
  141 + uint8_t pos = txhbcnt >> 3;
  142 + uint8_t bitmask = 1 << (7 - (txhbcnt & 0x7));
  143 + if( txhbdata[pos] & bitmask ) {
  144 + bus_set_low();
  145 + txhigh = 0;
  146 + }else{
  147 + bus_set_high();
  148 + txhigh = 1;
  149 + }
  150 + //update half bit counter
  151 + txhbcnt++;
  152 + //next transmit in 4 sample times
  153 + txspcnt = 4;
  154 + }
  155 + txspcnt--;
  156 + }
  157 + break;
  158 + case COLLISION_TX:
  159 + //keep bus low for 16 samples = 4 TE
  160 + bus_set_low();
  161 + txspcnt++;
  162 + if(txspcnt >= 16) _set_busstate_idle();
  163 + break;
  164 + }
  165 +}
  166 +
  167 +//push 2 half bits into the half bit transmit buffer, MSB first, 0x0=stop, 0x1= bit value 0, 0x2= bit value 1/start
  168 +void Dali::_tx_push_2hb(uint8_t hb) {
  169 + uint8_t pos = txhblen>>3;
  170 + uint8_t shift = 6 - (txhblen & 0x7);
  171 + txhbdata[pos] |= hb << shift;
  172 + txhblen += 2;
  173 +}
  174 +
  175 +//non-blocking transmit
  176 +//transmit if bus is IDLE, without checking hold off times, sends start+stop bits
  177 +uint8_t Dali::tx(uint8_t *data, uint8_t bitlen) {
  178 + if(bitlen > 32) return DALI_RESULT_FRAME_TOO_LONG;
  179 + if(busstate != IDLE) return DALI_RESULT_BUS_NOT_IDLE;
  180 +
  181 + //clear data
  182 + for(uint8_t i=0; i<9; i++) txhbdata[i]=0;
  183 +
  184 + //push data in transmit buffer
  185 + txhblen = 0;
  186 + _tx_push_2hb(0x2); //start bit
  187 + //data bits MSB first
  188 + for(uint8_t i=0; i<bitlen; i++) {
  189 + uint8_t pos = i>>3;
  190 + uint8_t mask = 1 << (7 - (i & 0x7));
  191 + _tx_push_2hb( data[pos] & mask ? 0x2 : 0x1 );
  192 + }
  193 + _tx_push_2hb(0x0); //stop bit
  194 + _tx_push_2hb(0x0); //stop bit
  195 +
  196 + //setup tx vars
  197 + txhbcnt = 0;
  198 + txspcnt = 0;
  199 + txcollision = 0;
  200 + rxstate = EMPTY;
  201 + busstate = TX;
  202 + return DALI_OK;
  203 +}
  204 +
  205 +uint8_t Dali::tx_state() {
  206 + if(txcollision) {
  207 + txcollision = 0;
  208 + return DALI_RESULT_COLLISION;
  209 + }
  210 + if(busstate == TX) return DALI_RESULT_TRANSMITTING;
  211 + return DALI_OK;
  212 +}
  213 +
  214 +
  215 +
  216 +
  217 +//-------------------------------------------------------------------
  218 +//manchester decode
  219 +/*
  220 +
  221 +Prefectly matched transmitter and sampling: 8 samples per bit
  222 +---------+ +---+ +-------+ +-------+ +------------------------
  223 + | | | | | | | |
  224 + +---+ +---+ +-------+ +---+
  225 +sample-> 012345670123456701234567012345670123456701234567012345670
  226 +sync-> ^ ^ ^ ^ ^ ^ ^ ^
  227 +decode-> start 1 1 0 1 0 stop stop
  228 +
  229 +
  230 +slow transmitter: 9 samples per bit
  231 +---------+ +----+ +--------+ +--------+ +------------------------
  232 + | | | | | | | |
  233 + +---+ +----+ +--------+ +---+
  234 +sample-> 0123456780123456780123456780123456780123456780123456780123456780
  235 +sync-> ^ ^ ^ ^ ^ ^ ^ ^
  236 +decode-> start 1 1 0 1 0 stop stop
  237 +
  238 +*/
  239 +
  240 +//compute weight for a 8 bit sample i
  241 +uint8_t Dali::_man_weight(uint8_t i) {
  242 + int8_t w = 0;
  243 + w += ((i>>7) & 1) ? 1 : -1;
  244 + w += ((i>>6) & 1) ? 2 : -2; //put more weight in middle
  245 + w += ((i>>5) & 1) ? 2 : -2; //put more weight in middle
  246 + w += ((i>>4) & 1) ? 1 : -1;
  247 + w -= ((i>>3) & 1) ? 1 : -1;
  248 + w -= ((i>>2) & 1) ? 2 : -2; //put more weight in middle
  249 + w -= ((i>>1) & 1) ? 2 : -2; //put more weight in middle
  250 + w -= ((i>>0) & 1) ? 1 : -1;
  251 + //w at this point:
  252 + //w = -12 perfect manchester encoded value 1
  253 + //...
  254 + //w = -2 very weak value 1
  255 + //w = 0 unknown (all samples high or low)
  256 + //...
  257 + //w = 12 perfect manchester encoded value 0
  258 +
  259 + w *= 2;
  260 + if(w<0) w = -w + 1;
  261 + return w;
  262 +}
  263 +
  264 +//call with bitpos <= DALI_RX_BUF_SIZE*8-8;
  265 +uint8_t Dali::_man_sample(uint8_t *edata, uint16_t bitpos, uint8_t *stop_coll) {
  266 + uint8_t pos = bitpos>>3;
  267 + uint8_t shift = bitpos & 0x7;
  268 + uint8_t sample = (edata[pos] << shift) | (edata[pos+1] >> (8-shift));
  269 +
  270 + //stop bit: received high (non-asserted) bus for last 8 samples
  271 + if(sample == 0xFF) *stop_coll = 1;
  272 +
  273 + //collision: received low (asserted) bus for last 8 samples
  274 + if(sample == 0x00) *stop_coll = 2;
  275 +
  276 + return sample;
  277 +}
  278 +
  279 +
  280 +//decode 8 times oversampled encoded data
  281 +//returns bitlen of decoded data, or 0 on collision
  282 +uint8_t Dali::_man_decode(uint8_t *edata, uint8_t ebitlen, uint8_t *ddata) {
  283 + uint8_t dbitlen = 0;
  284 + uint16_t ebitpos = 1;
  285 + while(ebitpos+1<ebitlen) {
  286 + uint8_t stop_coll = 0;
  287 + //weight at nominal oversample rate
  288 + uint8_t sample = _man_sample(edata, ebitpos, &stop_coll);
  289 + uint8_t weightmax = _man_weight(sample); //weight of maximum
  290 + uint8_t pmax = 8; //position of maximum
  291 +
  292 + //weight at nominal oversample rate - 1
  293 + sample = _man_sample(edata, ebitpos - 1, &stop_coll);
  294 + uint8_t w = _man_weight(sample);
  295 + if( weightmax < w) { //when equal keep pmax=8, the nominal oversample baud rate
  296 + weightmax = w;
  297 + pmax = 7;
  298 + }
  299 +
  300 + //weight at nominal oversample rate + 1
  301 + sample = _man_sample(edata, ebitpos + 1, &stop_coll);
  302 + w = _man_weight(sample);
  303 + if( weightmax < w ) { //when equal keep previous value
  304 + weightmax = w;
  305 + pmax = 9;
  306 + }
  307 +
  308 + //handle stop/collision
  309 + if(stop_coll==1) break; //stop
  310 + if(stop_coll==2) return 0; //collison
  311 +
  312 + //store mancheter bit
  313 + if(dbitlen > 0) { //ignore start bit
  314 + uint8_t bytepos = (dbitlen - 1) >> 3;
  315 + uint8_t bitpos = (dbitlen - 1) & 0x7;
  316 + if(bitpos == 0) ddata[bytepos] = 0; //empty data before storing first bit
  317 + ddata[bytepos] = (ddata[bytepos] << 1) | (weightmax & 1); //get databit from bit0 of weight
  318 + }
  319 + dbitlen++;
  320 + ebitpos += pmax; //jump to next mancheter bit, skipping over number of samples with max weight
  321 + }
  322 + if(dbitlen>1) dbitlen--;
  323 + return dbitlen;
  324 +}
  325 +
  326 +//non-blocking receive,
  327 +//returns 0 empty, 1 if busy receiving, 2 decode error, >2 number of bits received
  328 +uint8_t Dali::rx(uint8_t *ddata) {
  329 + switch(rxstate) {
  330 + case EMPTY: return 0;
  331 + case RECEIVING: return 1;
  332 + case COMPLETED:
  333 + rxstate = EMPTY;
  334 + uint8_t dlen = _man_decode(rxdata,rxpos*8,ddata);
  335 +
  336 +
  337 +#ifdef DALI_DEBUG
  338 + if(dlen!=8){
  339 + //print received samples
  340 + Serial.print("RX: len=");
  341 + Serial.print(rxpos*8);
  342 + Serial.print(" ");
  343 + for(uint8_t i=0;i<rxpos;i++) {
  344 + for(uint8_t m=0x80;m!=0x00;m>>=1) {
  345 + if(rxdata[i]&m) Serial.print("1"); else Serial.print("0");
  346 + }
  347 + Serial.print(" ");
  348 + }
  349 +
  350 + //print decoded data
  351 + Serial.print("decoded: len=");
  352 + Serial.print(dlen);
  353 + Serial.print(" ");
  354 + for(uint8_t i=0;i<dlen;i++) {
  355 + if( ddata[i>>3] & (1 << (7 - (i & 0x7))) ) Serial.print("1"); else Serial.print("0");
  356 + }
  357 + Serial.println();
  358 + }
  359 +#endif
  360 +
  361 + if(dlen<3) return 2;
  362 + return dlen;
  363 + }
  364 + return 0; //should not get here
  365 +}
  366 +
  367 +
  368 +//=================================================================
  369 +// HIGH LEVEL FUNCTIONS
  370 +//=================================================================
  371 +
  372 +//blocking send - wait until successful send or timeout
  373 +uint8_t Dali::tx_wait(uint8_t* data, uint8_t bitlen, uint16_t timeout_ms) {
  374 + if(bitlen>32) return DALI_RESULT_DATA_TOO_LONG;
  375 + uint16_t start_ms = milli();
  376 + while(1) {
  377 + //wait for 10ms idle
  378 + while(idlecnt < BEFORE_CMD_IDLE_MS){
  379 + //Serial.print('w');
  380 + if(milli() - start_ms > timeout_ms) return DALI_RESULT_TIMEOUT;
  381 + }
  382 + //try transmit
  383 + while(tx(data,bitlen) != DALI_OK){
  384 + //Serial.print('w');
  385 + if(milli() - start_ms > timeout_ms) return DALI_RESULT_TIMEOUT;
  386 + }
  387 + //wait for completion
  388 + uint8_t rv;
  389 + while(1) {
  390 + rv = tx_state();
  391 + if(rv != DALI_RESULT_TRANSMITTING) break;
  392 + if(milli() - start_ms > timeout_ms) return DALI_RESULT_TIMEOUT;
  393 + }
  394 + //exit if transmit was ok
  395 + if(rv == DALI_OK) return DALI_OK;
  396 + //not ok (for example collision) - retry until timeout
  397 + }
  398 + return DALI_RESULT_TIMEOUT;
  399 +}
  400 +
  401 +//blocking transmit 2 byte command, receive 1 byte reply (if a reply was sent)
  402 +//returns >=0 with reply byte
  403 +//returns <0 with negative result code
  404 +int16_t Dali::tx_wait_rx(uint8_t cmd0, uint8_t cmd1, uint16_t timeout_ms) {
  405 +#ifdef DALI_DEBUG
  406 + Serial.print("TX");
  407 + Serial.print(cmd0>>4,HEX);
  408 + Serial.print(cmd0&0xF,HEX);
  409 + Serial.print(cmd1>>4,HEX);
  410 + Serial.print(cmd1&0xF,HEX);
  411 + Serial.print(" ");
  412 +#endif
  413 + uint8_t data[4];
  414 + data[0] = cmd0;
  415 + data[1] = cmd1;
  416 + int16_t rv = tx_wait(data, 16, timeout_ms);
  417 + if(rv) return -rv;;
  418 +
  419 + //wait up to 10 ms for start of reply, additional 15ms for receive to complete
  420 + uint16_t rx_start_ms = milli();
  421 + uint16_t rx_timeout_ms = 10;
  422 + while(1) {
  423 + rv = rx(data);
  424 + switch( rv ) {
  425 + case 0: break; //nothing received yet, wait
  426 + case 1: rx_timeout_ms = 25; break; //extend timeout, wait for RX completion
  427 + case 2: return -DALI_RESULT_COLLISION; //report collision
  428 + default:
  429 + if(rv==8)
  430 + return data[0];
  431 + else
  432 + return -DALI_RESULT_INVALID_REPLY;
  433 + }
  434 + if(milli() - rx_start_ms > rx_timeout_ms) return -DALI_RESULT_NO_REPLY;
  435 + }
  436 + return -DALI_RESULT_NO_REPLY; //should not get here
  437 +}
  438 +
  439 +
  440 +//check YAAAAAA: 0000 0000 to 0011 1111 adr, 0100 0000 to 0100 1111 group, x111 1111 broadcast
  441 +uint8_t Dali::_check_yaaaaaa(uint8_t yaaaaaa) {
  442 + return (yaaaaaa<=0b01001111 || yaaaaaa==0b01111111 || yaaaaaa==0b11111111);
  443 +}
  444 +
  445 +void Dali::set_level(uint8_t level, uint8_t adr) {
  446 + if(_check_yaaaaaa(adr)) tx_wait_rx(adr<<1,level);
  447 +}
  448 +
  449 +int16_t Dali::cmd(uint16_t cmd, uint8_t arg) {
  450 + //Serial.print("dali_cmd[");Serial.print(cmd,HEX);Serial.print(",");Serial.print(arg,HEX);Serial.print(")");
  451 + uint8_t cmd0,cmd1;
  452 + if(cmd & 0x0100) {
  453 + //special commands: MUST NOT have YAAAAAAX pattern for cmd
  454 + //Serial.print(" SPC");
  455 + if(!_check_yaaaaaa(cmd>>1)) {
  456 + cmd0 = cmd;
  457 + cmd1 = arg;
  458 + }else{
  459 + return DALI_RESULT_INVALID_CMD;
  460 + }
  461 + }else{
  462 + //regular commands: MUST have YAAAAAA pattern for arg
  463 +
  464 + //Serial.print(" REG");
  465 + if(_check_yaaaaaa(arg)) {
  466 + cmd0 = arg<<1|1;
  467 + cmd1 = cmd;
  468 + }else{
  469 + return DALI_RESULT_INVALID_CMD;
  470 + }
  471 + }
  472 + if(cmd & 0x0200) {
  473 + //Serial.print(" REPEAT");
  474 + tx_wait_rx(cmd0, cmd1);
  475 + }
  476 + int16_t rv = tx_wait_rx(cmd0, cmd1);
  477 + //Serial.print(" rv=");Serial.println(rv);
  478 + return rv;
  479 +}
  480 +
  481 +
  482 +uint8_t Dali::set_operating_mode(uint8_t v, uint8_t adr) {
  483 + return _set_value(DALI_SET_OPERATING_MODE, DALI_QUERY_OPERATING_MODE, v, adr);
  484 +}
  485 +
  486 +uint8_t Dali::set_max_level(uint8_t v, uint8_t adr) {
  487 + return _set_value(DALI_SET_MAX_LEVEL, DALI_QUERY_MAX_LEVEL, v, adr);
  488 +}
  489 +
  490 +uint8_t Dali::set_min_level(uint8_t v, uint8_t adr) {
  491 + return _set_value(DALI_SET_MIN_LEVEL, DALI_QUERY_MIN_LEVEL, v, adr);
  492 +}
  493 +
  494 +
  495 +uint8_t Dali::set_system_failure_level(uint8_t v, uint8_t adr) {
  496 + return _set_value(DALI_SET_SYSTEM_FAILURE_LEVEL, DALI_QUERY_SYSTEM_FAILURE_LEVEL, v, adr);
  497 +}
  498 +
  499 +uint8_t Dali::set_power_on_level(uint8_t v, uint8_t adr) {
  500 + return _set_value(DALI_SET_POWER_ON_LEVEL, DALI_QUERY_POWER_ON_LEVEL, v, adr);
  501 +}
  502 +
  503 +//set a parameter value, returns 0 on success
  504 +uint8_t Dali::_set_value(uint16_t setcmd, uint16_t getcmd, uint8_t v, uint8_t adr) {
  505 + int16_t current_v = cmd(getcmd,adr); //get current parameter value
  506 + if(current_v == v) return 0;
  507 + cmd(DALI_DATA_TRANSFER_REGISTER0,v); //store value in DTR
  508 + int16_t dtr = cmd(DALI_QUERY_CONTENT_DTR0,adr); //get DTR value
  509 + if(dtr != v) return 1;
  510 + cmd(setcmd,adr); //set parameter value = DTR
  511 + current_v = cmd(getcmd,adr); //get current parameter value
  512 + if(current_v != v) return 2;
  513 + return 0;
  514 +}
  515 +
  516 +
  517 +
  518 +
  519 +//======================================================================
  520 +// Commissioning short addresses
  521 +//======================================================================
  522 +
  523 +//Sets the slave Note 1 to the INITIALISE status for15 minutes.
  524 +//Commands 259 to 270 are enabled only for a slave in this
  525 +//status.
  526 +
  527 +//set search address
  528 +void Dali::set_searchaddr(uint32_t adr) {
  529 + cmd(DALI_SEARCHADDRH,adr>>16);
  530 + cmd(DALI_SEARCHADDRM,adr>>8);
  531 + cmd(DALI_SEARCHADDRL,adr);
  532 +}
  533 +
  534 +//set search address, but set only changed bytes (takes less time)
  535 +void Dali::set_searchaddr_diff(uint32_t adr_new,uint32_t adr_current) {
  536 + if( (uint8_t)(adr_new>>16) != (uint8_t)(adr_current>>16) ) cmd(DALI_SEARCHADDRH,adr_new>>16);
  537 + if( (uint8_t)(adr_new>>8) != (uint8_t)(adr_current>>8) ) cmd(DALI_SEARCHADDRM,adr_new>>8);
  538 + if( (uint8_t)(adr_new) != (uint8_t)(adr_current) ) cmd(DALI_SEARCHADDRL,adr_new);
  539 +}
  540 +
  541 +//Is the random address smaller or equal to the search address?
  542 +//as more than one device can reply, the reply gets garbled
  543 +uint8_t Dali::compare() {
  544 + uint8_t retry = 2;
  545 + while(retry>0) {
  546 + //compare is true if we received any activity on the bus as reply.
  547 + //sometimes the reply is not registered... so only accept retry times 'no reply' as a real false compare
  548 + int16_t rv = cmd(DALI_COMPARE,0x00);
  549 + if(rv == -DALI_RESULT_COLLISION) return 1;
  550 + if(rv == -DALI_RESULT_INVALID_REPLY) return 1;
  551 + if(rv == 0xFF) return 1;
  552 +
  553 + retry--;
  554 + }
  555 + return 0;
  556 +}
  557 +
  558 +//The slave shall store the received 6-bit address (AAAAAA) as a short address if it is selected.
  559 +void Dali::program_short_address(uint8_t shortadr) {
  560 + cmd(DALI_PROGRAM_SHORT_ADDRESS, (shortadr << 1) | 0x01);
  561 +}
  562 +
  563 +//What is the short address of the slave being selected?
  564 +uint8_t Dali::query_short_address() {
  565 + return cmd(DALI_QUERY_SHORT_ADDRESS, 0x00) >> 1;
  566 +}
  567 +
  568 +//find addr with binary search
  569 +uint32_t Dali::find_addr() {
  570 + uint32_t adr = 0x800000;
  571 + uint32_t addsub = 0x400000;
  572 + uint32_t adr_last = adr;
  573 + set_searchaddr(adr);
  574 +
  575 + while(addsub) {
  576 + set_searchaddr_diff(adr,adr_last);
  577 + adr_last = adr;
  578 + //Serial.print("cmpadr=");
  579 + //Serial.print(adr,HEX);
  580 + uint8_t cmp = compare(); //returns 1 if searchadr > adr
  581 + //Serial.print("cmp ");
  582 + //Serial.print(adr,HEX);
  583 + //Serial.print(" = ");
  584 + //Serial.println(cmp);
  585 + if(cmp) adr-=addsub; else adr+=addsub;
  586 + addsub >>= 1;
  587 + }
  588 + set_searchaddr_diff(adr,adr_last);
  589 + adr_last = adr;
  590 + if(!compare()) {
  591 + adr++;
  592 + set_searchaddr_diff(adr,adr_last);
  593 + }
  594 + return adr;
  595 +}
  596 +
  597 +//init_arg=11111111 : all without short address
  598 +//init_arg=00000000 : all
  599 +//init_arg=0AAAAAA1 : only for this shortadr
  600 +//returns number of new short addresses assigned
  601 +uint8_t Dali::commission(uint8_t init_arg) {
  602 + uint8_t cnt = 0;
  603 + uint8_t arr[64];
  604 + uint8_t sa;
  605 + for(sa=0; sa<64; sa++) arr[sa]=0;
  606 +
  607 + //start commissioning
  608 + cmd(DALI_INITIALISE,init_arg);
  609 + cmd(DALI_RANDOMISE,0x00);
  610 + //need 100ms pause after RANDOMISE, scan takes care of this...
  611 +
  612 + //find used short addresses (run always, seems to work better than without...)
  613 + for(sa = 0; sa<64; sa++) {
  614 + int16_t rv = cmd(DALI_QUERY_STATUS,sa);
  615 + if(rv>=0) {
  616 + if(init_arg!=0b00000000) arr[sa]=1; //remove address from list if not in "all" mode
  617 + }
  618 + }
  619 +
  620 + //find random addresses and assign unused short addresses
  621 + while(1) {
  622 + uint32_t adr = find_addr();
  623 + if(adr>0xffffff) break; //no more random addresses found -> exit
  624 +
  625 + //find first unused short address
  626 + for(sa=0; sa<64; sa++) {
  627 + if(arr[sa]==0) break;
  628 + }
  629 + if(sa>=64) break; //all 64 short addresses assigned -> exit
  630 +
  631 + //mark short address as used
  632 + arr[sa] = 1;
  633 + cnt++;
  634 +
  635 + //assign short address
  636 + program_short_address(sa);
  637 +
  638 + //Serial.println(query_short_address()); //TODO check read adr, handle if not the same...
  639 +
  640 + //remove the device from the search
  641 + cmd(DALI_WITHDRAW,0x00);
  642 + }
  643 +
  644 + //terminate the DALI_INITIALISE command
  645 + cmd(DALI_TERMINATE,0x00);
  646 + return cnt;
  647 +}
  648 +
  649 +//======================================================================
  650 +// Memory
  651 +//======================================================================
  652 +uint8_t Dali::set_dtr0(uint8_t value, uint8_t adr) {
  653 + uint8_t retry=3;
  654 + while(retry) {
  655 + cmd(DALI_DATA_TRANSFER_REGISTER0,value); //store value in DTR
  656 + int16_t dtr = cmd(DALI_QUERY_CONTENT_DTR0,adr); //get DTR value
  657 + if(dtr == value) return 0;
  658 + retry--;
  659 + }
  660 + return 1;
  661 +}
  662 +
  663 +uint8_t Dali::set_dtr1(uint8_t value, uint8_t adr) {
  664 + uint8_t retry=3;
  665 + while(retry) {
  666 + cmd(DALI_DATA_TRANSFER_REGISTER1,value); //store value in DTR
  667 + int16_t dtr = cmd(DALI_QUERY_CONTENT_DTR1,adr); //get DTR value
  668 + if(dtr == value) return 0;
  669 + retry--;
  670 + }
  671 + return 1;
  672 +}
  673 +
  674 +uint8_t Dali::set_dtr2(uint8_t value, uint8_t adr) {
  675 + uint8_t retry=3;
  676 + while(retry) {
  677 + cmd(DALI_DATA_TRANSFER_REGISTER2,value); //store value in DTR
  678 + int16_t dtr = cmd(DALI_QUERY_CONTENT_DTR2,adr); //get DTR value
  679 + if(dtr == value) return 0;
  680 + retry--;
  681 + }
  682 + return 1;
  683 +}
  684 +
  685 +uint8_t Dali::read_memory_bank(uint8_t bank, uint8_t adr) {
  686 + uint16_t rv;
  687 +
  688 + if(set_dtr0(0, adr)) return 1;
  689 + if(set_dtr1(bank, adr)) return 2;
  690 +
  691 + //uint8_t data[255];
  692 + uint16_t len = cmd(DALI_READ_MEMORY_LOCATION, adr);
  693 +#ifdef DALI_DEBUG
  694 + Serial.print("memlen=");
  695 + Serial.println(len);
  696 + for(uint8_t i=0;i<len;i++) {
  697 + int16_t mem = cmd(DALI_READ_MEMORY_LOCATION, adr);
  698 + if(mem>=0) {
  699 + //data[i] = mem;
  700 + Serial.print(i,HEX);
  701 + Serial.print(":");
  702 + Serial.print(mem);
  703 + Serial.print(" 0x");
  704 + Serial.print(mem,HEX);
  705 + Serial.print(" ");
  706 + if(mem>=32 && mem <127) Serial.print((char)mem);
  707 + Serial.println();
  708 + }else if(mem!=-DALI_RESULT_NO_REPLY) {
  709 + Serial.print(i,HEX);
  710 + Serial.print(":err=");
  711 + Serial.println(mem);
  712 + }
  713 + //delay(10);
  714 + }
  715 +#endif
  716 +
  717 + uint16_t dtr0 = cmd(DALI_QUERY_CONTENT_DTR0,adr); //get DTR value
  718 + if(dtr0 != 255) return 4;
  719 +}
  720 +
  721 +
  722 +//======================================================================
... ...
qqqDALI.h 0 → 100644
  1 +/*###########################################################################
  2 + 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-14 Rewrite with sampling instead of pinchange
  20 +2020-11-10 Split off hardware specific code into separate class
  21 +2020-11-08 Created & tested on ATMega328 @ 8Mhz
  22 +###########################################################################*/
  23 +#include <inttypes.h>
  24 +
  25 +//-------------------------------------------------
  26 +//LOW LEVEL DRIVER DEFINES
  27 +#define DALI_BAUD 1200
  28 +
  29 +//low level
  30 +#define DALI_OK 0
  31 +#define DALI_RESULT_BUS_NOT_IDLE 1 //can't transmit, bus is not idle
  32 +#define DALI_RESULT_FRAME_TOO_LONG 2 //can't transmit, attempting to send more than 32 bits
  33 +#define DALI_RESULT_COLLISION 3 //bus collision occured
  34 +#define DALI_RESULT_TRANSMITTING 4 //currently transmitting
  35 +#define DALI_RESULT_RECEIVING 5 //currently receiving
  36 +
  37 +//high level
  38 +#define DALI_RESULT_NO_REPLY 101 //cmd() did not receive a reply (i.e. received a 'NO' Backward Frame)
  39 +#define DALI_RESULT_TIMEOUT 102 //Timeout waiting for DALI bus
  40 +#define DALI_RESULT_DATA_TOO_LONG 103 //Trying to send too many bytes (max 3)
  41 +#define DALI_RESULT_INVALID_CMD 104 //The cmd argument in the call to cmd() was invalid
  42 +#define DALI_RESULT_INVALID_REPLY 105 //cmd() received an invalid reply (not 8 bits)
  43 +
  44 +
  45 +//tx collision handling
  46 +#define DALI_TX_COLLISSION_AUTO 0 //handle tx collisions for non 8 bit frames
  47 +#define DALI_TX_COLLISSION_OFF 1 //don't handle tx collisions
  48 +#define DALI_TX_COLLISSION_ON 2 //handle all tx collisions
  49 +
  50 +#define DALI_RX_BUF_SIZE 40
  51 +
  52 +class Dali {
  53 +public:
  54 + //-------------------------------------------------
  55 + //LOW LEVEL DRIVER PUBLIC
  56 + void begin(uint8_t (*bus_is_high)(), void (*bus_set_low)(), void (*bus_set_high)());
  57 + void timer(); //call this function every 104.167 us (1200 baud 8x oversampled)
  58 + uint8_t tx(uint8_t *data, uint8_t bitlen); //low level non-blocking transmit
  59 + uint8_t rx(uint8_t *data); //low level non-blocking receive
  60 + uint8_t tx_state(); //low level tx state, returns DALI_RESULT_COLLISION, DALI_RESULT_TRANSMITTING or DALI_OK
  61 + uint8_t txcollisionhandling; //collision handling DALI_TX_COLLISSION_AUTO,DALI_TX_COLLISSION_OFF,DALI_TX_COLLISSION_ON
  62 + uint16_t milli(); //millis() implementation, 1 milli is 1.04167 ms (10 timer ticks), rollover 65 seconds
  63 + Dali() : busstate(0), ticks(0), _milli(0), idlecnt(0), txcollisionhandling(DALI_TX_COLLISSION_AUTO) {}; //initialize variables
  64 +
  65 + //-------------------------------------------------
  66 + //HIGH LEVEL PUBLIC
  67 + void set_level(uint8_t level, uint8_t adr=0xFF); //set arc level
  68 + 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
  69 + uint8_t set_operating_mode(uint8_t v, uint8_t adr=0xFF); //returns 0 on success
  70 + uint8_t set_max_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success
  71 + uint8_t set_min_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success
  72 + uint8_t set_system_failure_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success
  73 + uint8_t set_power_on_level(uint8_t v, uint8_t adr=0xFF); //returns 0 on success
  74 + uint8_t tx_wait(uint8_t* data, uint8_t bitlen, uint16_t timeout_ms=500); //blocking transmit bytes
  75 + int16_t tx_wait_rx(uint8_t cmd0, uint8_t cmd1, uint16_t timeout_ms=500); //blocking transmit and receive
  76 +
  77 + uint8_t read_memory_bank(uint8_t bank, uint8_t adr);
  78 + uint8_t set_dtr0(uint8_t value, uint8_t adr);
  79 + uint8_t set_dtr1(uint8_t value, uint8_t adr);
  80 + uint8_t set_dtr2(uint8_t value, uint8_t adr);
  81 +
  82 + //commissioning
  83 + uint8_t commission(uint8_t init_arg=0xff);
  84 + void set_searchaddr(uint32_t adr);
  85 + void set_searchaddr_diff(uint32_t adr_new,uint32_t adr_current);
  86 + uint8_t compare();
  87 + void program_short_address(uint8_t shortadr);
  88 + uint8_t query_short_address();
  89 + uint32_t find_addr();
  90 +
  91 +private:
  92 + //-------------------------------------------------
  93 + //LOW LEVEL DRIVER PRIVATE
  94 +
  95 + //BUS
  96 + volatile uint8_t busstate; //current bus state IDLE,TX,RX,COLLISION_RX,COLLISION_TX
  97 + volatile uint8_t ticks; //sample counter, wraps around. 1 tick is approx 0.1 ms, overflow 6.5 seconds
  98 + volatile uint16_t _milli; //millisecond counter, wraps around, overflow 256 ms
  99 + volatile uint8_t idlecnt; //number of idle samples (capped at 255)
  100 +
  101 + //RECEIVER
  102 + enum rx_stateEnum { EMPTY, RECEIVING, COMPLETED};
  103 + volatile rx_stateEnum rxstate; //state of receiver
  104 + volatile uint8_t rxdata[DALI_RX_BUF_SIZE]; //received samples
  105 + volatile uint8_t rxpos; //pos in rxdata
  106 + volatile uint8_t rxbyte; //last 8 samples, MSB is oldest
  107 + volatile uint8_t rxbitcnt; //bitcnt in rxbyte
  108 + volatile uint8_t rxidle; //idle tick counter during RX
  109 +
  110 +
  111 + //TRANSMITTER
  112 + volatile uint8_t txhbdata[9]; //half bit data to transmit (max 32 bits = 2+64+4 half bits = 9 bytes)
  113 + volatile uint8_t txhblen; //number of half bits to transmit, incl start + stop bits
  114 + volatile uint8_t txhbcnt; //number of transmitted half bits, incl start + stop bits
  115 + volatile uint8_t txspcnt; //sample count since last transmitted bit
  116 + volatile uint8_t txhigh; //currently bus is high
  117 + volatile uint8_t txcollision; //collision count (capped at 255)
  118 +
  119 + //hardware abstraction layer
  120 + uint8_t (*bus_is_high)(); //returns !=0 if DALI bus is in high (non-asserted) state
  121 + void (*bus_set_low)(); //set DALI bus in low (asserted) state
  122 + void (*bus_set_high)(); //set DALI bus in high (released) state
  123 +
  124 + void _init();
  125 + void _set_busstate_idle();
  126 + void _tx_push_2hb(uint8_t hb);
  127 +
  128 +
  129 + uint8_t _man_weight(uint8_t i);
  130 + uint8_t _man_sample(uint8_t *edata, uint16_t bitpos, uint8_t *stop_coll);
  131 + uint8_t _man_decode(uint8_t *edata, uint8_t ebitlen, uint8_t *ddata);
  132 +
  133 + //-------------------------------------------------
  134 + //HIGH LEVEL PRIVATE
  135 + uint8_t _check_yaaaaaa(uint8_t yaaaaaa); //check for yaaaaaa pattern
  136 + uint8_t _set_value(uint16_t setcmd, uint16_t getcmd, uint8_t v, uint8_t adr); //set a parameter value, returns 0 on success
  137 +
  138 +};
  139 +
  140 +
  141 +//-------------------------------------------------
  142 +//HIGH LEVEL DEFINES
  143 +
  144 +#define DALI_BAUD 1200
  145 +
  146 +
  147 +
  148 +//bit8=extended commands, bit9=repeat
  149 +#define DALI_OFF 0 //0 - Turns off lighting.
  150 +#define DALI_UP 1 //1 - Increases the lighting control level for 200 ms according to the Fade rate.
  151 +#define DALI_DOWN 2 //2 - Decreases the lighting control level for 200 ms according to the Fade rate.
  152 +#define DALI_STEP_UP 3 //3 - Increments the lighting control level (without fade).
  153 +#define DALI_STEP_DOWN 4 //4 - Decrements the lighting control level (without fade).
  154 +#define DALI_RECALL_MAX_LEVEL 5 //5 - Maximizes the lighting control level (without fade).
  155 +#define DALI_RECALL_MIN_LEVEL 6 //6 - Minimizes the lighting control level (without fade)
  156 +#define DALI_STEP_DOWN_AND_OFF 7 //7 - Decrements the lighting control level and turns off lighting if the level is at the minimum (without fade).
  157 +#define DALI_ON_AND_STEP_UP 8 //8 - Increments the lighting control level and turns on lighting if lighting is off (with fade).
  158 +#define DALI_ENABLE_DAPC_SEQUENCE 9 //9 - It shows the repeat start of the DAPC command.
  159 +#define DALI_GO_TO_LAST_ACTIVE_LEVEL 10 //10 DALI-2 - Adjusts the lighting control level to the last light control level according to the Fade time. (Command that exist only in IEC62386-102ed2.0)
  160 +#define DALI_RESERVED11 11 //11 - [Reserved]
  161 +#define DALI_RESERVED12 12 //12 - [Reserved]
  162 +#define DALI_RESERVED13 13 //13 - [Reserved]
  163 +#define DALI_RESERVED14 14 //14 - [Reserved]
  164 +#define DALI_RESERVED16 16 //16 - [Reserved]
  165 +#define DALI_GO_TO_SCENE0 16 //16 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  166 +#define DALI_GO_TO_SCENE1 17 //17 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  167 +#define DALI_GO_TO_SCENE2 18 //18 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  168 +#define DALI_GO_TO_SCENE3 19 //19 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  169 +#define DALI_GO_TO_SCENE4 20 //20 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  170 +#define DALI_GO_TO_SCENE5 21 //21 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  171 +#define DALI_GO_TO_SCENE6 22 //22 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  172 +#define DALI_GO_TO_SCENE7 23 //23 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  173 +#define DALI_GO_TO_SCENE8 24 //24 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  174 +#define DALI_GO_TO_SCENE9 25 //25 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  175 +#define DALI_GO_TO_SCENE10 26 //26 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  176 +#define DALI_GO_TO_SCENE11 27 //27 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  177 +#define DALI_GO_TO_SCENE12 28 //28 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  178 +#define DALI_GO_TO_SCENE13 29 //29 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  179 +#define DALI_GO_TO_SCENE14 30 //30 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  180 +#define DALI_GO_TO_SCENE15 31 //31 - Adjusts the lighting control level for Scene XXXX according to the fade time.
  181 +#define DALI_RESET 544 //32 REPEAT - Makes a slave an RESET state.
  182 +#define DALI_STORE_ACTUAL_LEVEL_IN_THE_DTR0 545 //33 REPEAT - Saves the current lighting control level to the DTR (DTR0). (In the parenthesis is a name in IEC62386-102ed2.0)
  183 +#define DALI_SAVE_PERSISTENT_VARIABLES 546 //34 REPEAT DALI-2 - Saves a variable in nonvolatile memory (NVM). (Command that exist only in IEC62386-102ed2.0)
  184 +#define DALI_SET_OPERATING_MODE 547 //35 REPEAT DALI-2 - Sets data of DTR0 as an operating mode. (Command that exist only in IEC62386-102ed2.0)
  185 +#define DALI_RESET_MEMORY_BANK 548 //36 REPEAT DALI-2 - Changes to the reset value the specified memory bank in DTR0. (Command that exist only in IEC62386-102ed2.0)
  186 +#define DALI_IDENTIFY_DEVICE 549 //37 REPEAT DALI-2 - Starts the identification state of the device. (Command that exist only in IEC62386-102ed2.0)
  187 +#define DALI_RESERVED38 550 //38 REPEAT - [Reserved]
  188 +#define DALI_RESERVED39 551 //39 REPEAT - [Reserved]
  189 +#define DALI_RESERVED40 552 //40 REPEAT - [Reserved]
  190 +#define DALI_RESERVED41 553 //41 REPEAT - [Reserved]
  191 +#define DALI_SET_MAX_LEVEL 554 //42 REPEAT - Specifies the DTR data as the maximum lighting control level. (In the parenthesis is a name in IEC62386-102ed2.0)
  192 +#define DALI_SET_MIN_LEVEL 555 //43 REPEAT - Specifies the DTR data as the minimum lighting control level. (In the parenthesis is a name in IEC62386-102ed2.0)
  193 +#define DALI_SET_SYSTEM_FAILURE_LEVEL 556 //44 REPEAT - Specifies the DTR data as the "FAILURELEVEL". (In the parenthesis is a name in IEC62386-102ed2.0)
  194 +#define DALI_SET_POWER_ON_LEVEL 557 //45 REPEAT - Specifies the DTR data as the "POWER ONLEVEL". (In the parenthesis is a name in IEC62386-102ed2.0)
  195 +#define DALI_SET_FADE_TIME 558 //46 REPEAT - Specifies the DTR data as the Fade time. (In the parenthesis is a name in IEC62386-102ed2.0)
  196 +#define DALI_SET_FADE_RATE 559 //47 REPEAT - Specifies the DTR data as the Fade rate. (In the parenthesis is a name in IEC62386-102ed2.0)
  197 +#define DALI_SET_EXTENDED_FADE_TIME 560 //48 REPEAT DALI-2 - Specifies the DTR data as the Extended Fade Time. (Command that exist only in IEC62386-102ed2.0)
  198 +#define DALI_RESERVED49 561 //49 REPEAT - [Reserved]
  199 +#define DALI_RESERVED50 562 //50 REPEAT - [Reserved]
  200 +#define DALI_RESERVED51 563 //51 REPEAT - [Reserved]
  201 +#define DALI_RESERVED52 564 //52 REPEAT - [Reserved]
  202 +#define DALI_RESERVED53 565 //53 REPEAT - [Reserved]
  203 +#define DALI_RESERVED54 566 //54 REPEAT - [Reserved]
  204 +#define DALI_RESERVED55 567 //55 REPEAT - [Reserved]
  205 +#define DALI_RESERVED56 568 //56 REPEAT - [Reserved]
  206 +#define DALI_RESERVED57 569 //57 REPEAT - [Reserved]
  207 +#define DALI_RESERVED58 570 //58 REPEAT - [Reserved]
  208 +#define DALI_RESERVED59 571 //59 REPEAT - [Reserved]
  209 +#define DALI_RESERVED60 572 //60 REPEAT - [Reserved]
  210 +#define DALI_RESERVED61 573 //61 REPEAT - [Reserved]
  211 +#define DALI_RESERVED62 574 //62 REPEAT - [Reserved]
  212 +#define DALI_RESERVED63 575 //63 REPEAT - [Reserved]
  213 +#define DALI_SET_SCENE0 576 //64 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  214 +#define DALI_SET_SCENE1 577 //65 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  215 +#define DALI_SET_SCENE2 578 //66 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  216 +#define DALI_SET_SCENE3 579 //67 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  217 +#define DALI_SET_SCENE4 580 //68 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  218 +#define DALI_SET_SCENE5 581 //69 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  219 +#define DALI_SET_SCENE6 582 //70 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  220 +#define DALI_SET_SCENE7 583 //71 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  221 +#define DALI_SET_SCENE8 584 //72 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  222 +#define DALI_SET_SCENE9 585 //73 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  223 +#define DALI_SET_SCENE10 586 //74 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  224 +#define DALI_SET_SCENE11 587 //75 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  225 +#define DALI_SET_SCENE12 588 //76 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  226 +#define DALI_SET_SCENE13 589 //77 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  227 +#define DALI_SET_SCENE14 590 //78 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  228 +#define DALI_SET_SCENE15 591 //79 REPEAT - Specifies the DTR data as Scene XXXX. (In the parenthesis is a name in IEC62386-102ed2.0)
  229 +#define DALI_REMOVE_FROM_SCENE0 592 //80 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  230 +#define DALI_REMOVE_FROM_SCENE1 593 //81 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  231 +#define DALI_REMOVE_FROM_SCENE2 594 //82 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  232 +#define DALI_REMOVE_FROM_SCENE3 595 //83 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  233 +#define DALI_REMOVE_FROM_SCENE4 596 //84 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  234 +#define DALI_REMOVE_FROM_SCENE5 597 //85 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  235 +#define DALI_REMOVE_FROM_SCENE6 598 //86 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  236 +#define DALI_REMOVE_FROM_SCENE7 599 //87 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  237 +#define DALI_REMOVE_FROM_SCENE8 600 //88 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  238 +#define DALI_REMOVE_FROM_SCENE9 601 //89 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  239 +#define DALI_REMOVE_FROM_SCENE10 602 //90 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  240 +#define DALI_REMOVE_FROM_SCENE11 603 //91 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  241 +#define DALI_REMOVE_FROM_SCENE12 604 //92 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  242 +#define DALI_REMOVE_FROM_SCENE13 605 //93 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  243 +#define DALI_REMOVE_FROM_SCENE14 606 //94 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  244 +#define DALI_REMOVE_FROM_SCENE15 607 //95 REPEAT - Deletes the Scene XXXX setting. (Specifies 1111 1111 for the scene register.)
  245 +#define DALI_ADD_TO_GROUP0 608 //96 REPEAT - Adds the slave to Group XXXX.
  246 +#define DALI_ADD_TO_GROUP1 609 //97 REPEAT - Adds the slave to Group XXXX.
  247 +#define DALI_ADD_TO_GROUP2 610 //98 REPEAT - Adds the slave to Group XXXX.
  248 +#define DALI_ADD_TO_GROUP3 611 //99 REPEAT - Adds the slave to Group XXXX.
  249 +#define DALI_ADD_TO_GROUP4 612 //100 REPEAT - Adds the slave to Group XXXX.
  250 +#define DALI_ADD_TO_GROUP5 613 //101 REPEAT - Adds the slave to Group XXXX.
  251 +#define DALI_ADD_TO_GROUP6 614 //102 REPEAT - Adds the slave to Group XXXX.
  252 +#define DALI_ADD_TO_GROUP7 615 //103 REPEAT - Adds the slave to Group XXXX.
  253 +#define DALI_ADD_TO_GROUP8 616 //104 REPEAT - Adds the slave to Group XXXX.
  254 +#define DALI_ADD_TO_GROUP9 617 //105 REPEAT - Adds the slave to Group XXXX.
  255 +#define DALI_ADD_TO_GROUP10 618 //106 REPEAT - Adds the slave to Group XXXX.
  256 +#define DALI_ADD_TO_GROUP11 619 //107 REPEAT - Adds the slave to Group XXXX.
  257 +#define DALI_ADD_TO_GROUP12 620 //108 REPEAT - Adds the slave to Group XXXX.
  258 +#define DALI_ADD_TO_GROUP13 621 //109 REPEAT - Adds the slave to Group XXXX.
  259 +#define DALI_ADD_TO_GROUP14 622 //110 REPEAT - Adds the slave to Group XXXX.
  260 +#define DALI_ADD_TO_GROUP15 623 //111 REPEAT - Adds the slave to Group XXXX.
  261 +#define DALI_REMOVE_FROM_GROUP0 624 //112 REPEAT - Deletes the slave from Group XXXX.
  262 +#define DALI_REMOVE_FROM_GROUP1 625 //113 REPEAT - Deletes the slave from Group XXXX.
  263 +#define DALI_REMOVE_FROM_GROUP2 626 //114 REPEAT - Deletes the slave from Group XXXX.
  264 +#define DALI_REMOVE_FROM_GROUP3 627 //115 REPEAT - Deletes the slave from Group XXXX.
  265 +#define DALI_REMOVE_FROM_GROUP4 628 //116 REPEAT - Deletes the slave from Group XXXX.
  266 +#define DALI_REMOVE_FROM_GROUP5 629 //117 REPEAT - Deletes the slave from Group XXXX.
  267 +#define DALI_REMOVE_FROM_GROUP6 630 //118 REPEAT - Deletes the slave from Group XXXX.
  268 +#define DALI_REMOVE_FROM_GROUP7 631 //119 REPEAT - Deletes the slave from Group XXXX.
  269 +#define DALI_REMOVE_FROM_GROUP8 632 //120 REPEAT - Deletes the slave from Group XXXX.
  270 +#define DALI_REMOVE_FROM_GROUP9 633 //121 REPEAT - Deletes the slave from Group XXXX.
  271 +#define DALI_REMOVE_FROM_GROUP10 634 //122 REPEAT - Deletes the slave from Group XXXX.
  272 +#define DALI_REMOVE_FROM_GROUP11 635 //123 REPEAT - Deletes the slave from Group XXXX.
  273 +#define DALI_REMOVE_FROM_GROUP12 636 //124 REPEAT - Deletes the slave from Group XXXX.
  274 +#define DALI_REMOVE_FROM_GROUP13 637 //125 REPEAT - Deletes the slave from Group XXXX.
  275 +#define DALI_REMOVE_FROM_GROUP14 638 //126 REPEAT - Deletes the slave from Group XXXX.
  276 +#define DALI_REMOVE_FROM_GROUP15 639 //127 REPEAT - Deletes the slave from Group XXXX.
  277 +#define DALI_SET_SHORT_ADDRESS 640 //128 REPEAT - Specifies the DTR data as a Short Address. (In the parenthesis is a name in IEC62386-102ed2.0)
  278 +#define DALI_ENABLE_WRITE_MEMORY 641 //129 REPEAT - Allows writing of the memory bank.
  279 +#define DALI_RESERVED130 642 //130 REPEAT - [Reserved]
  280 +#define DALI_RESERVED131 643 //131 REPEAT - [Reserved]
  281 +#define DALI_RESERVED132 644 //132 REPEAT - [Reserved]
  282 +#define DALI_RESERVED133 645 //133 REPEAT - [Reserved]
  283 +#define DALI_RESERVED134 646 //134 REPEAT - [Reserved]
  284 +#define DALI_RESERVED135 647 //135 REPEAT - [Reserved]
  285 +#define DALI_RESERVED136 648 //136 REPEAT - [Reserved]
  286 +#define DALI_RESERVED137 649 //137 REPEAT - [Reserved]
  287 +#define DALI_RESERVED138 650 //138 REPEAT - [Reserved]
  288 +#define DALI_RESERVED139 651 //139 REPEAT - [Reserved]
  289 +#define DALI_RESERVED140 652 //140 REPEAT - [Reserved]
  290 +#define DALI_RESERVED141 653 //141 REPEAT - [Reserved]
  291 +#define DALI_RESERVED142 654 //142 REPEAT - [Reserved]
  292 +#define DALI_RESERVED143 655 //143 REPEAT - [Reserved]
  293 +#define DALI_QUERY_STATUS 144 //144 - Returns "STATUS INFORMATION"
  294 +#define DALI_QUERY_CONTROL_GEAR_PRESENT 145 //145 - Is there a slave that can communicate? (In the parenthesis is a name in IEC62386-102ed2.0)
  295 +#define DALI_QUERY_LAMP_FAILURE 146 //146 - Is there a lamp problem?
  296 +#define DALI_QUERY_LAMP_POWER_ON 147 //147 - Is a lamp on?
  297 +#define DALI_QUERY_LIMIT_ERROR 148 //148 - Is the specified lighting control level out of the range from the minimum to the maximum values?
  298 +#define DALI_QUERY_RESET_STATE 149 //149 - Is the slave in 'RESET STATE'?
  299 +#define DALI_QUERY_MISSING_SHORT_ADDRESS 150 //150 - Does the slave not have a short address?
  300 +#define DALI_QUERY_VERSION_NUMBER 151 //151 - What is the corresponding IEC standard number?
  301 +#define DALI_QUERY_CONTENT_DTR0 152 //152 - What is the DTR content? (In the parenthesis is a name in IEC62386-102ed2.0)
  302 +#define DALI_QUERY_DEVICE_TYPE 153 //153 - What is the device type? (fluorescent lamp:0000 0000) (IEC62386-207 is 6 fixed)
  303 +#define DALI_QUERY_PHYSICAL_MINIMUM_LEVEL 154 //154 - What is the minimum lighting control level specified by the hardware?
  304 +#define DALI_QUERY_POWER_FAILURE 155 //155 - Has the slave operated without the execution of reset-command or the adjustment of the lighting control level?
  305 +#define DALI_QUERY_CONTENT_DTR1 156 //156 - What is the DTR1 content?
  306 +#define DALI_QUERY_CONTENT_DTR2 157 //157 - What is the DTR2 content?
  307 +#define DALI_QUERY_OPERATING_MODE 158 //158 DALI-2 - What is the Operating Mode? (Only IEC62386-102ed2.0 )
  308 +#define DALI_QUERY_LIGHT_SOURCE_TYPE 159 //159 DALI-2 - What is the Light source type? (Only IEC62386-102ed2.0 )
  309 +#define DALI_QUERY_ACTUAL_LEVEL 160 //160 - What is the "ACTUAL LEVEL" (the current lighting control level)?
  310 +#define DALI_QUERY_MAX_LEVEL 161 //161 - What is the maximum lighting control level?
  311 +#define DALI_QUERY_MIN_LEVEL 162 //162 - What is the minimum lighting control level?
  312 +#define DALI_QUERY_POWER_ON_LEVEL 163 //163 - What is the "POWER ON LEVEL" (the lighting control level when the power is turned on)?
  313 +#define DALI_QUERY_SYSTEM_FAILURE_LEVEL 164 //164 - What is the "SYSTEM FAILURE LEVEL" (the lighting control level when a failure occurs)?
  314 +#define DALI_QUERY_FADE_TIME_FADE_RATE 165 //165 - What are the Fade time and Fade rate?
  315 +#define DALI_QUERY_MANUFACTURER_SPECIFIC_MODE 166 //166 DALI-2 - What is the Specific Mode? (Command that exist only in IEC62386-102ed2.0)
  316 +#define DALI_QUERY_NEXT_DEVICE_TYPE 167 //167 DALI-2 - What is the next Device Type? (Command that exist only in IEC62386-102ed2.0)
  317 +#define DALI_QUERY_EXTENDED_FADE_TIME 168 //168 DALI-2 - What is the Extended Fade Time? (Command that exist only in IEC62386-102ed2.0)
  318 +#define DALI_QUERY_CONTROL_GEAR_FAILURE 169 //169 DALI-2 - Does a slave have the abnormality? (Command that exist only in IEC62386-102ed2.0)
  319 +#define DALI_RESERVED170 170 //170 - [Reserved]
  320 +#define DALI_RESERVED171 171 //171 - [Reserved]
  321 +#define DALI_RESERVED172 172 //172 - [Reserved]
  322 +#define DALI_RESERVED173 173 //173 - [Reserved]
  323 +#define DALI_RESERVED174 174 //174 - [Reserved]
  324 +#define DALI_RESERVED175 175 //175 - [Reserved]
  325 +#define DALI_QUERY_SCENE0_LEVEL 176 //176 - What is the lighting control level for SCENE XXXX?
  326 +#define DALI_QUERY_SCENE1_LEVEL 177 //177 - What is the lighting control level for SCENE XXXX?
  327 +#define DALI_QUERY_SCENE2_LEVEL 178 //178 - What is the lighting control level for SCENE XXXX?
  328 +#define DALI_QUERY_SCENE3_LEVEL 179 //179 - What is the lighting control level for SCENE XXXX?
  329 +#define DALI_QUERY_SCENE4_LEVEL 180 //180 - What is the lighting control level for SCENE XXXX?
  330 +#define DALI_QUERY_SCENE5_LEVEL 181 //181 - What is the lighting control level for SCENE XXXX?
  331 +#define DALI_QUERY_SCENE6_LEVEL 182 //182 - What is the lighting control level for SCENE XXXX?
  332 +#define DALI_QUERY_SCENE7_LEVEL 183 //183 - What is the lighting control level for SCENE XXXX?
  333 +#define DALI_QUERY_SCENE8_LEVEL 184 //184 - What is the lighting control level for SCENE XXXX?
  334 +#define DALI_QUERY_SCENE9_LEVEL 185 //185 - What is the lighting control level for SCENE XXXX?
  335 +#define DALI_QUERY_SCENE10_LEVEL 186 //186 - What is the lighting control level for SCENE XXXX?
  336 +#define DALI_QUERY_SCENE11_LEVEL 187 //187 - What is the lighting control level for SCENE XXXX?
  337 +#define DALI_QUERY_SCENE12_LEVEL 188 //188 - What is the lighting control level for SCENE XXXX?
  338 +#define DALI_QUERY_SCENE13_LEVEL 189 //189 - What is the lighting control level for SCENE XXXX?
  339 +#define DALI_QUERY_SCENE14_LEVEL 190 //190 - What is the lighting control level for SCENE XXXX?
  340 +#define DALI_QUERY_SCENE15_LEVEL 191 //191 - What is the lighting control level for SCENE XXXX?
  341 +#define DALI_QUERY_GROUPS_0_7 192 //192 - Does the slave belong to a group among groups 0 to 7? (Each bit corresponds to agroup.)
  342 +#define DALI_QUERY_GROUPS_8_15 193 //193 - Does the slave belong to a group among groups 8 to 15? (Each bit corresponds to agroup.)
  343 +#define DALI_QUERY_RANDOM_ADDRESS_H 194 //194 - What are the higher 8 bits of the random address?
  344 +#define DALI_QUERY_RANDOM_ADDRESS_M 195 //195 - What are the middle 8 bits of the random address?
  345 +#define DALI_QUERY_RANDOM_ADDRESS_L 196 //196 - What are the lower 8 bits of the random address?
  346 +#define DALI_READ_MEMORY_LOCATION 197 //197 - What is the memory location content?
  347 +#define DALI_RESERVED198 198 //198 - [Reserved]
  348 +#define DALI_RESERVED199 199 //199 - [Reserved]
  349 +#define DALI_RESERVED200 200 //200 - [Reserved]
  350 +#define DALI_RESERVED201 201 //201 - [Reserved]
  351 +#define DALI_RESERVED202 202 //202 - [Reserved]
  352 +#define DALI_RESERVED203 203 //203 - [Reserved]
  353 +#define DALI_RESERVED204 204 //204 - [Reserved]
  354 +#define DALI_RESERVED205 205 //205 - [Reserved]
  355 +#define DALI_RESERVED206 206 //206 - [Reserved]
  356 +#define DALI_RESERVED207 207 //207 - [Reserved]
  357 +#define DALI_RESERVED208 208 //208 - [Reserved]
  358 +#define DALI_RESERVED209 209 //209 - [Reserved]
  359 +#define DALI_RESERVED210 210 //210 - [Reserved]
  360 +#define DALI_RESERVED211 211 //211 - [Reserved]
  361 +#define DALI_RESERVED212 212 //212 - [Reserved]
  362 +#define DALI_RESERVED213 213 //213 - [Reserved]
  363 +#define DALI_RESERVED214 214 //214 - [Reserved]
  364 +#define DALI_RESERVED215 215 //215 - [Reserved]
  365 +#define DALI_RESERVED216 216 //216 - [Reserved]
  366 +#define DALI_RESERVED217 217 //217 - [Reserved]
  367 +#define DALI_RESERVED218 218 //218 - [Reserved]
  368 +#define DALI_RESERVED219 219 //219 - [Reserved]
  369 +#define DALI_RESERVED220 220 //220 - [Reserved]
  370 +#define DALI_RESERVED221 221 //221 - [Reserved]
  371 +#define DALI_RESERVED222 222 //222 - [Reserved]
  372 +#define DALI_RESERVED223 223 //223 - [Reserved]
  373 +#define DALI_REFERENCE_SYSTEM_POWER 224 //224 IEC62386-207 - Starts power measurement. (Command that exist only in IEC62386-207)
  374 +#define DALI_ENABLE_CURRENT_PROTECTOR 225 //225 IEC62386-207 - Enables the current protection. (Command that exist only in IEC62386-207)
  375 +#define DALI_DISABLE_CURRENT_PROTECTOR 226 //226 IEC62386-207 - Disables the current protection. (Command that exist only in IEC62386-207)
  376 +#define DALI_SELECT_DIMMING_CURVE 227 //227 IEC62386-207 - Selects Dimming curve. (Command that exist only in IEC62386-207)
  377 +#define DALI_STORE_DTR_AS_FAST_FADE_TIME 228 //228 IEC62386-207 - Sets the DTR of the data as Fast Fade Time.(Command that exist only in IEC62386-207)
  378 +#define DALI_RESERVED229 229 //229 - [Reserved]
  379 +#define DALI_RESERVED230 230 //230 - [Reserved]
  380 +#define DALI_RESERVED231 231 //231 - [Reserved]
  381 +#define DALI_RESERVED232 232 //232 - [Reserved]
  382 +#define DALI_RESERVED233 233 //233 - [Reserved]
  383 +#define DALI_RESERVED234 234 //234 - [Reserved]
  384 +#define DALI_RESERVED235 235 //235 - [Reserved]
  385 +#define DALI_RESERVED236 236 //236 - [Reserved]
  386 +#define DALI_QUERY_GEAR_TYPE 237 //237 IEC62386-207 - Returns ‘GEAR TYPE’ (Command that exist only in IEC62386-207)
  387 +#define DALI_QUERY_DIMMING_CURVE 238 //238 IEC62386-207 - Returns ’Dimming curve’in use (Command that exist only in IEC62386-207)
  388 +#define DALI_QUERY_POSSIBLE_OPERATING_MODE 239 //239 IEC62386-207 - Returns ‘POSSIBLEG OPERATING MODE’ (Command that exist only in IEC62386-207)
  389 +#define DALI_QUERY_FEATURES 240 //240 IEC62386-207 - Returns ‘FEATURES’ (Command that exist only in IEC62386-207)
  390 +#define DALI_QUERY_FAILURE_STATUS 241 //241 IEC62386-207 - Returns ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  391 +#define DALI_QUERY_SHORT_CIRCUIT 242 //242 IEC62386-207 - Returns bit0 short circuit of ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  392 +#define DALI_QUERY_OPEN_CIRCUIT 243 //243 IEC62386-207 - Returns bit1 open circuit of ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  393 +#define DALI_QUERY_LOAD_DECREASE 244 //244 IEC62386-207 - Returns bit2 load decrease of ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  394 +#define DALI_QUERY_LOAD_INDREASE 245 //245 IEC62386-207 - Returns bit3 load increase of‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  395 +#define DALI_QUERY_CURRENT_PROTECTOR_ACTIVE 246 //246 IEC62386-207 - Returns bit4 current protector active of ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  396 +#define DALI_QUERY_THERMAL_SHUTDOWN 247 //247 IEC62386-207 - Returns bit5 thermal shut down of ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  397 +#define DALI_QUERY_THERMAL_OVERLOAD 248 //248 IEC62386-207 - Returns bit6 thermal overload with light level reduction of ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  398 +#define DALI_QUERY_REFARENCE_RUNNING 249 //249 IEC62386-207 - Returns whetherReference System Power is in operation. (Command that exist only in IEC62386-207)
  399 +#define DALI_QUERY_REFERENCE_MEASURMENT_FAILED 250 //250 IEC62386-207 - Returns bit7 reference measurement failed of ‘FAILURE STATUS’ (Command that exist only in IEC62386-207)
  400 +#define DALI_QUERY_CURRENT_PROTECTOR_ENABLE 251 //251 IEC62386-207 - Returns state of Curent protector (Command that exist only in IEC62386-207)
  401 +#define DALI_QUERY_OPERATING_MODE 252 //252 IEC62386-207 - Returns ‘OPERATING MODE’ (Command that exist only in IEC62386-207)
  402 +#define DALI_QUERY_FAST_FADE_TIME 253 //253 IEC62386-207 - Returns set Fast fade time. (Command that exist only in IEC62386-207)
  403 +#define DALI_QUERY_MIN_FAST_FADE_TIME 254 //254 IEC62386-207 - Returns set Minimum fast fade time (Command that exist only in IEC62386-207)
  404 +#define DALI_QUERY_EXTENDED_VERSION_NUMBER 255 //255 IEC62386-207 - The version number of the extended support? IEC62386-207: 1, Other: NO(no response)
  405 +#define DALI_TERMINATE 0x01A1 //256 - Releases the INITIALISE state.
  406 +#define DALI_DATA_TRANSFER_REGISTER0 0x01A3 //257 - Stores the data XXXX XXXX to the DTR(DTR0). (In the parenthesis is a name in IEC62386-102ed2.0)
  407 +#define DALI_INITIALISE 0x03A5 //258 REPEAT - Sets the slave to the INITIALISE status for15 minutes. Commands 259 to 270 are enabled only for a slave in this status.
  408 +#define DALI_RANDOMISE 0x03A7 //259 REPEAT - Generates a random address.
  409 +#define DALI_COMPARE 0x01A9 //260 - Is the random address smaller or equal to the search address?
  410 +#define DALI_WITHDRAW 0x01AB //261 - Excludes slaves for which the random address and search address match from the Compare process.
  411 +#define DALI_RESERVED262 0x01AD //262 - [Reserved]
  412 +#define DALI_PING 0x01AF //263 DALI-2 - Ignores in the slave. (Command that exist only in IEC62386-102ed2.0)
  413 +#define DALI_SEARCHADDRH 0x01B1 //264 - Specifies the higher 8 bits of the search address.
  414 +#define DALI_SEARCHADDRM 0x01B3 //265 - Specifies the middle 8 bits of the search address.
  415 +#define DALI_SEARCHADDRL 0x01B5 //266 - Specifies the lower 8 bits of the search address.
  416 +#define DALI_PROGRAM_SHORT_ADDRESS 0x01B7 //267 - The slave shall store the received 6-bit address (AAA AAA) as a short address if it is selected.
  417 +#define DALI_VERIFY_SHORT_ADDRESS 0x01B9 //268 - Is the short address AAA AAA?
  418 +#define DALI_QUERY_SHORT_ADDRESS 0x01BB //269 - What is the short address of the slaveNote 2being selected?
  419 +#define DALI_PHYSICAL_SELECTION 0x01BD //270 not DALI-2 - Sets the slave to Physical Selection Mode and excludes the slave from the Compare process. (Excluding IEC62386-102ed2.0) (Command that exist only in IEC62386-102ed1.0, -207ed1.0)
  420 +#define DALI_RESERVED271 0x01BF //271 - [Reserved]
  421 +#define DALI_ENABLE_DEVICE_TYPE_X 0x01C1 //272 - Adds the device XXXX (a special device).
  422 +#define DALI_DATA_TRANSFER_REGISTER1 0x01C3 //273 - Stores data XXXX into DTR1.
  423 +#define DALI_DATA_TRANSFER_REGISTER2 0x01C5 //274 - Stores data XXXX into DTR2.
  424 +#define DALI_WRITE_MEMORY_LOCATION 0x01C7 //275 - Write data into the specified address of the specified memory bank. (There is BW) (DTR(DTR0):address, DTR1:memory bank number)
  425 +#define DALI_WRITE_MEMORY_LOCATION_NO_REPLY 0x01C9 //276 DALI-2 - Write data into the specified address of the specified memory bank. (There is no BW) (DTR(DTR0):address, TR1:memory bank number) (Command that exist only in IEC62386-102ed2.0)
  426 +#define DALI_RESERVED277 0x01CB //277 - [Reserved]
  427 +#define DALI_RESERVED278 0x01CD //278 - [Reserved]
  428 +#define DALI_RESERVED279 0x01CF //279 - [Reserved]
  429 +#define DALI_RESERVED280 0x01D1 //280 - [Reserved]
  430 +#define DALI_RESERVED281 0x01D3 //281 - [Reserved]
  431 +#define DALI_RESERVED282 0x01D5 //282 - [Reserved]
  432 +#define DALI_RESERVED283 0x01D7 //283 - [Reserved]
  433 +#define DALI_RESERVED284 0x01D9 //284 - [Reserved]
  434 +#define DALI_RESERVED285 0x01DB //285 - [Reserved]
  435 +#define DALI_RESERVED286 0x01DD //286 - [Reserved]
  436 +#define DALI_RESERVED287 0x01DF //287 - [Reserved]
  437 +#define DALI_RESERVED288 0x01E1 //288 - [Reserved]
  438 +#define DALI_RESERVED289 0x01E3 //289 - [Reserved]
  439 +#define DALI_RESERVED290 0x01E5 //290 - [Reserved]
  440 +#define DALI_RESERVED291 0x01E7 //291 - [Reserved]
  441 +#define DALI_RESERVED292 0x01E9 //292 - [Reserved]
  442 +#define DALI_RESERVED293 0x01EB //293 - [Reserved]
  443 +#define DALI_RESERVED294 0x01ED //294 - [Reserved]
  444 +#define DALI_RESERVED295 0x01DF //295 - [Reserved]
  445 +#define DALI_RESERVED296 0x01F1 //296 - [Reserved]
  446 +#define DALI_RESERVED297 0x01F3 //297 - [Reserved]
  447 +#define DALI_RESERVED298 0x01F5 //298 - [Reserved]
  448 +#define DALI_RESERVED299 0x01F7 //299 - [Reserved]
  449 +#define DALI_RESERVED300 0x01F9 //300 - [Reserved]
  450 +#define DALI_RESERVED301 0x01FB //301 - [Reserved]
  451 +#define DALI_RESERVED302 0x01FD //302 - [Reserved]
  452 +
  453 +
  454 +
  455 +
  456 +/*
  457 +SIGNAL CHARACTERISTICS
  458 +High Level: 9.5 to 22.5 V (Typical 16 V)
  459 +Low Level: -6.5 to + 6.5 V (Typical 0 V)
  460 +Te = half cycle = 416.67 us +/- 10 %
  461 +10 us <= tfall <= 100 us
  462 +10 us <= trise <= 100 us
  463 +
  464 +BIT TIMING
  465 +msb send first
  466 + logical 1 = 1Te Low 1Te High
  467 + logical 0 = 1Te High 1Te Low
  468 + Start bit = logical 1
  469 + Stop bit = 2Te High
  470 +
  471 +FRAME TIMING
  472 +FF: TX Forward Frame 2 bytes (38Te) = 2*(1start+16bits+2stop)
  473 +BF: RX Backward Frame 1 byte (22Te) = 2*(1start+8bits+2stop)
  474 +no reply: FF >22Te pause FF
  475 +with reply: FF >7Te <22Te pause BF >22Te pause FF
  476 +
  477 +
  478 +DALI commands
  479 +=============
  480 +In accordance with the DIN EN 60929 standard, addresses and commands are transmitted as numbers with a length of two bytes.
  481 +
  482 +These commands take the form YAAA AAAS xxXXxx. Each letter here stands for one bit.
  483 +
  484 +Y: type of address
  485 + 0bin: short address
  486 + 1bin: group address or collective call
  487 +
  488 +A: significant address bit
  489 +
  490 +S: selection bit (specifies the significance of the following eight bits):
  491 + 0bin: the 8 xxXXxx bits contain a value for direct control of the lamp power
  492 + 1bin: the 8 xxXXxx bits contain a command number.
  493 +
  494 +x: a bit in the lamp power or in the command number
  495 +
  496 +
  497 +Type of Addresses
  498 +=================
  499 +Type of Addresses Byte Description
  500 +Short address 0AAAAAAS (AAAAAA = 0 to 63, S = 0/1)
  501 +Group address 100AAAAS (AAAA = 0 to 15, S = 0/1)
  502 +Broadcast address 1111111S (S = 0/1)
  503 +Special command 101CCCC1 (CCCC = command number)
  504 +
  505 +
  506 +Direct DALI commands for lamp power
  507 +===================================
  508 +These commands take the form YAAA AAA0 xxXXxx.
  509 +
  510 +xxXXxx: the value representing the lamp power is transmitted in these 8 bits. It is calculated according to this formula:
  511 +
  512 +Pvalue = 10 ^ ((value-1) / (253/3)) * Pmax / 1000
  513 +
  514 +253 values from 1dec to 254dec are available for transmission in accordance with this formula.
  515 +
  516 +There are also 2 direct DALI commands with special meanings:
  517 +
  518 +Command; Command No; Description; Answer
  519 +00hex; 0dec; The DALI device dims using the current fade time down to the parameterised MIN value, and then switches off.; -
  520 +FFhex; 254dec; Mask (no change): this value is ignored in what follows, and is therefore not loaded into memory.; -
  521 +
  522 +
  523 +Indirect DALI commands for lamp power
  524 +=====================================
  525 +These commands take the form YAAA AAA1 xxXXxx.
  526 +
  527 +xxXXxx: These 8 bits transfer the command number. The available command numbers are listed and explained in the following tables in hexadecimal and decimal formats.
  528 +
  529 +Command; Command No; Description; Answer
  530 +00hex 0dez Extinguish the lamp (without fading) -
  531 +01hex 1dez Dim up 200 ms using the selected fade rate -
  532 +02hex 2dez Dim down 200 ms using the selected fade rate -
  533 +03hex 3dez Set the actual arc power level one step higher without fading. If the lamp is off, it will be not ignited. -
  534 +04hex 4dez Set the actual arc power level one step lower without fading. If the lamp has already it's minimum value, it is not switched off. -
  535 +05hex 5dez Set the actual arc power level to the maximum value. If the lamp is off, it will be ignited. -
  536 +06hex 6dez Set the actual arc power level to the minimum value. If the lamp is off, it will be ignited. -
  537 +07hex 7dez Set the actual arc power level one step lower without fading. If the lamp has already it's minimum value, it is switched off. -
  538 +08hex 8dez Set the actual arc power level one step higher without fading. If the lamp is off, it will be ignited. -
  539 +09hex ... 0Fhex 9dez ... 15dez reserved -
  540 +1nhex
  541 +(n: 0hex ... Fhex) 16dez ... 31dez Set the light level to the value stored for the selected scene (n) -
  542 +
  543 +
  544 +Configuration commands
  545 +======================
  546 +Command; Command No; Description; Answer
  547 +20hex 32dez Reset the parameters to default settings -
  548 +21hex 33dez Store the current light level in the DTR (Data Transfer Register) -
  549 +22hex ... 29hex 34dez ... 41dez reserved -
  550 +2Ahex 42dez Store the value in the DTR as the maximum level -
  551 +2Bhex 43dez Store the value in the DTR as the minimum level -
  552 +2Chex 44dez Store the value in the DTR as the system failure level -
  553 +2Dhex 45dez Store the value in the DTR as the power on level -
  554 +2Ehex 46dez Store the value in the DTR as the fade time -
  555 +2Fhex 47dez Store the value in the DTR as the fade rate -
  556 +30hex ... 3Fhex 48dez ... 63dez reserved -
  557 +4nhex
  558 +(n: 0hex ... Fhex) 64dez ... 79dez Store the value in the DTR as the selected scene (n) -
  559 +5nhex
  560 +(n: 0hex ... Fhex) 80dez ... 95dez Remove the selected scene (n) from the DALI slave -
  561 +6nhex
  562 +(n: 0hex ... Fhex) 96dez ... 111dez Add the DALI slave unit to the selected group (n) -
  563 +7nhex
  564 +(n: 0hex ... Fhex) 112dez ... 127dez Remove the DALI slave unit from the selected group (n) -
  565 +80hex 128dez Store the value in the DTR as a short address -
  566 +81hex ... 8Fhex 129dez ... 143dez reserved -
  567 +90hex 144dez Returns the status (XX) of the DALI slave XX
  568 +91hex 145dez Check if the DALI slave is working yes/no
  569 +92hex 146dez Check if there is a lamp failure yes/no
  570 +93hex 147dez Check if the lamp is operating yes/no
  571 +94hex 148dez Check if the slave has received a level out of limit yes/no
  572 +95hex 149dez Check if the DALI slave is in reset state yes/no
  573 +96hex 150dez Check if the DALI slave is missing a short address XX
  574 +97hex 151dez Returns the version number as XX
  575 +98hex 152dez Returns the content of the DTR as XX
  576 +99hex 153dez Returns the device type as XX
  577 +9Ahex 154dez Returns the physical minimum level as XX
  578 +9Bhex 155dez Check if the DALI slave is in power failure mode yes/no
  579 +9Chex ... 9Fhex 156dez ... 159dez reserved -
  580 +A0hex 160dez Returns the current light level as XX
  581 +A1hex 161dez Returns the maximum allowed light level as XX
  582 +A2hex 162dez Returns the minimum allowed light level as XX
  583 +A3hex 163dez Return the power up level as XX
  584 +A4hex 164dez Returns the system failure level as XX
  585 +A5hex 165dez Returns the fade time as X and the fade rate as Y XY
  586 +A6hex ... AFhex 166dez ... 175dez reserved -
  587 +Bnhex
  588 +(n: 0hex ... Fhex) 176dez ... 191dez Returns the light level XX for the selected scene (n) XX
  589 +C0hex 192dez Returns a bit pattern XX indicating which group (0-7) the DALI slave belongs to XX
  590 +C1hex 193dez Returns a bit pattern XX indicating which group (8-15) the DALI slave belongs to XX
  591 +C2hex 194dez Returns the high bits of the random address as HH
  592 +C3hex 195dez Return the middle bit of the random address as MM
  593 +C4hex 196dez Returns the lower bits of the random address as LL
  594 +C5hex ... DFhex 197dez ... 223dez reserved -
  595 +E0hex ... FFhex 224dez ... 255dez Returns application specific extension commands
  596 +
  597 +
  598 +Note Repeat of DALI commands
  599 +============================
  600 +According to IEC 60929, a DALI Master has to repeat several commands within 100 ms, so that DALI-Slaves will execute them.
  601 +
  602 +The DALI Master Terminal KL6811 repeats the commands 32dez to 128dez, 258dez and 259dez (bold marked) automatically to make the the double call from the user program unnecessary.
  603 +
  604 +The DALI Master Terminal KL6811 repeats also the commands 224dez to 255dez, if you have activated this with Bit 1 of the Control-Byte (CB.1) before.
  605 +
  606 +
  607 +DALI Control Device Type List
  608 +=============================
  609 +Type DEC Type HEX Name Comments
  610 +128 0x80 Unknown Device. If one of the devices below don't apply
  611 +129 0x81 Switch Device A Wall-Switch based Controller including, but not limited to ON/OFF devices, Scene switches, dimming device.
  612 +130 0x82 Slide Dimmer An analog/positional dimming controller
  613 +131 0x83 Motion/Occupancy Sensor. A device that indicates the presence of people within a control area.
  614 +132 0x84 Open-loop daylight Controller. A device that outputs current light level and/or sends control messages to actuators based on light passing a threshold.
  615 +133 0x85 Closed-loop daylight controller. A device that outputs current light level and/or sends control messages to actuators based on a change in light level.
  616 +134 0x86 Scheduler. A device that establishes the building mode based on time of day, or which provides control outputs.
  617 +135 0x87 Gateway. An interface to other control systems or communication busses
  618 +136 0x88 Sequencer. A device which sequences lights based on a triggering event
  619 +137 0x89 Power Supply *). A DALI Power Supply device which supplies power for the communication loop
  620 +138 0x8a Emergency Lighting Controller. A device, which is certified for use in control of emergency lighting, or, if not certified, for noncritical backup lighting.
  621 +139 0x8b Analog input unit. A general device with analog input.
  622 +140 0x8c Data Logger. A unit logging data (can be digital or analog data)
  623 +
  624 +
  625 +Flash Variables and Offset in Information
  626 +=========================================
  627 +Memory Name Offset
  628 +Power On Level [0]
  629 +System Failure Level [1]
  630 +Minimum Level [2]
  631 +Maximum Level [3]
  632 +Fade Rate [4]
  633 +Fade Time [5]
  634 +Short Address [6]
  635 +Group 0 through 7 [7]
  636 +Group 8 through 15 [8]
  637 +Scene 0 through 15 [9-24]
  638 +Random Address [25-27]
  639 +Fast Fade Time [28]
  640 +Failure Status [29]
  641 +Operating Mode [30]
  642 +Dimming Curve [31]
  643 +*/
... ...