[realtek-ambz] Implement SoftwareSerial class
This commit is contained in:
@@ -47,10 +47,10 @@ Core functions | ✔️ | ✔️
|
|||||||
GPIO/PWM/IRQ | ✔️/✔️/✔️ | ❓/✔️/❌
|
GPIO/PWM/IRQ | ✔️/✔️/✔️ | ❓/✔️/❌
|
||||||
Analog input (ADC) | ✔️ | ✔️
|
Analog input (ADC) | ✔️ | ✔️
|
||||||
Serial | ✔️ | ✔️
|
Serial | ✔️ | ✔️
|
||||||
Serial (extra) | ❌ | 1, 2
|
Serial (extra) | 0, 1, 2 | 1, 2
|
||||||
Flash I/O | ✔️ | ✔️
|
Flash I/O | ✔️ | ✔️
|
||||||
**CORE LIBRARIES** | |
|
**CORE LIBRARIES** | |
|
||||||
SoftwareSerial | ❌ | ❌
|
SoftwareSerial | ✔️ | ❌
|
||||||
SPI | ❌ | ❌
|
SPI | ❌ | ❌
|
||||||
Wire | ❗ | ❌
|
Wire | ❗ | ❌
|
||||||
**OTHER LIBRARIES** | |
|
**OTHER LIBRARIES** | |
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
* Common API
|
* Common API
|
||||||
* [FS](ltapi/classfs_1_1_f_s.md)
|
* [FS](ltapi/classfs_1_1_f_s.md)
|
||||||
* [Preferences](ltapi/class_i_preferences.md)
|
* [Preferences](ltapi/class_i_preferences.md)
|
||||||
|
* [SoftwareSerial](ltapi/class_software_serial.md)
|
||||||
* [WiFi API](ltapi/class_wi_fi_class.md)
|
* [WiFi API](ltapi/class_wi_fi_class.md)
|
||||||
* [TCP Client](ltapi/class_i_wi_fi_client.md)
|
* [TCP Client](ltapi/class_i_wi_fi_client.md)
|
||||||
* [SSL Client](ltapi/class_i_wi_fi_client_secure.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