Renamed

Dependencies:   mbed

bit_send.cpp

Committer:
ffxx68
Date:
2022-03-29
Revision:
5:062962db7a48
Parent:
2:dff96be9617e

File content as of revision 5:062962db7a48:

#include "mbed.h" 
#include "bit_send.h"

DigitalOut bit_out_port(D5);
DigitalOut led1(LED1);
// Serial pc1(USBTX,USBRX); defined in main
Ticker bit_ticker;
Timer total_time1;
Timer bit_time;

// volatile when read & write from both interrupts and main
// static is to keep value between calls
volatile uint8_t   bit_sync_flags; 
volatile uint64_t  bit_buffer; // a 64-bits buffer (position-masked)
volatile uint64_t  bit_read_mask; //  bit read position  
volatile uint64_t  bit_write_mask; // bit write position  
volatile uint64_t  bit_last_mask; //  position of last bit sent 

volatile uint8_t   bit_repeat_count = 0;
volatile uint8_t   bit_cycle_count = 0;

volatile uint32_t  total_switch_cnt = 0;

// To be called before a new stream is sent
void bitHandlerInit( void ) {

        debug_printf("bitHandlerInit\r\n") ;
       
        // timing ticker counters
        bit_repeat_count = 0;
        bit_cycle_count = 0;

        bit_sync_flags = 0; // clear all (set when needed)
        
        // buffer initial positions
        bit_read_mask = 1; 
        bit_write_mask = 1; 
        bit_buffer = 0;

        // start with a LOW level on output
        bit_out_port = 0; 
        
        // debugging counters
        total_switch_cnt = 0;
        
}

// Called after last bit to be sent has been sent
void bitHandlerStop ( void ) {
    
    bit_sync_flags |= BIT_LAST_SENT; // signal for no more bits to send
    bit_last_mask = bit_write_mask; // for consumer, to stop here
    // NOTE - ticker will be disabled in the handler itself
    // as it has to wait for last bit to be processed, first

}
           
// A bit (x) is composed of BIT_TICK_x_NCYCLES of alternating HIGH and LOW levels,
// with each level interval lasting BIT_TICK_x_REPEAT ticker repetitions.
// Example for bit "0" -- BIT_TICK_0_NCYCLES = 8, BIT_TICK_0_REPEAT = 2:
//           ___     ___     ___     ___   
// out     _|   |___|   |___|   |___|   |_
// cycle    7   6   5   4   3   2   1   0 ...
// repeat   1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ...
//
// the bit-handler bitTickHandler(), called every BIT_TICK_DELAY (Ticker object)
// will pull a bit from the circular buffer ( bit_buffer ), 
// which is populated from writer bitWaitSend().
// Writer takes care of synchronization of read and write buffer pointers,
// assuming writer is FASTER than consumer handler
void bitTickHandler ( void )
{

    if ( bit_cycle_count == 0 ) {
        // New bit to be pulled off the buffer - restart counters
        if ( bit_sync_flags & BIT_LAST_PROCESSING ) {
            // stop AFTER last bit has been pulled (see below)
            bit_ticker.detach ();
            led1 = 0; // ticker stopped
            bit_out_port = 0; // stream closure
            total_time1.stop();
        } else {
            // update read position (shift left mask)
            // and reset tick and cycle counters
            if ( ( bit_read_mask = bit_read_mask<<1 ) == 0 ) 
                bit_read_mask = 1; // circular buffer
            if ( bit_buffer & bit_read_mask ) {
                // bit-1 from buffer
                bit_cycle_count = BIT_TICK_1_NCYCLES;
                bit_repeat_count = BIT_TICK_1_REPEAT;
                bit_sync_flags |= BIT_SENDING;
            } else {
                // bit-0 from buffer
                bit_cycle_count = BIT_TICK_0_NCYCLES;
                bit_repeat_count = BIT_TICK_0_REPEAT;
                bit_sync_flags &= ~(BIT_SENDING);
            }
            if ( ( bit_sync_flags & BIT_LAST_SENT ) &&
                 ( bit_read_mask == bit_last_mask ) ) {
                // set BEFORE last bit being processed
                bit_sync_flags |= BIT_LAST_PROCESSING;
            }
        }
    }

    if ( --bit_repeat_count == 0 ) {
        // toggle output port level
        total_switch_cnt += 1;
        bit_out_port = !bit_out_port;
        if ( total_switch_cnt & 0x10 ) led1 != led1; // show activity
        // a ticker-repeat cycle has completed
        bit_cycle_count --;
        if ( bit_sync_flags & BIT_SENDING ) // the bit being sent
            bit_repeat_count = BIT_TICK_1_REPEAT;
        else
            bit_repeat_count = BIT_TICK_0_REPEAT;
    }
    
}

// Push a bit to the buffer.
// Waiting in an idle loop, though not 100% busy (wait),
// as thread signals (Mbed-RTOS) are not available on the L053R8
int bitWaitSend ( uint8_t bit_value, uint8_t invert ) {

    bit_time.reset();
    bit_time.start();
    // Both bit_read_position and bit_write_position cycle through the buffer
    // When they are the same, put sender on hold, for consumer to complete.
    // Polling regularly, then writing a new bit to buffer
    // when pointers are different (the slower handler has moved bit_read_mask).
    // Bit handler takes about 2ms to spool a single bit:
    //  ( BIT_TICK_x_CYCLE+1 ) * BIT_TICK_x_REPEAT * BIT_TICK_DELAY (us)
    // hence, as soon as writer can write new data, it has 32x2ms to write 
    // new bits before filling again the buffer.
    // Polling has to be frequent enough not to let consumer pull wrong bits...
    while ( ( bit_write_mask == bit_read_mask ) && ( bit_sync_flags & BIT_FIRST_SENT ) )
       wait_us ( 100 );

    // update buffer write position (shift left mask)
    if ( ( bit_write_mask = bit_write_mask<<1 ) == 0 )
        bit_write_mask = 1; // it's a circular buffer

    // push this bit to the buffer
    if ( (bit_value & 0x01) ^ (invert & 0x01) ) // ignore positions other than 1
        bit_buffer |= (bit_write_mask); // set
    else
        bit_buffer &= ~(bit_write_mask); // clear

    // on first bit only, start consumer too
    if ( !(bit_sync_flags & BIT_FIRST_SENT) ) {
        bit_ticker.attach_us ( &bitTickHandler, BIT_TICK_DELAY ); // start ticker
        bit_sync_flags |= BIT_FIRST_SENT; // first bit gone
        led1 = 1; // debugging purpose (ticker on)
        total_time1.reset();
        total_time1.start();
    }
    
    return bit_time.read_us();

}

bool bitHandlerRunning( void ) {
    
    return ( !(bit_sync_flags & BIT_LAST_PROCESSING) ) ;
    
}

///////////////////////////////////////////////////////////////////////////////
/* MAIN USED FOR A STANDALONE TEST BED
int main()
{

    int i, ii;
    char inVal;

    // flashing led1 on startup
    for (i=0; i<5; i+=1) {
        wait (0.1);
        led1 = !led1;
    }
    led1 = 0;
    
    pc1.baud(57600);

    // welcome message 
    pc1.printf("\n\r ** MBED ** test bit send ** \n\r");
    fflush(stdout);

    // main loop
    while(true) {
       
        pc1.printf("Hit a key ... \n\r");
        fflush(stdout);
        inVal=pc1.getc(); // wait for a key press (over serial)

        debug_printf("%.2x ", inVal);
        for ( ii = 0; ii < 8; ii++ )
            debug_printf( "%d", ((inVal & (1<<ii))!=0) );
        debug_printf("\n\r");
        
        ////////////////////////////////////////////////////////////
        // before a new bit stream to be sent
        bitHandlerInit();
        // Send bit "1" a number of times (testing)
        for ( i = 0; i < 10; i++ ) {
          for ( ii = 0; ii < 8; ii++ )
            bitWaitSend( ((inVal & (1<<ii))!=0), 0 ); // try to push a bit (waiting inside, on queue full)
        }
        // stop consumer after last bit
        bitHandlerStop();
        // time for handler to complete
        while( bitHandlerRunning() ) 
            wait (.1); 
        ////////////////////////////////////////////////////////////

        debug_printf("total time (us): %d \n\r", total_time1.read_us() );
        debug_printf("nr. of switches: %d \n\r", total_switch_cnt );
        debug_printf("avg time per switch (us): %d \n\r", 
            total_time1.read_us()/total_switch_cnt );

    }

}
*/