BayEOS-Arduino  1.8.0_0.0.4
HardwareSerialPlus.cpp
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <inttypes.h>
5 #include "Arduino.h"
6 
7 #include "HardwareSerialPlus.h"
8 #include "HardwareSerialPlus_private.h"
9 
10 // SerialEvent functions are weak, so when the user doesn't define them,
11 // the linker just sets their address to 0 (which is checked below).
12 // The Serialx_available is just a wrapper around Serialx.available(),
13 // but we can refer to it weakly so we don't pull in the entire
14 // HardwareSerial instance if the user doesn't also refer to it.
15 #if defined(HAVE_HWSERIAL0P)
16  void serialPlusEvent() __attribute__((weak));
17  bool Serial0Plus_available() __attribute__((weak));
18 #endif
19 
20 #if defined(HAVE_HWSERIAL1P)
21  void serialPlusEvent1() __attribute__((weak));
22  bool SerialPlus1_available() __attribute__((weak));
23 #endif
24 
25 #if defined(HAVE_HWSERIAL2P)
26  void serialPlusEvent2() __attribute__((weak));
27  bool SerialPlus2_available() __attribute__((weak));
28 #endif
29 
30 #if defined(HAVE_HWSERIAL3P)
31  void serialPlusEvent3() __attribute__((weak));
32  bool SerialPlus3_available() __attribute__((weak));
33 #endif
34 
35 void serialEventRun(void)
36 {
37 #if defined(HAVE_HWSERIAL0P)
38  if (Serial0Plus_available && serialPlusEvent && Serial0Plus_available()) serialPlusEvent();
39 #endif
40 #if defined(HAVE_HWSERIAL1P)
41  if (SerialPlus1_available && serialPlusEvent1 && SerialPlus1_available()) serialPlusEvent1();
42 #endif
43 #if defined(HAVE_HWSERIAL2P)
44  if (SerialPlus2_available && serialPlusEvent2 && SerialPlus2_available()) serialPlusEvent2();
45 #endif
46 #if defined(HAVE_HWSERIAL3P)
47  if (SerialPlus3_available && serialPlusEvent3 && SerialPlus3_available()) serialPlusEvent3();
48 #endif
49 }
50 
51 
52 
53 void HardwareSerialPlus::setRxBuffer(unsigned char* buffer, uint16_t size){
54  _rx_buffer = buffer;
55  _rx_buffer_size = size;
56 }
57 
58 void HardwareSerialPlus::setTxBuffer(unsigned char* buffer, uint16_t size){
59  _tx_buffer = buffer;
60  _tx_buffer_size = size;
61 }
62 
63 
64 
65 
66 // Actual interrupt handlers //////////////////////////////////////////////////////////////
67 
68 
69 void HardwareSerialPlus::_tx_udr_empty_irq(void)
70 {
71  // If interrupts are enabled, there must be more data in the output
72  // buffer. Send the next byte
73  unsigned char c = _tx_buffer[_tx_buffer_tail];
74  _tx_buffer_tail = (_tx_buffer_tail + 1) % _tx_buffer_size;
75 
76  *_udr = c;
77 
78  // clear the TXC bit -- "can be cleared by writing a one to its bit
79  // location". This makes sure flush() won't return until the bytes
80  // actually got written
81  sbi(*_ucsra, TXC0);
82 
83  if (_tx_buffer_head == _tx_buffer_tail) {
84  // Buffer empty, so disable interrupts
85  cbi(*_ucsrb, UDRIE0);
86  }
87 }
88 
89 void HardwareSerialPlus::begin(unsigned long baud, byte config)
90 {
91  // Try u2x mode first
92  uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
93  *_ucsra = 1 << U2X0;
94 
95  // hardcoded exception for 57600 for compatibility with the bootloader
96  // shipped with the Duemilanove and previous boards and the firmware
97  // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
98  // be > 4095, so switch back to non-u2x mode if the baud rate is too
99  // low.
100  if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095))
101  {
102  *_ucsra = 0;
103  baud_setting = (F_CPU / 8 / baud - 1) / 2;
104  }
105 
106  // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
107  *_ubrrh = baud_setting >> 8;
108  *_ubrrl = baud_setting;
109 
110  _written = false;
111 
112  //set the data bits, parity, and stop bits
113 #if defined(__AVR_ATmega8__)
114  config |= 0x80; // select UCSRC register (shared with UBRRH)
115 #endif
116  *_ucsrc = config;
117 
118  sbi(*_ucsrb, RXEN0);
119  sbi(*_ucsrb, TXEN0);
120  sbi(*_ucsrb, RXCIE0);
121  cbi(*_ucsrb, UDRIE0);
122 }
123 
124 void HardwareSerialPlus::end()
125 {
126  // wait for transmission of outgoing data
127  flush();
128 
129  cbi(*_ucsrb, RXEN0);
130  cbi(*_ucsrb, TXEN0);
131  cbi(*_ucsrb, RXCIE0);
132  cbi(*_ucsrb, UDRIE0);
133 
134  // clear any received data
135  _rx_buffer_head = _rx_buffer_tail;
136 }
137 
138 int HardwareSerialPlus::available(void)
139 {
140  return ((unsigned int)(_rx_buffer_size + _rx_buffer_head - _rx_buffer_tail)) % _rx_buffer_size;
141 }
142 
143 int HardwareSerialPlus::peek(void)
144 {
145  if (_rx_buffer_head == _rx_buffer_tail) {
146  return -1;
147  } else {
148  return _rx_buffer[_rx_buffer_tail];
149  }
150 }
151 
152 
153 int HardwareSerialPlus::read(void)
154 {
155  // if the head isn't ahead of the tail, we don't have any characters
156  if (_rx_buffer_head == _rx_buffer_tail) {
157  return -1;
158  } else {
159  unsigned char c = _rx_buffer[_rx_buffer_tail];
160  _rx_buffer_tail = (_rx_buffer_tail + 1) % _rx_buffer_size;
161  return c;
162  }
163 }
164 
165 int HardwareSerialPlus::availableForWrite(void)
166 {
167  uint8_t oldSREG = SREG;
168  cli();
169  uint16_t head = _tx_buffer_head;
170  uint16_t tail = _tx_buffer_tail;
171  SREG = oldSREG;
172  if (head >= tail) return _tx_buffer_size - 1 - head + tail;
173  return tail - head - 1;
174 }
175 
176 void HardwareSerialPlus::flush()
177 {
178  // If we have never written a byte, no need to flush. This special
179  // case is needed since there is no way to force the TXC (transmit
180  // complete) bit to 1 during initialization
181  if (!_written)
182  return;
183 
184  while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) {
185  if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))
186  // Interrupts are globally disabled, but the DR empty
187  // interrupt should be enabled, so poll the DR empty flag to
188  // prevent deadlock
189  if (bit_is_set(*_ucsra, UDRE0))
190  _tx_udr_empty_irq();
191  }
192  // If we get here, nothing is queued anymore (DRIE is disabled) and
193  // the hardware finished tranmission (TXC is set).
194 }
195 
196 size_t HardwareSerialPlus::write(uint8_t c)
197 {
198  _written = true;
199  // If the buffer and the data register is empty, just write the byte
200  // to the data register and be done. This shortcut helps
201  // significantly improve the effective datarate at high (>
202  // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
203  if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
204  *_udr = c;
205  sbi(*_ucsra, TXC0);
206  return 1;
207  }
208  uint16_t i = (_tx_buffer_head + 1) % _tx_buffer_size;
209 
210  // If the output buffer is full, there's nothing for it other than to
211  // wait for the interrupt handler to empty it a bit
212  while (i == _tx_buffer_tail) {
213  if (bit_is_clear(SREG, SREG_I)) {
214  // Interrupts are disabled, so we'll have to poll the data
215  // register empty flag ourselves. If it is set, pretend an
216  // interrupt has happened and call the handler to free up
217  // space for us.
218  if(bit_is_set(*_ucsra, UDRE0))
219  _tx_udr_empty_irq();
220  } else {
221  // nop, the interrupt handler will free up space for us
222  }
223  }
224 
225  _tx_buffer[_tx_buffer_head] = c;
226  _tx_buffer_head = i;
227 
228  sbi(*_ucsrb, UDRIE0);
229 
230  return 1;
231 }
232