Keep Full RAK Companion within flash using integer airtime blocks

This commit is contained in:
mikecarper committed 2026-10-19 20:36:16 -07:00
1 parent 1be8d88435
commit e0442880e1
5 files changed
+70 -7

No files matched your search

+1
View File
@@ -18,6 +18,7 @@
class RadioLibWrapper {
public:
mesh::RadioProfiles _profiles;
bool validateProfile(const mesh::RadioProfileParams& p) const { return mesh::RadioProfiles::valid(p); }
uint16_t profilePreamble(uint8_t profile) { return _profiles.preamble(profile, 32); }
uint32_t getEstAirtimeFor(int) { return 77; }
uint32_t getProfileAirtime(uint8_t, int, uint8_t = 0);
@@ -32,6 +32,7 @@ HARNESS = r'''
class RadioLibWrapper {
public:
mesh::RadioProfiles _profiles;
bool validateProfile(const mesh::RadioProfileParams& p) const { return mesh::RadioProfiles::valid(p); }
uint16_t profilePreamble(uint8_t profile) {
return _profiles.preamble(profile, 32);
}
+2
View File
@@ -155,9 +155,11 @@ class ForwardingProfileTimingTests(unittest.TestCase):
#include <cassert>
#include <cstdio>
#include <RadioProfiles.h>
#include <Packet.h>
class RadioLibWrapper {
public:
mesh::RadioProfiles _profiles;
bool validateProfile(const mesh::RadioProfileParams& p) const { return mesh::RadioProfiles::valid(p); }
unsigned legacy_calls = 0;
uint32_t getEstAirtimeFor(int length) { ++legacy_calls; return uint32_t(17 * length + 3); }
uint16_t profilePreamble(uint8_t profile) { return _profiles.params(profile).preamble; }
+56 -1
View File
@@ -27,10 +27,34 @@ struct RadioLibWrapper {
bool foreign=false;
bool supportsMeshtext()const{return foreign;}
bool supportsEthernetTunnel()const{return foreign;}
uint16_t profilePreamble(uint8_t)const{return 32;}
uint16_t profilePreamble(uint8_t profile)const{
const auto& p=_profiles.params(profile);
return p.protocol==mesh::RadioProfileProtocol::Meshtext?16:(p.preamble?p.preamble:32);
}
uint32_t getEstAirtimeFor(int){return 777;}
@METHODS@
};
// Preserve the previous floating-point formula as a regression oracle for the
// integer block-count optimization, including the high-band LDRO exception.
double referenceAirtime(const mesh::RadioProfileParams& p,int length,uint8_t cr,uint16_t preamble){
const double symbol=double(1U<<p.sf)*1000.0/p.bw;
const int de=(symbol>=16000
#if MESH_RADIO_PROFILE_CHIP==1121
||(p.freq>1000&&p.sf>10)
#endif
)?1:0;
const double blocks=ceil((8.0*length-4*p.sf+(p.sf<=6?20:28)+16)/(4*(p.sf-2*de)));
return ceil((preamble+(p.sf<=6?6.25:4.25)+8+(blocks>0?blocks*cr:0))*symbol/1000.0);
}
uint32_t referenceProfileAirtime(const mesh::RadioProfileParams& p,int length,uint8_t cr,uint16_t preamble){
const double airtime=referenceAirtime(p,length,cr,preamble);
const uint32_t rounded=airtime>UINT32_MAX?UINT32_MAX:uint32_t(airtime);
#if MESH_RADIO_PROFILE_CHIP==1110||MESH_RADIO_PROFILE_CHIP==1121
return rounded<200?200:rounded;
#else
return rounded;
#endif
}
int main(){
RadioLibWrapper w;
mesh::RadioProfileParams p;p.freq=MESH_RADIO_PROFILE_CHIP==1268?433:915;p.bw=125;p.sf=8;p.cr=5;
@@ -72,6 +96,37 @@ int main(){
assert(w.validateProfile(p));
#endif
}
// Exercise every packet length and coding rate, including SF5/6 overhead,
// zero-length negative numerators, narrow-band LDRO and high-band SF11/12.
// The tolerance edge and long preamble also cover the largest airtimes.
for(float frequency:{MESH_RADIO_PROFILE_CHIP==1268?433.0f:915.0f,2400.0f})
for(float bandwidth:{7.791f,7.8f,31.25f,62.5f,125.0f,500.0f,812.5f})
for(unsigned sf=5;sf<=12;++sf)
for(unsigned cr=5;cr<=8;++cr)
for(unsigned preamble:{0,8,32,65528}) {
p.freq=frequency;p.bw=bandwidth;p.sf=sf;p.cr=cr;p.preamble=preamble;
p.protocol=mesh::RadioProfileProtocol::MeshCore;
if(!w.validateProfile(p))continue;
w._profiles.primary=p;
for(int length=0;length<=255;++length) {
const auto expected=referenceProfileAirtime(p,length,cr,w.profilePreamble(0));
assert(w.getProfileAirtime(0,length)==expected);
assert(w.getProfileAirtime(0,length,cr)==expected);
assert(expected<35000000UL);
const uint16_t beacon_preamble=p.preamble?p.preamble:32;
const auto beacon_expected=length&&mesh::RadioProfiles::safePreamble(p,beacon_preamble)
?uint32_t(referenceAirtime(p,length,cr,beacon_preamble)):0;
assert(w.getBeaconAirtime(p,length)==beacon_expected);
}
assert(w.getProfileAirtime(0,255,4)==w.getProfileAirtime(0,255));
assert(w.getProfileAirtime(0,255,9)==w.getProfileAirtime(0,255));
}
// Meshtext fixes the preamble to 16 even when a long explicit value is saved.
w.foreign=true;p.freq=MESH_RADIO_PROFILE_CHIP==1268?433:915;
p.bw=125;p.sf=8;p.cr=5;p.preamble=65528;
p.protocol=mesh::RadioProfileProtocol::Meshtext;w._profiles.primary=p;
assert(w.getProfileAirtime(0,255)==referenceProfileAirtime(p,255,p.cr,16));
assert(w.getBeaconAirtime(p,255)==uint32_t(referenceAirtime(p,255,p.cr,16)));
}
'''.replace("#include <cassert>", "#include <cassert>\n#include <initializer_list>").replace("@METHODS@", methods)
with tempfile.TemporaryDirectory(prefix="profile-validation-") as folder: