[realtek-ambz] Implement SoftwareSerial class

This commit is contained in:
Kuba Szczodrzyński
2022-07-03 22:54:18 +02:00
parent 1b4265f522
commit 3cb944dde2
6 changed files with 222 additions and 2 deletions

View File

@@ -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** | |

View File

@@ -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)

View 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;
}

View 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

View File

@@ -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);
}

View File

@@ -0,0 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
#pragma once
#include <api/SoftwareSerial.h>