mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-11-04 13:17:15 +00:00
Restore shared Ethernet chip select on every acquisition
This commit is contained in:
1 parent
c0362a5dfc
commit
f07421afa5
2 files changed
+44
-1
No files matched your search
@@ -97,6 +97,13 @@ bool RAK13800EthernetInterface::beginHardware() {
|
||||
mac[3],
|
||||
mac[4],
|
||||
mac[5]);
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// OFF releases the shared pads to inputs. The vendor W5100 init is cached
|
||||
// after its first success and will not restore CS direction on reacquire.
|
||||
// Only tryEnable() reaches here, after storage and SPI ownership admission.
|
||||
digitalWrite(PIN_ETHERNET_SS, HIGH);
|
||||
pinMode(PIN_ETHERNET_SS, OUTPUT);
|
||||
#endif
|
||||
ETHERNET_SPI_PORT.begin();
|
||||
_spiStarted = true;
|
||||
Ethernet.init(ETHERNET_SPI_PORT, PIN_ETHERNET_SS);
|
||||
|
||||
@@ -400,9 +400,23 @@ int main(){
|
||||
defines=FLAGS + ["OTA_SEEDER_ONLY"])
|
||||
|
||||
def test_actual_companion_eth_is_opt_in_and_busy_handoff_never_touches_spi(self):
|
||||
self._run_companion_eth_probe()
|
||||
|
||||
def test_companion_eth_cs_reacquisition_negative_controls(self):
|
||||
for mutation in ("missing_cs_direction", "missing_cs_preload"):
|
||||
with self.subTest(mutation=mutation):
|
||||
self._run_companion_eth_probe(mutation)
|
||||
|
||||
def _run_companion_eth_probe(self, mutation=None):
|
||||
stem = ROOT / "src/helpers/ethernet/RAK13800/RAK13800EthernetInterface"
|
||||
cls = extract_braced(stem.with_suffix(".h").read_text(), "class RAK13800EthernetInterface") + ";"
|
||||
cpp = stem.with_suffix(".cpp").read_text()
|
||||
if mutation:
|
||||
statement = (" pinMode(PIN_ETHERNET_SS, OUTPUT);" if mutation == "missing_cs_direction"
|
||||
else " digitalWrite(PIN_ETHERNET_SS, HIGH);")
|
||||
startup = extract_braced(cpp, "bool RAK13800EthernetInterface::beginHardware()")
|
||||
self.assertEqual(startup.count(statement), 1)
|
||||
cpp = cpp.replace(startup, startup.replace(statement, ""))
|
||||
signatures = ("bool RAK13800EthernetInterface::begin()", "bool RAK13800EthernetInterface::beginHardware()",
|
||||
"bool RAK13800EthernetInterface::tryEnable()", "bool RAK13800EthernetInterface::tryDisable()",
|
||||
"bool RAK13800EthernetInterface::terminalShutdown(", "bool RAK13800EthernetInterface::shutdownForPowerOff(",
|
||||
@@ -418,6 +432,13 @@ int main(){
|
||||
source = source.replace("struct SPIClass {void begin(){assert(!spi);spi=true;++begins;} void end(){assert(spi);spi=false;++ends;}} ETHERNET_SPI_PORT;",
|
||||
"struct EthSpi{void begin(){assert(!spi);spi=true;++begins;}void end(){assert(spi);spi=false;++ends;}} ETHERNET_SPI_PORT;")
|
||||
source = source.replace("void init(SPIClass&,int)", "void init(EthSpi&,int)")
|
||||
# The pinned W5100 init returns early after its first success, so
|
||||
# only that first call configures CS. GPIO writes do not restore an
|
||||
# input's output direction on nRF52; each acquisition must do so.
|
||||
source = source.replace("int begin(uint8_t*){return result;}",
|
||||
"int begin(uint8_t*){static bool initialized=false;"
|
||||
"if(!initialized){pinMode(26,OUTPUT);digitalWrite(26,HIGH);initialized=true;}"
|
||||
"assert(mock_pin_modes[26]==OUTPUT && mock_pin_values[26]==HIGH);return result;}")
|
||||
source = source.replace("void disable(){disconnectClient();++cancels;}", "virtual void enable(){}\n virtual void disable(){disconnectClient();++cancels;}")
|
||||
source = source.replace("@CLASS@", cls).replace("@METHODS@", methods)
|
||||
source = source.replace("assert(spi);++closes;", "assert(spi&&!inserted);++closes;")
|
||||
@@ -431,27 +452,42 @@ bool release(void*){assert(!spi&&!rak4631_ethernet_owns_spi());++released;return
|
||||
int main(){
|
||||
RAK13800EthernetInterface owner;assert(owner.begin());owner.enable();
|
||||
assert(!owner.hardwareActive()&&!spi&&!begins&&!owner.tryEnable());
|
||||
assert(mock_cs_driven==0);
|
||||
owner.setSpiOwnershipHooks(prepare,canRelease,release,nullptr);
|
||||
inserted=true;assert(!owner.tryEnable()&&!prepared&&!begins);
|
||||
inserted=false;busy=true;assert(!owner.tryEnable()&&prepared==1&&!begins);
|
||||
busy=false;assert(rak4631_try_acquire_spi(RakSharedSpiOwner::Sd));
|
||||
assert(!owner.tryEnable()&&!begins&&rak4631_spi_owner()==RakSharedSpiOwner::Sd);
|
||||
assert(mock_cs_driven==0); // Rejected admission must never drive shared CS.
|
||||
rak4631_release_spi(RakSharedSpiOwner::Sd);
|
||||
assert(owner.tryEnable()&&owner.hardwareActive()&&rak4631_ethernet_owns_spi());
|
||||
release_busy=true;assert(!owner.tryDisable()&&owner.hardwareActive()&&ends==0);
|
||||
release_busy=false;assert(owner.tryDisable()&&!owner.hardwareActive()&&ends==1&&closes==4);
|
||||
assert(mock_pin_modes[26]==INPUT);
|
||||
assert(!rak4631_ethernet_owns_spi()&&released==2);
|
||||
Ethernet.result=0;assert(!owner.tryEnable()&&!owner.hardwareActive()&&ends==2&&!rak4631_ethernet_owns_spi());
|
||||
Ethernet.result=1;assert(owner.tryEnable());inserted=true;const auto calls=reads;
|
||||
assert(owner.available()==0&&owner.read()==-1&&owner.write(nullptr,0)==0&&reads==calls);
|
||||
owner.loop();assert(!owner.hardwareActive()&&rak4631_ethernet_owns_spi()&&reads==calls);
|
||||
assert(!owner.tryEnable());assert(owner.tryDisable()&&!rak4631_ethernet_owns_spi());
|
||||
assert(mock_pin_modes[26]==INPUT);
|
||||
inserted=false;assert(owner.tryEnable()&&owner.hardwareActive());
|
||||
assert(mock_pin_modes[26]==OUTPUT); // Also recover after SD insertion and removal.
|
||||
assert(owner.tryDisable()&&mock_pin_modes[26]==INPUT);
|
||||
}
|
||||
'''
|
||||
# The existing fixture's pad counter is irrelevant to the new mapped
|
||||
# GPIO mock; ownership/SPI/socket traffic remains production code.
|
||||
source = source.replace("ends=0,pads=0,cancels", "ends=0,cancels")
|
||||
run_native(self, source)
|
||||
spi = SPI.replace("inline void pinMode(int pin,int){touched.push_back(pin);}",
|
||||
"inline int mock_pin_modes[64]={},mock_pin_values[64]={};\n"
|
||||
"inline unsigned mock_cs_driven=0;\n"
|
||||
"inline void pinMode(int pin,int mode){"
|
||||
"if(pin==26&&mode==OUTPUT){assert(mock_pin_values[pin]==HIGH);++mock_cs_driven;}"
|
||||
"mock_pin_modes[pin]=mode;touched.push_back(pin);}")
|
||||
spi = spi.replace("inline void digitalWrite(int pin,int){touched.push_back(pin);}",
|
||||
"inline void digitalWrite(int pin,int value){mock_pin_values[pin]=value;touched.push_back(pin);}")
|
||||
run_native(self, source, {"SPI.h": spi}, negative=mutation is not None)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user