diff --git a/README.md b/README.md index 643a322..9c64963 100644 --- a/README.md +++ b/README.md @@ -47,10 +47,10 @@ Core functions | ✔️ | ✔️ GPIO/PWM/IRQ | ✔️/✔️/✔️ | ❓/✔️/❌ Analog input (ADC) | ✔️ | ✔️ Serial | ✔️ | ✔️ -Serial (extra) | ❌ | 1, 2 +Serial (extra) | 0, 1, 2 | 1, 2 Flash I/O | ✔️ | ✔️ **CORE LIBRARIES** | | -SoftwareSerial | ❌ | ❌ +SoftwareSerial | ✔️ | ❌ SPI | ❌ | ❌ Wire | ❗ | ❌ **OTHER LIBRARIES** | | diff --git a/SUMMARY.md b/SUMMARY.md index 3de385f..8d24066 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -14,6 +14,7 @@ * Common API * [FS](ltapi/classfs_1_1_f_s.md) * [Preferences](ltapi/class_i_preferences.md) + * [SoftwareSerial](ltapi/class_software_serial.md) * [WiFi API](ltapi/class_wi_fi_class.md) * [TCP Client](ltapi/class_i_wi_fi_client.md) * [SSL Client](ltapi/class_i_wi_fi_client_secure.md) diff --git a/arduino/libretuya/api/SoftwareSerial.cpp b/arduino/libretuya/api/SoftwareSerial.cpp new file mode 100644 index 0000000..9094b8c --- /dev/null +++ b/arduino/libretuya/api/SoftwareSerial.cpp @@ -0,0 +1,41 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ + +#include "SoftwareSerial.h" + +SoftwareSerial::SoftwareSerial(pin_size_t receivePin, pin_size_t transmitPin, bool inverted) { + data.rx.buf = NULL; + data.tx.buf = NULL; + data.rx.pin = receivePin; + data.tx.pin = transmitPin; + data.invert = inverted == true; +} + +int SoftwareSerial::available() { + return data.rx.buf->available(); +} + +int SoftwareSerial::peek() { + return data.rx.buf->peek(); +} + +int SoftwareSerial::read() { + return data.rx.buf->read_char(); +} + +void SoftwareSerial::flush() { + while (data.rx.buf->available()) { + yield(); + } +} + +size_t SoftwareSerial::write(uint8_t c) { + while (data.tx.buf->isFull()) { + yield(); + } + data.tx.buf->store_char(c); + if (data.tx.state == SS_IDLE) { + data.tx.state = SS_START; + this->startTx(); + } + return 1; +} diff --git a/arduino/libretuya/api/SoftwareSerial.h b/arduino/libretuya/api/SoftwareSerial.h new file mode 100644 index 0000000..0d21d43 --- /dev/null +++ b/arduino/libretuya/api/SoftwareSerial.h @@ -0,0 +1,74 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ + +#pragma once + +#include +#include +#include + +using namespace arduino; + +typedef enum { + SS_IDLE = 0, + SS_START, + SS_DATA0, + SS_DATA1, + SS_DATA2, + SS_DATA3, + SS_DATA4, + SS_DATA5, + SS_DATA6, + SS_DATA7, + SS_STOP, + SS_END, +} SoftState; + +typedef struct { + SoftState state; + RingBuffer *buf; + uint8_t byte; + pin_size_t pin; + void *param; +} SoftData; + +typedef struct { + SoftData rx; + SoftData tx; + uint8_t invert; + void *param; +} SoftSerial; + +class SoftwareSerial : public HardwareSerial { + private: + SoftSerial data; + void *param; + + public: + SoftwareSerial(pin_size_t receivePin, pin_size_t transmitPin, bool inverted = false); + + inline void begin(unsigned long baudrate) { + begin(baudrate, SERIAL_8N1); + } + + int available(); + int peek(); + int read(); + void flush(); + size_t write(uint8_t c); + + operator bool() { + return data.rx.buf || data.tx.buf; + } + + public: // Family needs to implement these methods only + void begin(unsigned long baudrate, uint16_t config); + void end(); + + private: + void startTx(); + void endTx(); + + using Print::write; +}; + +#define HAS_SERIAL_CLASS 1 diff --git a/arduino/realtek-ambz/libraries/SoftwareSerial/SoftwareSerial.cpp b/arduino/realtek-ambz/libraries/SoftwareSerial/SoftwareSerial.cpp new file mode 100644 index 0000000..a9e5da8 --- /dev/null +++ b/arduino/realtek-ambz/libraries/SoftwareSerial/SoftwareSerial.cpp @@ -0,0 +1,99 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ + +#include "SoftwareSerial.h" + +extern "C" { + +#include + +} // extern "C" + +#define TIMER_MAX 3 +#define OBJ ((gtimer_t *)this->param) + +static uint32_t timNum[TIMER_MAX] = {TIMER1, TIMER2, TIMER3}; +static gtimer_t *timObj[TIMER_MAX] = {NULL, NULL, NULL}; + +static void callback(SoftSerial *data) { + SoftData *tx = &data->tx; + + switch (tx->state) { + case SS_IDLE: + goto finish; + + case SS_END: + case SS_START: + if (!tx->buf->available()) + goto finish; + tx->byte = tx->buf->read_char(); + digitalWrite(tx->pin, LOW); + tx->state = SS_DATA0; + return; + + case SS_STOP: + digitalWrite(tx->pin, HIGH); + break; + + default: + digitalWrite(tx->pin, (tx->byte & 0x1) ^ data->invert); + tx->byte /= 2; + break; + } + + tx->state = (SoftState)(tx->state + 1); + return; + +finish: + gtimer_stop((gtimer_t *)data->param); + data->tx.state = SS_IDLE; + return; +} + +void SoftwareSerial::begin(unsigned long baudrate, uint16_t config) { + if (data.rx.buf || data.tx.buf) + return; + + uint8_t i; + for (i = 0; i < TIMER_MAX; i++) { + if (timObj[i] == NULL) + break; + } + if (i == TIMER_MAX) { + LT_E("No more timers for SoftwareSerial"); + return; + } + + pinMode(data.tx.pin, OUTPUT); + digitalWrite(data.tx.pin, HIGH); + + data.rx.buf = new RingBuffer(); + data.tx.buf = new RingBuffer(); + data.rx.state = SS_IDLE; + data.tx.state = SS_IDLE; + + uint32_t us = 1E6 / baudrate; + + timObj[i] = (gtimer_t *)malloc(sizeof(gtimer_t)); + param = data.param = data.tx.param = timObj[i]; + gtimer_init(OBJ, timNum[i]); + OBJ->is_periodcal = true; + OBJ->handler = (void *)callback; + OBJ->hid = (uint32_t)&data; + gtimer_reload(OBJ, us); +} + +void SoftwareSerial::end() { + gtimer_stop(OBJ); + gtimer_deinit(OBJ); + free(OBJ); + delete data.rx.buf; + delete data.tx.buf; +} + +void SoftwareSerial::startTx() { + gtimer_start(OBJ); +} + +void SoftwareSerial::endTx() { + gtimer_stop(OBJ); +} diff --git a/arduino/realtek-ambz/libraries/SoftwareSerial/SoftwareSerial.h b/arduino/realtek-ambz/libraries/SoftwareSerial/SoftwareSerial.h new file mode 100644 index 0000000..e711c8a --- /dev/null +++ b/arduino/realtek-ambz/libraries/SoftwareSerial/SoftwareSerial.h @@ -0,0 +1,5 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ + +#pragma once + +#include