Skip to content

Commit 6b36be6

Browse files
committed
optimized
1 parent 88e8514 commit 6b36be6

File tree

5 files changed

+90
-2
lines changed

5 files changed

+90
-2
lines changed

src/EventDispatcher/Event.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#define CONFIG_TOPIC_SWITCHES 115 // "s"
4949
#define CONFIG_TOPIC_TRIGGER 116 // "t"
5050
#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x"
51+
#define CONFIG_TOPIC_SWITCH_CHAIN 121 // "y"
5152

5253
#define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A"
5354
#define CONFIG_TOPIC_DURATION 65 // "A"
@@ -76,6 +77,7 @@
7677
#define CONFIG_TOPIC_LIGHT_UP 85 // "U"
7778
#define CONFIG_TOPIC_ACTIVE_LOW 86 // "V"
7879
#define CONFIG_TOPIC_POWER 87 // "W"
80+
#define CONFIG_TOPIC_NEXT_BOARD 88 // "X"
7981
#define CONFIG_TOPIC_TYPE 89 // "Y"
8082
#define CONFIG_TOPIC_EFFECT 89 // "Y"
8183
#define CONFIG_TOPIC_MODE 90 // "Z"

src/EventDispatcher/EventDispatcher.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) {
4141

4242
void EventDispatcher::setDebug(bool enabled) { debugEnabled = enabled; }
4343

44+
void EventDispatcher::setNextSwitchBoard(byte boardId) {
45+
nextSwitchBoard = boardId;
46+
}
47+
4448
void EventDispatcher::addListener(EventListener *eventListener) {
4549
addListener(eventListener, EVENT_SOURCE_ANY);
4650
}
@@ -153,6 +157,10 @@ size_t EventDispatcher::getV2PayloadBytes(ppuc::v2::FrameType frameType) {
153157
case ppuc::v2::kFrameOutputState:
154158
return ppuc::v2::BitsToBytes(runtimeConfig.coilBits) +
155159
ppuc::v2::BitsToBytes(runtimeConfig.lampBits);
160+
case ppuc::v2::kFrameSwitchState:
161+
return ppuc::v2::BitsToBytes(runtimeConfig.switchBits);
162+
case ppuc::v2::kFrameSwitchNoChange:
163+
return 0;
156164
case ppuc::v2::kFrameHeartbeat:
157165
case ppuc::v2::kFrameError:
158166
case ppuc::v2::kFrameReset:
@@ -226,11 +234,26 @@ bool EventDispatcher::processV2Frame(const byte* frame, size_t payloadBytes) {
226234
const size_t lampBytes = ppuc::v2::BitsToBytes(runtimeConfig.lampBits);
227235
applyOutputStates(&frame[4], coilBytes, &frame[4 + coilBytes], lampBytes);
228236
if (frame[2] == board) {
229-
sendSwitchStateFrame((byte)((board + 1) % ppuc::v2::kMaxBoards));
237+
if (switchDirty) {
238+
sendSwitchStateFrame(nextSwitchBoard);
239+
switchDirty = false;
240+
} else {
241+
sendSwitchNoChangeFrame(nextSwitchBoard);
242+
}
230243
}
231244
return true;
232245
}
233246

247+
if (frameType == ppuc::v2::kFrameSwitchState) {
248+
const size_t switchBytes = ppuc::v2::BitsToBytes(runtimeConfig.switchBits);
249+
applySwitchStates(&frame[4], switchBytes);
250+
return true;
251+
}
252+
253+
if (frameType == ppuc::v2::kFrameSwitchNoChange) {
254+
return true;
255+
}
256+
234257
if (frameType == ppuc::v2::kFrameReset) {
235258
dispatch(new Event(EVENT_RESET));
236259
return true;
@@ -405,6 +428,9 @@ void EventDispatcher::updateSwitchBitmap(Event *event) {
405428

406429
ppuc::v2::SetBitmapBit(switchStates, (uint16_t)mappedIndex,
407430
event->value != 0);
431+
if (!applyingRemoteSwitchState) {
432+
switchDirty = true;
433+
}
408434
}
409435

410436
void EventDispatcher::applyOutputStates(const byte *coils, size_t coilBytes,
@@ -437,6 +463,24 @@ void EventDispatcher::applyOutputStates(const byte *coils, size_t coilBytes,
437463
memcpy(outputLamps, lamps, lampBytes);
438464
}
439465

466+
void EventDispatcher::applySwitchStates(const byte* switches,
467+
size_t switchBytes) {
468+
// Global switch state is board-to-board on the RS485 bus. CPU/libppuc never
469+
// broadcasts switch states. Every board consumes incoming switch frames and
470+
// emits local switch events for fast-flip/effect listeners.
471+
applyingRemoteSwitchState = true;
472+
for (uint16_t n = 0; n < runtimeConfig.switchBits; ++n) {
473+
bool oldState = ppuc::v2::GetBitmapBit(switchStates, n);
474+
bool newState = ppuc::v2::GetBitmapBit(switches, n);
475+
if (oldState != newState) {
476+
dispatch(new Event(EVENT_SOURCE_SWITCH, switchIndexToNumber[n],
477+
newState ? 1 : 0, true));
478+
}
479+
}
480+
applyingRemoteSwitchState = false;
481+
memcpy(switchStates, switches, switchBytes);
482+
}
483+
440484
void EventDispatcher::sendSwitchStateFrame(byte nextBoard) {
441485
// Switch updates are transmitted as a compact V2 frame containing the full
442486
// dense switch bitmap. The CPU selects the responding board via token
@@ -472,6 +516,31 @@ void EventDispatcher::sendSwitchStateFrame(byte nextBoard) {
472516
lastPoll = millis();
473517
}
474518

519+
void EventDispatcher::sendSwitchNoChangeFrame(byte nextBoard) {
520+
byte* frame = v2DmaTxBuffer;
521+
frame[0] = ppuc::v2::kSyncByte;
522+
frame[1] = ppuc::v2::ComposeTypeAndFlags(ppuc::v2::kFrameSwitchNoChange,
523+
ppuc::v2::kFlagNone);
524+
frame[2] = nextBoard;
525+
frame[3] = txSequence++;
526+
uint16_t crc = ppuc::v2::Crc16Ccitt(frame, ppuc::v2::kHeaderBytes);
527+
frame[4] = highByte(crc);
528+
frame[5] = lowByte(crc);
529+
530+
if (!v2UartDmaActive || !sendV2FrameUartDma(frame, ppuc::v2::kResetFrameBytes)) {
531+
v2TxFallback++;
532+
digitalWrite(rs485Pin, HIGH); // Write.
533+
delayMicroseconds(RS485_MODE_SWITCH_DELAY);
534+
hwSerial->write(frame, ppuc::v2::kResetFrameBytes);
535+
hwSerial->flush();
536+
digitalWrite(rs485Pin, LOW); // Read.
537+
delayMicroseconds(RS485_MODE_SWITCH_DELAY);
538+
}
539+
540+
v2SwitchNoChangeTx++;
541+
lastPoll = millis();
542+
}
543+
475544
bool EventDispatcher::handleV2Frame() {
476545
if (hwSerial->available() < (int)ppuc::v2::kHeaderBytes) {
477546
return false;
@@ -490,7 +559,8 @@ bool EventDispatcher::handleV2Frame() {
490559
if (frameType != ppuc::v2::kFrameHeartbeat &&
491560
frameType != ppuc::v2::kFrameError &&
492561
frameType != ppuc::v2::kFrameReset && payloadBytes == 0 &&
493-
frameType != ppuc::v2::kFrameOutputState) {
562+
frameType != ppuc::v2::kFrameOutputState &&
563+
frameType != ppuc::v2::kFrameSwitchNoChange) {
494564
return false;
495565
}
496566

@@ -572,6 +642,8 @@ void EventDispatcher::update() {
572642
Serial.print(v2RxDmaTimeouts);
573643
Serial.print(" tx=");
574644
Serial.print(v2TxFrames);
645+
Serial.print(" tx_nochange=");
646+
Serial.print(v2SwitchNoChangeTx);
575647
Serial.print(" tx_fallback=");
576648
Serial.println(v2TxFallback);
577649
rp2040.resumeOtherCore();

src/EventDispatcher/EventDispatcher.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class EventDispatcher {
4040

4141
void setCrossLinkSerial(HardwareSerial& reference);
4242
void setDebug(bool enabled);
43+
void setNextSwitchBoard(byte boardId);
4344

4445
void addListener(EventListener* eventListener, char sourceId);
4546

@@ -61,8 +62,10 @@ class EventDispatcher {
6162
size_t getV2PayloadBytes(ppuc::v2::FrameType frameType);
6263
bool processV2Frame(const byte* frame, size_t payloadBytes);
6364
void sendSwitchStateFrame(byte nextBoard);
65+
void sendSwitchNoChangeFrame(byte nextBoard);
6466
void applyOutputStates(const byte* coils, size_t coilBytes, const byte* lamps,
6567
size_t lampBytes);
68+
void applySwitchStates(const byte* switches, size_t switchBytes);
6669
void updateSwitchBitmap(Event* event);
6770
int16_t findMappedIndex(const uint16_t* table, uint16_t count,
6871
uint16_t number);
@@ -109,11 +112,15 @@ class EventDispatcher {
109112
uint32_t v2RxDmaRestarts = 0;
110113
uint32_t v2RxDmaTimeouts = 0;
111114
uint32_t v2TxFrames = 0;
115+
uint32_t v2SwitchNoChangeTx = 0;
112116
uint32_t v2TxFallback = 0;
117+
bool switchDirty = false;
118+
bool applyingRemoteSwitchState = false;
113119

114120
bool rs485 = false;
115121
uint8_t rs485Pin = 0;
116122
byte board = 255;
123+
byte nextSwitchBoard = ppuc::v2::kNoBoard;
117124
uint32_t lastPoll;
118125
bool running = false;
119126

src/IOBoardController.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ void IOBoardController::handleEvent(ConfigEvent *event) {
117117
}
118118
break;
119119

120+
case CONFIG_TOPIC_SWITCH_CHAIN:
121+
if (event->key == CONFIG_TOPIC_NEXT_BOARD) {
122+
_eventDispatcher->setNextSwitchBoard((byte)event->value);
123+
}
124+
break;
125+
120126
case CONFIG_TOPIC_SWITCHES:
121127
switch (event->key) {
122128
case CONFIG_TOPIC_PORT:

src/PPUCProtocolV2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ enum FrameType : uint8_t {
4242
kFrameMapping = 0x06,
4343
kFrameReset = 0x07,
4444
kFrameConfig = 0x08,
45+
kFrameSwitchNoChange = 0x09,
4546
};
4647

4748
enum MappingDomain : uint8_t {

0 commit comments

Comments
 (0)