mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #3900 from haukepetersen/add_arduino_api
sys: added Arduino API to RIOT
This commit is contained in:
commit
2cc2adffee
2
.gitignore
vendored
2
.gitignore
vendored
@ -32,6 +32,8 @@ tags
|
||||
# Eclipse symbol file (output from make eclipsesym)
|
||||
eclipsesym.xml
|
||||
/toolchain
|
||||
# Ignore created Arduino sketch files
|
||||
_sketches.cpp
|
||||
|
||||
# local override files
|
||||
Makefile.local
|
||||
|
@ -381,6 +381,12 @@ ifneq (,$(filter schedstatistics,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter arduino,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += arduino
|
||||
FEATURES_REQUIRED += cpp
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter xtimer,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_timer
|
||||
endif
|
||||
|
@ -12,6 +12,7 @@ FEATURES_PROVIDED += periph_uart
|
||||
|
||||
# Various other features (if any)
|
||||
FEATURES_PROVIDED += cpp
|
||||
FEATURES_PROVIDED += arduino
|
||||
|
||||
# The board MPU family (used for grouping by the CI system)
|
||||
FEATURES_MCU_GROUP = cortex_m4
|
||||
|
46
boards/stm32f4discovery/include/arduino_board.h
Normal file
46
boards/stm32f4discovery/include/arduino_board.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 boards_stm32f4discovery
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Board specific configuration for the Arduino API
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef ARDUINO_BOARD_H
|
||||
#define ARDUINO_BOARD_H
|
||||
|
||||
#include "periph/gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARDUINO_LED (2)
|
||||
|
||||
static const gpio_t arduino_pinmap[] = {
|
||||
GPIO_PIN(PORT_D, 12),
|
||||
GPIO_PIN(PORT_D, 13),
|
||||
GPIO_PIN(PORT_D, 14),
|
||||
GPIO_PIN(PORT_D, 15),
|
||||
GPIO_PIN(PORT_A, 12),
|
||||
GPIO_PIN(PORT_A, 15),
|
||||
GPIO_PIN(PORT_B, 1),
|
||||
GPIO_PIN(PORT_B, 2),
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ARDUINO_BOARD_H */
|
||||
/** @} */
|
24
dist/tools/arduino/pre_build.sh
vendored
Executable file
24
dist/tools/arduino/pre_build.sh
vendored
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
# check if at least the application dir and one sketch is given
|
||||
if [ $# -lt 2 ]
|
||||
then
|
||||
echo "[Arduino pre-build] Error: not enough arguments given"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 'consume' the application and arduino directories (first argument)
|
||||
SRCDIR=$1
|
||||
shift
|
||||
APPDIR=$1
|
||||
shift
|
||||
|
||||
# create temporary file and put in the file header
|
||||
cat ${SRCDIR}/pre.snip > ${APPDIR}/_sketches.cpp
|
||||
# loop through the given sketches and include them into the temp file
|
||||
for sketch in $@
|
||||
do
|
||||
cat ${sketch} >> ${APPDIR}/_sketches.cpp
|
||||
done
|
||||
# and prepend the file with the arduino bootstrapping code
|
||||
cat ${SRCDIR}/post.snip >> ${APPDIR}/_sketches.cpp
|
@ -782,7 +782,8 @@ INPUT_ENCODING = UTF-8
|
||||
# *.qsf, *.as and *.js.
|
||||
|
||||
FILE_PATTERNS = *.txt \
|
||||
*.h
|
||||
*.h \
|
||||
*.hpp
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
|
20
examples/arduino_hello-world/Makefile
Normal file
20
examples/arduino_hello-world/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# name of your application
|
||||
APPLICATION = arduino_hello-world
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
USEMODULE += arduino
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
CFLAGS += -DDEVELHELP
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
43
examples/arduino_hello-world/README.md
Normal file
43
examples/arduino_hello-world/README.md
Normal file
@ -0,0 +1,43 @@
|
||||
examples/arduino_hello-world
|
||||
============================
|
||||
This application demonstrates the usage of Arduino sketches in RIOT.
|
||||
|
||||
The sketch itself is fairly simple. On startup, it initializes the LED pin to
|
||||
output mode, starts the serial port with a baudrate of 115200 and prints
|
||||
"Hello Arduino!" on the serial port. When running, the application echoes any
|
||||
newline terminated string that was received on the serial port, while toggling
|
||||
the default LED with a 1Hz frequency.
|
||||
|
||||
The sketch just uses some very primitive Arduino API elements for demonstration
|
||||
purposes:
|
||||
- control of digital pins (pinMode(), digital read and write)
|
||||
- the delay() function
|
||||
- reading and writing the serial port using the Serial class
|
||||
|
||||
Arduino and RIOT
|
||||
================
|
||||
For information on the Arduino support in RIOT please refer to the API
|
||||
documentation at http://doc.riot-os.org/group__sys__arduino.html
|
||||
|
||||
Usage
|
||||
=====
|
||||
Just send any newline terminated string to the board's serial port, and the
|
||||
board will echo this string.
|
||||
|
||||
Example output
|
||||
==============
|
||||
When using pyterm, the output will look similar to this:
|
||||
```
|
||||
2015-11-26 14:04:58,307 - INFO # main(): This is RIOT! (Version: xxx)
|
||||
2015-11-26 14:04:58,308 - INFO # Hello Arduino!
|
||||
hello again
|
||||
2015-11-26 14:06:29,800 - INFO # Echo: hello again
|
||||
are you still there?
|
||||
2015-11-26 14:06:48,301 - INFO # Echo: are you still there?
|
||||
|
||||
```
|
||||
If your board is equipped with an on-board LED, you should see this LED toggling
|
||||
every half a second.
|
||||
|
||||
NOTE: if your board's STDIO baudrate is not configured to be 115200 (see your
|
||||
board's `board.h`), the first line of the output may not be shown or scrambled.
|
63
examples/arduino_hello-world/hello-world.sketch
Normal file
63
examples/arduino_hello-world/hello-world.sketch
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Arduino Hello-World @ RIOT
|
||||
Prints 'Hello Arduino!' once on the serial port during startup, toggles the
|
||||
default LED twice each seconds and echoes incoming characters on the serial
|
||||
port.
|
||||
*/
|
||||
|
||||
// Per convention, RIOT defines a macro that is assigned the pin number of an
|
||||
// on-board LED. If no LED is available, the pin number defaults to 0. For
|
||||
// compatibility with the Arduino IDE, we also fall back to pin 0 here, if the
|
||||
// RIOT macro is not available
|
||||
#ifndef ARDUINO_LED
|
||||
#define ARDUINO_LED (0)
|
||||
#endif
|
||||
|
||||
// Assign the default LED pin
|
||||
int ledPin = ARDUINO_LED;
|
||||
|
||||
// input buffer for receiving chars on the serial port
|
||||
int buf[64];
|
||||
|
||||
// counter that counts the number of received chars
|
||||
int count = 0;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
// configure the LED pin to be output
|
||||
pinMode(ledPin, OUTPUT);
|
||||
// configure the first serial port to run with a baudrate of 115200
|
||||
Serial.begin(115200);
|
||||
// say hello
|
||||
Serial.println("Hello Arduino!");
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// toggle the LED
|
||||
digitalWrite(ledPin, !digitalRead(ledPin));
|
||||
// test if some chars were received
|
||||
while (Serial.available() > 0) {
|
||||
// read a single character
|
||||
int tmp = Serial.read();
|
||||
// if we got a line end, we echo the buffer
|
||||
if (tmp == '\n') {
|
||||
// start with printing 'ECHO: '
|
||||
Serial.write("Echo: ");
|
||||
// echo the buffer
|
||||
for (int i = 0; i < count; i++) {
|
||||
Serial.write(buf[i]);
|
||||
}
|
||||
// terminate the string with a newline
|
||||
Serial.write('\n');
|
||||
// reset the count variable
|
||||
count = 0;
|
||||
}
|
||||
// else we just remember the incoming char
|
||||
else {
|
||||
buf[count++] = tmp;
|
||||
}
|
||||
}
|
||||
// wait for half a second
|
||||
delay(500);
|
||||
}
|
@ -65,4 +65,8 @@ ifneq (,$(filter newlib,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/newlib/Makefile.include
|
||||
endif
|
||||
|
||||
ifneq (,$(filter arduino,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/arduino/Makefile.include
|
||||
endif
|
||||
|
||||
INCLUDES += -I$(RIOTBASE)/sys/libc/include
|
||||
|
1
sys/arduino/Makefile
Normal file
1
sys/arduino/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
9
sys/arduino/Makefile.include
Normal file
9
sys/arduino/Makefile.include
Normal file
@ -0,0 +1,9 @@
|
||||
# compile together the Arduino sketches of the application
|
||||
SKETCHES = $(wildcard $(APPDIR)*.sketch)
|
||||
SRCDIR = $(RIOTBASE)/sys/arduino
|
||||
|
||||
# run the Arduino pre-build script
|
||||
$(shell $(RIOTBASE)/dist/tools/arduino/pre_build.sh $(SRCDIR) $(APPDIR) $(SKETCHES))
|
||||
|
||||
# include the Arduino headers
|
||||
export INCLUDES += -I$(RIOTBASE)/sys/arduino/include
|
61
sys/arduino/base.cpp
Normal file
61
sys/arduino/base.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 Arduino core functionality
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "xtimer.h"
|
||||
#include "periph/gpio.h"
|
||||
}
|
||||
|
||||
#include "arduino.hpp"
|
||||
|
||||
static inline gpio_dir_t _dir(int mode)
|
||||
{
|
||||
return (mode == OUTPUT) ? GPIO_DIR_OUT : GPIO_DIR_IN;
|
||||
}
|
||||
|
||||
static inline gpio_pp_t _pr(int mode)
|
||||
{
|
||||
return (mode == INPUT_PULLUP) ? GPIO_PULLUP : GPIO_NOPULL;
|
||||
}
|
||||
|
||||
void pinMode(int pin, int mode)
|
||||
{
|
||||
gpio_init(arduino_pinmap[pin], _dir(mode), _pr(mode));
|
||||
}
|
||||
|
||||
void digitalWrite(int pin, int state)
|
||||
{
|
||||
gpio_write(arduino_pinmap[pin], state);
|
||||
}
|
||||
|
||||
int digitalRead(int pin)
|
||||
{
|
||||
if (gpio_read(arduino_pinmap[pin])) {
|
||||
return HIGH;
|
||||
}
|
||||
else {
|
||||
return LOW;
|
||||
}
|
||||
}
|
||||
|
||||
void delay(int msec)
|
||||
{
|
||||
xtimer_usleep(1000 * msec);
|
||||
}
|
136
sys/arduino/doc.txt
Normal file
136
sys/arduino/doc.txt
Normal file
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @defgroup sys_arduino Arduino
|
||||
* @ingroup sys
|
||||
* @brief Arduino in RIOT
|
||||
*
|
||||
* @section sec_about About
|
||||
*
|
||||
* This module enables users to run unmodified Arduino sketches in RIOT. For
|
||||
* this we aim at supporting the full Arduino API.
|
||||
*
|
||||
* The support of the Arduino API in RIOT is useful for multiple reasons:
|
||||
* - starting point for beginners
|
||||
* - run your existing sketches on any non-Arduino hardware supported by RIOT
|
||||
* - makes it easy to move from Arduino to RIOT
|
||||
* - use Ardunio device drivers in RIOT
|
||||
* - is fun to implement :-)
|
||||
*
|
||||
* Refer to @ref sys_arduino_api for the actual API documentation
|
||||
*
|
||||
*
|
||||
* @section sec_usage General usage
|
||||
*
|
||||
* To run you Arduino sketch in RIOT, just follow these steps:
|
||||
*
|
||||
* -# create an empty application
|
||||
* -# add the `arduino` module to your application, your `Makefile` should now
|
||||
* look something like this:
|
||||
* @code
|
||||
* APPLICATION = YOUR_APP_NAME
|
||||
* BOARD ?= YOUR_TARGET_PLATFORM
|
||||
* RIOTBASE ?= PATH_TO_RIOT_ROOT
|
||||
*
|
||||
* USEMODULE += arduino
|
||||
*
|
||||
* include $(RIOTBASE)/Makefile.include
|
||||
* @endcode
|
||||
*
|
||||
* -# copy you Arduino sktech(es) into your application folder. Currently they
|
||||
* must have the file ending `*.sketch` to be processed.
|
||||
* -# build, flash, and run your application the usual RIOT-way: simply call
|
||||
* `make all`, `make flash`, `make term`, etc.
|
||||
*
|
||||
* Thats all. As bonus you can of course use any existing RIOT code inside your
|
||||
* Arduino sketches - you simply have to add the includes to your sketch and
|
||||
* the corresponding modules to your `Makefile`.
|
||||
*
|
||||
* @note So far, all Arduino sketches MUST have the file ending `*.sketch` to
|
||||
* be recognized by RIOT's build system
|
||||
*
|
||||
*
|
||||
* @section sec_concept Concept
|
||||
*
|
||||
* For enabling RIOT to run Arduino sketches, we extended the build system to
|
||||
* handle `*.sketch` files and we implemented the Arduino API using RIOT's
|
||||
* native functions.
|
||||
*
|
||||
* @subsection sec_concept_build Extension of the build system
|
||||
*
|
||||
* Building Arduino sketches in RIOT is done in a two step process.
|
||||
*
|
||||
* First, the make system calls a dedicated
|
||||
* [Arduino build script](https://github.com/RIOT-OS/RIOT/tree/master/dist/tools/arduino/pre_build.sh),
|
||||
* which is called from the
|
||||
* [Makefile.include](https://github.com/RIOT-OS/RIOT/tree/master/sys/arduino/Makefile.include)
|
||||
* of the RIOT Arduino module.
|
||||
*
|
||||
* This script creates a temporary file called '_sketches.cpp' inside the
|
||||
* application folder. Into this file, the script copies some Arduino glue code (
|
||||
* [pre.snip](https://github.com/RIOT-OS/RIOT/blob/master/sys/arduino/pre.snip)
|
||||
* and
|
||||
* [post.snip](https://github.com/RIOT-OS/RIOT/blob/master/sys/arduino/post.snip))
|
||||
* together with the contents of all `*.sketch` files contained in the
|
||||
* application folder.
|
||||
*
|
||||
* Second, the RIOT make system is called as usual, processing the temporary
|
||||
* file containing all the Arduino code. Simple :-)
|
||||
*
|
||||
* @subsection sec_conecpt_api Implementation of the Arduino API
|
||||
*
|
||||
* For supporting the Arduino API, we have created our own function and class
|
||||
* definitions, using the exact same signatures as in the original Arduino
|
||||
* header files. These headers are then implemented using standard RIOT APIs,
|
||||
* e.g. the peripheral drivers, `xtimer`, etc.
|
||||
*
|
||||
*
|
||||
* @section sec_boardsupport Add Arduino support to a board
|
||||
*
|
||||
* @note As prerequisite, the board must have support for C++.
|
||||
*
|
||||
* To add Arduino support to a board, it has to provice the following:
|
||||
*
|
||||
* In `RIOT/board/BOARD/include/arduino_board.h`:
|
||||
* - a mapping of GPIO pins to Arduino pin numbers named `arduino_pinmap`, e.g.
|
||||
* @code{c}
|
||||
* static const gpio_t arduino_pinmap[] = {
|
||||
* GPIO_PIN(PORT_D, 12),
|
||||
* GPIO_PIN(PORT_D, 13),
|
||||
* GPIO_PIN(PORT_D, 14),
|
||||
* GPIO_PIN(PORT_D, 15),
|
||||
* GPIO_PIN(PORT_A, 12),
|
||||
* GPIO_PIN(PORT_A, 15),
|
||||
* GPIO_PIN(PORT_B, 1),
|
||||
* GPIO_PIN(PORT_B, 2),
|
||||
* ...
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* - a define `ARDUINO_LED` that is mapped to an Arduino pin number connected to
|
||||
* any on-board LED, or to pin 0 in case no LED is defined:
|
||||
* @code{c}
|
||||
* #define ARDUINO_LED (2)
|
||||
* @endcode
|
||||
* This links to the third entry in the `arduino_pinmap` array.
|
||||
*
|
||||
* In addition, you have to add the 'arduino' feature to the board. for this,
|
||||
* just add `FEATURES_PROVIDED += arduino` to the 'other features' section in
|
||||
* your boards `Makefile.features'.
|
||||
*
|
||||
* That's it, your board can now run Ardunio sketches.
|
||||
*
|
||||
*
|
||||
* @section sec_todo Open issues
|
||||
*
|
||||
* @todo Make it possible to bootstrap Arduino code manually from any RIOT
|
||||
* application. Include a pseudomule as e.g. arduino_base, which does not
|
||||
* implement a main function calling `setup()` and `loop()`, so these
|
||||
* functions have to be called manually from a RIOT application.
|
||||
* @todo Implement analog outputs (PWM mapping)
|
||||
* @todo Implement analog inputs (ADC mapping)
|
||||
* @todo Implement SPI interface class
|
||||
* @todo Add support for the 'Wrie Library' (I2C)
|
||||
* @todo Add means to include various Arduino Libraries (maybe as pkg?)
|
||||
* @todo Implement anything else that is missing...
|
||||
* @todo Adapt Arduino build script, so sketches do not have to have the file
|
||||
* ending `*.sketch` anymore
|
||||
*/
|
86
sys/arduino/include/arduino.hpp
Normal file
86
sys/arduino/include/arduino.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sys_arduino_api Arduino API
|
||||
* @ingroup sys_arduino
|
||||
* @brief Implementation of the Arduino API in RIOT
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Main interface definition of the Arduino API
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef ARDUINO_H
|
||||
#define ARDUINO_H
|
||||
|
||||
extern "C" {
|
||||
#include "periph/gpio.h"
|
||||
#include "arduino_board.h"
|
||||
}
|
||||
|
||||
#include "serialport.hpp"
|
||||
|
||||
/**
|
||||
* @brief Possible pin configurations
|
||||
*/
|
||||
enum {
|
||||
INPUT, /**< configure pin as input */
|
||||
OUTPUT, /**< configure pin as output */
|
||||
INPUT_PULLUP, /**< configure pin as input with pull-up resistor */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Possible pin states
|
||||
*/
|
||||
enum {
|
||||
LOW = 0, /**< pin is cleared */
|
||||
HIGH = 1, /**< pin is set */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Primary serial port (mapped to UART_DEV(0))
|
||||
*/
|
||||
static SerialPort Serial(UART_DEV(0));
|
||||
|
||||
/**
|
||||
* @brief Configure a pin as either input or output
|
||||
*
|
||||
* @param[in] pin pin to configure
|
||||
* @param[in] mode mode to set the pin to
|
||||
*/
|
||||
void pinMode(int pin, int mode);
|
||||
|
||||
/**
|
||||
* @brief Set the value for the given pin
|
||||
*
|
||||
* @param[in] pin pin to set
|
||||
* @param[in] state HIGH or LOW
|
||||
*/
|
||||
void digitalWrite(int pin, int state);
|
||||
|
||||
/**
|
||||
* @brief Read the current state of the given pin
|
||||
*
|
||||
* @param[in] pin pin to read
|
||||
*
|
||||
* @return state of the given pin, HIGH or LOW
|
||||
*/
|
||||
int digitalRead(int pin);
|
||||
|
||||
/**
|
||||
* @brief Sleep for a given amount of time [milliseconds]
|
||||
*
|
||||
* @param[in] msec number of milliseconds to sleep
|
||||
*/
|
||||
void delay(int msec);
|
||||
|
||||
#endif /* ARDUINO_H */
|
||||
/** @} */
|
301
sys/arduino/include/serialport.hpp
Normal file
301
sys/arduino/include/serialport.hpp
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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_api
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Definition of the Arduino 'Serial' interface
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef ARDUINO_SERIAL_H
|
||||
#define ARDUINO_SERIAL_H
|
||||
|
||||
extern "C" {
|
||||
#include "ringbuffer.h"
|
||||
#include "periph/uart.h"
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default RX buffer size - same as the original Arduino...
|
||||
*/
|
||||
#define SERIAL_RX_BUFSIZE (64)
|
||||
|
||||
/**
|
||||
* @brief Formatting options for Serial.print(int, format)
|
||||
*/
|
||||
enum SerialFormat {
|
||||
BIN, /**< format to binary representation */
|
||||
OCT, /**< format to octal representation */
|
||||
DEC, /**< format to decimal representation */
|
||||
HEX, /**< format to hex representation */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Arduino Serial Interface
|
||||
*/
|
||||
class SerialPort {
|
||||
|
||||
private:
|
||||
uart_t dev;
|
||||
char rx_mem[SERIAL_RX_BUFSIZE];
|
||||
ringbuffer_t rx_buf;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor maps the serial port to a RIOT UART device
|
||||
*
|
||||
* @param[in] dev RIOT UART device
|
||||
*/
|
||||
SerialPort(uart_t dev);
|
||||
|
||||
/**
|
||||
* @brief Get the number of bytes (characters) available for reading from
|
||||
* the serial port
|
||||
*
|
||||
* This is data that's already arrived and stored in the serial receive
|
||||
* buffer (which holds 64 bytes). available() inherits from the Stream
|
||||
* utility class.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Serial/Available
|
||||
*
|
||||
* @return The number of bytes available to read
|
||||
*/
|
||||
int available(void);
|
||||
|
||||
/**
|
||||
* @brief Sets the data rate in bits per second (baud) for serial data
|
||||
* transmission
|
||||
*
|
||||
* For communicating with the computer, use one of these rates: 300, 600,
|
||||
* 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, or 115200. You
|
||||
* can, however, specify other rates - for example, to communicate over
|
||||
* pins 0 and 1 with a component that requires a particular baud rate.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Serial/Begin
|
||||
*
|
||||
* @param[in] speed speed in bits per second (baud)
|
||||
*/
|
||||
void begin(int speed);
|
||||
|
||||
/**
|
||||
* @brief Disables serial communication, allowing the RX and TX pins to be
|
||||
* used for general input and output
|
||||
*
|
||||
* To re-enable serial communication, call @ref begin()
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Serial/End
|
||||
*/
|
||||
void end(void);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
*
|
||||
* Prints data to the serial port as human-readable ASCII text. This command
|
||||
* can take many forms. Numbers are printed using an ASCII character for
|
||||
* each digit. Floats are similarly printed as ASCII digits, defaulting to
|
||||
* two decimal places. Bytes are sent as a single character. Characters and
|
||||
* strings are sent as is.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Serial/Print
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t print(int val);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
*
|
||||
* @see print()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
* @param[in] format specifies the number base
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t print(int val, SerialFormat format);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t print(float val);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
*
|
||||
* @see print()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
* @param[in] format number of decimal places
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t print(float val, int format);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
*
|
||||
* @see print()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t print(char val);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
*
|
||||
* @see print()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t print(const char *val);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
* followed by a carriage return character (ASCII 13, or "\r") and
|
||||
* a newline character (ASCII 10, or "\n")
|
||||
*
|
||||
* This command takes the same forms as @ref print().
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Serial/Println
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t println(int val);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
* followed by a carriage return character (ASCII 13, or "\r") and
|
||||
* a newline character (ASCII 10, or "\n")
|
||||
*
|
||||
* @see println()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
* @param[in] format specifies the number base
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t println(int val, SerialFormat format);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
* followed by a carriage return character (ASCII 13, or "\r") and
|
||||
* a newline character (ASCII 10, or "\n")
|
||||
*
|
||||
* @see println()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t println(float val);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
* followed by a carriage return character (ASCII 13, or "\r") and
|
||||
* a newline character (ASCII 10, or "\n")
|
||||
*
|
||||
* @see println()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
* @param[in] format number of decimal places
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t println(float val, int format);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
* followed by a carriage return character (ASCII 13, or "\r") and
|
||||
* a newline character (ASCII 10, or "\n")
|
||||
*
|
||||
* @see println()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t println(char val);
|
||||
|
||||
/**
|
||||
* @brief Prints data to the serial port as human-readable ASCII text
|
||||
* followed by a carriage return character (ASCII 13, or "\r") and
|
||||
* a newline character (ASCII 10, or "\n")
|
||||
*
|
||||
* @see println()
|
||||
*
|
||||
* @param[in] val the value to print
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
size_t println(const char *val);
|
||||
|
||||
/**
|
||||
* @brief Reads incoming serial data
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Serial/Read
|
||||
*
|
||||
* @return the first byte of incoming serial data available
|
||||
* @return -1 if no data is available
|
||||
*/
|
||||
int read(void);
|
||||
|
||||
/**
|
||||
* @brief Writes binary data to the serial port
|
||||
*
|
||||
* This data is sent as a byte or series of bytes; to send the characters
|
||||
* representing the digits of a number use the @ref print() function instead.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Serial/Write
|
||||
*
|
||||
* @param[in] val a value to send as a single byte
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
int write(int val);
|
||||
|
||||
/**
|
||||
* @brief Writes binary data to the serial port
|
||||
*
|
||||
* @see write()
|
||||
*
|
||||
* @param[in] str a string to send as a series of bytes
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
int write(const char *str);
|
||||
|
||||
/**
|
||||
* @brief Writes binary data to the serial port
|
||||
* @details [long description]
|
||||
*
|
||||
* @param[in] buf an array to send as a series of bytes
|
||||
* @param[in] len the length of the buffer
|
||||
*
|
||||
* @return the number of bytes written, reading that number is optional
|
||||
*/
|
||||
int write(char *buf, int len);
|
||||
};
|
||||
|
||||
#endif /* ARDUINO_SERIAL_H */
|
||||
/** @} */
|
12
sys/arduino/post.snip
Normal file
12
sys/arduino/post.snip
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* run the Arduino setup */
|
||||
setup();
|
||||
/* and the event loop */
|
||||
while (1) {
|
||||
loop();
|
||||
}
|
||||
/* never reached */
|
||||
return 0;
|
||||
}
|
1
sys/arduino/pre.snip
Normal file
1
sys/arduino/pre.snip
Normal file
@ -0,0 +1 @@
|
||||
#include "arduino.hpp"
|
181
sys/arduino/serialport.cpp
Normal file
181
sys/arduino/serialport.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include "irq.h"
|
||||
}
|
||||
|
||||
#include "serialport.hpp"
|
||||
|
||||
void rx_cb(void *arg, char c)
|
||||
{
|
||||
ringbuffer_t *buf = (ringbuffer_t *)arg;
|
||||
ringbuffer_add_one(buf, c);
|
||||
}
|
||||
|
||||
SerialPort::SerialPort(uart_t dev)
|
||||
{
|
||||
this->dev = dev;
|
||||
}
|
||||
|
||||
int SerialPort::available(void)
|
||||
{
|
||||
return (int)rx_buf.avail;
|
||||
}
|
||||
|
||||
void SerialPort::begin(int baudrate)
|
||||
{
|
||||
/* this clears the contents of the ringbuffer... */
|
||||
ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
|
||||
uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
|
||||
}
|
||||
|
||||
void SerialPort::end(void)
|
||||
{
|
||||
uart_poweroff(dev);
|
||||
}
|
||||
|
||||
size_t SerialPort::print(int val)
|
||||
{
|
||||
return print(val, DEC);
|
||||
}
|
||||
|
||||
size_t SerialPort::print(int val, SerialFormat format)
|
||||
{
|
||||
char buf[64];
|
||||
size_t len;
|
||||
switch (format) {
|
||||
case BIN:
|
||||
/* TODO */
|
||||
return 0;
|
||||
case OCT:
|
||||
len = sprintf(buf, "%o", (unsigned)val);
|
||||
break;
|
||||
case DEC:
|
||||
len = sprintf(buf, "%i", val);
|
||||
break;
|
||||
case HEX:
|
||||
len = sprintf(buf, "%x", (unsigned)val);
|
||||
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];
|
||||
size_t len = sprintf(buf, "%.*f", format, val);
|
||||
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);
|
||||
}
|
||||
|
||||
size_t SerialPort::println(int val)
|
||||
{
|
||||
size_t res = print(val);
|
||||
write("\r\n");
|
||||
return (res + 2);
|
||||
}
|
||||
|
||||
size_t SerialPort::println(int val, SerialFormat format)
|
||||
{
|
||||
size_t res = print(val, format);
|
||||
write("\r\n");
|
||||
return (res + 2);
|
||||
}
|
||||
|
||||
size_t SerialPort::println(float val)
|
||||
{
|
||||
size_t res = print(val);
|
||||
write("\r\n");
|
||||
return (res + 2);
|
||||
}
|
||||
|
||||
size_t SerialPort::println(float val, int format)
|
||||
{
|
||||
size_t res = print(val, format);
|
||||
write("\r\n");
|
||||
return (res + 2);
|
||||
}
|
||||
|
||||
size_t SerialPort::println(char val)
|
||||
{
|
||||
size_t res = print(val);
|
||||
write("\r\n");
|
||||
return (res + 2);
|
||||
}
|
||||
|
||||
size_t SerialPort::println(const char *val)
|
||||
{
|
||||
size_t res = print(val);
|
||||
write("\r\n");
|
||||
return (res + 2);
|
||||
}
|
||||
|
||||
int SerialPort::read(void)
|
||||
{
|
||||
int res = -1;
|
||||
|
||||
disableIRQ();
|
||||
if (rx_buf.avail > 0) {
|
||||
res = ringbuffer_get_one(&rx_buf);
|
||||
}
|
||||
enableIRQ();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int SerialPort::write(int val)
|
||||
{
|
||||
uart_write(dev, (uint8_t *)&val, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SerialPort::write(const char *str)
|
||||
{
|
||||
uart_write(dev, (uint8_t *)str, strlen(str));
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
int SerialPort::write(char *buf, int len)
|
||||
{
|
||||
uart_write(dev, (uint8_t *)buf, len);
|
||||
return len;
|
||||
}
|
Loading…
Reference in New Issue
Block a user