mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-23 13:34:46 +00:00
Just start a new PR. Conflicts were too wild
This commit is contained in:
parent
fc5e80a5cc
commit
4c9f0b2646
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
@ -2,8 +2,9 @@
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"ms-vscode.cpptools",
|
||||
"platformio.platformio-ide",
|
||||
"trunk.io"
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ PhoneAPI::~PhoneAPI()
|
||||
void PhoneAPI::handleStartConfig()
|
||||
{
|
||||
// Must be before setting state (because state is how we know !connected)
|
||||
if (!isConnected()) {
|
||||
if (!isConnected())
|
||||
{
|
||||
onConnectionChanged(true);
|
||||
observe(&service.fromNumChanged);
|
||||
observe(&xModem.packetReady);
|
||||
@ -46,7 +47,8 @@ void PhoneAPI::handleStartConfig()
|
||||
|
||||
void PhoneAPI::close()
|
||||
{
|
||||
if (state != STATE_SEND_NOTHING) {
|
||||
if (state != STATE_SEND_NOTHING)
|
||||
{
|
||||
state = STATE_SEND_NOTHING;
|
||||
|
||||
unobserve(&service.fromNumChanged);
|
||||
@ -60,9 +62,11 @@ void PhoneAPI::close()
|
||||
|
||||
void PhoneAPI::checkConnectionTimeout()
|
||||
{
|
||||
if (isConnected()) {
|
||||
if (isConnected())
|
||||
{
|
||||
bool newContact = checkIsConnected();
|
||||
if (!newContact) {
|
||||
if (!newContact)
|
||||
{
|
||||
LOG_INFO("Lost phone connection\n");
|
||||
close();
|
||||
}
|
||||
@ -80,8 +84,10 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
// return (lastContactMsec != 0) &&
|
||||
|
||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||
if (pb_decode_from_bytes(buf, bufLength, &meshtastic_ToRadio_msg, &toRadioScratch)) {
|
||||
switch (toRadioScratch.which_payload_variant) {
|
||||
if (pb_decode_from_bytes(buf, bufLength, &meshtastic_ToRadio_msg, &toRadioScratch))
|
||||
{
|
||||
switch (toRadioScratch.which_payload_variant)
|
||||
{
|
||||
case meshtastic_ToRadio_packet_tag:
|
||||
return handleToRadioPacket(toRadioScratch.packet);
|
||||
case meshtastic_ToRadio_want_config_id_tag:
|
||||
@ -102,7 +108,9 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
// LOG_DEBUG("Error: unexpected ToRadio variant\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Error: ignoring malformed toradio\n");
|
||||
}
|
||||
|
||||
@ -125,7 +133,8 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
*/
|
||||
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
{
|
||||
if (!available()) {
|
||||
if (!available())
|
||||
{
|
||||
// LOG_DEBUG("getFromRadio=not available\n");
|
||||
return 0;
|
||||
}
|
||||
@ -133,7 +142,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
|
||||
|
||||
// Advance states as needed
|
||||
switch (state) {
|
||||
switch (state)
|
||||
{
|
||||
case STATE_SEND_NOTHING:
|
||||
LOG_INFO("getFromRadio=STATE_SEND_NOTHING\n");
|
||||
break;
|
||||
@ -150,18 +160,22 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
|
||||
break;
|
||||
|
||||
case STATE_SEND_NODEINFO: {
|
||||
case STATE_SEND_NODEINFO:
|
||||
{
|
||||
LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n");
|
||||
const meshtastic_NodeInfo *info = nodeInfoForPhone;
|
||||
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
|
||||
|
||||
if (info) {
|
||||
if (info)
|
||||
{
|
||||
LOG_INFO("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->last_heard, info->user.id,
|
||||
info->user.long_name);
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
|
||||
fromRadioScratch.node_info = *info;
|
||||
// Stay in current state until done sending nodeinfos
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO("Done sending nodeinfos\n");
|
||||
state = STATE_SEND_CHANNELS;
|
||||
// Go ahead and send that ID right now
|
||||
@ -176,7 +190,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.channel = channels.getByIndex(config_state);
|
||||
config_state++;
|
||||
// Advance when we have sent all of our Channels
|
||||
if (config_state >= MAX_NUM_CHANNELS) {
|
||||
if (config_state >= MAX_NUM_CHANNELS)
|
||||
{
|
||||
state = STATE_SEND_CONFIG;
|
||||
config_state = _meshtastic_AdminMessage_ConfigType_MIN + 1;
|
||||
}
|
||||
@ -185,7 +200,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
case STATE_SEND_CONFIG:
|
||||
LOG_INFO("getFromRadio=STATE_SEND_CONFIG\n");
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_tag;
|
||||
switch (config_state) {
|
||||
switch (config_state)
|
||||
{
|
||||
case meshtastic_Config_device_tag:
|
||||
fromRadioScratch.config.which_payload_variant = meshtastic_Config_device_tag;
|
||||
fromRadioScratch.config.payload_variant.device = config.device;
|
||||
@ -224,7 +240,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
|
||||
config_state++;
|
||||
// Advance when we have sent all of our config objects
|
||||
if (config_state > (_meshtastic_AdminMessage_ConfigType_MAX + 1)) {
|
||||
if (config_state > (_meshtastic_AdminMessage_ConfigType_MAX + 1))
|
||||
{
|
||||
state = STATE_SEND_MODULECONFIG;
|
||||
config_state = _meshtastic_AdminMessage_ModuleConfigType_MIN + 1;
|
||||
}
|
||||
@ -233,7 +250,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
case STATE_SEND_MODULECONFIG:
|
||||
LOG_INFO("getFromRadio=STATE_SEND_MODULECONFIG\n");
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_moduleConfig_tag;
|
||||
switch (config_state) {
|
||||
switch (config_state)
|
||||
{
|
||||
case meshtastic_ModuleConfig_mqtt_tag:
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_mqtt_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.mqtt = moduleConfig.mqtt;
|
||||
@ -276,7 +294,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
|
||||
config_state++;
|
||||
// Advance when we have sent all of our ModuleConfig objects
|
||||
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) {
|
||||
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1))
|
||||
{
|
||||
state = STATE_SEND_COMPLETE_ID;
|
||||
config_state = 0;
|
||||
}
|
||||
@ -293,16 +312,20 @@ 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 (queueStatusPacketForPhone) {
|
||||
if (queueStatusPacketForPhone)
|
||||
{
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_queueStatus_tag;
|
||||
fromRadioScratch.queueStatus = *queueStatusPacketForPhone;
|
||||
releaseQueueStatusPhonePacket();
|
||||
} else if (xmodemPacketForPhone) {
|
||||
}
|
||||
else if (xmodemPacketForPhone.control != meshtastic_XModem_Control_NUL)
|
||||
{
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_xmodemPacket_tag;
|
||||
fromRadioScratch.xmodemPacket = *xmodemPacketForPhone;
|
||||
free(xmodemPacketForPhone);
|
||||
xmodemPacketForPhone = NULL;
|
||||
} else if (packetForPhone) {
|
||||
fromRadioScratch.xmodemPacket = xmodemPacketForPhone;
|
||||
xmodemPacketForPhone = meshtastic_XModem_init_zero;
|
||||
}
|
||||
else if (packetForPhone)
|
||||
{
|
||||
printPacket("phone downloaded packet", packetForPhone);
|
||||
|
||||
// Encapsulate as a FromRadio packet
|
||||
@ -317,7 +340,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
}
|
||||
|
||||
// Do we have a message from the mesh?
|
||||
if (fromRadioScratch.which_payload_variant != 0) {
|
||||
if (fromRadioScratch.which_payload_variant != 0)
|
||||
{
|
||||
// Encapsulate as a FromRadio packet
|
||||
size_t numbytes = pb_encode_to_bytes(buf, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch);
|
||||
|
||||
@ -336,7 +360,8 @@ void PhoneAPI::handleDisconnect()
|
||||
|
||||
void PhoneAPI::releasePhonePacket()
|
||||
{
|
||||
if (packetForPhone) {
|
||||
if (packetForPhone)
|
||||
{
|
||||
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
|
||||
packetForPhone = NULL;
|
||||
}
|
||||
@ -344,7 +369,8 @@ void PhoneAPI::releasePhonePacket()
|
||||
|
||||
void PhoneAPI::releaseQueueStatusPhonePacket()
|
||||
{
|
||||
if (queueStatusPacketForPhone) {
|
||||
if (queueStatusPacketForPhone)
|
||||
{
|
||||
service.releaseQueueStatusToPool(queueStatusPacketForPhone);
|
||||
queueStatusPacketForPhone = NULL;
|
||||
}
|
||||
@ -355,7 +381,8 @@ void PhoneAPI::releaseQueueStatusPhonePacket()
|
||||
*/
|
||||
bool PhoneAPI::available()
|
||||
{
|
||||
switch (state) {
|
||||
switch (state)
|
||||
{
|
||||
case STATE_SEND_NOTHING:
|
||||
return false;
|
||||
case STATE_SEND_MY_INFO:
|
||||
@ -370,14 +397,15 @@ bool PhoneAPI::available()
|
||||
nodeInfoForPhone = nodeDB.readNextInfo();
|
||||
return true; // Always say we have something, because we might need to advance our state machine
|
||||
|
||||
case STATE_SEND_PACKETS: {
|
||||
case STATE_SEND_PACKETS:
|
||||
{
|
||||
if (!queueStatusPacketForPhone)
|
||||
queueStatusPacketForPhone = service.getQueueStatusForPhone();
|
||||
bool hasPacket = !!queueStatusPacketForPhone;
|
||||
if (hasPacket)
|
||||
return true;
|
||||
|
||||
if (!xmodemPacketForPhone)
|
||||
if (xmodemPacketForPhone.control != meshtastic_XModem_Control_NUL)
|
||||
xmodemPacketForPhone = xModem.getForPhone();
|
||||
hasPacket = !!packetForPhone;
|
||||
if (hasPacket)
|
||||
@ -413,10 +441,12 @@ int PhoneAPI::onNotify(uint32_t newValue)
|
||||
checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version doesn't call this
|
||||
// from idle)
|
||||
|
||||
if (state == STATE_SEND_PACKETS) {
|
||||
if (state == STATE_SEND_PACKETS)
|
||||
{
|
||||
LOG_INFO("Telling client we have new packets %u\n", newValue);
|
||||
onNowHasData(newValue);
|
||||
} else
|
||||
}
|
||||
else
|
||||
LOG_DEBUG("(Client not yet interested in packets)\n");
|
||||
|
||||
return 0;
|
||||
|
@ -19,118 +19,119 @@
|
||||
class PhoneAPI
|
||||
: public Observer<uint32_t> // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
|
||||
{
|
||||
enum State {
|
||||
STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config
|
||||
STATE_SEND_MY_INFO, // send our my info record
|
||||
STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
|
||||
STATE_SEND_CHANNELS, // Send all channels
|
||||
STATE_SEND_CONFIG, // Replacement for the old Radioconfig
|
||||
STATE_SEND_MODULECONFIG, // Send Module specific config
|
||||
STATE_SEND_COMPLETE_ID,
|
||||
STATE_SEND_PACKETS // send packets or debug strings
|
||||
};
|
||||
enum State
|
||||
{
|
||||
STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config
|
||||
STATE_SEND_MY_INFO, // send our my info record
|
||||
STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
|
||||
STATE_SEND_CHANNELS, // Send all channels
|
||||
STATE_SEND_CONFIG, // Replacement for the old Radioconfig
|
||||
STATE_SEND_MODULECONFIG, // Send Module specific config
|
||||
STATE_SEND_COMPLETE_ID,
|
||||
STATE_SEND_PACKETS // send packets or debug strings
|
||||
};
|
||||
|
||||
State state = STATE_SEND_NOTHING;
|
||||
State state = STATE_SEND_NOTHING;
|
||||
|
||||
uint8_t config_state = 0;
|
||||
uint8_t config_state = 0;
|
||||
|
||||
/**
|
||||
* Each packet sent to the phone has an incrementing count
|
||||
*/
|
||||
uint32_t fromRadioNum = 0;
|
||||
/**
|
||||
* Each packet sent to the phone has an incrementing count
|
||||
*/
|
||||
uint32_t fromRadioNum = 0;
|
||||
|
||||
/// We temporarily keep the packet here between the call to available and getFromRadio. We will free it after the phone
|
||||
/// downloads it
|
||||
meshtastic_MeshPacket *packetForPhone = NULL;
|
||||
/// We temporarily keep the packet here between the call to available and getFromRadio. We will free it after the phone
|
||||
/// downloads it
|
||||
meshtastic_MeshPacket *packetForPhone = NULL;
|
||||
|
||||
// file transfer packets destined for phone. Push it to the queue then free it.
|
||||
meshtastic_XModem *xmodemPacketForPhone = NULL;
|
||||
// file transfer packets destined for phone. Push it to the queue then free it.
|
||||
meshtastic_XModem xmodemPacketForPhone = meshtastic_XModem_init_zero;
|
||||
|
||||
// Keep QueueStatus packet just as packetForPhone
|
||||
meshtastic_QueueStatus *queueStatusPacketForPhone = NULL;
|
||||
// Keep QueueStatus packet just as packetForPhone
|
||||
meshtastic_QueueStatus *queueStatusPacketForPhone = NULL;
|
||||
|
||||
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
|
||||
const meshtastic_NodeInfo *nodeInfoForPhone = NULL;
|
||||
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
|
||||
const meshtastic_NodeInfo *nodeInfoForPhone = NULL;
|
||||
|
||||
meshtastic_ToRadio toRadioScratch = {
|
||||
0}; // this is a static scratch object, any data must be copied elsewhere before returning
|
||||
meshtastic_ToRadio toRadioScratch = {
|
||||
0}; // this is a static scratch object, any data must be copied elsewhere before returning
|
||||
|
||||
/// Use to ensure that clients don't get confused about old messages from the radio
|
||||
uint32_t config_nonce = 0;
|
||||
/// Use to ensure that clients don't get confused about old messages from the radio
|
||||
uint32_t config_nonce = 0;
|
||||
|
||||
public:
|
||||
PhoneAPI();
|
||||
public:
|
||||
PhoneAPI();
|
||||
|
||||
/// Destructor - calls close()
|
||||
virtual ~PhoneAPI();
|
||||
/// Destructor - calls close()
|
||||
virtual ~PhoneAPI();
|
||||
|
||||
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
|
||||
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
|
||||
virtual void close();
|
||||
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
|
||||
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
|
||||
virtual void close();
|
||||
|
||||
/**
|
||||
* Handle a ToRadio protobuf
|
||||
* @return true true if a packet was queued for sending (so that caller can yield)
|
||||
*/
|
||||
virtual bool handleToRadio(const uint8_t *buf, size_t len);
|
||||
/**
|
||||
* Handle a ToRadio protobuf
|
||||
* @return true true if a packet was queued for sending (so that caller can yield)
|
||||
*/
|
||||
virtual bool handleToRadio(const uint8_t *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Get the next packet we want to send to the phone
|
||||
*
|
||||
* We assume buf is at least FromRadio_size bytes long.
|
||||
* Returns number of bytes in the FromRadio packet (or 0 if no packet available)
|
||||
*/
|
||||
size_t getFromRadio(uint8_t *buf);
|
||||
/**
|
||||
* Get the next packet we want to send to the phone
|
||||
*
|
||||
* We assume buf is at least FromRadio_size bytes long.
|
||||
* Returns number of bytes in the FromRadio packet (or 0 if no packet available)
|
||||
*/
|
||||
size_t getFromRadio(uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Return true if we have data available to send to the phone
|
||||
*/
|
||||
bool available();
|
||||
/**
|
||||
* Return true if we have data available to send to the phone
|
||||
*/
|
||||
bool available();
|
||||
|
||||
bool isConnected() { return state != STATE_SEND_NOTHING; }
|
||||
bool isConnected() { return state != STATE_SEND_NOTHING; }
|
||||
|
||||
void setInitialState() { state = STATE_SEND_MY_INFO; }
|
||||
void setInitialState() { state = STATE_SEND_MY_INFO; }
|
||||
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
meshtastic_FromRadio fromRadioScratch = {};
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
meshtastic_FromRadio fromRadioScratch = {};
|
||||
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected) {}
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected) {}
|
||||
|
||||
/// If we haven't heard from the other side in a while then say not connected
|
||||
void checkConnectionTimeout();
|
||||
/// If we haven't heard from the other side in a while then say not connected
|
||||
void checkConnectionTimeout();
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() = 0;
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() = 0;
|
||||
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum) {}
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum) {}
|
||||
|
||||
/**
|
||||
* Subclasses can use this to find out when a client drops the link
|
||||
*/
|
||||
virtual void handleDisconnect();
|
||||
/**
|
||||
* Subclasses can use this to find out when a client drops the link
|
||||
*/
|
||||
virtual void handleDisconnect();
|
||||
|
||||
private:
|
||||
void releasePhonePacket();
|
||||
private:
|
||||
void releasePhonePacket();
|
||||
|
||||
void releaseQueueStatusPhonePacket();
|
||||
void releaseQueueStatusPhonePacket();
|
||||
|
||||
/// begin a new connection
|
||||
void handleStartConfig();
|
||||
/// begin a new connection
|
||||
void handleStartConfig();
|
||||
|
||||
/**
|
||||
* Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
|
||||
* @return true true if a packet was queued for sending
|
||||
*/
|
||||
bool handleToRadioPacket(meshtastic_MeshPacket &p);
|
||||
/**
|
||||
* Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
|
||||
* @return true true if a packet was queued for sending
|
||||
*/
|
||||
bool handleToRadioPacket(meshtastic_MeshPacket &p);
|
||||
|
||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||
virtual int onNotify(uint32_t newValue) override;
|
||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||
virtual int onNotify(uint32_t newValue) override;
|
||||
};
|
||||
|
114
src/xmodem.cpp
114
src/xmodem.cpp
@ -36,13 +36,13 @@ XModemAdapter xModem;
|
||||
|
||||
XModemAdapter::XModemAdapter()
|
||||
{
|
||||
xmodemStore = (meshtastic_XModem *)malloc(meshtastic_XModem_size);
|
||||
}
|
||||
|
||||
unsigned short XModemAdapter::crc16_ccitt(const pb_byte_t *buffer, int length)
|
||||
{
|
||||
unsigned short crc16 = 0;
|
||||
while (length != 0) {
|
||||
while (length != 0)
|
||||
{
|
||||
crc16 = (unsigned char)(crc16 >> 8) | (crc16 << 8);
|
||||
crc16 ^= *buffer;
|
||||
crc16 ^= (unsigned char)(crc16 & 0xff) >> 4;
|
||||
@ -66,32 +66,32 @@ int XModemAdapter::check(const pb_byte_t *buf, int sz, unsigned short tcrc)
|
||||
|
||||
void XModemAdapter::sendControl(meshtastic_XModem_Control c)
|
||||
{
|
||||
memset(xmodemStore, 0, meshtastic_XModem_size);
|
||||
xmodemStore->control = c;
|
||||
xmodemStore = meshtastic_XModem_init_zero;
|
||||
xmodemStore.control = c;
|
||||
LOG_DEBUG("XModem: Notify Sending control %d.\n", c);
|
||||
packetReady.notifyObservers(packetno);
|
||||
}
|
||||
|
||||
meshtastic_XModem *XModemAdapter::getForPhone()
|
||||
meshtastic_XModem XModemAdapter::getForPhone()
|
||||
{
|
||||
if (xmodemStore) {
|
||||
return xmodemStore;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return xmodemStore;
|
||||
}
|
||||
|
||||
void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
||||
{
|
||||
switch (xmodemPacket.control) {
|
||||
switch (xmodemPacket.control)
|
||||
{
|
||||
case meshtastic_XModem_Control_SOH:
|
||||
case meshtastic_XModem_Control_STX:
|
||||
if ((xmodemPacket.seq == 0) && !isReceiving && !isTransmitting) {
|
||||
if ((xmodemPacket.seq == 0) && !isReceiving && !isTransmitting)
|
||||
{
|
||||
// NULL packet has the destination filename
|
||||
memcpy(filename, &xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
||||
if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash
|
||||
if (xmodemPacket.control == meshtastic_XModem_Control_SOH)
|
||||
{ // Receive this file and put to Flash
|
||||
file = FSCom.open(filename, FILE_O_WRITE);
|
||||
if (file) {
|
||||
if (file)
|
||||
{
|
||||
sendControl(meshtastic_XModem_Control_ACK);
|
||||
isReceiving = true;
|
||||
packetno = 1;
|
||||
@ -100,19 +100,23 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
||||
sendControl(meshtastic_XModem_Control_NAK);
|
||||
isReceiving = false;
|
||||
break;
|
||||
} else { // Transmit this file from Flash
|
||||
}
|
||||
else
|
||||
{ // Transmit this file from Flash
|
||||
LOG_INFO("XModem: Transmitting file %s\n", filename);
|
||||
file = FSCom.open(filename, FILE_O_READ);
|
||||
if (file) {
|
||||
if (file)
|
||||
{
|
||||
packetno = 1;
|
||||
isTransmitting = true;
|
||||
memset(xmodemStore, 0, meshtastic_XModem_size);
|
||||
xmodemStore->control = meshtastic_XModem_Control_SOH;
|
||||
xmodemStore->seq = packetno;
|
||||
xmodemStore->buffer.size = file.read(xmodemStore->buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||
xmodemStore->crc16 = crc16_ccitt(xmodemStore->buffer.bytes, xmodemStore->buffer.size);
|
||||
LOG_DEBUG("XModem: STX Notify Sending packet %d, %d Bytes.\n", packetno, xmodemStore->buffer.size);
|
||||
if (xmodemStore->buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
||||
xmodemStore = meshtastic_XModem_init_zero;
|
||||
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
||||
xmodemStore.seq = packetno;
|
||||
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
||||
LOG_DEBUG("XModem: STX Notify Sending packet %d, %d Bytes.\n", packetno, xmodemStore.buffer.size);
|
||||
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes))
|
||||
{
|
||||
isEOT = true;
|
||||
// send EOT on next Ack
|
||||
}
|
||||
@ -123,11 +127,15 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
||||
isTransmitting = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (isReceiving) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isReceiving)
|
||||
{
|
||||
// normal file data packet
|
||||
if ((xmodemPacket.seq == packetno) &&
|
||||
check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) {
|
||||
check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16))
|
||||
{
|
||||
// valid packet
|
||||
file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
||||
sendControl(meshtastic_XModem_Control_ACK);
|
||||
@ -137,7 +145,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
||||
// invalid packet
|
||||
sendControl(meshtastic_XModem_Control_NAK);
|
||||
break;
|
||||
} else if (isTransmitting) {
|
||||
}
|
||||
else if (isTransmitting)
|
||||
{
|
||||
// just received something weird.
|
||||
sendControl(meshtastic_XModem_Control_CAN);
|
||||
isTransmitting = false;
|
||||
@ -160,8 +170,10 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
||||
break;
|
||||
case meshtastic_XModem_Control_ACK:
|
||||
// Acknowledge Send the next packet
|
||||
if (isTransmitting) {
|
||||
if (isEOT) {
|
||||
if (isTransmitting)
|
||||
{
|
||||
if (isEOT)
|
||||
{
|
||||
sendControl(meshtastic_XModem_Control_EOT);
|
||||
file.close();
|
||||
LOG_INFO("XModem: Finished sending file %s\n", filename);
|
||||
@ -171,45 +183,53 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
||||
}
|
||||
retrans = MAXRETRANS; // reset retransmit counter
|
||||
packetno++;
|
||||
memset(xmodemStore, 0, meshtastic_XModem_size);
|
||||
xmodemStore->control = meshtastic_XModem_Control_SOH;
|
||||
xmodemStore->seq = packetno;
|
||||
xmodemStore->buffer.size = file.read(xmodemStore->buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||
xmodemStore->crc16 = crc16_ccitt(xmodemStore->buffer.bytes, xmodemStore->buffer.size);
|
||||
LOG_DEBUG("XModem: ACK Notify Sending packet %d, %d Bytes.\n", packetno, xmodemStore->buffer.size);
|
||||
if (xmodemStore->buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
||||
xmodemStore = meshtastic_XModem_init_zero;
|
||||
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
||||
xmodemStore.seq = packetno;
|
||||
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
||||
LOG_DEBUG("XModem: ACK Notify Sending packet %d, %d Bytes.\n", packetno, xmodemStore.buffer.size);
|
||||
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes))
|
||||
{
|
||||
isEOT = true;
|
||||
// send EOT on next Ack
|
||||
}
|
||||
packetReady.notifyObservers(packetno);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// just received something weird.
|
||||
sendControl(meshtastic_XModem_Control_CAN);
|
||||
}
|
||||
break;
|
||||
case meshtastic_XModem_Control_NAK:
|
||||
// Negative acknowledge. Send the same buffer again
|
||||
if (isTransmitting) {
|
||||
if (--retrans <= 0) {
|
||||
if (isTransmitting)
|
||||
{
|
||||
if (--retrans <= 0)
|
||||
{
|
||||
sendControl(meshtastic_XModem_Control_CAN);
|
||||
file.close();
|
||||
LOG_INFO("XModem: Retransmit timeout, cancelling file %s\n", filename);
|
||||
isTransmitting = false;
|
||||
break;
|
||||
}
|
||||
memset(xmodemStore, 0, meshtastic_XModem_size);
|
||||
xmodemStore->control = meshtastic_XModem_Control_SOH;
|
||||
xmodemStore->seq = packetno;
|
||||
xmodemStore = meshtastic_XModem_init_zero;
|
||||
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
||||
xmodemStore.seq = packetno;
|
||||
file.seek((packetno - 1) * sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||
xmodemStore->buffer.size = file.read(xmodemStore->buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||
xmodemStore->crc16 = crc16_ccitt(xmodemStore->buffer.bytes, xmodemStore->buffer.size);
|
||||
LOG_DEBUG("XModem: NAK Notify Sending packet %d, %d Bytes.\n", packetno, xmodemStore->buffer.size);
|
||||
if (xmodemStore->buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
||||
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
||||
LOG_DEBUG("XModem: NAK Notify Sending packet %d, %d Bytes.\n", packetno, xmodemStore.buffer.size);
|
||||
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes))
|
||||
{
|
||||
isEOT = true;
|
||||
// send EOT on next Ack
|
||||
}
|
||||
packetReady.notifyObservers(packetno);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// just received something weird.
|
||||
sendControl(meshtastic_XModem_Control_CAN);
|
||||
}
|
||||
|
40
src/xmodem.h
40
src/xmodem.h
@ -40,37 +40,37 @@
|
||||
|
||||
class XModemAdapter
|
||||
{
|
||||
public:
|
||||
// Called when we put a fragment in the outgoing memory
|
||||
Observable<uint32_t> packetReady;
|
||||
public:
|
||||
// Called when we put a fragment in the outgoing memory
|
||||
Observable<uint32_t> packetReady;
|
||||
|
||||
XModemAdapter();
|
||||
XModemAdapter();
|
||||
|
||||
void handlePacket(meshtastic_XModem xmodemPacket);
|
||||
meshtastic_XModem *getForPhone();
|
||||
void handlePacket(meshtastic_XModem xmodemPacket);
|
||||
meshtastic_XModem getForPhone();
|
||||
|
||||
private:
|
||||
bool isReceiving = false;
|
||||
bool isTransmitting = false;
|
||||
bool isEOT = false;
|
||||
private:
|
||||
bool isReceiving = false;
|
||||
bool isTransmitting = false;
|
||||
bool isEOT = false;
|
||||
|
||||
int retrans = MAXRETRANS;
|
||||
int retrans = MAXRETRANS;
|
||||
|
||||
uint16_t packetno = 0;
|
||||
uint16_t packetno = 0;
|
||||
|
||||
#if defined(ARCH_NRF52)
|
||||
File file = File(FSCom);
|
||||
File file = File(FSCom);
|
||||
#else
|
||||
File file;
|
||||
File file;
|
||||
#endif
|
||||
|
||||
char filename[sizeof(meshtastic_XModem_buffer_t::bytes)] = {0};
|
||||
char filename[sizeof(meshtastic_XModem_buffer_t::bytes)] = {0};
|
||||
|
||||
protected:
|
||||
meshtastic_XModem *xmodemStore = NULL;
|
||||
unsigned short crc16_ccitt(const pb_byte_t *buffer, int length);
|
||||
int check(const pb_byte_t *buf, int sz, unsigned short tcrc);
|
||||
void sendControl(meshtastic_XModem_Control c);
|
||||
protected:
|
||||
meshtastic_XModem xmodemStore = meshtastic_XModem_init_zero;
|
||||
unsigned short crc16_ccitt(const pb_byte_t *buffer, int length);
|
||||
int check(const pb_byte_t *buf, int sz, unsigned short tcrc);
|
||||
void sendControl(meshtastic_XModem_Control c);
|
||||
};
|
||||
|
||||
extern XModemAdapter xModem;
|
||||
|
Loading…
Reference in New Issue
Block a user