Browse Source

initial ch390 ethernet support for thinknode m7 companion

pull/3049/head
liamcottle 2 weeks ago
parent
commit
5de857f8f8
  1. 5
      examples/companion_radio/main.cpp
  2. 9
      src/helpers/ethernet/Ethernet.h
  3. 207
      src/helpers/ethernet/ch390/CH390EthernetInterface.cpp
  4. 80
      src/helpers/ethernet/ch390/CH390EthernetInterface.h
  5. 36
      variants/thinknode_m7/platformio.ini

5
examples/companion_radio/main.cpp

@ -48,6 +48,9 @@ static uint32_t _atoi(const char* sp) {
#include <helpers/ArduinoSerialInterface.h> #include <helpers/ArduinoSerialInterface.h>
ArduinoSerialInterface serial_interface; ArduinoSerialInterface serial_interface;
HardwareSerial companion_serial(1); HardwareSerial companion_serial(1);
#elif defined(ETHERNET_ENABLED)
#include <helpers/ethernet/Ethernet.h>
ETHERNET_CLASS serial_interface;
#else #else
#include <helpers/ArduinoSerialInterface.h> #include <helpers/ArduinoSerialInterface.h>
ArduinoSerialInterface serial_interface; ArduinoSerialInterface serial_interface;
@ -240,6 +243,8 @@ void setup() {
companion_serial.setPins(SERIAL_RX, SERIAL_TX); companion_serial.setPins(SERIAL_RX, SERIAL_TX);
companion_serial.begin(115200); companion_serial.begin(115200);
serial_interface.begin(companion_serial); serial_interface.begin(companion_serial);
#elif defined(ETHERNET_ENABLED)
serial_interface.begin();
#else #else
serial_interface.begin(Serial); serial_interface.begin(Serial);
#endif #endif

9
src/helpers/ethernet/Ethernet.h

@ -0,0 +1,9 @@
#pragma once
#if defined(ETHERNET_ENABLED)
#if defined(ETHERNET_USE_CH390)
#include "helpers/ethernet/ch390/CH390EthernetInterface.h"
#else
#error "ETHERNET_ENABLED is defined, but no specific driver flag (e.g. ETHERNET_USE_CH390) was provided!"
#endif
#endif

207
src/helpers/ethernet/ch390/CH390EthernetInterface.cpp

@ -0,0 +1,207 @@
#include "CH390EthernetInterface.h"
#define RECV_STATE_IDLE 0
#define RECV_STATE_HDR_FOUND 1
#define RECV_STATE_LEN1_FOUND 2
#define RECV_STATE_LEN2_FOUND 3
bool CH390EthernetInterface::begin() {
ETHERNET_DEBUG_PRINTLN("Ethernet initializing");
// Init CH390
ch390_config_t config = CH390_DEFAULT_CONFIG();
config.spi_miso_gpio = ETH_MISO_PIN;
config.spi_mosi_gpio = ETH_MOSI_PIN;
config.spi_sck_gpio = ETH_SCLK_PIN;
config.spi_cs_gpio = ETH_CS_PIN;
config.int_gpio = ETH_INT_PIN;
if (!CH390.begin(config)) {
ETHERNET_DEBUG_PRINTLN("Failed to initialize CH390 hardware.");
return false;
}
// Setup Static IP if build flags are present
#if defined(ETHERNET_STATIC_IP) && defined(ETHERNET_STATIC_GATEWAY) && defined(ETHERNET_STATIC_SUBNET)
IPAddress ip(ETHERNET_STATIC_IP);
IPAddress gw(ETHERNET_STATIC_GATEWAY);
IPAddress sn(ETHERNET_STATIC_SUBNET);
CH390.config(ip, gw, sn);
#endif
// Start Server
server.begin();
ETHERNET_DEBUG_PRINTLN("listening on TCP port: %d", ETHERNET_TCP_PORT);
return true;
}
void CH390EthernetInterface::enable() {
if (_isEnabled) return;
_isEnabled = true;
clearBuffers();
}
void CH390EthernetInterface::disable() {
_isEnabled = false;
}
size_t CH390EthernetInterface::writeFrame(const uint8_t src[], size_t len) {
if (len > MAX_FRAME_SIZE) {
ETHERNET_DEBUG_PRINTLN("writeFrame(), frame too big, len=%d\n", len);
return 0;
}
if (deviceConnected && len > 0) {
if (send_queue_len >= FRAME_QUEUE_SIZE) {
ETHERNET_DEBUG_PRINTLN("writeFrame(), send_queue is full!");
return 0;
}
send_queue[send_queue_len].len = len; // add to send queue
memcpy(send_queue[send_queue_len].buf, src, len);
send_queue_len++;
return len;
}
return 0;
}
bool CH390EthernetInterface::isWriteBusy() const {
return false;
}
size_t CH390EthernetInterface::checkRecvFrame(uint8_t dest[]) {
if (server.hasClient()) {
auto newClient = server.available();
if (newClient) {
IPAddress new_ip = newClient.remoteIP();
uint16_t new_port = newClient.remotePort();
ETHERNET_DEBUG_PRINTLN(
"New client accepted %u.%u.%u.%u:%u",
new_ip[0], new_ip[1], new_ip[2], new_ip[3], new_port);
deviceConnected = false;
if (client) {
ETHERNET_DEBUG_PRINTLN("Closing previous client");
client.stop();
}
_state = RECV_STATE_IDLE;
_frame_len = 0;
_rx_len = 0;
client = newClient;
ETHERNET_DEBUG_PRINTLN("Switched to new client");
}
}
if (client.connected()) {
if (!deviceConnected) {
ETHERNET_DEBUG_PRINTLN(
"Got connection %u.%u.%u.%u:%u",
client.remoteIP()[0],
client.remoteIP()[1],
client.remoteIP()[2],
client.remoteIP()[3],
client.remotePort());
deviceConnected = true;
}
} else {
if (deviceConnected) {
deviceConnected = false;
ETHERNET_DEBUG_PRINTLN("Disconnected");
}
}
if (deviceConnected) {
if (send_queue_len > 0) { // first, check send queue
_last_write = millis();
int len = send_queue[0].len;
#if ETHERNET_RAW_LINE
ETHERNET_DEBUG_PRINTLN("TX line len=%d", len);
client.write(send_queue[0].buf, len);
client.write("\r\n", 2);
#else
uint8_t pkt[3+len]; // use same header as serial interface so client can delimit frames
pkt[0] = '>';
pkt[1] = (len & 0xFF); // LSB
pkt[2] = (len >> 8); // MSB
memcpy(&pkt[3], send_queue[0].buf, send_queue[0].len);
ETHERNET_DEBUG_PRINTLN("Sending frame len=%d", len);
#if ETHERNET_DEBUG_LOGGING && ARDUINO
ETHERNET_DEBUG_PRINTLN("TX frame len=%d", len);
#endif
client.write(pkt, 3 + len);
#endif
send_queue_len--;
for (int i = 0; i < send_queue_len; i++) { // delete top item from queue
send_queue[i] = send_queue[i + 1];
}
} else {
while (client.available()) {
int c = client.read();
if (c < 0) break;
#if ETHERNET_RAW_LINE
if (c == '\r' || c == '\n') {
if (_rx_len == 0) {
continue;
}
uint16_t out_len = _rx_len;
if (out_len > MAX_FRAME_SIZE) out_len = MAX_FRAME_SIZE;
memcpy(dest, _rx_buf, out_len);
_rx_len = 0;
return out_len;
}
if (_rx_len < MAX_FRAME_SIZE) {
_rx_buf[_rx_len] = (uint8_t)c;
_rx_len++;
}
#else
switch (_state) {
case RECV_STATE_IDLE:
if (c == '<') {
_state = RECV_STATE_HDR_FOUND;
}
break;
case RECV_STATE_HDR_FOUND:
_frame_len = (uint8_t)c;
_state = RECV_STATE_LEN1_FOUND;
break;
case RECV_STATE_LEN1_FOUND:
_frame_len |= ((uint16_t)c) << 8;
_rx_len = 0;
_state = _frame_len > 0 ? RECV_STATE_LEN2_FOUND : RECV_STATE_IDLE;
break;
default:
if (_rx_len < MAX_FRAME_SIZE) {
_rx_buf[_rx_len] = (uint8_t)c;
}
_rx_len++;
if (_rx_len >= _frame_len) {
if (_frame_len > MAX_FRAME_SIZE) {
_frame_len = MAX_FRAME_SIZE;
}
#if ETHERNET_DEBUG_LOGGING && ARDUINO
ETHERNET_DEBUG_PRINTLN("RX frame len=%d", _frame_len);
#endif
memcpy(dest, _rx_buf, _frame_len);
_state = RECV_STATE_IDLE;
return _frame_len;
}
}
#endif
}
}
}
return 0;
}
bool CH390EthernetInterface::isConnected() const {
return deviceConnected;
}
void CH390EthernetInterface::loop() {
}

80
src/helpers/ethernet/ch390/CH390EthernetInterface.h

@ -0,0 +1,80 @@
#pragma once
#include "../../BaseSerialInterface.h"
#include <SPI.h>
#include <WiFi.h>
#include <WiFiServer.h>
#include <WiFiClient.h>
#include <ESP32_CH390.h>
#ifndef ETHERNET_TCP_PORT
#define ETHERNET_TCP_PORT 5000
#endif
// define ETHERNET_RAW_LINE=1 to use raw line-based CLI instead of framed packets
class CH390EthernetInterface : public BaseSerialInterface {
bool deviceConnected;
bool _isEnabled;
unsigned long _last_write;
uint8_t _state;
uint16_t _frame_len;
uint16_t _rx_len;
uint8_t _rx_buf[MAX_FRAME_SIZE];
WiFiServer server;
WiFiClient client;
struct Frame {
uint8_t len;
uint8_t buf[MAX_FRAME_SIZE];
};
#define FRAME_QUEUE_SIZE 4
int send_queue_len;
Frame send_queue[FRAME_QUEUE_SIZE];
void clearBuffers() {
send_queue_len = 0;
_state = 0;
_frame_len = 0;
_rx_len = 0;
}
protected:
public:
CH390EthernetInterface() : server(ETHERNET_TCP_PORT) {
deviceConnected = false;
_isEnabled = false;
_last_write = 0;
send_queue_len = 0;
_state = 0;
_frame_len = 0;
_rx_len = 0;
}
bool begin();
void loop();
// BaseSerialInterface methods
void enable() override;
void disable() override;
bool isEnabled() const override { return _isEnabled; }
bool isConnected() const override;
bool isWriteBusy() const override;
size_t writeFrame(const uint8_t src[], size_t len) override;
size_t checkRecvFrame(uint8_t dest[]) override;
};
#if ETHERNET_DEBUG_LOGGING && ARDUINO
#include <Arduino.h>
#define ETHERNET_DEBUG_PRINT(F, ...) Serial.printf("ETH: " F, ##__VA_ARGS__)
#define ETHERNET_DEBUG_PRINTLN(F, ...) Serial.printf("ETH: " F "\n", ##__VA_ARGS__)
#define ETHERNET_DEBUG_PRINT_IP(name, ip) Serial.printf(name ": %u.%u.%u.%u" "\n", ip[0], ip[1], ip[2], ip[3])
#else
#define ETHERNET_DEBUG_PRINT(...) {}
#define ETHERNET_DEBUG_PRINTLN(...) {}
#define ETHERNET_DEBUG_PRINT_IP(...) {}
#endif

36
variants/thinknode_m7/platformio.ini

@ -34,6 +34,22 @@ build_src_filter = ${esp32_base.build_src_filter}
lib_deps = ${esp32_base.lib_deps} lib_deps = ${esp32_base.lib_deps}
stevemarple/MicroNMEA @ ^2.0.6 stevemarple/MicroNMEA @ ^2.0.6
[ThinkNode_M7_ethernet]
build_flags =
-D ETHERNET_ENABLED
-D ETHERNET_USE_CH390
-D ETHERNET_CLASS=CH390EthernetInterface
-D ETH_MISO_PIN=14
-D ETH_MOSI_PIN=48
-D ETH_SCLK_PIN=47
-D ETH_CS_PIN=21
-D ETH_INT_PIN=45
-D ETHERNET_DEBUG_LOGGING=1
build_src_filter =
+<helpers/ethernet/ch390/>
lib_deps =
https://github.com/liamcottle/ESP32-CH390.git#47b401f1de546118b03c18b5689dedec45871f2d
[env:ThinkNode_M7_repeater] [env:ThinkNode_M7_repeater]
extends = ThinkNode_M7 extends = ThinkNode_M7
build_src_filter = ${ThinkNode_M7.build_src_filter} build_src_filter = ${ThinkNode_M7.build_src_filter}
@ -130,6 +146,26 @@ lib_deps =
${ThinkNode_M7.lib_deps} ${ThinkNode_M7.lib_deps}
densaugeo/base64 @ ~1.4.0 densaugeo/base64 @ ~1.4.0
[env:ThinkNode_M7_companion_radio_ethernet]
extends = ThinkNode_M7
build_flags =
${ThinkNode_M7.build_flags}
${ThinkNode_M7_ethernet.build_flags}
-I examples/companion_radio/ui-orig
-D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40
-D DISPLAY_CLASS=NullDisplayDriver
-D OFFLINE_QUEUE_SIZE=256
build_src_filter = ${ThinkNode_M7.build_src_filter}
${ThinkNode_M7_ethernet.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp>
lib_deps = ${ThinkNode_M7.lib_deps}
${ThinkNode_M7_ethernet.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:ThinkNode_M7_kiss_modem] [env:ThinkNode_M7_kiss_modem]
extends = ThinkNode_M7 extends = ThinkNode_M7
build_src_filter = ${ThinkNode_M7.build_src_filter} build_src_filter = ${ThinkNode_M7.build_src_filter}

Loading…
Cancel
Save