Keep Full RAK Companion within flash using integer airtime blocks
This commit is contained in:
1 parent
1be8d88435
commit
e0442880e1
5 files changed
+70
-7
No files matched your search
@@ -674,9 +674,11 @@ uint32_t RadioLibWrapper::getBeaconAirtime(const mesh::RadioProfileParams& p, in
|
||||
|| (p.freq > 1000 && p.sf > 10)
|
||||
#endif
|
||||
? 1 : 0;
|
||||
const double coded = ceil((8.0 * length - 4 * p.sf + (p.sf <= 6 ? 20 : 28) + 16)
|
||||
/ (4 * (p.sf - 2 * de)));
|
||||
const double payload = 8 + (coded > 0 ? coded * p.cr : 0);
|
||||
// Round the small integer bit/block ratio without floating-point division.
|
||||
const int numerator = 8 * length - 4 * p.sf + (p.sf <= 6 ? 20 : 28) + 16;
|
||||
const int denominator = 4 * (p.sf - 2 * de);
|
||||
const int coded = numerator > 0 ? (numerator + denominator - 1) / denominator : 0;
|
||||
const double payload = 8 + coded * p.cr;
|
||||
return static_cast<uint32_t>(ceil((preamble + (p.sf <= 6 ? 6.25 : 4.25) + payload)
|
||||
* symbol / 1000.0));
|
||||
}
|
||||
@@ -1013,9 +1015,11 @@ uint32_t RadioLibWrapper::getProfileAirtime(uint8_t profile, int len, uint8_t cr
|
||||
|| (p.freq > 1000 && p.sf > 10)
|
||||
#endif
|
||||
? 1 : 0;
|
||||
const double coded = ceil((8.0 * len - 4 * p.sf + (p.sf <= 6 ? 20 : 28) + 16)
|
||||
/ (4 * (p.sf - 2 * de)));
|
||||
const double payload_symbols = 8 + (coded > 0 ? coded * cr : 0);
|
||||
// Round the small integer bit/block ratio without floating-point division.
|
||||
const int numerator = 8 * len - 4 * p.sf + (p.sf <= 6 ? 20 : 28) + 16;
|
||||
const int denominator = 4 * (p.sf - 2 * de);
|
||||
const int coded = numerator > 0 ? (numerator + denominator - 1) / denominator : 0;
|
||||
const double payload_symbols = 8 + coded * cr;
|
||||
const double suffix = p.sf <= 6 ? 6.25 : 4.25;
|
||||
const double airtime = ceil((profilePreamble(profile) + suffix + payload_symbols) * symbol / 1000.0);
|
||||
const uint32_t rounded = airtime > UINT32_MAX ? UINT32_MAX : uint32_t(airtime);
|
||||
|
||||
+1
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user