Commit ea6e27eec8442c043ec22fc31e136ff2d3f5feff

Authored by NabiyevTR
Committed by GitHub
1 parent b7c9255d

Add files via upload

Dali.cpp 0 → 100644
  1 +
  2 +#include "Dali.h"
  3 +#include <SoftwareSerial.h>
  4 +
  5 +
  6 +
  7 +Dali::Dali() //constructor
  8 +{
  9 + applyWorkAround1Mhz = 0;
  10 +}
  11 +
  12 +
  13 +void Dali::setTxPin(uint8_t pin)
  14 +{
  15 + TxPin = pin; // user sets the digital pin as output
  16 + pinMode(TxPin, OUTPUT);
  17 + digitalWrite(TxPin, HIGH);
  18 +}
  19 +
  20 +void Dali::setRxAnalogPin(uint8_t pin)
  21 +{
  22 + RxAnalogPin = pin; // user sets the digital pin as output
  23 +}
  24 +
  25 +void Dali::workAround1MhzTinyCore(uint8_t a)
  26 +{
  27 + applyWorkAround1Mhz = a;
  28 +}
  29 +
  30 +void Dali::setupAnalogReceive(uint8_t pin)
  31 +{
  32 + setRxAnalogPin(pin); // user sets the analog pin as input
  33 +}
  34 +
  35 +
  36 +void Dali::setupTransmit(uint8_t pin)
  37 +{
  38 + setTxPin(pin);
  39 + speedFactor = 2;
  40 + //we don't use exact calculation of passed time spent outside of transmitter
  41 + //because of high ovehead associated with it, instead we use this
  42 + //emprirically determined values to compensate for the time loss
  43 +
  44 + #if F_CPU == 1000000UL
  45 + uint16_t compensationFactor = 88; //must be divisible by 8 for workaround
  46 + #elif F_CPU == 8000000UL
  47 + uint16_t compensationFactor = 12;
  48 + #else //16000000Mhz
  49 + uint16_t compensationFactor = 4;
  50 + #endif
  51 +
  52 +#if (F_CPU == 80000000UL) || (F_CPU == 160000000) // ESP8266 80MHz or 160 MHz
  53 + delay1 = delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2;
  54 +#else
  55 + delay1 = (HALF_BIT_INTERVAL >> speedFactor) - compensationFactor;
  56 + delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2;
  57 +
  58 + #if F_CPU == 1000000UL
  59 + delay2 -= 22; //22+2 = 24 is divisible by 8
  60 + if (applyWorkAround1Mhz) { //definition of micro delay is broken for 1MHz speed in tiny cores as of now (May 2013)
  61 + //this is a workaround that will allow us to transmit on 1Mhz
  62 + //divide the wait time by 8
  63 + delay1 >>= 3;
  64 + delay2 >>= 3;
  65 + }
  66 + #endif
  67 +#endif
  68 +
  69 + }
  70 +
  71 +
  72 +void Dali::transmit(uint8_t cmd1, uint8_t cmd2) // transmit commands to DALI bus (address byte, command byte)
  73 +{
  74 + sendBit(1);
  75 + sendByte(cmd1);
  76 + sendByte(cmd2);
  77 + digitalWrite(TxPin, HIGH);
  78 +}
  79 +
  80 +
  81 +void Dali::sendByte(uint8_t b)
  82 +{
  83 + for (int i = 7; i >= 0; i--)
  84 + {
  85 + sendBit((b >> i) & 1);
  86 + }
  87 +}
  88 +
  89 +
  90 +void Dali::sendBit(int b)
  91 +{
  92 + if (b) {
  93 + sendOne();
  94 + }
  95 + else {
  96 + sendZero();
  97 + }
  98 +}
  99 +
  100 +
  101 +void Dali::sendZero(void)
  102 +{
  103 + digitalWrite(TxPin, HIGH);
  104 + delayMicroseconds(delay2);
  105 + digitalWrite(TxPin, LOW);
  106 + delayMicroseconds(delay1);
  107 +
  108 +}
  109 +
  110 +
  111 +void Dali::sendOne(void)
  112 +{
  113 + digitalWrite(TxPin, LOW);
  114 + delayMicroseconds(delay2);
  115 + digitalWrite(TxPin, HIGH);
  116 + delayMicroseconds(delay1);
  117 +}
  118 +
  119 +
  120 +void Dali::busTest() //DALI bus test
  121 +{
  122 + int maxLevel;
  123 + int minLevel;
  124 +
  125 + //Luminaries must turn on and turn off. If not, check connection.
  126 + delay(100);
  127 + dali.transmit(BROADCAST_C, OFF_C); //Broadcast ON
  128 + delay(500);
  129 + dali.transmit(BROADCAST_C, ON_C); //Broadcast OFF
  130 + delay(100);
  131 + while (!Serial);
  132 +
  133 + //Receive response from luminaries: max and min level
  134 + dali.transmit(BROADCAST_C, QUERY_STATUS);
  135 + maxLevel = dali.maxResponseLevel();
  136 + dali.transmit(BROADCAST_C, QUERY_STATUS);
  137 + minLevel = dali.minResponseLevel();
  138 +
  139 + dali.analogLevel = (int)(maxLevel + minLevel) / 2;
  140 +
  141 +
  142 +
  143 +
  144 +
  145 +}
  146 +
  147 +
  148 +void Dali::splitAdd(long input, uint8_t &highbyte, uint8_t &middlebyte, uint8_t &lowbyte)
  149 +{
  150 + highbyte = input >> 16;
  151 + middlebyte = input >> 8;
  152 + lowbyte = input;
  153 +}
  154 +
  155 +
  156 +
  157 +// define min response level
  158 +int Dali::minResponseLevel()
  159 +{
  160 +
  161 + const uint8_t dalistep = 40; //us
  162 + uint16_t rxmin = 1024;
  163 + uint16_t dalidata;
  164 + long idalistep;
  165 +
  166 +
  167 +
  168 + for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) {
  169 + dalidata = analogRead(RxAnalogPin);
  170 + if (dalidata < rxmin) {
  171 + rxmin = dalidata;
  172 + };
  173 + delayMicroseconds(dalistep);
  174 + }
  175 + return rxmin;
  176 +}
  177 +
  178 +// define max response level
  179 +int Dali::maxResponseLevel()
  180 +{
  181 +
  182 + const uint8_t dalistep = 40; //us
  183 + uint16_t rxmax = 0;
  184 + uint16_t dalidata;
  185 + long idalistep;
  186 +
  187 +
  188 + for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) {
  189 + dalidata = analogRead(RxAnalogPin);
  190 + if (dalidata > rxmax) {
  191 + rxmax = dalidata;
  192 + };
  193 + delayMicroseconds(dalistep);
  194 + }
  195 + return rxmax;
  196 +}
  197 +
  198 +
  199 +//scan for individual short address
  200 +void Dali::scanShortAdd()
  201 +{
  202 +
  203 + const int delayTime = 10;
  204 + const uint8_t start_ind_adress = 0;
  205 + const uint8_t finish_ind_adress = 127;
  206 + uint8_t add_byte;
  207 + uint8_t device_short_add;
  208 + String response;
  209 +
  210 + dali.transmit(BROADCAST_C, OFF_C); // Broadcast Off
  211 + delay(delayTime);
  212 + Serial.println("Short addresses:");
  213 +
  214 + for (device_short_add = start_ind_adress; device_short_add <= 63; device_short_add++) {
  215 +
  216 + add_byte = 1 + (device_short_add << 1); // convert short address to address byte
  217 +
  218 +
  219 + dali.transmit(add_byte, QUERY_STATUS); //query status
  220 +
  221 +
  222 + if (minResponseLevel() < dali.analogLevel) {
  223 + response = "YES";
  224 + dali.transmit(add_byte, ON_C); // switch on
  225 + delay(1000);
  226 + dali.transmit(add_byte, OFF_C); // switch off
  227 + delay(1000);
  228 + }
  229 + else {
  230 + response = "NO";
  231 + }
  232 +
  233 +
  234 + Serial.print("BIN: ");
  235 + Serial.print(device_short_add, BIN);
  236 + Serial.print(" ");
  237 + Serial.print("DEC: ");
  238 + Serial.print(device_short_add, DEC);
  239 + Serial.print(" ");
  240 + Serial.print("HEX: ");
  241 + Serial.print(device_short_add, HEX);
  242 + Serial.print(" ");
  243 + Serial.print("Response: ");
  244 + Serial.print(response);
  245 + Serial.println();
  246 +
  247 + }
  248 +
  249 + dali.transmit(BROADCAST_C, ON_C); // Broadcast On
  250 + Serial.println();
  251 + delay(delayTime);
  252 +
  253 +}
  254 +
  255 +
  256 +int Dali::readBinaryString(char *s)
  257 +{
  258 + int result = 0;
  259 + while (*s) {
  260 + result <<= 1;
  261 + if (*s++ == '1') result |= 1;
  262 + }
  263 + return result;
  264 +}
  265 +
  266 +
  267 +bool Dali::cmdCheck(String & input, int & cmd1, int & cmd2)
  268 +{
  269 + bool test = true;
  270 +
  271 + input.replace(" ", ""); // Delete spaces
  272 +
  273 + if (input.length() != 16) {
  274 + test = false; //check if command contain 16bit
  275 + }
  276 + else {
  277 + for (int i = 0; i <= input.length() - 1; i++) {
  278 + if ((int)input.charAt(i) == 49 or (int)input.charAt(i) == 48) {}
  279 + else {
  280 + test = false;
  281 + };
  282 + };
  283 + };
  284 +
  285 + if (test) {
  286 + cmd1 = readBinaryString(input.substring(0, 8).c_str());
  287 + cmd2 = readBinaryString(input.substring(8, 16).c_str());
  288 + }
  289 +
  290 + return test;
  291 +}
  292 +
  293 +void Dali::initialisation() {
  294 +
  295 + const int delaytime = 10; //ms
  296 +
  297 + long low_longadd = 0x000000;
  298 + long high_longadd = 0xFFFFFF;
  299 + long longadd = (long)(low_longadd + high_longadd) / 2;
  300 + uint8_t highbyte;
  301 + uint8_t middlebyte;
  302 + uint8_t lowbyte;
  303 + uint8_t short_add = 0;
  304 + uint8_t cmd2;
  305 +
  306 +
  307 + delay(delaytime);
  308 + dali.transmit(BROADCAST_C, RESET);
  309 + delay(delaytime);
  310 + dali.transmit(BROADCAST_C, RESET);
  311 + delay(delaytime);
  312 + dali.transmit(BROADCAST_C, OFF_C);
  313 + delay(delaytime);
  314 + dali.transmit(0b10100101, 0b00000000); //initialise
  315 + delay(delaytime);
  316 + dali.transmit(0b10100101, 0b00000000); //initialise
  317 + delay(delaytime);
  318 + dali.transmit(0b10100111, 0b00000000); //randomise
  319 + delay(delaytime);
  320 + dali.transmit(0b10100111, 0b00000000); //randomise
  321 +
  322 + Serial.println("Searching fo long addresses:");
  323 +
  324 + while (longadd <= 0xFFFFFF - 2 and short_add <= 64) {
  325 + while ((high_longadd - low_longadd) > 1) {
  326 +
  327 + dali.splitAdd(longadd, highbyte, middlebyte, lowbyte); //divide 24bit adress into three 8bit adresses
  328 + delay(delaytime);
  329 + dali.transmit(0b10110001, highbyte); //search HB
  330 + delay(delaytime);
  331 + dali.transmit(0b10110011, middlebyte); //search MB
  332 + delay(delaytime);
  333 + dali.transmit(0b10110101, lowbyte); //search LB
  334 + delay(delaytime);
  335 + dali.transmit(0b10101001, 0b00000000); //compare
  336 +
  337 + if (minResponseLevel() > dali.analogLevel)
  338 + {
  339 + low_longadd = longadd;
  340 + }
  341 + else
  342 + {
  343 + high_longadd = longadd;
  344 + }
  345 +
  346 + longadd = (low_longadd + high_longadd) / 2; //center
  347 +
  348 + Serial.print("BIN: ");
  349 + Serial.print(longadd + 1, BIN);
  350 + Serial.print(" ");
  351 + Serial.print("DEC: ");
  352 + Serial.print(longadd + 1, DEC);
  353 + Serial.print(" ");
  354 + Serial.print("HEX: ");
  355 + Serial.print(longadd + 1, HEX);
  356 + Serial.println();
  357 + } // second while
  358 +
  359 +
  360 + if (high_longadd != 0xFFFFFF)
  361 + {
  362 + splitAdd(longadd + 1, highbyte, middlebyte, lowbyte);
  363 + dali.transmit(0b10110001, highbyte); //search HB
  364 + delay(delaytime);
  365 + dali.transmit(0b10110011, middlebyte); //search MB
  366 + delay(delaytime);
  367 + dali.transmit(0b10110101, lowbyte); //search LB
  368 + delay(delaytime);
  369 + dali.transmit(0b10110111, 1 + (short_add << 1)); //program short adress
  370 + delay(delaytime);
  371 + dali.transmit(0b10101011, 0b00000000); //withdraw
  372 + delay(delaytime);
  373 + dali.transmit(1 + (short_add << 1), ON_C);
  374 + delay(1000);
  375 + dali.transmit(1 + (short_add << 1), OFF_C);
  376 + delay(delaytime);
  377 + short_add++;
  378 +
  379 + Serial.println("Assigning a short address");
  380 +
  381 + high_longadd = 0xFFFFFF;
  382 + longadd = (low_longadd + high_longadd) / 2;
  383 +
  384 + }
  385 + else {
  386 + Serial.println("End");
  387 + }
  388 + } // first while
  389 +
  390 +
  391 + dali.transmit(0b10100001, 0b00000000); //terminate
  392 + dali.transmit(BROADCAST_C, ON_C); //broadcast on
  393 +}
  394 +
  395 +
  396 +
  397 +
  398 +
  399 +
  400 + Dali dali;
... ...
Dali.h 0 → 100644
  1 +
  2 +
  3 +#ifndef dali_h
  4 +#define dali_h
  5 +#include <SoftwareSerial.h>
  6 +
  7 +//timer scaling factors for different transmission speeds
  8 +#define MAN_300 0
  9 +#define MAN_600 1
  10 +#define MAN_1200 2
  11 +#define MAN_2400 3
  12 +#define MAN_4800 4
  13 +#define MAN_9600 5
  14 +#define MAN_19200 6
  15 +#define MAN_38400 7
  16 +
  17 +/*
  18 +Timer 2 in the ATMega328 and Timer 1 in a ATtiny85 is used to find the time between
  19 +each transition coming from the demodulation circuit.
  20 +Their setup is for sampling the input in regular intervals.
  21 +For practical reasons we use power of 2 timer prescaller for sampling,
  22 +for best timing we use pulse lenght as integer multiple of sampling speed.
  23 +We chose to sample every 8 ticks, and pulse lenght of 48 ticks
  24 +thats 6 samples per pulse, lower sampling rate (3) will not work well for
  25 +innacurate clocks (like internal oscilator) higher sampling rate (12) will
  26 +cause too much overhead and will not work at higher transmission speeds.
  27 +This gives us 16000000Hz/48/256 = 1302 pulses per second (so it's not really 1200)
  28 +At different transmission speeds or on different microcontroller frequencies, clock prescaller is adjusted
  29 +to be compatible with those values. We allow about 50% clock speed difference both ways
  30 +allowing us to transmit even with up to 100% in clock speed difference
  31 +*/
  32 +
  33 +// DALI coomands
  34 +#define BROADCAST_DP 0b11111110
  35 +#define BROADCAST_C 0b11111111
  36 +#define ON_DP 0b11111110
  37 +#define OFF_DP 0b00000000
  38 +#define ON_C 0b00000101
  39 +#define OFF_C 0b00000000
  40 +# define QUERY_STATUS 0b10010000
  41 +# define RESET 0b00100000
  42 +
  43 +
  44 +//setup timing for transmitter
  45 +#define HALF_BIT_INTERVAL 1666
  46 +
  47 +
  48 +
  49 +
  50 +
  51 +#if defined(ARDUINO) && ARDUINO >= 100
  52 + #include "Arduino.h"
  53 +#else
  54 + #include "WProgram.h"
  55 + #include <pins_arduino.h>
  56 +#endif
  57 +
  58 +class Dali
  59 +{
  60 + public:
  61 + Dali(); //the constructor
  62 + void setTxPin(uint8_t pin); //set the arduino digital pin for transmit.
  63 + void setRxAnalogPin(uint8_t pin); //set the arduino digital pin for receive.
  64 + void workAround1MhzTinyCore(uint8_t a = 1); //apply workaround for defect in tiny Core library for 1Mhz
  65 + void setupTransmit(uint8_t pin); //set up transmission
  66 + void setupAnalogReceive(uint8_t pin);
  67 + void transmit(uint8_t cmd1, uint8_t cmd2); //transmit 16 bits of data
  68 + void scanShortAdd(); //scan for short address
  69 + void busTest(); // bus test
  70 + void initialisation(); //initialization of new luminaries
  71 + bool cmdCheck(String & input, int & cmd1, int & cmd2);
  72 +
  73 + int minResponseLevel();
  74 + int maxResponseLevel();
  75 +
  76 + uint8_t speedFactor;
  77 + uint16_t delay1;
  78 + uint16_t delay2;
  79 +
  80 + long daliTimeout = 20000; //us, DALI response timeout
  81 + int analogLevel = 870; //analog border level (less - "0"; more - "1")
  82 +
  83 +
  84 +
  85 +
  86 + private:
  87 +
  88 + void sendByte(uint8_t b); //transmit 8 bits of data
  89 + void sendBit(int b); //transmit 1 bit of data
  90 + void sendZero(void); //transmit "0"
  91 + void sendOne(void); //transmit "1"
  92 + void splitAdd(long input, uint8_t &highbyte, uint8_t &middlebyte, uint8_t &lowbyte); //split random address
  93 +
  94 +
  95 + int readBinaryString(char *s);
  96 +
  97 + uint8_t TxPin;
  98 + uint8_t RxAnalogPin;
  99 + uint8_t applyWorkAround1Mhz;
  100 + uint8_t rxAnalogPin = 0;
  101 +
  102 +};//end of class Dali
  103 +
  104 +// Cant really do this as a real C++ class, since we need to have
  105 +// an ISR
  106 +extern "C"
  107 +{
  108 +
  109 +
  110 + }
  111 +
  112 +extern Dali dali;
  113 +
  114 +#endif
... ...
keywords.txt 0 → 100644
  1 + dali KEYWORD1 setTxPin KEYWORD2 setRxAnalogPin KEYWORD2 workAround1MhzTinyCore KEYWORD2 setupTransmit KEYWORD2 setupAnalogReceive KEYWORD2 transmit KEYWORD2 scanShortAdd KEYWORD2 busTest KEYWORD2 initialisation KEYWORD2 cmdCheck KEYWORD2 minResponseLevel KEYWORD2 maxResponseLevel KEYWORD2
0 2 \ No newline at end of file
... ...