pxt-calliope/libs/core/serial.cpp
2021-11-25 17:27:39 +01:00

233 lines
6.8 KiB
C++

#include "pxt.h"
#define MICROBIT_SERIAL_READ_BUFFER_LENGTH 64
// make sure USB_TX and USB_RX don't overlap with other pin ids
// also, 1001,1002 need to be kept in sync with getPin() function
enum SerialPin {
P0 = MICROBIT_ID_IO_P12,
P1 = MICROBIT_ID_IO_P0,
P2 = MICROBIT_ID_IO_P1,
P3 = MICROBIT_ID_IO_P16,
C16 = MICROBIT_ID_IO_P2,
C17 = MICROBIT_ID_IO_P8,
USB_TX = 1001,
USB_RX = 1002
};
enum BaudRate {
//% block=115200
BaudRate115200 = 115200,
//% block=57600
BaudRate57600 = 57600,
//% block=38400
BaudRate38400 = 38400,
//% block=31250
BaudRate31250 = 31250,
//% block=28800
BaudRate28800 = 28800,
//% block=19200
BaudRate19200 = 19200,
//% block=14400
BaudRate14400 = 14400,
//% block=9600
BaudRate9600 = 9600,
//% block=4800
BaudRate4800 = 4800,
//% block=2400
BaudRate2400 = 2400,
//% block=1200
BaudRate1200 = 1200
};
//% weight=2 color=#002050 icon="\uf287"
//% advanced=true
namespace serial {
// note that at least one // followed by % is needed per declaration!
/**
* Read a line of text from the serial port and return the buffer when the delimiter is met.
* @param delimiter text delimiter that separates each text chunk
*/
//% help=serial/read-until
//% blockId=serial_read_until block="serial|read until %delimiter=serial_delimiter_conv"
//% weight=19
String readUntil(String delimiter) {
return PSTR(uBit.serial.readUntil(MSTR(delimiter)));
}
/**
* Read the buffered received data as a string
*/
//% help=serial/read-string
//% blockId=serial_read_buffer block="serial|read string"
//% weight=18
String readString() {
int n = uBit.serial.getRxBufferSize();
if (n == 0) return mkString("", 0);
return PSTR(uBit.serial.read(n, MicroBitSerialMode::ASYNC));
}
/**
* Register an event to be fired when one of the delimiter is matched.
* @param delimiters the characters to match received characters against.
*/
//% help=serial/on-data-received
//% weight=18 blockId=serial_on_data_received block="serial|on data received %delimiters=serial_delimiter_conv"
void onDataReceived(String delimiters, Action body) {
uBit.serial.eventOn(MSTR(delimiters));
registerWithDal(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_DELIM_MATCH, body);
// lazy initialization of serial buffers
uBit.serial.read(MicroBitSerialMode::ASYNC);
}
/**
* Send a piece of text through the serial connection.
*/
//% help=serial/write-string
//% weight=87 blockGap=8
//% blockId=serial_writestring block="serial|write string %text"
//% text.shadowOptions.toString=true
void writeString(String text) {
if (!text) return;
uBit.serial.send(MSTR(text));
}
/**
* Send a buffer through serial connection
*/
//% blockId=serial_writebuffer block="serial|write buffer %buffer=serial_readbuffer"
//% help=serial/write-buffer advanced=true weight=6
void writeBuffer(Buffer buffer) {
if (!buffer) return;
uBit.serial.send(buffer->data, buffer->length);
}
/**
* Read multiple characters from the receive buffer.
* If length is positive, pauses until enough characters are present.
* @param length default buffer length
*/
//% blockId=serial_readbuffer block="serial|read buffer %length"
//% help=serial/read-buffer advanced=true weight=5
Buffer readBuffer(int length) {
auto mode = SYNC_SLEEP;
if (length <= 0) {
length = uBit.serial.getRxBufferSize();
mode = ASYNC;
}
auto buf = mkBuffer(NULL, length);
auto res = buf;
registerGCObj(buf); // make sure buffer is pinned, while we wait for data
int read = uBit.serial.read(buf->data, buf->length, mode);
if (read != length) {
res = mkBuffer(buf->data, read);
}
unregisterGCObj(buf);
return res;
}
bool tryResolvePin(SerialPin p, PinName& name) {
switch(p) {
#if !MICROBIT_CODAL
case SerialPin::USB_TX: name = USBTX; return true;
case SerialPin::USB_RX: name = USBRX; return true;
#endif
default:
auto pin = getPin(p);
if (NULL != pin) {
name = (PinName)pin->name;
return true;
}
}
return false;
}
/**
* Set the serial input and output to use pins instead of the USB connection.
* @param tx the new transmission pin, eg: SerialPin.P0
* @param rx the new reception pin, eg: SerialPin.P1
* @param rate the new baud rate. eg: 115200
*/
//% weight=10
//% help=serial/redirect
//% blockId=serial_redirect block="serial|redirect to|TX %tx|RX %rx|at baud rate %rate"
//% blockExternalInputs=1
//% tx.fieldEditor="gridpicker" tx.fieldOptions.columns=3
//% tx.fieldOptions.tooltips="false"
//% rx.fieldEditor="gridpicker" rx.fieldOptions.columns=3
//% rx.fieldOptions.tooltips="false"
//% blockGap=8
void redirect(SerialPin tx, SerialPin rx, BaudRate rate) {
#if MICROBIT_CODAL
if (getPin(tx) && getPin(rx))
uBit.serial.redirect(*getPin(tx), *getPin(rx));
uBit.serial.setBaud(rate);
#else
PinName txn;
PinName rxn;
if (tryResolvePin(tx, txn) && tryResolvePin(rx, rxn))
uBit.serial.redirect(txn, rxn);
uBit.serial.baud((int)rate);
#endif
}
/**
Set the baud rate of the serial port
*/
//% weight=10
//% blockId=serial_setbaudrate block="serial|set baud rate %rate"
//% blockGap=8 inlineInputMode=inline
//% help=serial/set-baud-rate
//% group="Configuration" advanced=true
void setBaudRate(BaudRate rate) {
#if MICROBIT_CODAL
uBit.serial.setBaud(rate);
#else
uBit.serial.baud((int)rate);
#endif
}
/**
* Direct the serial input and output to use the USB connection.
*/
//% weight=9 help=serial/redirect-to-usb
//% blockId=serial_redirect_to_usb block="serial|redirect to USB"
void redirectToUSB() {
#if MICROBIT_CODAL
uBit.serial.redirect(uBit.io.usbTx, uBit.io.usbRx);
uBit.serial.setBaud(115200);
#else
uBit.serial.redirect(USBTX, USBRX);
uBit.serial.baud(115200);
#endif
}
/**
* Sets the size of the RX buffer in bytes
* @param size length of the rx buffer in bytes, eg: 32
*/
//% help=serial/set-rx-buffer-size
//% blockId=serialSetRxBufferSize block="serial set rx buffer size to $size"
//% advanced=true
void setRxBufferSize(uint8_t size) {
uBit.serial.setRxBufferSize(size);
}
/**
* Sets the size of the TX buffer in bytes
* @param size length of the tx buffer in bytes, eg: 32
*/
//% help=serial/set-tx-buffer-size
//% blockId=serialSetTxBufferSize block="serial set tx buffer size to $size"
//% advanced=true
void setTxBufferSize(uint8_t size) {
uBit.serial.setTxBufferSize(size);
}
}