Thomas Cauwelier / Mbed 2 deprecated visible_light_communication

Dependencies:   SoftSerial SDFileSystem mbed wave_player

Revision:
20:d2a8daeb6eb7
Parent:
19:822d93e0bf34
Child:
21:2a91babf5a6d
--- a/MySoftSerial.cpp	Wed May 10 18:21:14 2017 +0200
+++ b/MySoftSerial.cpp	Sat May 13 16:21:17 2017 +0200
@@ -5,10 +5,19 @@
 #include "MySoftSerial.h"
 #include "Manchester.h"
 
+uint32_t overhead_us = 200 * 1000000 / SystemCoreClock;
+
 MySoftSerial::MySoftSerial(PinName TX, PinName RX, const char *name) : SoftSerial(TX, RX, name) {
+    max_time_between_transmission_us = 100000;
+    calc_required_correction_symbols();
     format(16, SoftSerial::None, 1);
-    timer.reset();
-    timer.start();
+    start_bits = 4;
+    dc_offset_timer.reset();
+    dc_offset_timer.start();
+}
+
+void MySoftSerial::calc_required_correction_symbols() {
+    required_correction_transmissions = (int) ceil(30000.0 / (16 * bit_period));
 }
 
 MySoftSerial::~MySoftSerial() {
@@ -17,8 +26,10 @@
 
 int MySoftSerial::putc(int c) {
     c = Manchester::encode(c);
-    timer.stop();
-    if(timer.read_us() > max_time_between_transmission_us){
+    // check if last transmission was not too long ago
+    dc_offset_timer.stop();
+    if (dc_offset_timer.read_us() > max_time_between_transmission_us) {
+        // transmission was too long ago, must correct the dc offset
         correct_dc_offset();
     }
     return _putc(c);
@@ -26,18 +37,20 @@
 
 int MySoftSerial::getc() {
     int character = _getc();
-    timer.reset();
-    timer.start();
     return Manchester::decode(character);
 }
 
 void MySoftSerial::prepare_tx(int c) {
-
-    SoftSerial::prepare_tx(c);
+    // _char is transmitted lsb first
+    _char = c << start_bits; // make room for start bits
+    _char |= 0b1010; //add start bits (lsb first)
+    _char |= 0xFFFF << (start_bits + _bits); // pad with stop bits
+    _char &= ~(1<<_total_bits); // zero after last stop bit   ~(1<<_total_bits) = ...111101111...
 }
 
 void MySoftSerial::baud(int baudrate) {
     SoftSerial::baud(baudrate);
+    calc_required_correction_symbols();
 }
 
 int MySoftSerial::readable() {
@@ -49,10 +62,86 @@
 }
 
 void MySoftSerial::correct_dc_offset() {
-    for (int i = 0; i < 1; ++i) {
+    for (int i = 0; i < required_correction_transmissions; ++i) {
+        //16 bit_periods
         tx->write(0);
         wait_us(bit_period * 12); // send 12 zeros
         tx->write(1);
         wait_us(bit_period * 4); // send 4 ones
     }
 }
+
+void MySoftSerial::rx_gpio_irq_handler(void) {
+    rxticker.prime();
+    rxticker.setNext(bit_period + (bit_period >> 1) - overhead_us); // jump 1.5 bit periods
+    rx->fall(NULL);
+    rxticker.attach(this, &MySoftSerial::rx_detect_start);
+    start_bit = 1; // start from second bit
+    rx_bit = 0;
+    rx_error = false;
+}
+
+void MySoftSerial::rx_detect_start(void){
+    int val = rx->read();
+
+    // check start pattern
+    // todo store pattern in array or int
+    bool ok;
+    switch(start_bit){
+        case 0:
+            ok = val==0;
+            break;
+        case 1:
+            ok = val==1;
+            break;
+        case 2:
+            ok = val==0;
+            break;
+        case 3:
+            ok = val==1;
+            rxticker.attach(this, &MySoftSerial::tx_handler);
+            break;
+        default:
+            ok = false;
+    }
+
+    if(ok){
+        rx_bit++;
+        rxticker.setNext(bit_period);
+    } else {
+        // start pattern was not correct, this is not a data packet
+        rxticker.detach();
+        rx->fall(this, &SoftSerial::rx_gpio_irq_handler);
+    }
+}
+
+void MySoftSerial::format(int bits, SoftSerial::Parity parity, int stop_bits) {
+    SoftSerial::format(bits, parity, stop_bits);
+    _total_bits = 4 + _bits + _stop_bits;
+}
+
+void MySoftSerial::tx_handler(void) {
+    if (tx_bit == _total_bits) {
+        tx_bit = -1;
+        // transmission done, start measuring time until next transmission
+        dc_offset_timer.reset();
+        dc_offset_timer.start();
+
+        fpointer[TxIrq].call();
+        return;
+    }
+
+    //Flip output
+    int cur_out = tx->read();
+    tx->write(!cur_out);
+
+    //Calculate when to do it again
+    int count = bit_period;
+    tx_bit++;
+    while(((_char >> tx_bit) & 0x01) == !cur_out) {
+        count+=bit_period;
+        tx_bit++;
+    }
+
+    txticker.setNext(count);
+}