2015-09-18 23:00:31 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 Freie Universität Berlin
|
|
|
|
*
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser General
|
|
|
|
* Public License v2.1. See the file LICENSE in the top level directory for more
|
|
|
|
* details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ingroup sys_arduino
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @file
|
|
|
|
* @brief Implementation of the Arduino 'Serial' interface
|
|
|
|
*
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
|
|
*
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
extern "C" {
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2021-12-25 13:29:28 +01:00
|
|
|
#include "assert.h"
|
2020-10-27 15:31:42 +01:00
|
|
|
#include "fmt.h"
|
2015-09-18 23:00:31 +02:00
|
|
|
#include "irq.h"
|
2021-12-25 13:29:28 +01:00
|
|
|
#include "kernel_defines.h"
|
|
|
|
|
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
#include "stdio_base.h"
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#include "serialport.hpp"
|
|
|
|
|
2016-03-15 14:24:48 +01:00
|
|
|
void rx_cb(void *arg, uint8_t c)
|
2015-09-18 23:00:31 +02:00
|
|
|
{
|
|
|
|
ringbuffer_t *buf = (ringbuffer_t *)arg;
|
2016-03-15 14:24:48 +01:00
|
|
|
ringbuffer_add_one(buf, (char)c);
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SerialPort::SerialPort(uart_t dev)
|
|
|
|
{
|
2021-12-25 13:29:28 +01:00
|
|
|
#if !IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
assert(dev != UART_UNDEF);
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
this->dev = dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SerialPort::available(void)
|
|
|
|
{
|
2021-12-25 13:29:28 +01:00
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
if (this->dev == UART_UNDEF) {
|
|
|
|
#if IS_USED(MODULE_STDIO_AVAILABLE)
|
|
|
|
return stdio_available();
|
|
|
|
#else /* IS_USED(MODULE_STDIO_AVAILABLE) */
|
|
|
|
return 0;
|
|
|
|
#endif /* IS_USED(MODULE_STDIO_AVAILABLE) */
|
|
|
|
}
|
|
|
|
#endif /* IS_USED(MODULE_ARDUINO_SERIAL_STDIO) */
|
2015-09-18 23:00:31 +02:00
|
|
|
return (int)rx_buf.avail;
|
|
|
|
}
|
|
|
|
|
2016-10-24 11:01:48 +02:00
|
|
|
void SerialPort::begin(long baudrate)
|
2015-09-18 23:00:31 +02:00
|
|
|
{
|
|
|
|
/* this clears the contents of the ringbuffer... */
|
|
|
|
ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
|
2021-12-25 13:29:28 +01:00
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
if (this->dev == UART_UNDEF) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SerialPort::end(void)
|
|
|
|
{
|
2021-12-25 13:29:28 +01:00
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
if (this->dev == UART_UNDEF) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
uart_poweroff(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(int val)
|
|
|
|
{
|
2019-08-29 13:29:38 +02:00
|
|
|
return print((long)val, DEC);
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(int val, SerialFormat format)
|
2019-08-29 13:29:38 +02:00
|
|
|
{
|
|
|
|
if (format == DEC) {
|
|
|
|
return print((long)val, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Propagation to long of negative number changes binary representation.
|
|
|
|
* This cast should add leading zeros to the binary representation, that
|
|
|
|
* will be skipped by print(unsigned long, SerialFormat)
|
|
|
|
*/
|
|
|
|
return print((unsigned long)((unsigned)val), format);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(unsigned int val)
|
|
|
|
{
|
|
|
|
return print((unsigned long)val, DEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(unsigned int val, SerialFormat format)
|
|
|
|
{
|
|
|
|
return print((unsigned long)val, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(long val)
|
|
|
|
{
|
|
|
|
return print(val, DEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(long val, SerialFormat format)
|
|
|
|
{
|
|
|
|
if (format == DEC) {
|
|
|
|
char buf[64];
|
|
|
|
size_t len;
|
|
|
|
len = sprintf(buf, "%li", val);
|
|
|
|
write(buf, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return print((unsigned long)val, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(unsigned long val)
|
|
|
|
{
|
|
|
|
return print(val, DEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(unsigned long val, SerialFormat format)
|
2015-09-18 23:00:31 +02:00
|
|
|
{
|
|
|
|
char buf[64];
|
|
|
|
size_t len;
|
|
|
|
switch (format) {
|
|
|
|
case BIN:
|
2019-08-29 13:29:38 +02:00
|
|
|
len = 0;
|
|
|
|
{
|
|
|
|
static const unsigned long mask = 1UL << (8 * sizeof(unsigned long) - 1);
|
|
|
|
unsigned pos = 0;
|
|
|
|
while (!(val & (mask >> pos))) {
|
|
|
|
pos ++;
|
|
|
|
}
|
|
|
|
for (; pos < 8 * sizeof(unsigned long); pos++) {
|
|
|
|
buf[len++] = (val & (mask >> pos)) ? '1' : '0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-09-18 23:00:31 +02:00
|
|
|
case OCT:
|
2019-08-29 13:29:38 +02:00
|
|
|
len = sprintf(buf, "%lo", val);
|
2015-09-18 23:00:31 +02:00
|
|
|
break;
|
|
|
|
case DEC:
|
2019-08-29 13:29:38 +02:00
|
|
|
len = sprintf(buf, "%lu", val);
|
2015-09-18 23:00:31 +02:00
|
|
|
break;
|
|
|
|
case HEX:
|
2019-08-29 13:29:38 +02:00
|
|
|
len = sprintf(buf, "%lx", val);
|
2015-09-18 23:00:31 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
write(buf, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(float val)
|
|
|
|
{
|
|
|
|
return print(val, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(float val, int format)
|
|
|
|
{
|
|
|
|
char buf[64];
|
2020-10-27 15:31:42 +01:00
|
|
|
size_t len = fmt_float(buf, val, format);
|
2015-09-18 23:00:31 +02:00
|
|
|
write(buf, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(char val)
|
|
|
|
{
|
|
|
|
return (size_t)write((int)val);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::print(const char *val)
|
|
|
|
{
|
|
|
|
return (size_t)write(val);
|
|
|
|
}
|
|
|
|
|
2019-08-29 13:29:38 +02:00
|
|
|
template<typename T> size_t SerialPort::_println(T val)
|
2015-09-18 23:00:31 +02:00
|
|
|
{
|
|
|
|
size_t res = print(val);
|
|
|
|
write("\r\n");
|
2019-08-29 13:29:38 +02:00
|
|
|
return res + 2;
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
2019-08-29 13:29:38 +02:00
|
|
|
template<typename T> size_t SerialPort::_println(T val, SerialFormat format)
|
2015-09-18 23:00:31 +02:00
|
|
|
{
|
|
|
|
size_t res = print(val, format);
|
|
|
|
write("\r\n");
|
2019-08-29 13:29:38 +02:00
|
|
|
return res + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(int val)
|
|
|
|
{
|
|
|
|
return _println<int>(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(int val, SerialFormat format)
|
|
|
|
{
|
|
|
|
return _println<int>(val, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(unsigned int val)
|
|
|
|
{
|
|
|
|
return _println<unsigned int>(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(unsigned int val, SerialFormat format)
|
|
|
|
{
|
|
|
|
return _println<unsigned int>(val, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(long val)
|
|
|
|
{
|
|
|
|
return _println<long>(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(long val, SerialFormat format)
|
|
|
|
{
|
|
|
|
return _println<long>(val, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(unsigned long val)
|
|
|
|
{
|
|
|
|
return _println<unsigned long>(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(unsigned long val, SerialFormat format)
|
|
|
|
{
|
|
|
|
return _println<unsigned long>(val, format);
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(float val)
|
|
|
|
{
|
2019-08-29 13:29:38 +02:00
|
|
|
return _println<float>(val);
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(float val, int format)
|
|
|
|
{
|
2019-08-29 13:29:38 +02:00
|
|
|
/* cannot use template here, second parameter differs in type */
|
2015-09-18 23:00:31 +02:00
|
|
|
size_t res = print(val, format);
|
|
|
|
write("\r\n");
|
2019-08-29 13:29:38 +02:00
|
|
|
return res + 2;
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(char val)
|
|
|
|
{
|
2019-08-29 13:29:38 +02:00
|
|
|
return _println<char>(val);
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(const char *val)
|
|
|
|
{
|
2019-08-29 13:29:38 +02:00
|
|
|
return _println<const char *>(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SerialPort::println(void)
|
|
|
|
{
|
2015-09-18 23:00:31 +02:00
|
|
|
write("\r\n");
|
2019-08-29 13:29:38 +02:00
|
|
|
return 2;
|
2015-09-18 23:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int SerialPort::read(void)
|
|
|
|
{
|
|
|
|
int res = -1;
|
|
|
|
|
2016-03-19 09:25:47 +01:00
|
|
|
irq_disable();
|
2021-12-25 13:29:28 +01:00
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
if (this->dev == UART_UNDEF) {
|
|
|
|
char chr;
|
|
|
|
if (this->available()) {
|
|
|
|
res = (stdio_read((void *)&chr, 1) == 1) ? chr : -1;
|
|
|
|
}
|
|
|
|
irq_enable();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
if (rx_buf.avail > 0) {
|
|
|
|
res = ringbuffer_get_one(&rx_buf);
|
|
|
|
}
|
2016-03-19 09:25:47 +01:00
|
|
|
irq_enable();
|
2015-09-18 23:00:31 +02:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SerialPort::write(int val)
|
|
|
|
{
|
2021-12-25 13:29:28 +01:00
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
if (this->dev == UART_UNDEF) {
|
|
|
|
stdio_write((const void *)&val, 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
uart_write(dev, (uint8_t *)&val, 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SerialPort::write(const char *str)
|
|
|
|
{
|
2021-12-25 13:29:28 +01:00
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
if (this->dev == UART_UNDEF) {
|
|
|
|
stdio_write((const void *)str, strlen(str));
|
|
|
|
return strlen(str);
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
uart_write(dev, (uint8_t *)str, strlen(str));
|
|
|
|
return strlen(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
int SerialPort::write(char *buf, int len)
|
|
|
|
{
|
2021-12-25 13:29:28 +01:00
|
|
|
#if IS_USED(MODULE_ARDUINO_SERIAL_STDIO)
|
|
|
|
if (this->dev == UART_UNDEF) {
|
|
|
|
stdio_write((const void *)buf, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-18 23:00:31 +02:00
|
|
|
uart_write(dev, (uint8_t *)buf, len);
|
|
|
|
return len;
|
|
|
|
}
|