Pico-Arduino
PicoHardwareSerial.h
1 #pragma once
2 
3 #include "pins_arduino.h"
4 #include "Stream.h"
5 #include "HardwareSerial.h"
6 #include "RingBufferN.h"
7 #include "pico/stdlib.h"
8 #include "hardware/uart.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <tusb.h>
12 
13 #ifndef BUFFER_SIZE
14 #define BUFFER_SIZE 512
15 #endif
16 
17 #if !defined(TINYUSB_HOST_LINKED) && !defined(TINYUSB_DEVICE_LINKED)
18 
19 extern "C" {
20 static bool tud_cdc_connected (void);
21 }
22 
28 class PicoSerialUSB : public HardwareSerial {
29  public:
30  PicoSerialUSB(){
31  }
32 
33  // opens the processing - calling the pico stdio_usb_init
34  void begin() {
35  stdio_usb_init ();
36  is_open = true;
37  };
38 
39  //needed because Stadnard Arduino requires this all but parameter has no impact on USB
40  virtual void begin(unsigned long baudrate) {
41  begin();
42  };
43 
44  // needed because Stadnard Arduino requires this all but both parameters have no impact on USB
45  virtual void begin(unsigned long baudrate, uint16_t config){
46  begin();
47  }
48 
49  // deactivates the output to USB
50  virtual void end() {
51  is_open = false;
52  }
53 
54  virtual int available(void){
55  readBuffer();
56  return buffer.available();
57  }
58 
59  virtual int peek(void) {
60  readBuffer();
61  return buffer.peek();
62  }
63 
64  virtual int read(void){
65  // we might need to flush the current ouptut...
66  flush();
67  // try to refill the buffer
68  readBuffer();
69  return buffer.read_char();
70  }
71 
72  virtual void flush(void) {
73  stdio_flush();
74  }
75 
76  // provide implmentation of standard Arduino output of single character
77  virtual size_t write(uint8_t c) {
78  size_t len = putchar(c);
79 #ifndef PICO_ARDUINO_NO_FLUSH
80  stdio_flush();
81 #endif
82  return len;
83  }
84 
85  // provide implmentation of standard Arduino output of multiple characters
86  virtual size_t write(const uint8_t *buffer, size_t size){
87  int result;
88  for (size_t j=0;j<size;j++){
89  result += putchar(buffer[j]);
90  }
91  stdio_flush();
92  return result;
93  }
94 
95  // Pull in default implementations
96  using Print::write; // pull in write(str) and write(buf, size) from Print
97  using Print::print; // pull in write(str) and write(buf, size) from Print
98  using Print::println; // pull in write(str) and write(buf, size) from Print
99 
100  virtual operator bool(){
101  return tud_cdc_connected() && is_open;
102  };
103 
104  protected:
105  bool is_open;
106  RingBufferN<BUFFER_SIZE> buffer;
107 
108  void readBuffer() {
109  // refill buffer only if it is empty
110  if (buffer.available()==0){
111  // fill buffer as long as we have space
112  int wait_time = 1000;
113  int c = getchar_timeout_us(wait_time);
114  while(c!=PICO_ERROR_TIMEOUT && buffer.availableForStore()>0){
115  buffer.store_char(c);
116  c = getchar_timeout_us(wait_time);
117  }
118  }
119  }
120 
121 };
122 
123 #endif
124 
130  public:
131  PicoSerialUART(){
132  }
133 
134  PicoSerialUART(int uart_no) {
135  this->uart_no = uart_no;
136  this->uart = uart_no == 0 ? uart0 : uart1;
137  }
138 
139  virtual void begin(unsigned long baudrate=PICO_DEFAULT_UART_BAUD_RATE) {
140  begin(baudrate, -1, -1, SERIAL_8N1);
141  }
142 
143  virtual void begin(unsigned long baudrate, uint16_t config) {
144  begin(baudrate, -1, -1, config);
145  }
146 
159  virtual void begin(unsigned long baudrate, int rxPin, int txPin, uint32_t config=SERIAL_8N1, bool invert=false, bool cts=false, bool rts=false) {
160  Logger.info("PicoHardwareSerial::begin", toStr(baudrate));
161  rx_pin = rxPin;
162  tx_pin = txPin;
163  uart_init(uart, baudrate);
164  setupDefaultRxTxPins();
165  uart_set_hw_flow(uart, cts, rts);
166  set_config(config);
167  uart_set_translate_crlf(uart, false);
168  uart_set_fifo_enabled(uart, true);
169 
170  uint rate_effective = uart_set_baudrate(uart,baudrate);
171  open = uart_is_enabled(uart);
172  if (Logger.isLogging(PicoLogger::Info)) {
173  Logger.info("baud_rate requested:",toStr(baudrate));
174  Logger.info("baud_rate effective:",toStr(rate_effective));
175  Logger.info("uart_is_enabled:", open ? "true" : "false");
176  }
177 
178  }
179 
180  virtual void end(){
181  Logger.info("PicoHardwareSerial::end ",toStr(uart_no));
182  uart_deinit(uart);
183  open = false;
184  }
185 
186  virtual int available(void){
187  readBuffer();
188  return buffer.available();
189  }
190 
191  virtual int availableForWrite(void){
192  return uart_is_writable(uart);
193  }
194 
195  virtual int peek(void){
196  readBuffer();
197  return buffer.peek();
198  }
199 
200  virtual int read(void){
201  readBuffer();
202  return buffer.read_char();
203  }
204 
205  using Print::write; // pull in write(str) and write(buf, size) from Print
206  using Print::print; // pull in write(str) and write(buf, size) from Print
207  using Print::println; // pull in write(str) and write(buf, size) from Print
208 
209  virtual size_t write(uint8_t c) {
210  bool ok = uart_is_writable (uart);
211  if (ok){
212  uart_putc(uart, c);
213  }
214  return ok ? 1 : 0;
215  }
216 
217  virtual size_t write(const uint8_t *buffer, size_t size){
218  uart_write_blocking(uart, buffer, size);
219  return size;
220  }
221 
222  uint32_t baudRate(){
223  return baud_rate;
224  }
225 
226  virtual void flush(void) {
227  };
228 
229  virtual operator bool(){
230  return open;
231  };
232 
233 
234  protected:
235  RingBufferN<BUFFER_SIZE> buffer;
236  uart_inst_t *uart;
237  uint baud_rate;
238  int tx_pin;
239  int rx_pin;
240  int uart_no;
241  bool open = false;
242 
243  // filles the read buffer
244  void readBuffer(bool refill=false) {
245  // refill buffer only when requested or when it is empty
246  if (refill || buffer.available()==0){
247  while(buffer.availableForStore()>0 && uart_is_readable(uart) ) {
248  char c = uart_get_hw(uart)->dr;
249  buffer.store_char(c);
250  }
251  }
252  }
253 
254  void set_config(uint32_t config){
255  Logger.info("set_config");
256  //data, parity, and stop bits
257  switch(config){
258  case SERIAL_5N1:
259  uart_set_format(uart, 5, 1,UART_PARITY_NONE);
260  break;
261  case SERIAL_6N1:
262  uart_set_format(uart, 6, 1,UART_PARITY_NONE);
263  break;
264  case SERIAL_7N1:
265  uart_set_format(uart, 7, 1,UART_PARITY_NONE);
266  break;
267  case SERIAL_8N1:
268  Logger.info("SERIAL_8N1 - UART_PARITY_NONE");
269  uart_set_format(uart, 8, 1,UART_PARITY_NONE);
270  break;
271  case SERIAL_5N2:
272  uart_set_format(uart, 5, 2,UART_PARITY_NONE);
273  break;
274  case SERIAL_6N2:
275  uart_set_format(uart, 6, 2,UART_PARITY_NONE);
276  break;
277  case SERIAL_7N2:
278  uart_set_format(uart, 7, 2,UART_PARITY_NONE);
279  break;
280  case SERIAL_8N2:
281  uart_set_format(uart, 8, 2,UART_PARITY_NONE);
282  break;
283  case SERIAL_5E1:
284  uart_set_format(uart, 5, 1,UART_PARITY_EVEN);
285  break;
286  case SERIAL_6E1:
287  uart_set_format(uart, 6, 1,UART_PARITY_EVEN);
288  break;
289  case SERIAL_7E1:
290  uart_set_format(uart, 7, 1,UART_PARITY_EVEN);
291  break;
292  case SERIAL_8E1:
293  uart_set_format(uart, 8, 1,UART_PARITY_EVEN);
294  break;
295  case SERIAL_5E2:
296  uart_set_format(uart, 5, 2,UART_PARITY_EVEN);
297  break;
298  case SERIAL_6E2:
299  uart_set_format(uart, 6, 2,UART_PARITY_EVEN);
300  break;
301  case SERIAL_7E2:
302  uart_set_format(uart, 7, 2,UART_PARITY_EVEN);
303  break;
304  case SERIAL_8E2:
305  uart_set_format(uart, 8, 2,UART_PARITY_EVEN);
306  break;
307  case SERIAL_5O1:
308  uart_set_format(uart, 5, 1,UART_PARITY_ODD);
309  break;
310  case SERIAL_6O1:
311  uart_set_format(uart, 6, 1,UART_PARITY_ODD);
312  break;
313  case SERIAL_7O1:
314  uart_set_format(uart, 7, 1,UART_PARITY_ODD);
315  break;
316  case SERIAL_8O1:
317  uart_set_format(uart, 8, 1,UART_PARITY_ODD);
318  break;
319  case SERIAL_5O2:
320  uart_set_format(uart, 5, 2,UART_PARITY_ODD);
321  break;
322  case SERIAL_6O2:
323  uart_set_format(uart, 6, 2,UART_PARITY_ODD);
324  break;
325  case SERIAL_7O2:
326  uart_set_format(uart, 7, 2,UART_PARITY_ODD);
327  break;
328  case SERIAL_8O2:
329  uart_set_format(uart, 8, 2,UART_PARITY_ODD);
330  break;
331  };
332  }
333 
334  void setupDefaultRxTxPins(){
335  Logger.info("setupDefaultRxTxPins");
336  // we use different pins for uart0 and uar1. We assign values only if it has not been defined in setup
337  if (uart_no==0){
338  if (rx_pin==-1) {
339  rx_pin = SERIAL1_RX;
340  }
341  if (tx_pin==-1){
342  tx_pin = SERIAL1_TX;
343  }
344  } else {
345  if (rx_pin==-1){
346  rx_pin = SERIAL2_RX;
347  }
348  if (tx_pin==-1){
349  tx_pin = SERIAL2_TX;
350  }
351  }
352  // display pin assignments
353  if (Logger.isLogging()) {
354  Logger.info("Using UART: ", toStr(uart_no));
355  Logger.info("txPin is ", toStr(tx_pin));
356  Logger.info("rxPin is ", toStr(rx_pin));
357  }
358  if (tx_pin!=-1) {
359  gpio_set_function(tx_pin, GPIO_FUNC_UART);
360  }
361  if (rx_pin!=-1){
362  gpio_set_function(rx_pin, GPIO_FUNC_UART);
363  }
364 
365  }
366 
367  const char* toStr(int value){
368  static char buffer[10];
369  itoa(value,buffer,10);
370  return (const char*)buffer;
371  }
372 };
373 
Serial Stream for a defined UART. By default we use the following pins: UART0 tx/rx = gp0/gp1; UART1 ...
Definition: PicoHardwareSerial.h:129
virtual void begin(unsigned long baudrate, int rxPin, int txPin, uint32_t config=SERIAL_8N1, bool invert=false, bool cts=false, bool rts=false)
Initialization to output to UART.
Definition: PicoHardwareSerial.h:159
PicoUSBSerial is using the pico USB output. It is mapped to the Arduino Serial variable.
Definition: PicoHardwareSerial.h:28
Definition: HardwareSerial.h:88