mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-01 23:50:38 +00:00
@@ -20,9 +20,7 @@ void consolePrintf(const char *format, ...)
|
||||
va_start(arg, format);
|
||||
console->vprintf(format, arg);
|
||||
va_end(arg);
|
||||
#ifdef ARCH_ESP32
|
||||
console->flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole")
|
||||
@@ -51,6 +49,10 @@ int32_t SerialConsole::runOnce()
|
||||
return runOncePart();
|
||||
}
|
||||
|
||||
void SerialConsole::flush() {
|
||||
Port.flush();
|
||||
}
|
||||
|
||||
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
bool SerialConsole::checkIsConnected()
|
||||
{
|
||||
|
||||
@@ -26,6 +26,8 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
void flush();
|
||||
|
||||
protected:
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
|
||||
@@ -26,6 +26,12 @@ class MeshPacketQueue
|
||||
/** return true if the queue is empty */
|
||||
bool empty();
|
||||
|
||||
/** return amount of free packets in Queue */
|
||||
size_t getFree() { return maxLen - queue.size(); }
|
||||
|
||||
/** return total size of the Queue */
|
||||
size_t getMaxLen() { return maxLen; }
|
||||
|
||||
MeshPacket *dequeue();
|
||||
|
||||
MeshPacket *getFront();
|
||||
|
||||
@@ -52,10 +52,15 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and
|
||||
|
||||
MeshService service;
|
||||
|
||||
static MemoryDynamic<QueueStatus> staticQueueStatusPool;
|
||||
|
||||
Allocator<QueueStatus> &queueStatusPool = staticQueueStatusPool;
|
||||
|
||||
#include "Router.h"
|
||||
|
||||
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
|
||||
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE)
|
||||
{
|
||||
lastQueueStatus = { 0, 0, 16, 0 };
|
||||
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
|
||||
}
|
||||
|
||||
@@ -83,6 +88,11 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
|
||||
/// Do idle processing (mostly processing messages which have been queued from the radio)
|
||||
void MeshService::loop()
|
||||
{
|
||||
if (lastQueueStatus.free == 0) { // check if there is now free space in TX queue
|
||||
QueueStatus qs = router->getQueueStatus();
|
||||
if (qs.free != lastQueueStatus.free)
|
||||
(void)sendQueueStatusToPhone(qs, 0, 0);
|
||||
}
|
||||
if (oldFromNum != fromNum) { // We don't want to generate extra notifies for multiple new packets
|
||||
fromNumChanged.notifyObservers(fromNum);
|
||||
oldFromNum = fromNum;
|
||||
@@ -179,12 +189,43 @@ bool MeshService::cancelSending(PacketId id)
|
||||
return router->cancelSending(nodeDB.getNodeNum(), id);
|
||||
}
|
||||
|
||||
ErrorCode MeshService::sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id)
|
||||
{
|
||||
QueueStatus *copied = queueStatusPool.allocCopy(qs);
|
||||
|
||||
copied->res = res;
|
||||
copied->mesh_packet_id = mesh_packet_id;
|
||||
|
||||
if (toPhoneQueueStatusQueue.numFree() == 0) {
|
||||
LOG_DEBUG("NOTE: tophone queue status queue is full, discarding oldest\n");
|
||||
QueueStatus *d = toPhoneQueueStatusQueue.dequeuePtr(0);
|
||||
if (d)
|
||||
releaseQueueStatusToPool(d);
|
||||
}
|
||||
|
||||
lastQueueStatus = *copied;
|
||||
|
||||
res = toPhoneQueueStatusQueue.enqueue(copied, 0);
|
||||
fromNum++;
|
||||
|
||||
return res ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
}
|
||||
|
||||
void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone)
|
||||
{
|
||||
uint32_t mesh_packet_id = p->id;
|
||||
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||
|
||||
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
|
||||
router->sendLocal(p, src);
|
||||
ErrorCode res = router->sendLocal(p, src);
|
||||
|
||||
/* NOTE(pboldin): Prepare and send QueueStatus message to the phone as a
|
||||
* high-priority message. */
|
||||
QueueStatus qs = router->getQueueStatus();
|
||||
ErrorCode r = sendQueueStatusToPhone(qs, res, mesh_packet_id);
|
||||
if (r != ERRNO_OK) {
|
||||
LOG_DEBUG("Can't send status to phone");
|
||||
}
|
||||
|
||||
if (ccToPhone) {
|
||||
sendToPhone(p);
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "../platform/portduino/SimRadio.h"
|
||||
#endif
|
||||
|
||||
extern Allocator<QueueStatus> &queueStatusPool;
|
||||
|
||||
/**
|
||||
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
||||
*
|
||||
@@ -29,6 +31,12 @@ class MeshService
|
||||
/// FIXME - save this to flash on deep sleep
|
||||
PointerQueue<MeshPacket> toPhoneQueue;
|
||||
|
||||
// keep list of QueueStatus packets to be send to the phone
|
||||
PointerQueue<QueueStatus> toPhoneQueueStatusQueue;
|
||||
|
||||
// This holds the last QueueStatus send
|
||||
QueueStatus lastQueueStatus;
|
||||
|
||||
/// The current nonce for the newest packet which has been queued for the phone
|
||||
uint32_t fromNum = 0;
|
||||
|
||||
@@ -56,6 +64,12 @@ class MeshService
|
||||
/// Allows the bluetooth handler to free packets after they have been sent
|
||||
void releaseToPool(MeshPacket *p) { packetPool.release(p); }
|
||||
|
||||
/// Return the next QueueStatus packet destined to the phone.
|
||||
QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); }
|
||||
|
||||
// Release QueueStatus packet to pool
|
||||
void releaseQueueStatusToPool(QueueStatus *p) { queueStatusPool.release(p); }
|
||||
|
||||
/**
|
||||
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
|
||||
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep
|
||||
@@ -100,6 +114,8 @@ class MeshService
|
||||
/// needs to keep the packet around it makes a copy
|
||||
int handleFromRadio(const MeshPacket *p);
|
||||
friend class RoutingModule;
|
||||
|
||||
ErrorCode sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);
|
||||
};
|
||||
|
||||
extern MeshService service;
|
||||
|
||||
@@ -50,6 +50,7 @@ void PhoneAPI::close()
|
||||
|
||||
unobserve(&service.fromNumChanged);
|
||||
releasePhonePacket(); // Don't leak phone packets on shutdown
|
||||
releaseQueueStatusPhonePacket();
|
||||
|
||||
onConnectionChanged(false);
|
||||
}
|
||||
@@ -282,14 +283,19 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
case STATE_SEND_PACKETS:
|
||||
// Do we have a message from the mesh?
|
||||
LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n");
|
||||
if (packetForPhone) {
|
||||
if (queueStatusPacketForPhone) {
|
||||
|
||||
fromRadioScratch.which_payload_variant = FromRadio_queueStatus_tag;
|
||||
fromRadioScratch.queueStatus = *queueStatusPacketForPhone;
|
||||
releaseQueueStatusPhonePacket();
|
||||
} else if (packetForPhone) {
|
||||
printPacket("phone downloaded packet", packetForPhone);
|
||||
|
||||
// Encapsulate as a FromRadio packet
|
||||
fromRadioScratch.which_payload_variant = FromRadio_packet_tag;
|
||||
fromRadioScratch.packet = *packetForPhone;
|
||||
releasePhonePacket();
|
||||
}
|
||||
releasePhonePacket();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -322,6 +328,14 @@ void PhoneAPI::releasePhonePacket()
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneAPI::releaseQueueStatusPhonePacket()
|
||||
{
|
||||
if (queueStatusPacketForPhone) {
|
||||
service.releaseQueueStatusToPool(queueStatusPacketForPhone);
|
||||
queueStatusPacketForPhone = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we have data available to send to the phone
|
||||
*/
|
||||
@@ -342,9 +356,15 @@ bool PhoneAPI::available()
|
||||
return true; // Always say we have something, because we might need to advance our state machine
|
||||
|
||||
case STATE_SEND_PACKETS: {
|
||||
if (!queueStatusPacketForPhone)
|
||||
queueStatusPacketForPhone = service.getQueueStatusForPhone();
|
||||
bool hasPacket = !!queueStatusPacketForPhone;
|
||||
if (hasPacket)
|
||||
return true;
|
||||
|
||||
if (!packetForPhone)
|
||||
packetForPhone = service.getForPhone();
|
||||
bool hasPacket = !!packetForPhone;
|
||||
hasPacket = !!packetForPhone;
|
||||
// LOG_DEBUG("available hasPacket=%d\n", hasPacket);
|
||||
return hasPacket;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ class PhoneAPI : public Observer<uint32_t> // FIXME, we shouldn't be inheriting
|
||||
/// downloads it
|
||||
MeshPacket *packetForPhone = NULL;
|
||||
|
||||
// Keep QueueStatus packet just as packetForPhone
|
||||
QueueStatus *queueStatusPacketForPhone = NULL;
|
||||
|
||||
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
|
||||
const NodeInfo *nodeInfoForPhone = NULL;
|
||||
|
||||
@@ -115,6 +118,8 @@ class PhoneAPI : public Observer<uint32_t> // FIXME, we shouldn't be inheriting
|
||||
private:
|
||||
void releasePhonePacket();
|
||||
|
||||
void releaseQueueStatusPhonePacket();
|
||||
|
||||
/// begin a new connection
|
||||
void handleStartConfig();
|
||||
|
||||
|
||||
@@ -115,6 +115,13 @@ class RadioInterface
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p) = 0;
|
||||
|
||||
/** Return TX queue status */
|
||||
virtual QueueStatus getQueueStatus() {
|
||||
QueueStatus qs;
|
||||
qs.res = qs.mesh_packet_id = qs.free = qs.maxlen = 0;
|
||||
return qs;
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id) { return false; }
|
||||
|
||||
|
||||
@@ -158,6 +158,17 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
#endif
|
||||
}
|
||||
|
||||
QueueStatus RadioLibInterface::getQueueStatus()
|
||||
{
|
||||
QueueStatus qs;
|
||||
|
||||
qs.res = qs.mesh_packet_id = 0;
|
||||
qs.free = txQueue.getFree();
|
||||
qs.maxlen = txQueue.getMaxLen();
|
||||
|
||||
return qs;
|
||||
}
|
||||
|
||||
bool RadioLibInterface::canSleep()
|
||||
{
|
||||
bool res = txQueue.empty();
|
||||
|
||||
@@ -153,6 +153,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
*/
|
||||
virtual void startSend(MeshPacket *txp);
|
||||
|
||||
QueueStatus getQueueStatus();
|
||||
|
||||
protected:
|
||||
|
||||
/** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */
|
||||
|
||||
@@ -148,6 +148,11 @@ void Router::setReceivedMessage()
|
||||
runASAP = true;
|
||||
}
|
||||
|
||||
QueueStatus Router::getQueueStatus()
|
||||
{
|
||||
return iface->getQueueStatus();
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p, RxSource src)
|
||||
{
|
||||
// No need to deliver externally if the destination is the local node
|
||||
|
||||
@@ -55,6 +55,9 @@ class Router : protected concurrency::OSThread
|
||||
*/
|
||||
MeshPacket *allocForSending();
|
||||
|
||||
/** Return Underlying interface's TX queue status */
|
||||
QueueStatus getQueueStatus();
|
||||
|
||||
/**
|
||||
* @return our local nodenum */
|
||||
NodeNum getNodeNum();
|
||||
|
||||
@@ -33,14 +33,14 @@
|
||||
|
||||
#include "unishox2.h"
|
||||
|
||||
/// byte is unsigned char
|
||||
typedef unsigned char byte;
|
||||
/// uint8_t is unsigned char
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
/// possible horizontal sets and states
|
||||
enum {USX_ALPHA = 0, USX_SYM, USX_NUM, USX_DICT, USX_DELTA, USX_NUM_TEMP};
|
||||
|
||||
/// This 2D array has the characters for the sets USX_ALPHA, USX_SYM and USX_NUM. Where a character cannot fit into a byte, 0 is used and handled in code.
|
||||
byte usx_sets[][28] = {{ 0, ' ', 'e', 't', 'a', 'o', 'i', 'n',
|
||||
/// This 2D array has the characters for the sets USX_ALPHA, USX_SYM and USX_NUM. Where a character cannot fit into a uint8_t, 0 is used and handled in code.
|
||||
uint8_t usx_sets[][28] = {{ 0, ' ', 'e', 't', 'a', 'o', 'i', 'n',
|
||||
's', 'r', 'l', 'c', 'd', 'h', 'u', 'p', 'm', 'b',
|
||||
'g', 'w', 'f', 'y', 'v', 'k', 'q', 'j', 'x', 'z'},
|
||||
{'"', '{', '}', '_', '<', '>', ':', '\n',
|
||||
@@ -53,22 +53,22 @@ byte usx_sets[][28] = {{ 0, ' ', 'e', 't', 'a', 'o', 'i', 'n',
|
||||
/// Stores position of letter in usx_sets.
|
||||
/// First 3 bits - position in usx_hcodes
|
||||
/// Next 5 bits - position in usx_vcodes
|
||||
byte usx_code_94[94];
|
||||
uint8_t usx_code_94[94];
|
||||
|
||||
/// Vertical codes starting from the MSB
|
||||
byte usx_vcodes[] = { 0x00, 0x40, 0x60, 0x80, 0x90, 0xA0, 0xB0,
|
||||
uint8_t usx_vcodes[] = { 0x00, 0x40, 0x60, 0x80, 0x90, 0xA0, 0xB0,
|
||||
0xC0, 0xD0, 0xD8, 0xE0, 0xE4, 0xE8, 0xEC,
|
||||
0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF7, 0xF8,
|
||||
0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF };
|
||||
|
||||
/// Length of each veritical code
|
||||
byte usx_vcode_lens[] = { 2, 3, 3, 4, 4, 4, 4,
|
||||
uint8_t usx_vcode_lens[] = { 2, 3, 3, 4, 4, 4, 4,
|
||||
4, 5, 5, 6, 6, 6, 7,
|
||||
7, 7, 7, 7, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8 };
|
||||
|
||||
/// Vertical Codes and Set number for frequent sequences in sets USX_SYM and USX_NUM. First 3 bits indicate set (USX_SYM/USX_NUM) and rest are vcode positions
|
||||
byte usx_freq_codes[] = {(1 << 5) + 25, (1 << 5) + 26, (1 << 5) + 27, (2 << 5) + 23, (2 << 5) + 24, (2 << 5) + 25};
|
||||
uint8_t usx_freq_codes[] = {(1 << 5) + 25, (1 << 5) + 26, (1 << 5) + 27, (2 << 5) + 23, (2 << 5) + 24, (2 << 5) + 25};
|
||||
|
||||
/// Not used
|
||||
const int UTF8_MASK[] = {0xE0, 0xF0, 0xF8};
|
||||
@@ -117,7 +117,7 @@ const int UTF8_PREFIX[] = {0xC0, 0xE0, 0xF0};
|
||||
#define USX_OFFSET_94 33
|
||||
|
||||
/// global to indicate whether initialization is complete or not
|
||||
byte is_inited = 0;
|
||||
uint8_t is_inited = 0;
|
||||
|
||||
/// Fills the usx_code_94 94 letter array based on sets of characters at usx_sets \n
|
||||
/// For each element in usx_code_94, first 3 msb bits is set (USX_ALPHA / USX_SYM / USX_NUM) \n
|
||||
@@ -128,7 +128,7 @@ void init_coder() {
|
||||
memset(usx_code_94, '\0', sizeof(usx_code_94));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 28; j++) {
|
||||
byte c = usx_sets[i][j];
|
||||
uint8_t c = usx_sets[i][j];
|
||||
if (c > 32) {
|
||||
usx_code_94[c - USX_OFFSET_94] = (i << 5) + j;
|
||||
if (c >= 'a' && c <= 'z')
|
||||
@@ -145,7 +145,7 @@ unsigned int usx_mask[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF};
|
||||
/// Appends specified number of bits to the output (out) \n
|
||||
/// If maximum limit (olen) is reached, -1 is returned \n
|
||||
/// Otherwise clen bits in code are appended to out starting with MSB
|
||||
int append_bits(char *out, int olen, int ol, byte code, int clen) {
|
||||
int append_bits(char *out, int olen, int ol, uint8_t code, int clen) {
|
||||
|
||||
|
||||
//printf("%d,%x,%d,%d\n", ol, code, clen, state);
|
||||
@@ -154,8 +154,8 @@ int append_bits(char *out, int olen, int ol, byte code, int clen) {
|
||||
int oidx;
|
||||
unsigned char a_byte;
|
||||
|
||||
byte cur_bit = ol % 8;
|
||||
byte blen = clen;
|
||||
uint8_t cur_bit = ol % 8;
|
||||
uint8_t blen = clen;
|
||||
a_byte = code & usx_mask[blen - 1];
|
||||
a_byte >>= cur_bit;
|
||||
if (blen + cur_bit > 8)
|
||||
@@ -181,7 +181,7 @@ int append_bits(char *out, int olen, int ol, byte code, int clen) {
|
||||
} while (0)
|
||||
|
||||
/// Appends switch code to out depending on the state (USX_DELTA or other)
|
||||
int append_switch_code(char *out, int olen, int ol, byte state) {
|
||||
int append_switch_code(char *out, int olen, int ol, uint8_t state) {
|
||||
if (state == USX_DELTA) {
|
||||
SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, UNI_STATE_SPL_CODE, UNI_STATE_SPL_CODE_LEN));
|
||||
SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, UNI_STATE_SW_CODE, UNI_STATE_SW_CODE_LEN));
|
||||
@@ -191,9 +191,9 @@ int append_switch_code(char *out, int olen, int ol, byte state) {
|
||||
}
|
||||
|
||||
/// Appends given horizontal and veritical code bits to out
|
||||
int append_code(char *out, int olen, int ol, byte code, byte *state, const byte usx_hcodes[], const byte usx_hcode_lens[]) {
|
||||
byte hcode = code >> 5;
|
||||
byte vcode = code & 0x1F;
|
||||
int append_code(char *out, int olen, int ol, uint8_t code, uint8_t *state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) {
|
||||
uint8_t hcode = code >> 5;
|
||||
uint8_t vcode = code & 0x1F;
|
||||
if (!usx_hcode_lens[hcode] && hcode != USX_ALPHA)
|
||||
return ol;
|
||||
switch (hcode) {
|
||||
@@ -221,11 +221,11 @@ int append_code(char *out, int olen, int ol, byte code, byte *state, const byte
|
||||
}
|
||||
|
||||
/// Length of bits used to represent count for each level
|
||||
const byte count_bit_lens[5] = {2, 4, 7, 11, 16};
|
||||
const uint8_t count_bit_lens[5] = {2, 4, 7, 11, 16};
|
||||
/// Cumulative counts represented at each level
|
||||
const int32_t count_adder[5] = {4, 20, 148, 2196, 67732};
|
||||
/// Codes used to specify the level that the count belongs to
|
||||
const byte count_codes[] = {0x01, 0x82, 0xC3, 0xE4, 0xF4};
|
||||
const uint8_t count_codes[] = {0x01, 0x82, 0xC3, 0xE4, 0xF4};
|
||||
/// Encodes given count to out
|
||||
int encodeCount(char *out, int olen, int ol, int count) {
|
||||
// First five bits are code and Last three bits of codes represent length
|
||||
@@ -245,15 +245,15 @@ int encodeCount(char *out, int olen, int ol, int count) {
|
||||
}
|
||||
|
||||
/// Length of bits used to represent delta code for each level
|
||||
const byte uni_bit_len[5] = {6, 12, 14, 16, 21};
|
||||
const uint8_t uni_bit_len[5] = {6, 12, 14, 16, 21};
|
||||
/// Cumulative delta codes represented at each level
|
||||
const int32_t uni_adder[5] = {0, 64, 4160, 20544, 86080};
|
||||
|
||||
/// Encodes the unicode code point given by code to out. prev_code is used to calculate the delta
|
||||
int encodeUnicode(char *out, int olen, int ol, int32_t code, int32_t prev_code) {
|
||||
// First five bits are code and Last three bits of codes represent length
|
||||
//const byte codes[8] = {0x00, 0x42, 0x83, 0xA3, 0xC3, 0xE4, 0xF5, 0xFD};
|
||||
const byte codes[6] = {0x01, 0x82, 0xC3, 0xE4, 0xF5, 0xFD};
|
||||
//const uint8_t codes[8] = {0x00, 0x42, 0x83, 0xA3, 0xC3, 0xE4, 0xF5, 0xFD};
|
||||
const uint8_t codes[6] = {0x01, 0x82, 0xC3, 0xE4, 0xF5, 0xFD};
|
||||
int32_t till = 0;
|
||||
int32_t diff = code - prev_code;
|
||||
if (diff < 0)
|
||||
@@ -331,7 +331,7 @@ int32_t readUTF8(const char *in, int len, int l, int *utf8len) {
|
||||
/// This is also used for Unicode strings \n
|
||||
/// This is a crude implementation that is not optimized. Assuming only short strings \n
|
||||
/// are encoded, this is not much of an issue.
|
||||
int matchOccurance(const char *in, int len, int l, char *out, int olen, int *ol, byte *state, const byte usx_hcodes[], const byte usx_hcode_lens[]) {
|
||||
int matchOccurance(const char *in, int len, int l, char *out, int olen, int *ol, uint8_t *state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) {
|
||||
int j, k;
|
||||
int longest_dist = 0;
|
||||
int longest_len = 0;
|
||||
@@ -372,7 +372,7 @@ int matchOccurance(const char *in, int len, int l, char *out, int olen, int *ol,
|
||||
/// This is also used for Unicode strings \n
|
||||
/// This is a crude implementation that is not optimized. Assuming only short strings \n
|
||||
/// are encoded, this is not much of an issue.
|
||||
int matchLine(const char *in, int len, int l, char *out, int olen, int *ol, struct us_lnk_lst *prev_lines, byte *state, const byte usx_hcodes[], const byte usx_hcode_lens[]) {
|
||||
int matchLine(const char *in, int len, int l, char *out, int olen, int *ol, struct us_lnk_lst *prev_lines, uint8_t *state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) {
|
||||
int last_ol = *ol;
|
||||
int last_len = 0;
|
||||
int last_dist = 0;
|
||||
@@ -431,7 +431,7 @@ int matchLine(const char *in, int len, int l, char *out, int olen, int *ol, stru
|
||||
|
||||
/// Returns 4 bit code assuming ch falls between '0' to '9', \n
|
||||
/// 'A' to 'F' or 'a' to 'f'
|
||||
byte getBaseCode(char ch) {
|
||||
uint8_t getBaseCode(char ch) {
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return (ch - '0') << 4;
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
@@ -458,7 +458,7 @@ char getNibbleType(char ch) {
|
||||
}
|
||||
|
||||
/// Starts coding of nibble sets
|
||||
int append_nibble_escape(char *out, int olen, int ol, byte state, const byte usx_hcodes[], const byte usx_hcode_lens[]) {
|
||||
int append_nibble_escape(char *out, int olen, int ol, uint8_t state, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) {
|
||||
SAFE_APPEND_BITS(ol = append_switch_code(out, olen, ol, state));
|
||||
SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, usx_hcodes[USX_NUM], usx_hcode_lens[USX_NUM]));
|
||||
SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, 0, 2));
|
||||
@@ -471,7 +471,7 @@ long min_of(long c, long i) {
|
||||
}
|
||||
|
||||
/// Appends the terminator code depending on the state, preset and whether full terminator needs to be encoded to out or not \n
|
||||
int append_final_bits(char *const out, const int olen, int ol, const byte state, const byte is_all_upper, const byte usx_hcodes[], const byte usx_hcode_lens[]) {
|
||||
int append_final_bits(char *const out, const int olen, int ol, const uint8_t state, const uint8_t is_all_upper, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) {
|
||||
if (usx_hcode_lens[USX_ALPHA]) {
|
||||
if (USX_NUM != state) {
|
||||
// for num state, append TERM_CODE directly
|
||||
@@ -486,7 +486,7 @@ int append_final_bits(char *const out, const int olen, int ol, const byte state,
|
||||
SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, TERM_BYTE_PRESET_1, is_all_upper ? TERM_BYTE_PRESET_1_LEN_UPPER : TERM_BYTE_PRESET_1_LEN_LOWER));
|
||||
}
|
||||
|
||||
// fill byte with the last bit
|
||||
// fill uint8_t with the last bit
|
||||
SAFE_APPEND_BITS(ol = append_bits(out, olen, ol, (ol == 0 || out[(ol-1)/8] << ((ol-1)&7) >= 0) ? 0 : 0xFF, (8 - ol % 8) & 7));
|
||||
|
||||
return ol;
|
||||
@@ -500,21 +500,21 @@ int append_final_bits(char *const out, const int olen, int ol, const byte state,
|
||||
} while (0)
|
||||
|
||||
// Main API function. See unishox2.h for documentation
|
||||
int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) {
|
||||
int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) {
|
||||
|
||||
byte state;
|
||||
uint8_t state;
|
||||
|
||||
int l, ll, ol;
|
||||
char c_in, c_next;
|
||||
int prev_uni;
|
||||
byte is_upper, is_all_upper;
|
||||
uint8_t is_upper, is_all_upper;
|
||||
#if (UNISHOX_API_OUT_AND_LEN(0,1)) == 0
|
||||
const int olen = INT_MAX - 1;
|
||||
const int rawolen = olen;
|
||||
const byte need_full_term_codes = 0;
|
||||
const uint8_t need_full_term_codes = 0;
|
||||
#else
|
||||
const int rawolen = olen;
|
||||
byte need_full_term_codes = 0;
|
||||
uint8_t need_full_term_codes = 0;
|
||||
if (olen < 0) {
|
||||
need_full_term_codes = 1;
|
||||
olen *= -1;
|
||||
@@ -735,9 +735,9 @@ int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(cha
|
||||
}
|
||||
}
|
||||
if (state == USX_DELTA && (c_in == ' ' || c_in == '.' || c_in == ',')) {
|
||||
byte spl_code = (c_in == ',' ? 0xC0 : (c_in == '.' ? 0xE0 : (c_in == ' ' ? 0 : 0xFF)));
|
||||
uint8_t spl_code = (c_in == ',' ? 0xC0 : (c_in == '.' ? 0xE0 : (c_in == ' ' ? 0 : 0xFF)));
|
||||
if (spl_code != 0xFF) {
|
||||
byte spl_code_len = (c_in == ',' ? 3 : (c_in == '.' ? 4 : (c_in == ' ' ? 1 : 4)));
|
||||
uint8_t spl_code_len = (c_in == ',' ? 3 : (c_in == '.' ? 4 : (c_in == ' ' ? 1 : 4)));
|
||||
SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, UNI_STATE_SPL_CODE, UNI_STATE_SPL_CODE_LEN));
|
||||
SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, spl_code, spl_code_len));
|
||||
continue;
|
||||
@@ -833,7 +833,7 @@ int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(cha
|
||||
}
|
||||
|
||||
// Main API function. See unishox2.h for documentation
|
||||
int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) {
|
||||
int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) {
|
||||
return unishox2_compress_lines(in, len, UNISHOX_API_OUT_AND_LEN(out, olen), usx_hcodes, usx_hcode_lens, usx_freq_seq, usx_templates, NULL);
|
||||
}
|
||||
|
||||
@@ -852,10 +852,10 @@ int read8bitCode(const char *in, int len, int bit_no) {
|
||||
int bit_pos = bit_no & 0x07;
|
||||
int char_pos = bit_no >> 3;
|
||||
len >>= 3;
|
||||
byte code = (((byte)in[char_pos]) << bit_pos);
|
||||
uint8_t code = (((uint8_t)in[char_pos]) << bit_pos);
|
||||
char_pos++;
|
||||
if (char_pos < len) {
|
||||
code |= ((byte)in[char_pos]) >> (8 - bit_pos);
|
||||
code |= ((uint8_t)in[char_pos]) >> (8 - bit_pos);
|
||||
} else
|
||||
code |= (0xFF >> (8 - bit_pos));
|
||||
return code;
|
||||
@@ -864,17 +864,17 @@ int read8bitCode(const char *in, int len, int bit_no) {
|
||||
/// The list of veritical codes is split into 5 sections. Used by readVCodeIdx()
|
||||
#define SECTION_COUNT 5
|
||||
/// Used by readVCodeIdx() for finding the section under which the code read using read8bitCode() falls
|
||||
byte usx_vsections[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xFF};
|
||||
uint8_t usx_vsections[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xFF};
|
||||
/// Used by readVCodeIdx() for finding the section vertical position offset
|
||||
byte usx_vsection_pos[] = {0, 4, 8, 12, 20};
|
||||
uint8_t usx_vsection_pos[] = {0, 4, 8, 12, 20};
|
||||
/// Used by readVCodeIdx() for masking the code read by read8bitCode()
|
||||
byte usx_vsection_mask[] = {0x7F, 0x3F, 0x1F, 0x0F, 0x0F};
|
||||
uint8_t usx_vsection_mask[] = {0x7F, 0x3F, 0x1F, 0x0F, 0x0F};
|
||||
/// Used by readVCodeIdx() for shifting the code read by read8bitCode() to obtain the vpos
|
||||
byte usx_vsection_shift[] = {5, 4, 3, 1, 0};
|
||||
uint8_t usx_vsection_shift[] = {5, 4, 3, 1, 0};
|
||||
|
||||
/// Vertical decoder lookup table - 3 bits code len, 5 bytes vertical pos
|
||||
/// code len is one less as 8 cannot be accommodated in 3 bits
|
||||
byte usx_vcode_lookup[36] = {
|
||||
uint8_t usx_vcode_lookup[36] = {
|
||||
(1 << 5) + 0, (1 << 5) + 0, (2 << 5) + 1, (2 << 5) + 2, // Section 1
|
||||
(3 << 5) + 3, (3 << 5) + 4, (3 << 5) + 5, (3 << 5) + 6, // Section 2
|
||||
(3 << 5) + 7, (3 << 5) + 7, (4 << 5) + 8, (4 << 5) + 9, // Section 3
|
||||
@@ -887,19 +887,19 @@ byte usx_vcode_lookup[36] = {
|
||||
};
|
||||
|
||||
/// Decodes the vertical code from the given bitstream at in \n
|
||||
/// This is designed to use less memory using a 36 byte buffer \n
|
||||
/// compared to using a 256 byte buffer to decode the next 8 bits read by read8bitCode() \n
|
||||
/// This is designed to use less memory using a 36 uint8_t buffer \n
|
||||
/// compared to using a 256 uint8_t buffer to decode the next 8 bits read by read8bitCode() \n
|
||||
/// by splitting the list of vertical codes. \n
|
||||
/// Decoder is designed for using less memory, not speed. \n
|
||||
/// Returns the veritical code index or 99 if match could not be found. \n
|
||||
/// Also updates bit_no_p with how many ever bits used by the vertical code.
|
||||
int readVCodeIdx(const char *in, int len, int *bit_no_p) {
|
||||
if (*bit_no_p < len) {
|
||||
byte code = read8bitCode(in, len, *bit_no_p);
|
||||
uint8_t code = read8bitCode(in, len, *bit_no_p);
|
||||
int i = 0;
|
||||
do {
|
||||
if (code <= usx_vsections[i]) {
|
||||
byte vcode = usx_vcode_lookup[usx_vsection_pos[i] + ((code & usx_vsection_mask[i]) >> usx_vsection_shift[i])];
|
||||
uint8_t vcode = usx_vcode_lookup[usx_vsection_pos[i] + ((code & usx_vsection_mask[i]) >> usx_vsection_shift[i])];
|
||||
(*bit_no_p) += ((vcode >> 5) + 1);
|
||||
if (*bit_no_p > len)
|
||||
return 99;
|
||||
@@ -912,16 +912,16 @@ int readVCodeIdx(const char *in, int len, int *bit_no_p) {
|
||||
|
||||
/// Mask for retrieving each code to be decoded according to its length \n
|
||||
/// Same as usx_mask so redundant
|
||||
byte len_masks[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF};
|
||||
uint8_t len_masks[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF};
|
||||
/// Decodes the horizontal code from the given bitstream at in \n
|
||||
/// depending on the hcodes defined using usx_hcodes and usx_hcode_lens \n
|
||||
/// Returns the horizontal code index or 99 if match could not be found. \n
|
||||
/// Also updates bit_no_p with how many ever bits used by the horizontal code.
|
||||
int readHCodeIdx(const char *in, int len, int *bit_no_p, const byte usx_hcodes[], const byte usx_hcode_lens[]) {
|
||||
int readHCodeIdx(const char *in, int len, int *bit_no_p, const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[]) {
|
||||
if (!usx_hcode_lens[USX_ALPHA])
|
||||
return USX_ALPHA;
|
||||
if (*bit_no_p < len) {
|
||||
byte code = read8bitCode(in, len, *bit_no_p);
|
||||
uint8_t code = read8bitCode(in, len, *bit_no_p);
|
||||
for (int code_pos = 0; code_pos < 5; code_pos++) {
|
||||
if (usx_hcode_lens[code_pos] && (code & len_masks[usx_hcode_lens[code_pos] - 1]) == usx_hcodes[code_pos]) {
|
||||
*bit_no_p += usx_hcode_lens[code_pos];
|
||||
@@ -1083,12 +1083,12 @@ char getHexChar(int32_t nibble, int hex_type) {
|
||||
}
|
||||
|
||||
// Main API function. See unishox2.h for documentation
|
||||
int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) {
|
||||
int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) {
|
||||
|
||||
int dstate;
|
||||
int bit_no;
|
||||
int h, v;
|
||||
byte is_all_upper;
|
||||
uint8_t is_all_upper;
|
||||
#if (UNISHOX_API_OUT_AND_LEN(0,1)) == 0
|
||||
const int olen = INT_MAX - 1;
|
||||
#endif
|
||||
@@ -1155,7 +1155,7 @@ int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(c
|
||||
} else
|
||||
h = dstate;
|
||||
char c = 0;
|
||||
byte is_upper = is_all_upper;
|
||||
uint8_t is_upper = is_all_upper;
|
||||
v = readVCodeIdx(in, len, &bit_no);
|
||||
if (v == 99 || h == 99) {
|
||||
bit_no = orig_bit_no;
|
||||
@@ -1357,7 +1357,7 @@ int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(c
|
||||
}
|
||||
|
||||
// Main API function. See unishox2.h for documentation
|
||||
int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) {
|
||||
int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const uint8_t usx_hcodes[], const uint8_t usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) {
|
||||
return unishox2_decompress_lines(in, len, UNISHOX_API_OUT_AND_LEN(out, olen), usx_hcodes, usx_hcode_lens, usx_freq_seq, usx_templates, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,10 +95,10 @@ bool initEthernet()
|
||||
|
||||
getMacAddr(mac); // FIXME use the BLE MAC for now...
|
||||
|
||||
if (config.network.eth_mode == Config_NetworkConfig_EthMode_DHCP) {
|
||||
if (config.network.address_mode == Config_NetworkConfig_AddressMode_DHCP) {
|
||||
LOG_INFO("starting Ethernet DHCP\n");
|
||||
status = Ethernet.begin(mac);
|
||||
} else if (config.network.eth_mode == Config_NetworkConfig_EthMode_STATIC) {
|
||||
} else if (config.network.address_mode == Config_NetworkConfig_AddressMode_STATIC) {
|
||||
LOG_INFO("starting Ethernet Static\n");
|
||||
Ethernet.begin(mac, config.network.ipv4_config.ip, config.network.ipv4_config.dns, config.network.ipv4_config.subnet);
|
||||
} else {
|
||||
|
||||
@@ -60,12 +60,12 @@ typedef enum _Config_PositionConfig_PositionFlags {
|
||||
Config_PositionConfig_PositionFlags_SPEED = 512
|
||||
} Config_PositionConfig_PositionFlags;
|
||||
|
||||
typedef enum _Config_NetworkConfig_EthMode {
|
||||
typedef enum _Config_NetworkConfig_AddressMode {
|
||||
/* obtain ip address via DHCP */
|
||||
Config_NetworkConfig_EthMode_DHCP = 0,
|
||||
Config_NetworkConfig_AddressMode_DHCP = 0,
|
||||
/* use static ip address */
|
||||
Config_NetworkConfig_EthMode_STATIC = 1
|
||||
} Config_NetworkConfig_EthMode;
|
||||
Config_NetworkConfig_AddressMode_STATIC = 1
|
||||
} Config_NetworkConfig_AddressMode;
|
||||
|
||||
/* How the GPS coordinates are displayed on the OLED screen. */
|
||||
typedef enum _Config_DisplayConfig_GpsCoordinateFormat {
|
||||
@@ -292,7 +292,7 @@ typedef struct _Config_NetworkConfig {
|
||||
/* Enable Ethernet */
|
||||
bool eth_enabled;
|
||||
/* acquire an address via DHCP or assign static */
|
||||
Config_NetworkConfig_EthMode eth_mode;
|
||||
Config_NetworkConfig_AddressMode address_mode;
|
||||
/* struct to keep static address */
|
||||
bool has_ipv4_config;
|
||||
Config_NetworkConfig_IpV4Config ipv4_config;
|
||||
@@ -416,9 +416,9 @@ extern "C" {
|
||||
#define _Config_PositionConfig_PositionFlags_MAX Config_PositionConfig_PositionFlags_SPEED
|
||||
#define _Config_PositionConfig_PositionFlags_ARRAYSIZE ((Config_PositionConfig_PositionFlags)(Config_PositionConfig_PositionFlags_SPEED+1))
|
||||
|
||||
#define _Config_NetworkConfig_EthMode_MIN Config_NetworkConfig_EthMode_DHCP
|
||||
#define _Config_NetworkConfig_EthMode_MAX Config_NetworkConfig_EthMode_STATIC
|
||||
#define _Config_NetworkConfig_EthMode_ARRAYSIZE ((Config_NetworkConfig_EthMode)(Config_NetworkConfig_EthMode_STATIC+1))
|
||||
#define _Config_NetworkConfig_AddressMode_MIN Config_NetworkConfig_AddressMode_DHCP
|
||||
#define _Config_NetworkConfig_AddressMode_MAX Config_NetworkConfig_AddressMode_STATIC
|
||||
#define _Config_NetworkConfig_AddressMode_ARRAYSIZE ((Config_NetworkConfig_AddressMode)(Config_NetworkConfig_AddressMode_STATIC+1))
|
||||
|
||||
#define _Config_DisplayConfig_GpsCoordinateFormat_MIN Config_DisplayConfig_GpsCoordinateFormat_DEC
|
||||
#define _Config_DisplayConfig_GpsCoordinateFormat_MAX Config_DisplayConfig_GpsCoordinateFormat_OSGR
|
||||
@@ -453,7 +453,7 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
#define Config_NetworkConfig_eth_mode_ENUMTYPE Config_NetworkConfig_EthMode
|
||||
#define Config_NetworkConfig_address_mode_ENUMTYPE Config_NetworkConfig_AddressMode
|
||||
|
||||
|
||||
#define Config_DisplayConfig_gps_format_ENUMTYPE Config_DisplayConfig_GpsCoordinateFormat
|
||||
@@ -472,7 +472,7 @@ extern "C" {
|
||||
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
||||
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
||||
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_AddressMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
||||
#define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN, _Config_DisplayConfig_DisplayMode_MIN, 0}
|
||||
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
@@ -481,7 +481,7 @@ extern "C" {
|
||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
||||
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
||||
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_AddressMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
||||
#define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN, _Config_DisplayConfig_DisplayMode_MIN, 0}
|
||||
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
@@ -519,7 +519,7 @@ extern "C" {
|
||||
#define Config_NetworkConfig_wifi_psk_tag 4
|
||||
#define Config_NetworkConfig_ntp_server_tag 5
|
||||
#define Config_NetworkConfig_eth_enabled_tag 6
|
||||
#define Config_NetworkConfig_eth_mode_tag 7
|
||||
#define Config_NetworkConfig_address_mode_tag 7
|
||||
#define Config_NetworkConfig_ipv4_config_tag 8
|
||||
#define Config_DisplayConfig_screen_on_secs_tag 1
|
||||
#define Config_DisplayConfig_gps_format_tag 2
|
||||
@@ -613,7 +613,7 @@ X(a, STATIC, SINGULAR, STRING, wifi_ssid, 3) \
|
||||
X(a, STATIC, SINGULAR, STRING, wifi_psk, 4) \
|
||||
X(a, STATIC, SINGULAR, STRING, ntp_server, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, eth_enabled, 6) \
|
||||
X(a, STATIC, SINGULAR, UENUM, eth_mode, 7) \
|
||||
X(a, STATIC, SINGULAR, UENUM, address_mode, 7) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, ipv4_config, 8)
|
||||
#define Config_NetworkConfig_CALLBACK NULL
|
||||
#define Config_NetworkConfig_DEFAULT NULL
|
||||
|
||||
@@ -36,6 +36,9 @@ PB_BIND(MyNodeInfo, MyNodeInfo, AUTO)
|
||||
PB_BIND(LogRecord, LogRecord, AUTO)
|
||||
|
||||
|
||||
PB_BIND(QueueStatus, QueueStatus, AUTO)
|
||||
|
||||
|
||||
PB_BIND(FromRadio, FromRadio, 2)
|
||||
|
||||
|
||||
|
||||
@@ -621,6 +621,17 @@ typedef struct _LogRecord {
|
||||
LogRecord_Level level;
|
||||
} LogRecord;
|
||||
|
||||
typedef struct _QueueStatus {
|
||||
/* Last attempt to queue status, ErrorCode */
|
||||
int8_t res;
|
||||
/* Free entries in the outgoing queue */
|
||||
uint8_t free;
|
||||
/* Maximum entries in the outgoing queue */
|
||||
uint8_t maxlen;
|
||||
/* What was mesh packet id that generated this response? */
|
||||
uint32_t mesh_packet_id;
|
||||
} QueueStatus;
|
||||
|
||||
/* Packets from the radio to the phone will appear on the fromRadio characteristic.
|
||||
It will support READ and NOTIFY. When a new packet arrives the device will BLE notify?
|
||||
It will sit in that descriptor until consumed by the phone,
|
||||
@@ -657,6 +668,8 @@ typedef struct _FromRadio {
|
||||
ModuleConfig moduleConfig;
|
||||
/* One packet is sent for each channel */
|
||||
Channel channel;
|
||||
/* Queue status info */
|
||||
QueueStatus queueStatus;
|
||||
};
|
||||
} FromRadio;
|
||||
|
||||
@@ -755,6 +768,7 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
|
||||
#define Compressed_portnum_ENUMTYPE PortNum
|
||||
|
||||
|
||||
@@ -769,6 +783,7 @@ extern "C" {
|
||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default}
|
||||
#define MyNodeInfo_init_default {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
|
||||
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
||||
#define QueueStatus_init_default {0, 0, 0, 0}
|
||||
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
|
||||
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
||||
#define Compressed_init_default {_PortNum_MIN, {0, {0}}}
|
||||
@@ -782,6 +797,7 @@ extern "C" {
|
||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero}
|
||||
#define MyNodeInfo_init_zero {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
|
||||
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||
#define QueueStatus_init_zero {0, 0, 0, 0}
|
||||
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
|
||||
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
||||
#define Compressed_init_zero {_PortNum_MIN, {0, {0}}}
|
||||
@@ -873,6 +889,10 @@ extern "C" {
|
||||
#define LogRecord_time_tag 2
|
||||
#define LogRecord_source_tag 3
|
||||
#define LogRecord_level_tag 4
|
||||
#define QueueStatus_res_tag 1
|
||||
#define QueueStatus_free_tag 2
|
||||
#define QueueStatus_maxlen_tag 3
|
||||
#define QueueStatus_mesh_packet_id_tag 4
|
||||
#define FromRadio_id_tag 1
|
||||
#define FromRadio_packet_tag 2
|
||||
#define FromRadio_my_info_tag 3
|
||||
@@ -883,6 +903,7 @@ extern "C" {
|
||||
#define FromRadio_rebooted_tag 8
|
||||
#define FromRadio_moduleConfig_tag 9
|
||||
#define FromRadio_channel_tag 10
|
||||
#define FromRadio_queueStatus_tag 11
|
||||
#define ToRadio_packet_tag 1
|
||||
#define ToRadio_want_config_id_tag 3
|
||||
#define ToRadio_disconnect_tag 4
|
||||
@@ -1022,6 +1043,14 @@ X(a, STATIC, SINGULAR, UENUM, level, 4)
|
||||
#define LogRecord_CALLBACK NULL
|
||||
#define LogRecord_DEFAULT NULL
|
||||
|
||||
#define QueueStatus_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, INT32, res, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, free, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, maxlen, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, mesh_packet_id, 4)
|
||||
#define QueueStatus_CALLBACK NULL
|
||||
#define QueueStatus_DEFAULT NULL
|
||||
|
||||
#define FromRadio_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, id, 1) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 2) \
|
||||
@@ -1032,7 +1061,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,log_record,log_record), 6)
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,config_complete_id,config_complete_id), 7) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,rebooted,rebooted), 8) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), 9) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11)
|
||||
#define FromRadio_CALLBACK NULL
|
||||
#define FromRadio_DEFAULT NULL
|
||||
#define FromRadio_payload_variant_packet_MSGTYPE MeshPacket
|
||||
@@ -1042,6 +1072,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10)
|
||||
#define FromRadio_payload_variant_log_record_MSGTYPE LogRecord
|
||||
#define FromRadio_payload_variant_moduleConfig_MSGTYPE ModuleConfig
|
||||
#define FromRadio_payload_variant_channel_MSGTYPE Channel
|
||||
#define FromRadio_payload_variant_queueStatus_MSGTYPE QueueStatus
|
||||
|
||||
#define ToRadio_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \
|
||||
@@ -1067,6 +1098,7 @@ extern const pb_msgdesc_t MeshPacket_msg;
|
||||
extern const pb_msgdesc_t NodeInfo_msg;
|
||||
extern const pb_msgdesc_t MyNodeInfo_msg;
|
||||
extern const pb_msgdesc_t LogRecord_msg;
|
||||
extern const pb_msgdesc_t QueueStatus_msg;
|
||||
extern const pb_msgdesc_t FromRadio_msg;
|
||||
extern const pb_msgdesc_t ToRadio_msg;
|
||||
extern const pb_msgdesc_t Compressed_msg;
|
||||
@@ -1082,6 +1114,7 @@ extern const pb_msgdesc_t Compressed_msg;
|
||||
#define NodeInfo_fields &NodeInfo_msg
|
||||
#define MyNodeInfo_fields &MyNodeInfo_msg
|
||||
#define LogRecord_fields &LogRecord_msg
|
||||
#define QueueStatus_fields &QueueStatus_msg
|
||||
#define FromRadio_fields &FromRadio_msg
|
||||
#define ToRadio_fields &ToRadio_msg
|
||||
#define Compressed_fields &Compressed_msg
|
||||
@@ -1095,6 +1128,7 @@ extern const pb_msgdesc_t Compressed_msg;
|
||||
#define MyNodeInfo_size 179
|
||||
#define NodeInfo_size 258
|
||||
#define Position_size 137
|
||||
#define QueueStatus_size 23
|
||||
#define RouteDiscovery_size 40
|
||||
#define Routing_size 42
|
||||
#define ToRadio_size 324
|
||||
|
||||
@@ -71,10 +71,10 @@ typedef struct _EnvironmentMetrics {
|
||||
|
||||
/* Types of Measurements the telemetry module is equipped to handle */
|
||||
typedef struct _Telemetry {
|
||||
/* This is usually not sent over the mesh (to save space), but it is sent
|
||||
from the phone so that the local device can set its RTC If it is sent over
|
||||
the mesh (because there are devices on the mesh without GPS), it will only
|
||||
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
|
||||
/* This is usually not sent over the mesh (to save space), but it is sent
|
||||
from the phone so that the local device can set its RTC If it is sent over
|
||||
the mesh (because there are devices on the mesh without GPS), it will only
|
||||
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
|
||||
seconds since 1970 */
|
||||
uint32_t time;
|
||||
pb_size_t which_variant;
|
||||
|
||||
@@ -169,7 +169,7 @@ bool initWifi()
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.setAutoReconnect(false);
|
||||
WiFi.setSleep(false);
|
||||
if (config.network.eth_mode == Config_NetworkConfig_EthMode_STATIC && config.network.ipv4_config.ip != 0) {
|
||||
if (config.network.address_mode == Config_NetworkConfig_AddressMode_STATIC && config.network.ipv4_config.ip != 0) {
|
||||
WiFi.config(config.network.ipv4_config.ip,
|
||||
config.network.ipv4_config.gateway,
|
||||
config.network.ipv4_config.subnet,
|
||||
|
||||
@@ -42,26 +42,22 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
if (!moduleConfig.external_notification.enabled) {
|
||||
return INT32_MAX; // we don't need this thread here...
|
||||
} else {
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if ((nagCycleCutoff < millis()) && !rtttl::isPlaying()) {
|
||||
#else
|
||||
if (nagCycleCutoff < millis()) {
|
||||
#endif
|
||||
// let the song finish if we reach timeout
|
||||
nagCycleCutoff = UINT32_MAX;
|
||||
LOG_INFO("Turning off external notification: ");
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (getExternal(i)) {
|
||||
setExternalOff(i);
|
||||
externalTurnedOn[i] = 0;
|
||||
LOG_INFO("%d ", i);
|
||||
}
|
||||
setExternalOff(i);
|
||||
externalTurnedOn[i] = 0;
|
||||
LOG_INFO("%d ", i);
|
||||
}
|
||||
LOG_INFO("\n");
|
||||
isNagging = false;
|
||||
return INT32_MAX; // save cycles till we're needed again
|
||||
}
|
||||
|
||||
// If the output is turned on, turn it back off after the given period of time.
|
||||
if (nagCycleCutoff != UINT32_MAX) {
|
||||
if (isNagging) {
|
||||
if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms
|
||||
? moduleConfig.external_notification.output_ms
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
|
||||
@@ -80,16 +76,14 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
}
|
||||
|
||||
// now let the PWM buzzer play
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if (moduleConfig.external_notification.use_pwm) {
|
||||
if (rtttl::isPlaying()) {
|
||||
rtttl::play();
|
||||
} else if (nagCycleCutoff >= millis()) {
|
||||
} else if (isNagging && (nagCycleCutoff >= millis())) {
|
||||
// start the song again if we have time left
|
||||
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
@@ -140,10 +134,9 @@ bool ExternalNotificationModule::getExternal(uint8_t index)
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::stopNow() {
|
||||
#ifndef ARCH_PORTDUINO
|
||||
rtttl::stop();
|
||||
#endif
|
||||
nagCycleCutoff = 1; // small value
|
||||
isNagging = false;
|
||||
setIntervalFromNow(0);
|
||||
}
|
||||
|
||||
@@ -230,6 +223,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
if (moduleConfig.external_notification.alert_bell) {
|
||||
if (containsBell) {
|
||||
LOG_INFO("externalNotificationModule - Notification Bell\n");
|
||||
isNagging = true;
|
||||
setExternalOn(0);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
@@ -242,6 +236,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
if (moduleConfig.external_notification.alert_bell_vibra) {
|
||||
if (containsBell) {
|
||||
LOG_INFO("externalNotificationModule - Notification Bell (Vibra)\n");
|
||||
isNagging = true;
|
||||
setExternalOn(1);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
@@ -254,12 +249,11 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
if (moduleConfig.external_notification.alert_bell_buzzer) {
|
||||
if (containsBell) {
|
||||
LOG_INFO("externalNotificationModule - Notification Bell (Buzzer)\n");
|
||||
isNagging = true;
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn(2);
|
||||
} else {
|
||||
#ifndef ARCH_PORTDUINO
|
||||
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
||||
#endif
|
||||
}
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
@@ -271,6 +265,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
|
||||
if (moduleConfig.external_notification.alert_message) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module\n");
|
||||
isNagging = true;
|
||||
setExternalOn(0);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
@@ -279,33 +274,33 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
}
|
||||
}
|
||||
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
if (moduleConfig.external_notification.alert_message_vibra) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module (Vibra)\n");
|
||||
setExternalOn(1);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message_buzzer) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)\n");
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn(2);
|
||||
} else {
|
||||
#ifndef ARCH_PORTDUINO
|
||||
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
||||
#endif
|
||||
}
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message_vibra) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module (Vibra)\n");
|
||||
isNagging = true;
|
||||
setExternalOn(1);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message_buzzer) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)\n");
|
||||
isNagging = true;
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn(2);
|
||||
} else {
|
||||
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
||||
}
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
|
||||
setIntervalFromNow(0); // run once so we know if we should do something
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,18 @@
|
||||
#include "configuration.h"
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#include <NonBlockingRtttl.h>
|
||||
#else
|
||||
// Noop class for portduino.
|
||||
class rtttl
|
||||
{
|
||||
public:
|
||||
explicit rtttl() {}
|
||||
static bool isPlaying() { return false; }
|
||||
static void play() {}
|
||||
static void begin(byte a, const char * b) {};
|
||||
static void stop() {}
|
||||
static bool done() { return true; }
|
||||
};
|
||||
#endif
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
@@ -39,6 +51,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
bool isNagging = false;
|
||||
|
||||
virtual AdminMessageHandleResult handleAdminMessageForModule(const MeshPacket &mp, AdminMessage *request, AdminMessage *response) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ void setupModules()
|
||||
|
||||
new RangeTestModule();
|
||||
#elif defined(ARCH_NRF52)
|
||||
new ExternalNotificationModule();
|
||||
externalNotificationModule = new ExternalNotificationModule();
|
||||
#endif
|
||||
|
||||
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra acks
|
||||
|
||||
@@ -215,6 +215,16 @@ void SimRadio::startReceive(MeshPacket *p) {
|
||||
handleReceiveInterrupt(p);
|
||||
}
|
||||
|
||||
QueueStatus SimRadio::getQueueStatus()
|
||||
{
|
||||
QueueStatus qs;
|
||||
|
||||
qs.res = qs.mesh_packet_id = 0;
|
||||
qs.free = txQueue.getFree();
|
||||
qs.maxlen = txQueue.getMaxLen();
|
||||
|
||||
return qs;
|
||||
}
|
||||
|
||||
void SimRadio::handleReceiveInterrupt(MeshPacket *p)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,9 @@ class SimRadio : public RadioInterface
|
||||
*/
|
||||
virtual void startReceive(MeshPacket *p);
|
||||
|
||||
QueueStatus getQueueStatus() override;
|
||||
|
||||
|
||||
protected:
|
||||
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
|
||||
bool isReceiving = false;
|
||||
|
||||
Reference in New Issue
Block a user