ALPHA WORK IN PROGRESS. DO NOT USE IN PRODUCTION CODE. based on:\\ IAR Application Note G - 001 Generic Software UART\\ mbed/trunk/Serial.h\\ the venerable Andy Kirkham's MAX3100\\
SoftwareSerial.cpp@0:25b087be2989, 2012-03-17 (annotated)
- Committer:
- chag
- Date:
- Sat Mar 17 17:25:55 2012 +0000
- Revision:
- 0:25b087be2989
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
chag | 0:25b087be2989 | 1 | #include "mbed.h" |
chag | 0:25b087be2989 | 2 | #include "SoftwareSerial.h" |
chag | 0:25b087be2989 | 3 | |
chag | 0:25b087be2989 | 4 | namespace chag { |
chag | 0:25b087be2989 | 5 | |
chag | 0:25b087be2989 | 6 | /*unsigned char SoftwareSerial::inbuf[SOFTWARE_SERIAL_RX_BUFFER_SIZE]; |
chag | 0:25b087be2989 | 7 | unsigned char SoftwareSerial::qin = 0; |
chag | 0:25b087be2989 | 8 | unsigned char SoftwareSerial::qout = 0; |
chag | 0:25b087be2989 | 9 | char SoftwareSerial::flag_rx_waiting_for_stop_bit; |
chag | 0:25b087be2989 | 10 | char SoftwareSerial::flag_rx_off; |
chag | 0:25b087be2989 | 11 | char SoftwareSerial::rx_mask; |
chag | 0:25b087be2989 | 12 | char SoftwareSerial::flag_rx_ready; |
chag | 0:25b087be2989 | 13 | char SoftwareSerial::flag_tx_ready; |
chag | 0:25b087be2989 | 14 | char SoftwareSerial::timer_rx_ctr; |
chag | 0:25b087be2989 | 15 | char SoftwareSerial::timer_tx_ctr; |
chag | 0:25b087be2989 | 16 | char SoftwareSerial::bits_left_in_rx; |
chag | 0:25b087be2989 | 17 | char SoftwareSerial::bits_left_in_tx; |
chag | 0:25b087be2989 | 18 | char SoftwareSerial::rx_num_of_bits; |
chag | 0:25b087be2989 | 19 | char SoftwareSerial::tx_num_of_bits; |
chag | 0:25b087be2989 | 20 | char SoftwareSerial::internal_rx_buffer; |
chag | 0:25b087be2989 | 21 | char SoftwareSerial::internal_tx_buffer; |
chag | 0:25b087be2989 | 22 | char SoftwareSerial::user_tx_buffer; |
chag | 0:25b087be2989 | 23 | */ |
chag | 0:25b087be2989 | 24 | |
chag | 0:25b087be2989 | 25 | DigitalOut led1(LED1); |
chag | 0:25b087be2989 | 26 | DigitalOut led2(LED2); |
chag | 0:25b087be2989 | 27 | DigitalOut led3(LED3); |
chag | 0:25b087be2989 | 28 | DigitalOut led4(LED4); |
chag | 0:25b087be2989 | 29 | |
chag | 0:25b087be2989 | 30 | |
chag | 0:25b087be2989 | 31 | SoftwareSerial::SoftwareSerial(PinName tx, PinName rx, const char *name) { |
chag | 0:25b087be2989 | 32 | // save pins |
chag | 0:25b087be2989 | 33 | |
chag | 0:25b087be2989 | 34 | this->tx = (tx == NC) ? (DigitalOut *)NULL : new DigitalOut(tx); |
chag | 0:25b087be2989 | 35 | this->rx = (rx == NC) ? (DigitalIn *)NULL : new DigitalIn(rx); |
chag | 0:25b087be2989 | 36 | |
chag | 0:25b087be2989 | 37 | flag_tx_ready = false; |
chag | 0:25b087be2989 | 38 | flag_rx_ready = false; |
chag | 0:25b087be2989 | 39 | flag_rx_waiting_for_stop_bit = false; |
chag | 0:25b087be2989 | 40 | flag_rx_off = (rx == NC); |
chag | 0:25b087be2989 | 41 | rx_num_of_bits = 10; |
chag | 0:25b087be2989 | 42 | tx_num_of_bits = 10; |
chag | 0:25b087be2989 | 43 | |
chag | 0:25b087be2989 | 44 | set_tx_pin_low(); |
chag | 0:25b087be2989 | 45 | |
chag | 0:25b087be2989 | 46 | baud(9600); |
chag | 0:25b087be2989 | 47 | } |
chag | 0:25b087be2989 | 48 | |
chag | 0:25b087be2989 | 49 | void SoftwareSerial::baud(int baudrate) { |
chag | 0:25b087be2989 | 50 | baud_rate = baudrate; |
chag | 0:25b087be2989 | 51 | ticker.detach(); |
chag | 0:25b087be2989 | 52 | |
chag | 0:25b087be2989 | 53 | ticker.attach_us(this, &SoftwareSerial::timer_isr, 1000000.0 / (baudrate * 3.0)); |
chag | 0:25b087be2989 | 54 | |
chag | 0:25b087be2989 | 55 | //timer_set( baud_rate ); // Sets the timer to 3 times the baud rate. |
chag | 0:25b087be2989 | 56 | //set_timer_interrupt( &SoftwareSerial::timer_isr ); |
chag | 0:25b087be2989 | 57 | } |
chag | 0:25b087be2989 | 58 | |
chag | 0:25b087be2989 | 59 | // putc, etc |
chag | 0:25b087be2989 | 60 | |
chag | 0:25b087be2989 | 61 | int SoftwareSerial::readable() { |
chag | 0:25b087be2989 | 62 | return( kbhit() ); |
chag | 0:25b087be2989 | 63 | } |
chag | 0:25b087be2989 | 64 | |
chag | 0:25b087be2989 | 65 | int SoftwareSerial::writeable() { |
chag | 0:25b087be2989 | 66 | return ( 1 ); |
chag | 0:25b087be2989 | 67 | } |
chag | 0:25b087be2989 | 68 | |
chag | 0:25b087be2989 | 69 | // end |
chag | 0:25b087be2989 | 70 | |
chag | 0:25b087be2989 | 71 | |
chag | 0:25b087be2989 | 72 | int SoftwareSerial::get_rx_pin_status() { |
chag | 0:25b087be2989 | 73 | // Returns 0 or 1 dependent on whether the receive pin is high or low. |
chag | 0:25b087be2989 | 74 | return( rx->read() ); |
chag | 0:25b087be2989 | 75 | } |
chag | 0:25b087be2989 | 76 | |
chag | 0:25b087be2989 | 77 | void SoftwareSerial::set_tx_pin_high() { |
chag | 0:25b087be2989 | 78 | // Sets the transmit pin to the high state. |
chag | 0:25b087be2989 | 79 | tx->write(1); |
chag | 0:25b087be2989 | 80 | //led4 = 1; |
chag | 0:25b087be2989 | 81 | } |
chag | 0:25b087be2989 | 82 | |
chag | 0:25b087be2989 | 83 | void SoftwareSerial::set_tx_pin_low() { |
chag | 0:25b087be2989 | 84 | // Sets the transmit pin to the low state. |
chag | 0:25b087be2989 | 85 | tx->write(0); |
chag | 0:25b087be2989 | 86 | //led4 = 0; |
chag | 0:25b087be2989 | 87 | } |
chag | 0:25b087be2989 | 88 | |
chag | 0:25b087be2989 | 89 | void SoftwareSerial::idle() { |
chag | 0:25b087be2989 | 90 | // Background functions to execute while waiting for input. |
chag | 0:25b087be2989 | 91 | |
chag | 0:25b087be2989 | 92 | } |
chag | 0:25b087be2989 | 93 | |
chag | 0:25b087be2989 | 94 | |
chag | 0:25b087be2989 | 95 | // protected/private members |
chag | 0:25b087be2989 | 96 | |
chag | 0:25b087be2989 | 97 | void SoftwareSerial::timer_isr( void ) { |
chag | 0:25b087be2989 | 98 | char mask, start_bit, flag_in; |
chag | 0:25b087be2989 | 99 | |
chag | 0:25b087be2989 | 100 | // Transmitter Section |
chag | 0:25b087be2989 | 101 | if ( flag_tx_ready ) { |
chag | 0:25b087be2989 | 102 | if( --timer_tx_ctr<=0 ) { |
chag | 0:25b087be2989 | 103 | mask = internal_tx_buffer&1; |
chag | 0:25b087be2989 | 104 | internal_tx_buffer >>= 1; |
chag | 0:25b087be2989 | 105 | if ( mask ) { |
chag | 0:25b087be2989 | 106 | set_tx_pin_high(); |
chag | 0:25b087be2989 | 107 | } else { |
chag | 0:25b087be2989 | 108 | set_tx_pin_low(); |
chag | 0:25b087be2989 | 109 | } |
chag | 0:25b087be2989 | 110 | timer_tx_ctr = 3; |
chag | 0:25b087be2989 | 111 | if ( --bits_left_in_tx<=0 ) { |
chag | 0:25b087be2989 | 112 | flag_tx_ready = false; |
chag | 0:25b087be2989 | 113 | } |
chag | 0:25b087be2989 | 114 | } |
chag | 0:25b087be2989 | 115 | } |
chag | 0:25b087be2989 | 116 | |
chag | 0:25b087be2989 | 117 | // Receiver Section |
chag | 0:25b087be2989 | 118 | if ( flag_rx_off==false ) { |
chag | 0:25b087be2989 | 119 | if ( flag_rx_waiting_for_stop_bit ) { |
chag | 0:25b087be2989 | 120 | if ( --timer_rx_ctr<=0 ) { |
chag | 0:25b087be2989 | 121 | flag_rx_waiting_for_stop_bit = false; |
chag | 0:25b087be2989 | 122 | flag_rx_ready = false; |
chag | 0:25b087be2989 | 123 | internal_rx_buffer &= 0xFF; |
chag | 0:25b087be2989 | 124 | if ( internal_rx_buffer!=0xC2 ) { |
chag | 0:25b087be2989 | 125 | inbuf[qin] = internal_rx_buffer; |
chag | 0:25b087be2989 | 126 | if ( ++qin>=SOFTWARE_SERIAL_RX_BUFFER_SIZE ) { |
chag | 0:25b087be2989 | 127 | qin = 0; |
chag | 0:25b087be2989 | 128 | } |
chag | 0:25b087be2989 | 129 | } |
chag | 0:25b087be2989 | 130 | } |
chag | 0:25b087be2989 | 131 | } else { // rx_test_busy |
chag | 0:25b087be2989 | 132 | if ( flag_rx_ready==false ) { |
chag | 0:25b087be2989 | 133 | start_bit = get_rx_pin_status(); |
chag | 0:25b087be2989 | 134 | // Test for Start Bit |
chag | 0:25b087be2989 | 135 | if ( start_bit==0 ) { |
chag | 0:25b087be2989 | 136 | flag_rx_ready = true; |
chag | 0:25b087be2989 | 137 | internal_rx_buffer = 0; |
chag | 0:25b087be2989 | 138 | timer_rx_ctr = 4; |
chag | 0:25b087be2989 | 139 | bits_left_in_rx = rx_num_of_bits; |
chag | 0:25b087be2989 | 140 | rx_mask = 1; |
chag | 0:25b087be2989 | 141 | } |
chag | 0:25b087be2989 | 142 | } else { // rx_busy |
chag | 0:25b087be2989 | 143 | if ( --timer_rx_ctr<=0 ) { // rcv |
chag | 0:25b087be2989 | 144 | timer_rx_ctr = 3; |
chag | 0:25b087be2989 | 145 | flag_in = get_rx_pin_status(); |
chag | 0:25b087be2989 | 146 | if ( flag_in ) { |
chag | 0:25b087be2989 | 147 | internal_rx_buffer |= rx_mask; |
chag | 0:25b087be2989 | 148 | } |
chag | 0:25b087be2989 | 149 | rx_mask <<= 1; |
chag | 0:25b087be2989 | 150 | if ( --bits_left_in_rx<=0 ) { |
chag | 0:25b087be2989 | 151 | flag_rx_waiting_for_stop_bit = true; |
chag | 0:25b087be2989 | 152 | } |
chag | 0:25b087be2989 | 153 | } |
chag | 0:25b087be2989 | 154 | } |
chag | 0:25b087be2989 | 155 | } |
chag | 0:25b087be2989 | 156 | } |
chag | 0:25b087be2989 | 157 | } |
chag | 0:25b087be2989 | 158 | |
chag | 0:25b087be2989 | 159 | int SoftwareSerial::getc( void ) { |
chag | 0:25b087be2989 | 160 | char ch; |
chag | 0:25b087be2989 | 161 | |
chag | 0:25b087be2989 | 162 | do { |
chag | 0:25b087be2989 | 163 | while ( qout==qin ) { |
chag | 0:25b087be2989 | 164 | idle(); |
chag | 0:25b087be2989 | 165 | } |
chag | 0:25b087be2989 | 166 | ch = inbuf[qout] & 0xFF; |
chag | 0:25b087be2989 | 167 | if ( ++qout>=SOFTWARE_SERIAL_RX_BUFFER_SIZE ) { |
chag | 0:25b087be2989 | 168 | qout = 0; |
chag | 0:25b087be2989 | 169 | } |
chag | 0:25b087be2989 | 170 | } while ( ch==0x0A || ch==0xC2 ); |
chag | 0:25b087be2989 | 171 | return( (int)ch ); |
chag | 0:25b087be2989 | 172 | } |
chag | 0:25b087be2989 | 173 | |
chag | 0:25b087be2989 | 174 | int SoftwareSerial::putc( int c ) { |
chag | 0:25b087be2989 | 175 | led1 = !led1; |
chag | 0:25b087be2989 | 176 | while ( flag_tx_ready ); |
chag | 0:25b087be2989 | 177 | user_tx_buffer = c; |
chag | 0:25b087be2989 | 178 | |
chag | 0:25b087be2989 | 179 | // invoke_UART_transmit |
chag | 0:25b087be2989 | 180 | timer_tx_ctr = 3; |
chag | 0:25b087be2989 | 181 | bits_left_in_tx = tx_num_of_bits; |
chag | 0:25b087be2989 | 182 | internal_tx_buffer = (user_tx_buffer<<1) | 0x200; |
chag | 0:25b087be2989 | 183 | flag_tx_ready = true; |
chag | 0:25b087be2989 | 184 | return(1); |
chag | 0:25b087be2989 | 185 | } |
chag | 0:25b087be2989 | 186 | |
chag | 0:25b087be2989 | 187 | void SoftwareSerial::flush_input_buffer( void ) { |
chag | 0:25b087be2989 | 188 | qin = 0; |
chag | 0:25b087be2989 | 189 | qout = 0; |
chag | 0:25b087be2989 | 190 | } |
chag | 0:25b087be2989 | 191 | |
chag | 0:25b087be2989 | 192 | char SoftwareSerial::kbhit( void ) { |
chag | 0:25b087be2989 | 193 | return( qin!=qout ); |
chag | 0:25b087be2989 | 194 | } |
chag | 0:25b087be2989 | 195 | |
chag | 0:25b087be2989 | 196 | void SoftwareSerial::turn_rx_on( void ) { |
chag | 0:25b087be2989 | 197 | flag_rx_off = false; |
chag | 0:25b087be2989 | 198 | } |
chag | 0:25b087be2989 | 199 | |
chag | 0:25b087be2989 | 200 | void SoftwareSerial::turn_rx_off( void ) { |
chag | 0:25b087be2989 | 201 | flag_rx_off = true; |
chag | 0:25b087be2989 | 202 | } |
chag | 0:25b087be2989 | 203 | |
chag | 0:25b087be2989 | 204 | |
chag | 0:25b087be2989 | 205 | } // end namespace |