Software UART program using Infra-Red LED and IR-Detector

Dependents:   TestVirtualisation Bf_SoftSerial_IR

Files at this revision

API Documentation at this revision

Comitter:
kenjiArai
Date:
Fri May 15 04:11:01 2020 +0000
Parent:
14:dc766032cdd6
Commit message:
Updated several functions based on SoftSerial library.

Changed in this revision

SoftSerial_IR.cpp Show annotated file Show diff for this revision Revisions of this file
SoftSerial_IR.h Show annotated file Show diff for this revision Revisions of this file
SoftSerial_Ticker_IR.h Show annotated file Show diff for this revision Revisions of this file
SoftSerial_rx_IR.cpp Show annotated file Show diff for this revision Revisions of this file
SoftSerial_tx_IR.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_IR.cpp
--- a/SoftSerial_IR.cpp	Fri Dec 28 10:03:35 2018 +0000
+++ b/SoftSerial_IR.cpp	Fri May 15 04:11:01 2020 +0000
@@ -1,17 +1,19 @@
-// Apply for Infrared LED and IR-Detector
-//      Modified by JH1PJL Dec. 28th, 2018
+// Modified by K.Arai / JH1PJL     May 15th, 2020
 
 #include "SoftSerial_IR.h"
 
-SoftSerial_IR::SoftSerial_IR(PinName TX, PinName RX, const char* name) {
+SoftSerial_IR::SoftSerial_IR(PinName TX, PinName RX, const char* name)
+{
     tx_en = rx_en = false;
     read_buffer = 0;
     if (TX != NC) {
+        //tx = new DigitalOut(TX);
         tx = new PwmOut(TX);
         tx_en = true;
+        tx->period(1.0f / 38000.0f);    // PWM = 38kHz
+        //tx->write(1);
         tx->write(0.0f);
         tx_bit = -1;
-        tx->period(1.0f / 38000.0f);    // PWM = 38kHz
         txticker.attach(this, &SoftSerial_IR::tx_handler);
     }
     if (RX != NC) {
@@ -19,39 +21,32 @@
         rx_en = true;
         out_valid = false;
         rxticker.attach(this, &SoftSerial_IR::rx_handler);
-        rx->fall(this, &SoftSerial_IR::rx_gpio_irq_handler);
+        rx->fall(callback(this, &SoftSerial_IR::rx_gpio_irq_handler));
     }
-    
+
     baud(2400);
     format();
-    set_parameter();
 }
 
-SoftSerial_IR::~SoftSerial_IR() {
-    if (tx_en){
+SoftSerial_IR::~SoftSerial_IR()
+{
+    if (tx_en) {
         delete(tx);
     }
-    if (rx_en){
+    if (rx_en) {
         delete(rx);
     }
 }
 
-void SoftSerial_IR::baud(int baudrate) {
+void SoftSerial_IR::baud(int baudrate)
+{
     bit_period = 1000000 / baudrate;
 }
 
-void SoftSerial_IR::format(int bits, Parity parity, int stop_bits) {
+void SoftSerial_IR::format(int bits, Parity parity, int stop_bits)
+{
     _bits = bits;
     _parity = parity;
     _stop_bits = stop_bits;
-    _total_bits = 1 + _bits + _stop_bits + (bool)_parity;
+    _total_bits = 2 + _bits + _stop_bits + (bool)_parity;
 }
-
-void SoftSerial_IR::set_parameter(
-        uint32_t tick_offset,
-        int32_t rx_detect_center_offset
-    )
-{
-    timestamp_offset = tick_offset;
-    overhead_us_IR = rx_detect_center_offset;
-}
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_IR.h
--- a/SoftSerial_IR.h	Fri Dec 28 10:03:35 2018 +0000
+++ b/SoftSerial_IR.h	Fri May 15 04:11:01 2020 +0000
@@ -1,29 +1,54 @@
-// Apply for Infrared LED and IR-Detector
-//      Modified by JH1PJL Dec. 28th, 2018
+/*
+    Original Library by Erik- & SonyPony
+    https://os.mbed.com/users/Sissors/code/SoftSerial/
+
+    Modified by K.Arai / JH1PJL     May 15th, 2020
 
-#ifndef SOFTSERIALIR_H
-#define SOFTSERIALIR_H
+    modified functions
+        tx_handler()
+        prepare_tx()
+        prime()
+        rx_gpio_irq_handler() and others
+ */
+
+#ifndef SOFTSERIAL_IR_H
+#define SOFTSERIAL_IR_H
 
 #include "mbed.h"
 #include "SoftSerial_Ticker_IR.h"
 
+#define DEBUG_TIMING    2   // 0=no debug, 1=tx, 2=rx
+
+#if (MBED_MAJOR_VERSION == 2)
+#   define  YIELD   {;}
+#elif (MBED_MAJOR_VERSION == 5)
+#   define  YIELD   {ThisThread::yield();}
+#endif
+
 /** A software serial implementation
  *
  */
-class SoftSerial_IR: public Stream {
+class SoftSerial_IR: public Stream
+{
 
 public:
     /**
     * Constructor
     *
     * @param TX Name of the TX pin, NC for not connected
-    * @param RX Name of the RX pin, NC for not connected, 
-    *           must be capable of being InterruptIn
+    * @param RX Name of the RX pin, NC for not connected,
+    *        must be capable of being InterruptIn
     * @param name Name of the connection
     */
     SoftSerial_IR(PinName TX, PinName RX, const char* name = NULL);
     virtual ~SoftSerial_IR();
 
+    /** Set the baud rate of the serial port
+     *
+     *  @param baudrate The baudrate of the serial port (default = 2400).
+     */
+    void baud(int baudrate);
+
     enum Parity {
         None = 0,
         Odd,
@@ -41,8 +66,9 @@
      *
      *  @param bits The number of bits in a word (default = 8)
      *  @param parity The parity used
-     *   (SerialBase::None, SerialBase::Odd, SerialBase::Even,
-     *    SerialBase::Forced1, SerialBase::Forced0; default = SerialBase::None)
+     *   (SoftSerial_IR::None, SoftSerial_IR::Odd, SoftSerial_IR::Even,
+     *   SoftSerial_IR::Forced1, SoftSerial_IR::Forced0;
+     *   default = SoftSerial_IR::None)
      *  @param stop The number of stop bits (default = 1)
      */
     void format(int bits=8, Parity parity=SoftSerial_IR::None, int stop_bits=1);
@@ -66,51 +92,43 @@
     /** Attach a function to call whenever a serial interrupt is generated
      *
      *  @param fptr A pointer to a void function, or 0 to set as none
-     *  @param type Which serial interrupt to attach the member function to
-     *         (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
+     *  @param type Which serial interrupt to attach the member function
+     *       to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
      */
-    void attach(void (*fptr)(void), IrqType type=RxIrq) {
-        fpointer[type].attach(fptr);
+    void attach(void (*fptr)(void), IrqType type=RxIrq)
+    {
+        fpointer[type] = Callback<void()>(fptr);
     }
 
-    /** Attach a member function to call whenever a serial interrupt
-     *   is generated
+    /** Attach a member function to call
+     *      whenever a serial interrupt is generated
      *
      *  @param tptr pointer to the object to call the member function on
      *  @param mptr pointer to the member function to be called
      *  @param type Which serial interrupt to attach the member function
-     *         to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
+     *       to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
      */
     template<typename T>
-    void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) {
-        fpointer[type].attach(tptr, mptr);
+    void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq)
+    {
+        fpointer[type] = Callback<void()>(tptr, mptr);
     }
 
     /** Generate a break condition on the serial line
      */
     void send_break();
 
-    /** Set adjust parameter
-     *
-     *  @param tick_offset  Due to timestamp offset, need adjust it
-     *  @param rx_detect_center_offset offset for RX bit Hi&Lo detection timing 
-     */
-    void set_parameter(uint32_t tick_offset = 3550 ,
-                       int32_t rx_detect_center_offset = -50);
-
 protected:
+    //DigitalOut *tx;
     PwmOut *tx;
     InterruptIn *rx;
-  
+
     bool tx_en, rx_en;
     int bit_period;
     int _bits, _stop_bits, _total_bits;
     Parity _parity;
-    
-    FunctionPointer fpointer[2];
 
-    int32_t overhead_us_IR;
-    uint32_t timestamp_offset;
+    Callback<void()>  fpointer[2];
 
     //rx
     void rx_gpio_irq_handler(void);
@@ -119,19 +137,20 @@
     volatile int out_buffer;
     volatile bool out_valid;
     bool rx_error;
-    FlexTicker_IR rxticker;
-    
+    FlexTicker rxticker;
+
+    bool rx_1st;
+    uint32_t rx_st_time;
+
     //tx
     void tx_handler(void);
     void prepare_tx(int c);
-    FlexTicker_IR txticker;
+    FlexTicker txticker;
     int _char;
     volatile int tx_bit;
 
     virtual int _getc();
     virtual int _putc(int c);
-
-    void baud(int baudrate);
 };
 
 #endif
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_Ticker_IR.h
--- a/SoftSerial_Ticker_IR.h	Fri Dec 28 10:03:35 2018 +0000
+++ b/SoftSerial_Ticker_IR.h	Fri May 15 04:11:01 2020 +0000
@@ -1,42 +1,47 @@
-// Apply for Infrared LED and IR-Detector
-//      Modified by JH1PJL Dec. 28th, 2018
+//A modified version of the regular ticker/timeout libraries
+//      to allow us to do timeout without losing accuracy
 
-// A modified version of the regular ticker/timeout libraries 
-//  to allow us to do timeout without losing accuracy
+// Modified by K.Arai / JH1PJL     May 15th, 2020
 
-#ifndef FLEXTICKERIR_H
-#define FLEXTICKERIR_H
+#ifndef FLEXTICKER_H
+#define FLEXTICKER_H
 
 #include "mbed.h"
 
-class FlexTicker_IR: public TimerEvent {
-    public:
+class FlexTicker: public TimerEvent
+{
+public:
     template<typename T>
-    void attach(T* tptr, void (T::*mptr)(void)) {
-        _function.attach(tptr, mptr);
+    void attach(T* tptr, void (T::*mptr)(void))
+    {
+        _function = Callback<void()>(tptr, mptr);
     }
- 
+
     /** Detach the function
      */
-    void detach() {
+    void detach()
+    {
         remove();
     }
-    
-    void setNext(int delay) {
+
+    void setNext(int delay)
+    {
         insert(event.timestamp + delay);
     }
-    
-    void prime(uint32_t offset) {
-        event.timestamp = us_ticker_read() - offset;
+
+    void prime(int comp_time = 0)
+    {
+        event.timestamp = us_ticker_read() + comp_time;
     }
- 
+
 protected:
-    virtual void handler() {
+    virtual void handler()
+    {
         _function.call();
     }
- 
+
     unsigned int _delay;
-    FunctionPointer _function;
+    Callback<void()> _function;
 };
 
 #endif
\ No newline at end of file
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_rx_IR.cpp
--- a/SoftSerial_rx_IR.cpp	Fri Dec 28 10:03:35 2018 +0000
+++ b/SoftSerial_rx_IR.cpp	Fri May 15 04:11:01 2020 +0000
@@ -1,44 +1,100 @@
-// Apply for Infrared LED and IR-Detector
-//      Modified by JH1PJL Dec. 28th, 2018
+// Modified by K.Arai / JH1PJL     May 15th, 2020
 
 #include "SoftSerial_IR.h"
 
-//extern DigitalOut  myled;    // Debug
+//------------------------------------------------------------------------------
+#if     defined(TARGET_NUCLEO_L152RE)
+#       define MAGIC_NUM        (-560)
+#elif   defined(TARGET_NUCLEO_F401RE)
+#       define MAGIC_NUM        (-205)
+#elif   defined(TARGET_NUCLEO_F411RE)
+#       define MAGIC_NUM        (-180)
+#elif   defined(TARGET_NUCLEO_F446RE)
+#       define MAGIC_NUM        (-115)
+#elif   defined(TARGET_NUCLEO_L432KC)
+#       define MAGIC_NUM        (-50)
+#elif   defined(TARGET_NUCLEO_L476RG)
+#       define MAGIC_NUM        (-50)
+#elif   defined(TARGET_K64F)
+#       define MAGIC_NUM        (0)
+#else
+#       warning "you need to tune MAGIC_NUM! in SoftSerial_rx_IR.cpp"
+#       define MAGIC_NUM        (0)
+#endif
+//------------------------------------------------------------------------------
 
-int SoftSerial_IR::_getc( void ) {
-    while(!readable());
+
+// please make a constructor in main.cpp if you use below pc & led
+#if DEBUG_TIMING == 2
+    extern Serial pc;
+    extern DigitalOut test_point;
+#   define TP_ON   {test_point = 1;}
+#   define TP_OFF  {test_point = 0;}
+#   define DBG_PRINTF(...) pc.printf(__VA_ARGS__)
+#else
+#   define TP_ON   {;}
+#   define TP_OFF  {;}
+#   define DBG_PRINTF(...) {;}
+#endif
+
+
+int SoftSerial_IR::_getc( void )
+{
+    while(!readable()) {
+        YIELD;
+    }
     out_valid = false;
     return out_buffer;
 }
 
-int SoftSerial_IR::readable(void) {
+int SoftSerial_IR::readable(void)
+{
     return out_valid;
 }
 
 //Start receiving byte
-void SoftSerial_IR::rx_gpio_irq_handler(void) {
-    //myled = !myled; // Debug
-    rxticker.prime(timestamp_offset);
-    rxticker.setNext(bit_period + (bit_period >> 1) - overhead_us_IR);
+void SoftSerial_IR::rx_gpio_irq_handler(void)
+{
+    TP_ON;
+    rxticker.prime(MAGIC_NUM);
     rx->fall(NULL);
     rx_bit = 0;
     rx_error = false;
-};    
+    // dummy setting for 1st timer interrupt
+    rx_1st = true;
+    rx_st_time = us_ticker_read();
+    rxticker.setNext(10);
+    TP_OFF;
+};
 
-void SoftSerial_IR::rx_handler(void) {
-    //myled = !myled; // Debug
+void SoftSerial_IR::rx_handler(void)
+{
+    TP_ON;
+    // dummy IRQ for 1st shot
+    if (rx_1st) {
+        rx_1st = false;
+        int next_preiod = us_ticker_read() - rx_st_time;
+        next_preiod = bit_period + (bit_period >> 1) - next_preiod;
+        if (next_preiod > 0) {
+            rxticker.setNext(next_preiod);
+        } else {
+            rxticker.setNext(5);
+        }
+        TP_OFF;
+        return;
+    }
     //Receive data
     int val = rx->read();
- 
+
     rxticker.setNext(bit_period);
     rx_bit++;
-    
-    
+
     if (rx_bit <= _bits) {
         read_buffer |= val << (rx_bit - 1);
+        TP_OFF;
         return;
     }
-    
+
     //Receive parity
     bool parity_count;
     if (rx_bit == _bits + 1) {
@@ -63,26 +119,31 @@
                 if ((!parity_count) && (_parity == Odd))
                     rx_error = true;
                 return;
+            case None:
+            default:
+                ;
         }
     }
-    
+
     //Receive stop
     if (rx_bit < _bits + (bool)_parity + _stop_bits) {
         if (!val)
             rx_error = true;
+        TP_OFF;
         return;
-    }    
-    
+    }
+
     //The last stop bit
     if (!val)
         rx_error = true;
-    
+
     if (!rx_error) {
         out_valid = true;
         out_buffer = read_buffer;
         fpointer[RxIrq].call();
     }
     read_buffer = 0;
-    rxticker.detach(); 
-    rx->fall(this, &SoftSerial_IR::rx_gpio_irq_handler);
+    rxticker.detach();
+    rx->fall(callback(this, &SoftSerial_IR::rx_gpio_irq_handler));
+    TP_OFF;
 }
diff -r dc766032cdd6 -r 8d343be3382d SoftSerial_tx_IR.cpp
--- a/SoftSerial_tx_IR.cpp	Fri Dec 28 10:03:35 2018 +0000
+++ b/SoftSerial_tx_IR.cpp	Fri May 15 04:11:01 2020 +0000
@@ -1,91 +1,124 @@
-// Apply for Infrared LED and IR-Detector
-//      Modified by JH1PJL Dec. 28th, 2018
+// Modified by K.Arai / JH1PJL     May 15th, 2020
 
 #include "SoftSerial_IR.h"
 
+// please make a constructor in main.cpp if you use below pc & led
+#if DEBUG_TIMING == 1
+    extern Serial pc;
+    extern DigitalOut test_point;
+#   define TP_ON   {test_point = 1;}
+#   define TP_OFF  {test_point = 0;}
+#   define DBG_PRINTF(...) pc.printf(__VA_ARGS__)
+#else
+#   define TP_ON   {;}
+#   define TP_OFF  {;}
+#   define DBG_PRINTF(...) {;}
+#endif
+
 int SoftSerial_IR::_putc(int c)
 {
-    while(!writeable());
+    while(!writeable()) {
+        YIELD;
+    }
     prepare_tx(c);
     tx_bit = 0;
-    txticker.prime(timestamp_offset);
+    //tx->write(1);
+    tx->write(0.0f);    // output 1
+    txticker.prime();
     tx_handler();
     return 0;
 }
 
 void SoftSerial_IR::send_break(void) {
-    while(!writeable());
+    while(!writeable()) {
+        YIELD;
+    }
     //Just to make sure it appears as non-writable to other threads/IRQs
-    tx_bit = 0;
+    tx_bit = 0;         
+    //tx->write(0);
     tx->write(0.5f);    // output 0
     wait_us((bit_period * _total_bits * 3) / 2);
+    //tx->write(1);
     tx->write(0.0f);    // output 1
     tx_bit = -1;
 }
 
 int SoftSerial_IR::writeable(void)
 {
-    if (!tx_en)
+    if (!tx_en) {
         return false;
-    if (tx_bit == -1)
+    }
+    if (tx_bit == -1) {
         return true;
+    }
     return false;
 }
 
 void SoftSerial_IR::tx_handler(void)
 {
+    TP_ON;
     if (tx_bit == _total_bits) {
         tx_bit = -1;
+        //tx->write(1);
+        tx->write(0.0f);    // output 1
         fpointer[TxIrq].call();
+        TP_OFF;
         return;
     }
-
-    //Flip output
-    float tx_out = tx->read();
-    int cur_out = 0;
-    if (tx_out == 0.5f){    // current duty 50%
-        cur_out = 0;        // current = 0
-        tx->write(0.0f);    // output port 0 to 1
+    if (tx_bit == 0){
+        //tx->write(1);
+        tx->write(0.0f);    // output 1
+        txticker.setNext(10);
     } else {
-        cur_out = 1;        // current = 1
-        tx->write(0.5f);    // output port 1 to 0
+        int bitchk = _char >> tx_bit;
+        if (bitchk & 1) {
+            //tx->write(1);
+            tx->write(0.0f);    // output 1
+        } else {
+            //tx->write(0);
+            tx->write(0.5f);    // output 0
+        }
+        txticker.setNext(bit_period);
     }
-
-    //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);
+    TP_OFF;
 }
 
 void SoftSerial_IR::prepare_tx(int c)
 {
-    _char = c << 1;
+    _char = c << 2;   // set start bit as bit1 and dummy as bit0
 
     bool parity;
     switch (_parity) {
         case Forced1:
             _char |= 1 << (_bits + 1);
+            break;
         case Even:
             parity = false;
             for (int i = 0; i<_bits; i++) {
-                if (((_char >> i) & 0x01) == 1)
+                if (((_char >> i) & 0x01) == 1) {
                     parity = !parity;
+                }
             }
             _char |= parity << (_bits + 1);
+            break;
         case Odd:
             parity = true;
             for (int i = 0; i<_bits; i++) {
-                if (((_char >> i) & 0x01) == 1)
+                if (((_char >> i) & 0x01) == 1) {
                     parity = !parity;
+                }
             }
             _char |= parity << (_bits + 1);
+            break;
+        case Forced0:
+        case None:
+        default:
+            ;
     }
-    
-    _char |= 0xFFFF << (1 + _bits + (bool)_parity);
-    _char &= ~(1<<_total_bits);
+    // added one dummy at LSB bit
+    int num = 1 + _bits + (bool)_parity + 1;
+    _char |= 0xffffffff << num;
+    _char |= 1UL;
+    _char &= ~(1 << _total_bits);
 }