DALI send/recv library.

Dependents:   dali_sample

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DALI.cpp Source File

DALI.cpp

Go to the documentation of this file.
00001 /*
00002  * DALI send/recv library
00003  * Copyright (c) 2020 Hiroshi Suga
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  */
00006 
00007 /** @file
00008  * @brief DALI send/recv
00009  */
00010  
00011 #include "mbed.h"
00012 #include "DALI.h"
00013 
00014 #define BUFFER_SIZE 20
00015 
00016 #define TIME_BITTIME    833 // us, 1200bps
00017 #define TIME_BITTIME1p2 417 // us, 1200bps 1/2
00018 #define TIME_BITTIME3p4 625 // us, 1200bps 3/4
00019 #define TIME_BETWEEN    10000 // us >22Te
00020 
00021 
00022 DALI::DALI (PinName tx, PinName rx) : _tx(tx), _rx(rx) {
00023     _rx.mode(PullUp);
00024     _rx.fall(this, &DALI::isr_rx);
00025     _rx.rise(this, &DALI::isr_rx);
00026     _tx = 0;
00027 
00028     recv_buf = new CircBuffer<int>(BUFFER_SIZE);
00029     send_buf = new CircBuffer<int>(BUFFER_SIZE);
00030 
00031     mode = 0;
00032     count = 0;
00033     timeflg = 0;
00034     busy = 0;
00035 }
00036 
00037 int DALI::read (enum DALI_FRAME *frame, int *addr, int *value) {
00038     int dat;
00039 
00040     if (recv_buf->dequeue(&dat)) {
00041         if (dat & (1<<16)) {
00042             *frame = BACKWARD;
00043             *value = dat & 0xff;
00044         } else {
00045             if (dat & (1<<15)) {
00046                 // group
00047                 if (dat & (1<<8)) {
00048                     *frame = FORWARD_GROUP_IAP;
00049                 } else {
00050                     *frame = FORWARD_GROUP_DAP;
00051                 }
00052             } else {
00053                 // short
00054                 if (dat & (1<<8)) {
00055                     *frame = FORWARD_SHORT_IAP;
00056                 } else {
00057                     *frame = FORWARD_SHORT_DAP;
00058                 }
00059             }
00060             *addr = (dat >> 9) & 0x3f;
00061             *value = dat & 0xff;
00062         }
00063         return 0;
00064     }
00065     return -1;
00066 }
00067 
00068 int DALI::readable () {
00069     return ! recv_buf->isEmpty();
00070 }
00071 
00072 void DALI::isr_send () {
00073 
00074     if (! busy) {
00075         if (mode) return; // recv working
00076 
00077         _ticker.detach();
00078         // next data
00079         int dat, bit;
00080         busy = 1;
00081         send_buf->dequeue(&dat);
00082         bit = (dat >> 20) & 0x0fff;
00083         send_bit = (1 << bit) << 2;
00084         send_data = dat & 0x0fffff;
00085         halfbit = 0;
00086         _ticker.attach_us(this, &DALI::isr_send, TIME_BITTIME1p2);
00087     }
00088 
00089     if (send_bit & 3) {
00090         // stop bit
00091         _tx = 0;
00092     } else
00093     if ((halfbit == 0 && (send_data & send_bit)) || (halfbit == 1 && !(send_data & send_bit))) {
00094         // low
00095         _tx = 1;
00096     } else {
00097         // high
00098         _tx = 0;
00099     }
00100 
00101     if (halfbit) {
00102         halfbit = 0;
00103         send_bit >>= 1;
00104 
00105         if (send_bit == 0) {
00106             // end of data
00107             _ticker.detach();
00108             busy = 0;
00109             if (! send_buf->isEmpty()) {
00110                 // next data
00111                 _ticker.attach_us(this, &DALI::isr_send, TIME_BETWEEN);
00112             }
00113         }
00114     } else {
00115         halfbit = 1;
00116     }
00117 }
00118 
00119 int DALI::writable () {
00120     return ! send_buf->isFull();
00121 }
00122 
00123 int DALI::write (enum DALI_FRAME frame, int addr, int value) {
00124     int dat, bit;
00125 
00126     switch (frame) {
00127     case FORWARD_SHORT_DAP:
00128         dat = (0<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff);
00129         bit = 16;
00130         break;
00131 
00132     case FORWARD_SHORT_IAP:
00133         dat = (0<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff);
00134         bit = 16;
00135         break;
00136 
00137     case FORWARD_GROUP_DAP:
00138         dat = (1<<15) | ((addr & 0x3f) << 9) | (0<<8) | (value & 0xff);
00139         bit = 16;
00140         break;
00141 
00142     case FORWARD_GROUP_IAP:
00143         dat = (1<<15) | ((addr & 0x3f) << 9) | (1<<8) | (value & 0xff);
00144         bit = 16;
00145         break;
00146 
00147     case BACKWARD:
00148         dat = (value & 0xff);
00149         bit = 8;
00150         break;
00151 
00152     default:
00153         return -1;
00154     }
00155 
00156     dat = ((1<<bit) | dat) << 2; // start bit
00157     dat |= bit << 20;
00158     send_buf->queue(dat);
00159 
00160     if (! busy) {
00161         while (mode); // wait recv
00162         // begin data
00163         busy = 1;
00164         send_buf->dequeue(&dat);
00165         bit = (dat >> 20) & 0x0fff;
00166         send_bit = (1 << bit) << 2;
00167         send_data = dat & 0x0fffff;
00168         halfbit = 0;
00169         _ticker.attach_us(this, &DALI::isr_send, TIME_BITTIME1p2);
00170     }
00171     return 0;
00172 }
00173 
00174 void DALI::isr_rx () {
00175 
00176     if (timeflg || busy) return;
00177 
00178     timeflg = 1;
00179     _timer.detach();
00180     _timer.attach_us(this, &DALI::isr_timer, TIME_BITTIME3p4);
00181 
00182     if (_rx.read() && mode == 0) {
00183         // start bit
00184         mode ++;
00185         recv_data = 0;
00186         recv_bit = 0x8000;
00187     }
00188 }
00189 
00190 void DALI::isr_timer () {
00191     timeflg = 0;
00192     _timer.detach();
00193     _timer.attach_us(this, &DALI::isr_timeout, TIME_BITTIME);
00194 
00195     if (recv_bit) {
00196         // data bit
00197         if (_rx.read()) {
00198             // high
00199             recv_data |= recv_bit;
00200         } else {
00201             // low
00202             recv_data &= ~recv_bit;
00203         }
00204         recv_bit >>= 1;
00205     } else
00206     if (mode == 1) {
00207         if (_rx.read()) {
00208             // error
00209             mode = 0;
00210         } else {
00211             // stop bit 1
00212             mode ++;
00213         }
00214     }
00215 }
00216 
00217 void DALI::isr_timeout () {
00218     timeflg = 0;
00219     _timer.detach();
00220 
00221     if (recv_bit) {
00222         // Backward frame (8bit)
00223         if (mode == 1 && _rx.read() == 0 && !(recv_data & (1<<7))) {
00224             // stop bit 2
00225             recv_data = (1<<16) | (recv_data >> 8);
00226             recv_buf->queue(recv_data);
00227             mode = 0;
00228         } else {
00229             mode = 0;
00230         }
00231     } else {
00232         // Forward frame (16bit)
00233         if (mode == 2 && _rx.read() == 0) {
00234             // stop bit 2
00235             recv_buf->queue(recv_data);
00236             mode = 0;
00237         } else {
00238             mode = 0;
00239         }
00240     }
00241 }