[realtek-ambz] Implement SoftwareSerial class
This commit is contained in:
@@ -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** | |
|
||||
|
||||
@@ -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)
|
||||
|
||||
41
arduino/libretuya/api/SoftwareSerial.cpp
Normal file
41
arduino/libretuya/api/SoftwareSerial.cpp
Normal file
@@ -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;
|
||||
}
|
||||
74
arduino/libretuya/api/SoftwareSerial.h
Normal file
74
arduino/libretuya/api/SoftwareSerial.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/HardwareSerial.h>
|
||||
#include <api/RingBuffer.h>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,99 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#include "SoftwareSerial.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <timer_api.h>
|
||||
|
||||
} // 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);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/SoftwareSerial.h>
|
||||
Reference in New Issue
Block a user