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