fix: prevent ESP32 KISS modem stalls under USB backpressure

Switch ESP32-S3 KISS modem environments to HWCDC and move outbound KISS writes to a non-blocking queued frame path so loop() and TX completion keep progressing when the host reads slowly. Add native backpressure regression tests and correct the native_kiss_modem test filter so this suite runs directly with pio test.
This commit is contained in:
ViezeVingertjes
2026-07-18 22:43:55 +02:00
parent 795989b918
commit fb2c61f862
15 changed files with 701 additions and 46 deletions
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <cstdint>
#include <cmath>
#include "Stream.h"
inline uint32_t g_mock_millis = 0;
using std::isnan;
inline uint32_t millis() {
return g_mock_millis;
}
inline void delay(uint32_t ms) {
g_mock_millis += ms;
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <cstddef>
#include <cstdint>
class CayenneLPP {
public:
explicit CayenneLPP(size_t) {}
const uint8_t* getBuffer() const { return nullptr; }
uint16_t getSize() const { return 0; }
};
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <cstdint>
#include <cstring>
#include "Utils.h"
namespace mesh {
class Identity {
public:
uint8_t pub_key[PUB_KEY_SIZE];
Identity() {
std::memset(pub_key, 0, sizeof(pub_key));
}
explicit Identity(const uint8_t* src) {
std::memcpy(pub_key, src, PUB_KEY_SIZE);
}
bool verify(const uint8_t*, const uint8_t*, int) const {
return true;
}
};
class LocalIdentity : public Identity {
public:
LocalIdentity() : Identity() {}
void sign(uint8_t* sig, const uint8_t*, int) const {
std::memset(sig, 0x5A, SIGNATURE_SIZE);
}
void calcSharedSecret(uint8_t* secret, const uint8_t*) const {
std::memset(secret, 0x11, PUB_KEY_SIZE);
}
};
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <cstdint>
namespace mesh {
class Radio {
public:
virtual ~Radio() = default;
virtual bool isReceiving() { return false; }
virtual uint32_t getEstAirtimeFor(uint16_t) { return 10; }
virtual bool startSendRaw(const uint8_t*, uint16_t) { return true; }
virtual bool isSendComplete() { return true; }
virtual void onSendFinished() {}
virtual int16_t getNoiseFloor() { return -120; }
};
class MainBoard {
public:
virtual ~MainBoard() = default;
virtual uint16_t getBattMilliVolts() { return 4200; }
virtual float getMCUTemperature() { return 25.0f; }
virtual const char* getManufacturerName() { return "mock-board"; }
virtual void reboot() {}
};
}
+17 -4
View File
@@ -1,10 +1,23 @@
#pragma once
// Mock Stream class for native testing
// Provides minimal interface needed by Utils.h
#include <cstddef>
#include <cstdint>
class Stream {
public:
virtual void print(char c) {}
virtual void print(const char* str) {}
virtual ~Stream() = default;
virtual size_t write(uint8_t) { return 1; }
virtual size_t write(const uint8_t* buffer, size_t size) {
size_t total = 0;
for (size_t i = 0; i < size; i++) {
total += write(buffer[i]);
}
return total;
}
virtual int available() { return 0; }
virtual int availableForWrite() { return 0; }
virtual int read() { return -1; }
virtual void flush() {}
virtual void print(char) {}
virtual void print(const char*) {}
};
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <algorithm>
#define PUB_KEY_SIZE 32
#define PRV_KEY_SIZE 64
#define SIGNATURE_SIZE 64
#define CIPHER_MAC_SIZE 16
namespace mesh {
class RNG {
public:
virtual ~RNG() = default;
virtual void random(uint8_t* dest, size_t sz) = 0;
};
class Utils {
public:
static void sha256(uint8_t* hash, size_t hash_len, const uint8_t*, int) {
std::memset(hash, 0, hash_len);
}
static int encryptThenMAC(const uint8_t*, uint8_t* dest, const uint8_t* src, int src_len) {
int out_len = src_len + CIPHER_MAC_SIZE;
std::memset(dest, 0xAA, CIPHER_MAC_SIZE);
std::memcpy(dest + CIPHER_MAC_SIZE, src, src_len);
return out_len;
}
static int MACThenDecrypt(const uint8_t*, uint8_t* dest, const uint8_t* src, int src_len) {
if (src_len < CIPHER_MAC_SIZE) {
return 0;
}
int out_len = src_len - CIPHER_MAC_SIZE;
std::memcpy(dest, src + CIPHER_MAC_SIZE, out_len);
return out_len;
}
};
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <cstdint>
#include "CayenneLPP.h"
class SensorManager {
public:
virtual ~SensorManager() = default;
virtual bool querySensors(uint8_t, CayenneLPP&) { return false; }
};