From c4b6360695925a2a51abfe35fddbaba6b5742902 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Wed, 28 Apr 2021 15:59:32 -0700 Subject: [PATCH] add support for replying last message if it was lost.. --- PROTOCOL.md | 6 ++++++ comms.c | 38 +++++++++++++++++++++++++++++++++++++- comms.h | 8 ++++++++ lora.py | 13 +++++++++++++ lora_comms.py | 10 ++++++++-- 5 files changed, 72 insertions(+), 3 deletions(-) diff --git a/PROTOCOL.md b/PROTOCOL.md index d34bf65..ebbd244 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -10,6 +10,12 @@ initiator does not receive a response to it's query, it will resend the request until it does. It is required that the responder be able to detect this, and resend the last response. +The respondent will cache message responses after the session has been +confirmed, but before that, it is unneccessary, as there is no harm to +reprocess the messages. The more complicated part is dealing w/ a +missed confirmed reply, as the state will need to be back tracked (saved) +to decode the repeated confirm request. + both sides: meta-AD('com.funkthat.lora.irrigation..v0.0.1') key() diff --git a/comms.c b/comms.c index 67f2410..381cadc 100644 --- a/comms.c +++ b/comms.c @@ -5,6 +5,19 @@ static const size_t MAC_LEN = 8; static const size_t CHALLENGE_LEN = 16; static const uint8_t domain[] = "com.funkthat.lora.irrigation.shared.v0.0.1"; +static int comms_pktbuf_equal(struct pktbuf a, struct pktbuf b); + +/* returns 1 if equal, 0 if not equal */ +static int +comms_pktbuf_equal(struct pktbuf a, struct pktbuf b) +{ + + if (a.pktlen != b.pktlen) + return 0; + + return memcmp(a.pkt, b.pkt, a.pktlen) == 0; +} + size_t _strobe_state_size() { @@ -48,6 +61,14 @@ comms_process(struct comms_state *cs, struct pktbuf pbin, struct pktbuf *pbout) struct pktbuf pbmsg, pbrep; ssize_t cnt, ret, msglen; + /* if the current msg matches the previous */ + if (comms_pktbuf_equal(pbin, cs->cs_prevmsg)) { + /* send the previous response */ + pbout->pktlen = cs->cs_prevmsgresp.pktlen; + memcpy(pbout->pkt, cs->cs_prevmsgresp.pkt, pbout->pktlen); + return; + } + strobe_attach_buffer(&cs->cs_state, pbin.pkt, pbin.pktlen); cnt = strobe_get(&cs->cs_state, APP_CIPHERTEXT, buf, pbin.pktlen - @@ -108,8 +129,23 @@ comms_process(struct comms_state *cs, struct pktbuf pbin, struct pktbuf *pbout) ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN); break; - } + } } + /* set the output buffer length */ pbout->pktlen = ret; + + if (ret != 0) { + /* we accepted a new message store it */ + + /* store the req */ + cs->cs_prevmsg.pkt = cs->cs_prevmsgbuf; + cs->cs_prevmsg.pktlen = pbin.pktlen; + memcpy(cs->cs_prevmsg.pkt, pbin.pkt, pbin.pktlen); + + /* store the response */ + cs->cs_prevmsgresp.pkt = cs->cs_prevmsgrespbuf; + cs->cs_prevmsgresp.pktlen = pbout->pktlen; + memcpy(cs->cs_prevmsgresp.pkt, pbout->pkt, pbout->pktlen); + } } diff --git a/comms.h b/comms.h index b9e44fb..d2dd2e9 100644 --- a/comms.h +++ b/comms.h @@ -3,6 +3,8 @@ #include +#define COMMS_MAXMSG 64 + struct pktbuf { uint8_t *pkt; uint16_t pktlen; @@ -23,6 +25,12 @@ struct comms_state { strobe_s cs_start; /* special starting state cache */ process_msgfunc_t cs_procmsg; + + struct pktbuf cs_prevmsg; + struct pktbuf cs_prevmsgresp; + + uint8_t cs_prevmsgbuf[COMMS_MAXMSG]; + uint8_t cs_prevmsgrespbuf[COMMS_MAXMSG]; }; size_t _strobe_state_size(); diff --git a/lora.py b/lora.py index a05eadd..cc19395 100644 --- a/lora.py +++ b/lora.py @@ -311,6 +311,19 @@ class TestLORANode(unittest.IsolatedAsyncioTestCase): _self.assertEqual(expectlen, outbuf.pktlen) + # save what was originally replied + origmsg = outbuf._from() + + # pretend that the reply didn't make it + r = make_pktbuf(gb) + outbuf = make_pktbuf(outbytes) + + lora_comms.comms_process(commstate, r, + outbuf) + + # make sure that the reply matches previous + _self.assertEqual(origmsg, outbuf._from()) + # pass the reply back await self.put(outbytes[:outbuf.pktlen]) diff --git a/lora_comms.py b/lora_comms.py index 67d2c20..fa87fd2 100644 --- a/lora_comms.py +++ b/lora_comms.py @@ -1,5 +1,5 @@ from ctypes import Structure, POINTER, CFUNCTYPE, pointer -from ctypes import c_uint8, c_uint16, c_ssize_t, c_size_t, c_uint64 +from ctypes import c_uint8, c_uint16, c_ssize_t, c_size_t, c_uint64, c_int from ctypes import CDLL class PktBuf(Structure): @@ -21,7 +21,6 @@ def make_pktbuf(s): if isinstance(s, bytearray): obj = s pb.pkt = pointer(c_uint8.from_buffer(s)) - #print('mp:', repr(pb.pkt)) else: obj = (c_uint8 * len(s))(*s) pb.pkt = obj @@ -44,8 +43,15 @@ class CommsState(Structure): _fields_ = [ # The alignment of these may be off ('cs_state', c_uint64 * _strobe_state_u64_cnt), + ('cs_comm_state', c_int), ('cs_start', c_uint64 * _strobe_state_u64_cnt), ('cs_procmsg', process_msgfunc_t), + + ('cs_prevmsg', PktBuf), + ('cs_prevmsgresp', PktBuf), + + ('cs_prevmsgbuf', c_uint8 * 64), + ('cs_prevmsgrespbuf', c_uint8 * 64), ] for func, ret, args in [