#include "Dali.h" #include Dali::Dali() //constructor { applyWorkAround1Mhz = 0; } void Dali::setTxPin(uint8_t pin) { TxPin = pin; // user sets the digital pin as output pinMode(TxPin, OUTPUT); digitalWrite(TxPin, HIGH); } void Dali::setRxAnalogPin(uint8_t pin) { RxAnalogPin = pin; // user sets the digital pin as output } void Dali::workAround1MhzTinyCore(uint8_t a) { applyWorkAround1Mhz = a; } void Dali::setupAnalogReceive(uint8_t pin) { setRxAnalogPin(pin); // user sets the analog pin as input } void Dali::setupTransmit(uint8_t pin) { setTxPin(pin); speedFactor = 2; //we don't use exact calculation of passed time spent outside of transmitter //because of high ovehead associated with it, instead we use this //emprirically determined values to compensate for the time loss #if F_CPU == 1000000UL uint16_t compensationFactor = 88; //must be divisible by 8 for workaround #elif F_CPU == 8000000UL uint16_t compensationFactor = 12; #else //16000000Mhz uint16_t compensationFactor = 4; #endif #if (F_CPU == 80000000UL) || (F_CPU == 160000000) // ESP8266 80MHz or 160 MHz delay1 = delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2; #else delay1 = (HALF_BIT_INTERVAL >> speedFactor) - compensationFactor; delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2; #if F_CPU == 1000000UL delay2 -= 22; //22+2 = 24 is divisible by 8 if (applyWorkAround1Mhz) { //definition of micro delay is broken for 1MHz speed in tiny cores as of now (May 2013) //this is a workaround that will allow us to transmit on 1Mhz //divide the wait time by 8 delay1 >>= 3; delay2 >>= 3; } #endif #endif } void Dali::transmit(uint8_t cmd1, uint8_t cmd2) // transmit commands to DALI bus (address byte, command byte) { sendBit(1); sendByte(cmd1); sendByte(cmd2); digitalWrite(TxPin, HIGH); } void Dali::sendByte(uint8_t b) { for (int i = 7; i >= 0; i--) { sendBit((b >> i) & 1); } } void Dali::sendBit(int b) { if (b) { sendOne(); } else { sendZero(); } } void Dali::sendZero(void) { digitalWrite(TxPin, HIGH); delayMicroseconds(delay2); digitalWrite(TxPin, LOW); delayMicroseconds(delay1); } void Dali::sendOne(void) { digitalWrite(TxPin, LOW); delayMicroseconds(delay2); digitalWrite(TxPin, HIGH); delayMicroseconds(delay1); } void Dali::busTest() //DALI bus test { int maxLevel; int minLevel; //Luminaries must turn on and turn off. If not, check connection. delay(100); dali.transmit(BROADCAST_C, OFF_C); //Broadcast ON delay(500); dali.transmit(BROADCAST_C, ON_C); //Broadcast OFF delay(100); while (!Serial); //Receive response from luminaries: max and min level dali.transmit(BROADCAST_C, QUERY_STATUS); maxLevel = dali.maxResponseLevel(); dali.transmit(BROADCAST_C, QUERY_STATUS); minLevel = dali.minResponseLevel(); dali.analogLevel = (int)(maxLevel + minLevel) / 2; } void Dali::splitAdd(long input, uint8_t &highbyte, uint8_t &middlebyte, uint8_t &lowbyte) { highbyte = input >> 16; middlebyte = input >> 8; lowbyte = input; } // define min response level int Dali::minResponseLevel() { const uint8_t dalistep = 40; //us uint16_t rxmin = 1024; uint16_t dalidata; long idalistep; for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) { dalidata = analogRead(RxAnalogPin); if (dalidata < rxmin) { rxmin = dalidata; }; delayMicroseconds(dalistep); } return rxmin; } // define max response level int Dali::maxResponseLevel() { const uint8_t dalistep = 40; //us uint16_t rxmax = 0; uint16_t dalidata; long idalistep; for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) { dalidata = analogRead(RxAnalogPin); if (dalidata > rxmax) { rxmax = dalidata; }; delayMicroseconds(dalistep); } return rxmax; } //scan for individual short address void Dali::scanShortAdd() { const int delayTime = 10; const uint8_t start_ind_adress = 0; const uint8_t finish_ind_adress = 127; uint8_t add_byte; uint8_t device_short_add; String response; dali.transmit(BROADCAST_C, OFF_C); // Broadcast Off delay(delayTime); Serial.println("Short addresses:"); for (device_short_add = start_ind_adress; device_short_add <= 63; device_short_add++) { add_byte = 1 + (device_short_add << 1); // convert short address to address byte dali.transmit(add_byte, QUERY_STATUS); //query status if (minResponseLevel() < dali.analogLevel) { response = "YES"; dali.transmit(add_byte, ON_C); // switch on delay(1000); dali.transmit(add_byte, OFF_C); // switch off delay(1000); } else { response = "NO"; } Serial.print("BIN: "); Serial.print(device_short_add, BIN); Serial.print(" "); Serial.print("DEC: "); Serial.print(device_short_add, DEC); Serial.print(" "); Serial.print("HEX: "); Serial.print(device_short_add, HEX); Serial.print(" "); Serial.print("Response: "); Serial.print(response); Serial.println(); } dali.transmit(BROADCAST_C, ON_C); // Broadcast On Serial.println(); delay(delayTime); } int Dali::readBinaryString(char *s) { int result = 0; while (*s) { result <<= 1; if (*s++ == '1') result |= 1; } return result; } bool Dali::cmdCheck(String & input, int & cmd1, int & cmd2) { bool test = true; input.replace(" ", ""); // Delete spaces if (input.length() != 16) { test = false; //check if command contain 16bit } else { for (int i = 0; i <= input.length() - 1; i++) { if ((int)input.charAt(i) == 49 or (int)input.charAt(i) == 48) {} else { test = false; }; }; }; if (test) { cmd1 = readBinaryString(input.substring(0, 8).c_str()); cmd2 = readBinaryString(input.substring(8, 16).c_str()); } return test; } void Dali::initialisation() { const int delaytime = 10; //ms long low_longadd = 0x000000; long high_longadd = 0xFFFFFF; long longadd = (long)(low_longadd + high_longadd) / 2; uint8_t highbyte; uint8_t middlebyte; uint8_t lowbyte; uint8_t short_add = 0; uint8_t cmd2; delay(delaytime); dali.transmit(BROADCAST_C, RESET); delay(delaytime); dali.transmit(BROADCAST_C, RESET); delay(delaytime); dali.transmit(BROADCAST_C, OFF_C); delay(delaytime); dali.transmit(0b10100101, 0b00000000); //initialise delay(delaytime); dali.transmit(0b10100101, 0b00000000); //initialise delay(delaytime); dali.transmit(0b10100111, 0b00000000); //randomise delay(delaytime); dali.transmit(0b10100111, 0b00000000); //randomise Serial.println("Searching fo long addresses:"); while (longadd <= 0xFFFFFF - 2 and short_add <= 64) { while ((high_longadd - low_longadd) > 1) { dali.splitAdd(longadd, highbyte, middlebyte, lowbyte); //divide 24bit adress into three 8bit adresses delay(delaytime); dali.transmit(0b10110001, highbyte); //search HB delay(delaytime); dali.transmit(0b10110011, middlebyte); //search MB delay(delaytime); dali.transmit(0b10110101, lowbyte); //search LB delay(delaytime); dali.transmit(0b10101001, 0b00000000); //compare if (minResponseLevel() > dali.analogLevel) { low_longadd = longadd; } else { high_longadd = longadd; } longadd = (low_longadd + high_longadd) / 2; //center Serial.print("BIN: "); Serial.print(longadd + 1, BIN); Serial.print(" "); Serial.print("DEC: "); Serial.print(longadd + 1, DEC); Serial.print(" "); Serial.print("HEX: "); Serial.print(longadd + 1, HEX); Serial.println(); } // second while if (high_longadd != 0xFFFFFF) { splitAdd(longadd + 1, highbyte, middlebyte, lowbyte); dali.transmit(0b10110001, highbyte); //search HB delay(delaytime); dali.transmit(0b10110011, middlebyte); //search MB delay(delaytime); dali.transmit(0b10110101, lowbyte); //search LB delay(delaytime); dali.transmit(0b10110111, 1 + (short_add << 1)); //program short adress delay(delaytime); dali.transmit(0b10101011, 0b00000000); //withdraw delay(delaytime); dali.transmit(1 + (short_add << 1), ON_C); delay(1000); dali.transmit(1 + (short_add << 1), OFF_C); delay(delaytime); short_add++; Serial.println("Assigning a short address"); high_longadd = 0xFFFFFF; longadd = (low_longadd + high_longadd) / 2; } else { Serial.println("End"); } } // first while dali.transmit(0b10100001, 0b00000000); //terminate dali.transmit(BROADCAST_C, ON_C); //broadcast on } Dali dali;