diff --git a/RF-Clown-M5Shark-Fix/RfClown.ino b/RF-Clown-M5Shark-Fix/RfClown.ino new file mode 100644 index 0000000..a1e2e6c --- /dev/null +++ b/RF-Clown-M5Shark-Fix/RfClown.ino @@ -0,0 +1,552 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#include "setting.h" +#include "config.h" + +void IRAM_ATTR handleButton() { + unsigned long currentTime = millis(); + if (currentTime - lastPressTime > debounceDelay) { + ChangeRequested = true; + lastPressTime = currentTime; + } +} + +void IRAM_ATTR handleButton1() { + unsigned long currentTime = millis(); + if (currentTime - lastPressTime > debounceDelay) { + ChangeRequested1 = true; + lastPressTime = currentTime; + } +} + +void IRAM_ATTR handleButton2() { + unsigned long currentTime = millis(); + if (currentTime - lastPressTime > debounceDelay) { + if (current == DEACTIVE_MODE) current = ACTIVE_MODE; + else current = DEACTIVE_MODE; + lastPressTime = currentTime; + } +} + +void configure_Radio(RF24 &radio, const byte *channels, size_t size) { + configureNrf(radio); +// quiet-log: radio.printPrettyDetails(); + for (size_t i = 0; i < size; i++) { + radio.setChannel(channels[i]); + radio.startConstCarrier(RF24_PA_MAX, channels[i]); + } +} + +void initialize_MultiMode() { + if (RadioA.begin()) { + configure_Radio(RadioA, channelGroup_1, channelGroup_1_len); + } + if (RadioB.begin()) { + configure_Radio(RadioB, channelGroup_2, channelGroup_2_len); + } + if (RadioC.begin()) { + configure_Radio(RadioC, channelGroup_3, channelGroup_3_len); + } +} + +void initialize_Radios() { + if (current == ACTIVE_MODE) { + initialize_MultiMode(); + } else if (current == DEACTIVE_MODE) { + RadioA.powerDown(); + RadioB.powerDown(); + RadioC.powerDown(); + delay(100); + } +} + +static const uint8_t HEADER_H = 12; +static const uint8_t PAD = 6; +static const uint8_t CARD_H = 36; +static const uint8_t RADIUS = 3; +static const uint8_t DOT_Y = 64 - 6; + +static const char* kMenuLabels[] = { + "WiFi", "Video TX", "RC", "BLE", "Bluetooth", "USB Wireless", "Zigbee", "NRF24" +}; +static const int kMenuCount = sizeof(kMenuLabels)/sizeof(kMenuLabels[0]); + +static int menuIndexFromMode(OperationMode m) { + switch (m) { + case WiFi_MODULE: return 0; + case VIDEO_TX_MODULE: return 1; + case RC_MODULE: return 2; + case BLE_MODULE: return 3; + case Bluetooth_MODULE: return 4; + case USB_WIRELESS_MODULE: return 5; + case ZIGBEE_MODULE: return 6; + case NRF24_MODULE: return 7; + default: return 0; + } +} +static OperationMode modeFromMenuIndex(int idx) { + switch (idx) { + case 0: return WiFi_MODULE; + case 1: return VIDEO_TX_MODULE; + case 2: return RC_MODULE; + case 3: return BLE_MODULE; + case 4: return Bluetooth_MODULE; + case 5: return USB_WIRELESS_MODULE; + case 6: return ZIGBEE_MODULE; + case 7: return NRF24_MODULE; + default: return WiFi_MODULE; + } +} + +void spectrum() { + const uint8_t HDR_H = 10; + const int TOP = HDR_H + 12; + const int BOT = SCREEN_H - 2; + const int H = BOT - TOP; + const int STRIDE = 3; + const int BINS = SCREEN_W / STRIDE; + const int BAR_W = 1; + static uint8_t h[BINS]; + static int8_t v[BINS]; + static bool init = false; + if (!init) { + for (int i = 0; i < BINS; ++i) { + h[i] = random(0, H + 1); + v[i] = random(-2, 3); + } + init = true; + } + for (int i = 0; i < BINS; ++i) { + int8_t a = (int8_t)random(-1, 2); + v[i] += a; + if (v[i] > 3) v[i] = 3; + if (v[i] < -3) v[i] = -3; + int16_t nh = (int16_t)h[i] + v[i]; + if (nh < 0) { + nh = 0; + v[i] = -(v[i] * 3) / 4; + if (v[i] == 0) v[i] = 1; + } else if (nh > H) { + nh = H; + v[i] = -(v[i] * 3) / 4; + if (v[i] == 0) v[i] = -1; + } + h[i] = (uint8_t)nh; + } + for (int i = 0; i < BINS; ++i) { + int x = i * STRIDE; + int bh = h[i]; + if (bh <= 0) continue; + int y = BOT - bh; + u8g2.drawVLine(x, y, bh); + } + u8g2.sendBuffer(); +} + +static void drawHeaderBar() { + const uint8_t W = 128; + const uint8_t H = HEADER_H; + const uint8_t TXT_Y = 2; + u8g2.setDrawColor(1); + u8g2.drawBox(0, 0, W, H); + u8g2.setFont(FONT_SMALL); + u8g2.setDrawColor(0); + u8g2.drawStr(PAD, TXT_Y, "RF-Clown"); + const char* ver = "v2.0.0"; + int vw = u8g2.getStrWidth(ver); + u8g2.drawStr(W - vw - 4, TXT_Y, ver); + u8g2.setDrawColor(1); + u8g2.drawHLine(0, H - 1, W); +} + +static void drawPillOutline(int x,int y,int w,int h){ + if (h & 1) h--; if (y & 1) y--; + u8g2.drawRFrame(x, y, w, h, h/2); +} +static void drawPillKnob(int x,int y,int w,int h,float pos){ + if (h & 1) h--; if (y & 1) y--; + int r=h/2, cxL=x+r, cxR=x+w-r-1, cy=y+r; + int cx=(int)lroundf(cxL + (cxR - cxL)*pos); + int knob = max(2, r-3); + u8g2.drawDisc(cx, cy, knob); +} +static void drawPillToggle(int x,int y,int w,int h,bool on){ + drawPillOutline(x,y,w,h); + drawPillKnob(x,y,w,h, on?0.0f:1.0f); +} + +static void drawPaginationDots(int active){ + int totalW = (kMenuCount * 6) - 2; + int startX = (128 - totalW) / 2; + for (int i=0;i fromIdx) ? -1 : 1; + for (int s = 0; s <= STEPS; s++) { + float t = (float)s / (float)STEPS; + float e = (t < 0.5f) ? 4.0f*t*t*t : 1.0f - powf(-2.0f*t + 2.0f, 3)/2.0f; + int shift = (int)(e * W + 0.5f); + int centerFrom = (W/2) + (-dir * shift); + int centerTo = (W/2) + ( dir * (W - shift)); + u8g2.clearBuffer(); + drawHeaderBar(); + drawCardAtCenter(centerFrom, fromIdx); + drawCardAtCenter(centerTo, toIdx); + drawPaginationDots(toIdx); + u8g2.sendBuffer(); + delay(DT); + } + renderStaticMenu(toIdx); +} + +static void animateToggleKnobForFocus(int focusIdx, bool fromActive, bool toActive){ + float start = (fromActive ? 0.0f : 1.0f); + float end = (toActive ? 0.0f : 1.0f); + const int STEPS = 10; + const uint8_t FRAME_MS = 12; + for (int s=0; s<=STEPS; s++){ + float t = (float)s / (float)STEPS; + float e = (t < 0.5f) ? 2.0f*t*t : 1.0f - powf(-2.0f*t + 2.0f, 2)/2.0f; + float p = start + (end - start) * e; + u8g2.clearBuffer(); + drawHeaderBar(); + const int W = 128; + const int w = W - PAD*2; + const int x = W/2 - w/2; + const int y = HEADER_H + 4; + u8g2.setDrawColor(0); + u8g2.drawBox(x+1, y+1, w-2, CARD_H-2); + u8g2.setDrawColor(1); + u8g2.drawRFrame(x, y, w, CARD_H, RADIUS); + u8g2.setFont(FONT_MEDIUM); u8g2.setCursor(x+12, y+4); u8g2.print(kMenuLabels[focusIdx]); + u8g2.setFont(FONT_SMALL); u8g2.setCursor(x+12, y+16); u8g2.print("----"); + const int pillW=24, pillH=14; + const int pillY=(y + ((CARD_H-pillH)/2)) & ~1; + const int pillX=x + w - pillW - 10; + drawPillOutline(pillX, pillY, pillW, pillH); + drawPillKnob(pillX, pillY, pillW, pillH, p); + drawPaginationDots(focusIdx); + u8g2.sendBuffer(); + delay(FRAME_MS); + } + renderStaticMenu(focusIdx); +} + +void update_OLED() { + int focus = menuIndexFromMode(current_Mode); + renderStaticMenu(focus); +} + +void menuPrev() { + int fromIdx = menuIndexFromMode(current_Mode); + int toIdx = (fromIdx == 0) ? (kMenuCount - 1) : (fromIdx - 1); + current_Mode = modeFromMenuIndex(toIdx); + animateToMenu(fromIdx, toIdx); +} +void menuNext() { + int fromIdx = menuIndexFromMode(current_Mode); + int toIdx = (fromIdx == (kMenuCount - 1)) ? 0 : (fromIdx + 1); + current_Mode = modeFromMenuIndex(toIdx); + animateToMenu(fromIdx, toIdx); +} +void menuToggleActive() { + int focus = menuIndexFromMode(current_Mode); + bool wasActive = (current == ACTIVE_MODE); + current = wasActive ? DEACTIVE_MODE : ACTIVE_MODE; + animateToggleKnobForFocus(focus, wasActive, !wasActive); +} + +void checkMode() { + if (ChangeRequested) { + ChangeRequested = false; + current_Mode = static_cast((current_Mode == 0) ? 7 : (current_Mode - 1)); + } else if (ChangeRequested1) { + ChangeRequested1 = false; + current_Mode = static_cast((current_Mode + 1) % 8); + } +} + + +// ===== M5-Shark RF-Clown diagnostic patch ===== +// Purpose: stable button polling, mode/state serial logs, and NeoPixel/status LED feedback. +// This does not change RF power or add RF attack capability. + +static const char* modeNameSafe() { + return kMenuLabels[menuIndexFromMode(current_Mode)]; +} + +static void statusLed(uint8_t r, uint8_t g, uint8_t b) { + // If NeoPixel pin is correct, this LED should show status. + // If it does not light, the M5-Shark board likely uses a different NeoPixel GPIO. + pixels.setPixelColor(0, pixels.Color(r, g, b)); + pixels.show(); +} + +static void printModeState(const char* reason) { + Serial.print("[RF-Clown] "); + Serial.print(reason); + Serial.print(" | Mode: "); + Serial.print(modeNameSafe()); + Serial.print(" | State: "); + Serial.println(current == ACTIVE_MODE ? "ACTIVE" : "DEACTIVE"); +} + +static void pollButtonsM5Shark() { + static uint32_t lastEventMs = 0; + static int lastL = HIGH; + static int lastR = HIGH; + static int lastS = HIGH; + + int nowL = digitalRead(PIN_BTN_L); + int nowR = digitalRead(PIN_BTN_R); + int nowS = digitalRead(PIN_BTN_S); + + uint32_t now = millis(); + if (now - lastEventMs < 160) { + lastL = nowL; + lastR = nowR; + lastS = nowS; + return; + } + + // Active-low buttons with INPUT_PULLUP + if (lastL == HIGH && nowL == LOW) { + ChangeRequested = true; + lastEventMs = now; + Serial.println("[BTN] LEFT / previous mode"); + } + + if (lastR == HIGH && nowR == LOW) { + ChangeRequested1 = true; + lastEventMs = now; + Serial.println("[BTN] RIGHT / next mode"); + } + + if (lastS == HIGH && nowS == LOW) { + // SELECT should directly toggle ACTIVE/DEACTIVE in polling mode. + current = (current == ACTIVE_MODE) ? DEACTIVE_MODE : ACTIVE_MODE; + ChangeRequested2 = false; + lastEventMs = now; + Serial.println("[BTN] SELECT / active-deactive"); + } + + lastL = nowL; + lastR = nowR; + lastS = nowS; +} + +static void diagTickM5Shark() { + static OperationMode lastMode = current_Mode; + static Operation lastState = current; + + if (lastMode != current_Mode || lastState != current) { + printModeState("changed"); + + if (current == ACTIVE_MODE) { + // Green = selected mode active + statusLed(0, 80, 0); + } else { + // Blue = standby/deactive + statusLed(0, 0, 80); + } + + lastMode = current_Mode; + lastState = current; + } +} +// ===== End diagnostic patch ===== + + + +static void printChannelVerify(const char* mode, byte requested) { + static uint32_t lastPrintMs = 0; + static OperationMode lastMode = current_Mode; + static Operation lastState = current; + + uint32_t now = millis(); + bool modeStateChanged = (lastMode != current_Mode || lastState != current); + + // Print immediately on mode/state change, otherwise max once every 2000 ms. + if (!modeStateChanged && (now - lastPrintMs < 2000)) { + return; + } + + lastPrintMs = now; + lastMode = current_Mode; + lastState = current; + + Serial.print("[CHANNEL] Mode: "); + Serial.print(mode); + Serial.print(" | requested="); + Serial.print(requested); + Serial.print(" (~"); + Serial.print(2400 + requested); + Serial.print(" MHz)"); + + Serial.print(" | A="); + Serial.print(RadioA.getChannel()); + Serial.print(" B="); + Serial.print(RadioB.getChannel()); + Serial.print(" C="); + Serial.println(RadioC.getChannel()); +} + + +void setup() { + Serial.begin(115200); + delay(500); + pixels.begin(); + pixels.setBrightness(40); + statusLed(0, 0, 80); + Serial.println("[RF-Clown] Boot diagnostic patch active"); + printModeState("boot"); + + Serial.begin(115200); + initialize_MultiMode(); + Wire.begin(); + Wire.setClock(400000); + u8g2.begin(); + u8g2.setBusClock(400000); + u8g2.setFont(FONT_SMALL); + u8g2.setDrawColor(1); + u8g2.setFontPosTop(); + esp_bt_controller_deinit(); + esp_wifi_stop(); + esp_wifi_deinit(); + esp_wifi_disconnect(); + pinMode(PIN_BTN_L, INPUT_PULLUP); + pinMode(PIN_BTN_R, INPUT_PULLUP); + pinMode(PIN_BTN_S, INPUT_PULLUP); + // M5-Shark diagnostic patch: using polling instead of interrupt for LEFT button + // M5-Shark diagnostic patch: using polling instead of interrupt for RIGHT button + // M5-Shark diagnostic patch: using polling instead of interrupt for SELECT button + + initialize_Radios(); + conf(); + update_OLED(); +} + +void loop() { + pollButtonsM5Shark(); + checkMode(); + diagTickM5Shark(); + static Operation lastActivity = current; + static OperationMode lastFocus = current_Mode; + if (current_Mode != lastFocus) { + int fromIdx = menuIndexFromMode(lastFocus); + int toIdx = menuIndexFromMode(current_Mode); + animateToMenu(fromIdx, toIdx); + lastFocus = current_Mode; + return; + } + if (current != lastActivity) { + initialize_Radios(); + int focus = menuIndexFromMode(current_Mode); + bool wasActive = (lastActivity == ACTIVE_MODE); + bool nowActive = (current == ACTIVE_MODE); + animateToggleKnobForFocus(focus, wasActive, nowActive); + lastActivity = current; + return; + } + if (current_Mode == BLE_MODULE) { + int randomIndex = random(0, sizeof(ble_channels) / sizeof(ble_channels[0])); + byte channel = ble_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("BLE", channel); + } else if (current_Mode == Bluetooth_MODULE) { + int randomIndex = random(0, sizeof(bluetooth_channels) / sizeof(bluetooth_channels[0])); + byte channel = bluetooth_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("Bluetooth", channel); + } else if (current_Mode == WiFi_MODULE) { + int randomIndex = random(0, sizeof(WiFi_channels) / sizeof(WiFi_channels[0])); + byte channel = WiFi_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("WiFi", channel); + } else if (current_Mode == USB_WIRELESS_MODULE) { + int randomIndex = random(0, sizeof(usbWireless_channels) / sizeof(usbWireless_channels[0])); + byte channel = usbWireless_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("USB Wireless", channel); + } else if (current_Mode == VIDEO_TX_MODULE) { + int randomIndex = random(0, sizeof(videoTransmitter_channels) / sizeof(videoTransmitter_channels[0])); + byte channel = videoTransmitter_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("Video TX", channel); + } else if (current_Mode == RC_MODULE) { + int randomIndex = random(0, sizeof(rc_channels) / sizeof(rc_channels[0])); + byte channel = rc_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("RC", channel); + } else if (current_Mode == ZIGBEE_MODULE) { + int randomIndex = random(0, sizeof(zigbee_channels) / sizeof(zigbee_channels[0])); + byte channel = zigbee_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("Zigbee", channel); + } else if (current_Mode == NRF24_MODULE) { + int randomIndex = random(0, sizeof(nrf24_channels) / sizeof(nrf24_channels[0])); + byte channel = nrf24_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + printChannelVerify("NRF24", channel); + } +} diff --git a/RF-Clown-M5Shark-Fix/RfClown.ino.channelverify.2569-05-25-1428 b/RF-Clown-M5Shark-Fix/RfClown.ino.channelverify.2569-05-25-1428 new file mode 100644 index 0000000..891345a --- /dev/null +++ b/RF-Clown-M5Shark-Fix/RfClown.ino.channelverify.2569-05-25-1428 @@ -0,0 +1,509 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#include "setting.h" +#include "config.h" + +void IRAM_ATTR handleButton() { + unsigned long currentTime = millis(); + if (currentTime - lastPressTime > debounceDelay) { + ChangeRequested = true; + lastPressTime = currentTime; + } +} + +void IRAM_ATTR handleButton1() { + unsigned long currentTime = millis(); + if (currentTime - lastPressTime > debounceDelay) { + ChangeRequested1 = true; + lastPressTime = currentTime; + } +} + +void IRAM_ATTR handleButton2() { + unsigned long currentTime = millis(); + if (currentTime - lastPressTime > debounceDelay) { + if (current == DEACTIVE_MODE) current = ACTIVE_MODE; + else current = DEACTIVE_MODE; + lastPressTime = currentTime; + } +} + +void configure_Radio(RF24 &radio, const byte *channels, size_t size) { + configureNrf(radio); + radio.printPrettyDetails(); + for (size_t i = 0; i < size; i++) { + radio.setChannel(channels[i]); + radio.startConstCarrier(RF24_PA_MAX, channels[i]); + } +} + +void initialize_MultiMode() { + if (RadioA.begin()) { + configure_Radio(RadioA, channelGroup_1, channelGroup_1_len); + } + if (RadioB.begin()) { + configure_Radio(RadioB, channelGroup_2, channelGroup_2_len); + } + if (RadioC.begin()) { + configure_Radio(RadioC, channelGroup_3, channelGroup_3_len); + } +} + +void initialize_Radios() { + if (current == ACTIVE_MODE) { + initialize_MultiMode(); + } else if (current == DEACTIVE_MODE) { + RadioA.powerDown(); + RadioB.powerDown(); + RadioC.powerDown(); + delay(100); + } +} + +static const uint8_t HEADER_H = 12; +static const uint8_t PAD = 6; +static const uint8_t CARD_H = 36; +static const uint8_t RADIUS = 3; +static const uint8_t DOT_Y = 64 - 6; + +static const char* kMenuLabels[] = { + "WiFi", "Video TX", "RC", "BLE", "Bluetooth", "USB Wireless", "Zigbee", "NRF24" +}; +static const int kMenuCount = sizeof(kMenuLabels)/sizeof(kMenuLabels[0]); + +static int menuIndexFromMode(OperationMode m) { + switch (m) { + case WiFi_MODULE: return 0; + case VIDEO_TX_MODULE: return 1; + case RC_MODULE: return 2; + case BLE_MODULE: return 3; + case Bluetooth_MODULE: return 4; + case USB_WIRELESS_MODULE: return 5; + case ZIGBEE_MODULE: return 6; + case NRF24_MODULE: return 7; + default: return 0; + } +} +static OperationMode modeFromMenuIndex(int idx) { + switch (idx) { + case 0: return WiFi_MODULE; + case 1: return VIDEO_TX_MODULE; + case 2: return RC_MODULE; + case 3: return BLE_MODULE; + case 4: return Bluetooth_MODULE; + case 5: return USB_WIRELESS_MODULE; + case 6: return ZIGBEE_MODULE; + case 7: return NRF24_MODULE; + default: return WiFi_MODULE; + } +} + +void spectrum() { + const uint8_t HDR_H = 10; + const int TOP = HDR_H + 12; + const int BOT = SCREEN_H - 2; + const int H = BOT - TOP; + const int STRIDE = 3; + const int BINS = SCREEN_W / STRIDE; + const int BAR_W = 1; + static uint8_t h[BINS]; + static int8_t v[BINS]; + static bool init = false; + if (!init) { + for (int i = 0; i < BINS; ++i) { + h[i] = random(0, H + 1); + v[i] = random(-2, 3); + } + init = true; + } + for (int i = 0; i < BINS; ++i) { + int8_t a = (int8_t)random(-1, 2); + v[i] += a; + if (v[i] > 3) v[i] = 3; + if (v[i] < -3) v[i] = -3; + int16_t nh = (int16_t)h[i] + v[i]; + if (nh < 0) { + nh = 0; + v[i] = -(v[i] * 3) / 4; + if (v[i] == 0) v[i] = 1; + } else if (nh > H) { + nh = H; + v[i] = -(v[i] * 3) / 4; + if (v[i] == 0) v[i] = -1; + } + h[i] = (uint8_t)nh; + } + for (int i = 0; i < BINS; ++i) { + int x = i * STRIDE; + int bh = h[i]; + if (bh <= 0) continue; + int y = BOT - bh; + u8g2.drawVLine(x, y, bh); + } + u8g2.sendBuffer(); +} + +static void drawHeaderBar() { + const uint8_t W = 128; + const uint8_t H = HEADER_H; + const uint8_t TXT_Y = 2; + u8g2.setDrawColor(1); + u8g2.drawBox(0, 0, W, H); + u8g2.setFont(FONT_SMALL); + u8g2.setDrawColor(0); + u8g2.drawStr(PAD, TXT_Y, "RF-Clown"); + const char* ver = "v2.0.0"; + int vw = u8g2.getStrWidth(ver); + u8g2.drawStr(W - vw - 4, TXT_Y, ver); + u8g2.setDrawColor(1); + u8g2.drawHLine(0, H - 1, W); +} + +static void drawPillOutline(int x,int y,int w,int h){ + if (h & 1) h--; if (y & 1) y--; + u8g2.drawRFrame(x, y, w, h, h/2); +} +static void drawPillKnob(int x,int y,int w,int h,float pos){ + if (h & 1) h--; if (y & 1) y--; + int r=h/2, cxL=x+r, cxR=x+w-r-1, cy=y+r; + int cx=(int)lroundf(cxL + (cxR - cxL)*pos); + int knob = max(2, r-3); + u8g2.drawDisc(cx, cy, knob); +} +static void drawPillToggle(int x,int y,int w,int h,bool on){ + drawPillOutline(x,y,w,h); + drawPillKnob(x,y,w,h, on?0.0f:1.0f); +} + +static void drawPaginationDots(int active){ + int totalW = (kMenuCount * 6) - 2; + int startX = (128 - totalW) / 2; + for (int i=0;i fromIdx) ? -1 : 1; + for (int s = 0; s <= STEPS; s++) { + float t = (float)s / (float)STEPS; + float e = (t < 0.5f) ? 4.0f*t*t*t : 1.0f - powf(-2.0f*t + 2.0f, 3)/2.0f; + int shift = (int)(e * W + 0.5f); + int centerFrom = (W/2) + (-dir * shift); + int centerTo = (W/2) + ( dir * (W - shift)); + u8g2.clearBuffer(); + drawHeaderBar(); + drawCardAtCenter(centerFrom, fromIdx); + drawCardAtCenter(centerTo, toIdx); + drawPaginationDots(toIdx); + u8g2.sendBuffer(); + delay(DT); + } + renderStaticMenu(toIdx); +} + +static void animateToggleKnobForFocus(int focusIdx, bool fromActive, bool toActive){ + float start = (fromActive ? 0.0f : 1.0f); + float end = (toActive ? 0.0f : 1.0f); + const int STEPS = 10; + const uint8_t FRAME_MS = 12; + for (int s=0; s<=STEPS; s++){ + float t = (float)s / (float)STEPS; + float e = (t < 0.5f) ? 2.0f*t*t : 1.0f - powf(-2.0f*t + 2.0f, 2)/2.0f; + float p = start + (end - start) * e; + u8g2.clearBuffer(); + drawHeaderBar(); + const int W = 128; + const int w = W - PAD*2; + const int x = W/2 - w/2; + const int y = HEADER_H + 4; + u8g2.setDrawColor(0); + u8g2.drawBox(x+1, y+1, w-2, CARD_H-2); + u8g2.setDrawColor(1); + u8g2.drawRFrame(x, y, w, CARD_H, RADIUS); + u8g2.setFont(FONT_MEDIUM); u8g2.setCursor(x+12, y+4); u8g2.print(kMenuLabels[focusIdx]); + u8g2.setFont(FONT_SMALL); u8g2.setCursor(x+12, y+16); u8g2.print("----"); + const int pillW=24, pillH=14; + const int pillY=(y + ((CARD_H-pillH)/2)) & ~1; + const int pillX=x + w - pillW - 10; + drawPillOutline(pillX, pillY, pillW, pillH); + drawPillKnob(pillX, pillY, pillW, pillH, p); + drawPaginationDots(focusIdx); + u8g2.sendBuffer(); + delay(FRAME_MS); + } + renderStaticMenu(focusIdx); +} + +void update_OLED() { + int focus = menuIndexFromMode(current_Mode); + renderStaticMenu(focus); +} + +void menuPrev() { + int fromIdx = menuIndexFromMode(current_Mode); + int toIdx = (fromIdx == 0) ? (kMenuCount - 1) : (fromIdx - 1); + current_Mode = modeFromMenuIndex(toIdx); + animateToMenu(fromIdx, toIdx); +} +void menuNext() { + int fromIdx = menuIndexFromMode(current_Mode); + int toIdx = (fromIdx == (kMenuCount - 1)) ? 0 : (fromIdx + 1); + current_Mode = modeFromMenuIndex(toIdx); + animateToMenu(fromIdx, toIdx); +} +void menuToggleActive() { + int focus = menuIndexFromMode(current_Mode); + bool wasActive = (current == ACTIVE_MODE); + current = wasActive ? DEACTIVE_MODE : ACTIVE_MODE; + animateToggleKnobForFocus(focus, wasActive, !wasActive); +} + +void checkMode() { + if (ChangeRequested) { + ChangeRequested = false; + current_Mode = static_cast((current_Mode == 0) ? 7 : (current_Mode - 1)); + } else if (ChangeRequested1) { + ChangeRequested1 = false; + current_Mode = static_cast((current_Mode + 1) % 8); + } +} + + +// ===== M5-Shark RF-Clown diagnostic patch ===== +// Purpose: stable button polling, mode/state serial logs, and NeoPixel/status LED feedback. +// This does not change RF power or add RF attack capability. + +static const char* modeNameSafe() { + return kMenuLabels[menuIndexFromMode(current_Mode)]; +} + +static void statusLed(uint8_t r, uint8_t g, uint8_t b) { + // If NeoPixel pin is correct, this LED should show status. + // If it does not light, the M5-Shark board likely uses a different NeoPixel GPIO. + pixels.setPixelColor(0, pixels.Color(r, g, b)); + pixels.show(); +} + +static void printModeState(const char* reason) { + Serial.print("[RF-Clown] "); + Serial.print(reason); + Serial.print(" | Mode: "); + Serial.print(modeNameSafe()); + Serial.print(" | State: "); + Serial.println(current == ACTIVE_MODE ? "ACTIVE" : "DEACTIVE"); +} + +static void pollButtonsM5Shark() { + static uint32_t lastEventMs = 0; + static int lastL = HIGH; + static int lastR = HIGH; + static int lastS = HIGH; + + int nowL = digitalRead(PIN_BTN_L); + int nowR = digitalRead(PIN_BTN_R); + int nowS = digitalRead(PIN_BTN_S); + + uint32_t now = millis(); + if (now - lastEventMs < 160) { + lastL = nowL; + lastR = nowR; + lastS = nowS; + return; + } + + // Active-low buttons with INPUT_PULLUP + if (lastL == HIGH && nowL == LOW) { + ChangeRequested = true; + lastEventMs = now; + Serial.println("[BTN] LEFT / previous mode"); + } + + if (lastR == HIGH && nowR == LOW) { + ChangeRequested1 = true; + lastEventMs = now; + Serial.println("[BTN] RIGHT / next mode"); + } + + if (lastS == HIGH && nowS == LOW) { + // SELECT should directly toggle ACTIVE/DEACTIVE in polling mode. + current = (current == ACTIVE_MODE) ? DEACTIVE_MODE : ACTIVE_MODE; + ChangeRequested2 = false; + lastEventMs = now; + Serial.println("[BTN] SELECT / active-deactive"); + } + + lastL = nowL; + lastR = nowR; + lastS = nowS; +} + +static void diagTickM5Shark() { + static OperationMode lastMode = current_Mode; + static Operation lastState = current; + + if (lastMode != current_Mode || lastState != current) { + printModeState("changed"); + + if (current == ACTIVE_MODE) { + // Green = selected mode active + statusLed(0, 80, 0); + } else { + // Blue = standby/deactive + statusLed(0, 0, 80); + } + + lastMode = current_Mode; + lastState = current; + } +} +// ===== End diagnostic patch ===== + + +void setup() { + Serial.begin(115200); + delay(500); + pixels.begin(); + pixels.setBrightness(40); + statusLed(0, 0, 80); + Serial.println("[RF-Clown] Boot diagnostic patch active"); + printModeState("boot"); + + Serial.begin(115200); + initialize_MultiMode(); + Wire.begin(); + Wire.setClock(400000); + u8g2.begin(); + u8g2.setBusClock(400000); + u8g2.setFont(FONT_SMALL); + u8g2.setDrawColor(1); + u8g2.setFontPosTop(); + esp_bt_controller_deinit(); + esp_wifi_stop(); + esp_wifi_deinit(); + esp_wifi_disconnect(); + pinMode(PIN_BTN_L, INPUT_PULLUP); + pinMode(PIN_BTN_R, INPUT_PULLUP); + pinMode(PIN_BTN_S, INPUT_PULLUP); + // M5-Shark diagnostic patch: using polling instead of interrupt for LEFT button + // M5-Shark diagnostic patch: using polling instead of interrupt for RIGHT button + // M5-Shark diagnostic patch: using polling instead of interrupt for SELECT button + + initialize_Radios(); + conf(); + update_OLED(); +} + +void loop() { + pollButtonsM5Shark(); + checkMode(); + diagTickM5Shark(); + static Operation lastActivity = current; + static OperationMode lastFocus = current_Mode; + if (current_Mode != lastFocus) { + int fromIdx = menuIndexFromMode(lastFocus); + int toIdx = menuIndexFromMode(current_Mode); + animateToMenu(fromIdx, toIdx); + lastFocus = current_Mode; + return; + } + if (current != lastActivity) { + initialize_Radios(); + int focus = menuIndexFromMode(current_Mode); + bool wasActive = (lastActivity == ACTIVE_MODE); + bool nowActive = (current == ACTIVE_MODE); + animateToggleKnobForFocus(focus, wasActive, nowActive); + lastActivity = current; + return; + } + if (current_Mode == BLE_MODULE) { + int randomIndex = random(0, sizeof(ble_channels) / sizeof(ble_channels[0])); + byte channel = ble_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } else if (current_Mode == Bluetooth_MODULE) { + int randomIndex = random(0, sizeof(bluetooth_channels) / sizeof(bluetooth_channels[0])); + byte channel = bluetooth_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } else if (current_Mode == WiFi_MODULE) { + int randomIndex = random(0, sizeof(WiFi_channels) / sizeof(WiFi_channels[0])); + byte channel = WiFi_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } else if (current_Mode == USB_WIRELESS_MODULE) { + int randomIndex = random(0, sizeof(usbWireless_channels) / sizeof(usbWireless_channels[0])); + byte channel = usbWireless_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } else if (current_Mode == VIDEO_TX_MODULE) { + int randomIndex = random(0, sizeof(videoTransmitter_channels) / sizeof(videoTransmitter_channels[0])); + byte channel = videoTransmitter_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } else if (current_Mode == RC_MODULE) { + int randomIndex = random(0, sizeof(rc_channels) / sizeof(rc_channels[0])); + byte channel = rc_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } else if (current_Mode == ZIGBEE_MODULE) { + int randomIndex = random(0, sizeof(zigbee_channels) / sizeof(zigbee_channels[0])); + byte channel = zigbee_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } else if (current_Mode == NRF24_MODULE) { + int randomIndex = random(0, sizeof(nrf24_channels) / sizeof(nrf24_channels[0])); + byte channel = nrf24_channels[randomIndex]; + RadioA.setChannel(channel); + RadioB.setChannel(channel); + RadioC.setChannel(channel); + } +} diff --git a/RF-Clown-M5Shark-Fix/config.h b/RF-Clown-M5Shark-Fix/config.h new file mode 100644 index 0000000..7fa866f --- /dev/null +++ b/RF-Clown-M5Shark-Fix/config.h @@ -0,0 +1,104 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#ifndef CONFIG_H +#define CONFIG_H + +#define SCREEN_W 128 +#define SCREEN_H 64 + +// ---------------- Pins ---------------- +#define PIN_BTN_L 27 +#define PIN_BTN_R 25 +#define PIN_BTN_S 26 + +// nRF24-specific Pins +#define NRF_CE_PIN_A 5 +#define NRF_CSN_PIN_A 17 +#define NRF_CE_PIN_B 16 +#define NRF_CSN_PIN_B 4 +#define NRF_CE_PIN_C 15 +#define NRF_CSN_PIN_C 2 + +// Common dependencies +#include "setting.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; + +extern Adafruit_NeoPixel pixels; + +// BLE-specific dependencies +#include +#include +#include + +// nRF24-specific dependencies +#include +#include + +// WiFi-specific dependencies +#include +#include +#include +#include +#include +#include +#include + +// ESP-specific configurations +#include +#include + +// External declarations +extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; +extern Adafruit_NeoPixel pixels; + +static const uint8_t* FONT_SMALL = u8g2_font_5x8_tf; +static const uint8_t* FONT_MEDIUM = u8g2_font_6x12_tf; +static const uint8_t* FONT_ICON_FALLBACK = u8g2_font_open_iconic_thing_2x_t; + +enum OperationMode {WiFi_MODULE, VIDEO_TX_MODULE, RC_MODULE, BLE_MODULE, Bluetooth_MODULE, USB_WIRELESS_MODULE, ZIGBEE_MODULE, NRF24_MODULE}; +extern OperationMode current_Mode; + +enum Operation {DEACTIVE_MODE, ACTIVE_MODE}; +extern volatile Operation current; + +extern byte channelGroup_1[]; +extern byte channelGroup_2[]; +extern byte channelGroup_3[]; + + + +extern const size_t channelGroup_1_len; +extern const size_t channelGroup_2_len; +extern const size_t channelGroup_3_len; + +const byte bluetooth_channels[] = {32, 34, 46, 48, 50, 52, 0, 1, 2, 4, 6, 8, 22, 24, 26, 28, 30, 74, 76, 78, 80}; +const byte ble_channels[] = {2, 26, 80}; +const byte WiFi_channels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; +const byte usbWireless_channels[] = {40, 50, 60}; +const byte videoTransmitter_channels[] = {70, 75, 80}; +const byte rc_channels[] = {1, 3, 5, 7}; +const byte zigbee_channels[] = {11, 15, 20, 25}; +const byte nrf24_channels[] = {76, 78, 79}; + +extern volatile bool ChangeRequested; +extern volatile bool ChangeRequested1; +extern volatile bool ChangeRequested2; + +extern unsigned long lastPressTime; +const unsigned long debounceDelay = 200; + +#endif // CONFIG_H diff --git a/RF-Clown-M5Shark-Fix/config.h.bak.2569-05-25-1305 b/RF-Clown-M5Shark-Fix/config.h.bak.2569-05-25-1305 new file mode 100644 index 0000000..ec61a8f --- /dev/null +++ b/RF-Clown-M5Shark-Fix/config.h.bak.2569-05-25-1305 @@ -0,0 +1,98 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#ifndef CONFIG_H +#define CONFIG_H + +#define SCREEN_W 128 +#define SCREEN_H 64 + +// ---------------- Pins ---------------- +#define PIN_BTN_L 27 +#define PIN_BTN_R 25 +#define PIN_BTN_S 26 + +// nRF24-specific Pins +#define NRF_CE_PIN_A 5 +#define NRF_CSN_PIN_A 17 +#define NRF_CE_PIN_B 16 +#define NRF_CSN_PIN_B 4 +#define NRF_CE_PIN_C 15 +#define NRF_CSN_PIN_C 2 + +// Common dependencies +#include "setting.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); + +Adafruit_NeoPixel pixels(1, 14, NEO_GRB + NEO_KHZ800); + +// BLE-specific dependencies +#include +#include +#include + +// nRF24-specific dependencies +#include +#include + +// WiFi-specific dependencies +#include +#include +#include +#include +#include +#include +#include + +// ESP-specific configurations +#include +#include + +// External declarations +extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; +extern Adafruit_NeoPixel pixels; + +static const uint8_t* FONT_SMALL = u8g2_font_5x8_tf; +static const uint8_t* FONT_MEDIUM = u8g2_font_6x12_tf; +static const uint8_t* FONT_ICON_FALLBACK = u8g2_font_open_iconic_thing_2x_t; + +enum OperationMode {WiFi_MODULE, VIDEO_TX_MODULE, RC_MODULE, BLE_MODULE, Bluetooth_MODULE, USB_WIRELESS_MODULE, ZIGBEE_MODULE, NRF24_MODULE}; +OperationMode current_Mode = WiFi_MODULE; + +enum Operation {DEACTIVE_MODE, ACTIVE_MODE}; +volatile Operation current = DEACTIVE_MODE; + +byte channelGroup_1[] = {2, 5, 8, 11}; +byte channelGroup_2[] = {26, 29, 32, 35}; +byte channelGroup_3[] = {80, 83, 86, 89}; + +const byte bluetooth_channels[] = {32, 34, 46, 48, 50, 52, 0, 1, 2, 4, 6, 8, 22, 24, 26, 28, 30, 74, 76, 78, 80}; +const byte ble_channels[] = {2, 26, 80}; +const byte WiFi_channels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; +const byte usbWireless_channels[] = {40, 50, 60}; +const byte videoTransmitter_channels[] = {70, 75, 80}; +const byte rc_channels[] = {1, 3, 5, 7}; +const byte zigbee_channels[] = {11, 15, 20, 25}; +const byte nrf24_channels[] = {76, 78, 79}; + +volatile bool ChangeRequested = false; +volatile bool ChangeRequested1 = false; +volatile bool ChangeRequested2 = false; + +unsigned long lastPressTime = 0; +const unsigned long debounceDelay = 200; + +#endif // CONFIG_H diff --git a/RF-Clown-M5Shark-Fix/docs/M5SHARK_RF_CLOWN_FIX.md b/RF-Clown-M5Shark-Fix/docs/M5SHARK_RF_CLOWN_FIX.md new file mode 100644 index 0000000..f1b871f --- /dev/null +++ b/RF-Clown-M5Shark-Fix/docs/M5SHARK_RF_CLOWN_FIX.md @@ -0,0 +1,551 @@ +# M5-Shark RF-Clown V2 Fix Notes + +**Fixed by:** Aung Myat Thu [w01f] +**Device:** M5-Shark RF-Clown V2 +**Board:** ESP32-D0WD-V3 + nRF24L01+ modules +**Purpose:** Firmware debugging, UI fix, button fix, LED/status logging, and safe RF module validation + +> This document is for authorized RF lab research, firmware debugging, and defensive hardware validation only. Do not use RF-active modes against public devices, neighbors, office devices, or unknown networks. + +--- + +## 1. Summary + +The M5-Shark RF-Clown unit originally showed only a simple: + +```text +Active / Deactive +``` + +interface and did not expose the expected RF-Clown V2 mode UI. + +After firmware modification and Arduino CLI compilation, the device now shows and navigates the expected modes: + +```text +WiFi +Video TX +RC +BLE +Bluetooth +USB Wireless +Zigbee +NRF24 +``` + +The fixes include: + +```text +Compile fix +Button polling fix +SELECT Active/Deactive fix +Mode/state serial debug +Channel verification logging +Reduced serial flood +RF24 radio detection confirmation +``` + +--- + +## 2. Tested Hardware + +Detected ESP32: + +```bash +esptool --port /dev/ttyUSB0 chip-id +``` + +Observed: + +```text +Chip type: ESP32-D0WD-V3 +Crystal frequency: 40MHz +USB bridge: Silicon Labs CP210x UART Bridge +Port: /dev/ttyUSB0 +Flash size: 16MB +``` + +--- + +## 3. Backup Commands + +### 4MB Backup + +```bash +cd ~/rf-clown-backup + +sudo esptool --port /dev/ttyUSB0 --baud 115200 \ + read-flash 0x00000 0x400000 rf-clown-original-backup-4mb.bin +``` + +### 16MB Backup + +```bash +cd ~/rf-clown-backup + +sudo esptool --port /dev/ttyUSB0 --baud 115200 \ + read-flash 0x00000 0x1000000 rf-clown-original-backup-16mb-slow.bin +``` + +### Restore 4MB Backup + +```bash +cd ~/rf-clown-backup + +sudo esptool --chip esp32 --port /dev/ttyUSB0 --baud 115200 \ + write-flash 0x00000 rf-clown-original-backup-4mb.bin +``` + +### Restore 16MB Backup + +```bash +cd ~/rf-clown-backup + +sudo esptool --chip esp32 --port /dev/ttyUSB0 --baud 115200 \ + write-flash 0x00000 rf-clown-original-backup-16mb-slow.bin +``` + +--- + +## 4. Arduino CLI Setup + +Install ESP32 platform and libraries: + +```bash +arduino-cli config init +arduino-cli core update-index +arduino-cli core install esp32:esp32@2.0.17 + +arduino-cli lib install "U8g2" +arduino-cli lib install "RF24" +arduino-cli lib install "Adafruit NeoPixel" +``` + +Compile: + +```bash +cd ~/rf-clown-backup/RF-Clown/RfClown + +arduino-cli compile --fqbn esp32:esp32:esp32 . +``` + +Upload: + +```bash +arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32 . +``` + +Do not use: + +```bash +sudo arduino-cli upload +``` + +unless the ESP32 platform is also installed for the root user. + +If serial permission fails: + +```bash +sudo usermod -aG uucp,lock $USER +sudo chmod 666 /dev/ttyUSB0 +``` + +--- + +## 5. Compile Fix + +The source had multiple-definition linker errors because global variables were defined directly in header files. + +Affected symbols included: + +```text +u8g2 +pixels +current_Mode +current +channelGroup_1 +channelGroup_2 +channelGroup_3 +ChangeRequested +ChangeRequested1 +ChangeRequested2 +lastPressTime +neoPixelActive +oledBrightness +``` + +Fix: + +```text +Move global definitions into globals.cpp +Keep extern declarations in config.h / setting.h +Add channel group length variables for extern arrays +``` + +Example header declaration: + +```cpp +extern byte channelGroup_1[]; +extern byte channelGroup_2[]; +extern byte channelGroup_3[]; + +extern const size_t channelGroup_1_len; +extern const size_t channelGroup_2_len; +extern const size_t channelGroup_3_len; +``` + +Example `globals.cpp` definition: + +```cpp +byte channelGroup_1[] = {2, 5, 8, 11}; +byte channelGroup_2[] = {26, 29, 32, 35}; +byte channelGroup_3[] = {80, 83, 86, 89}; + +const size_t channelGroup_1_len = sizeof(channelGroup_1); +const size_t channelGroup_2_len = sizeof(channelGroup_2); +const size_t channelGroup_3_len = sizeof(channelGroup_3); +``` + +--- + +## 6. Button Fix + +Interrupt-based button handling was unreliable on this M5-Shark unit. + +Fix: + +```text +Disable attachInterrupt() button handling +Use polling with debounce +Print button activity to Serial +``` + +Expected mapping: + +```text +LEFT = previous mode +RIGHT = next mode +SELECT = Active / Deactive +``` + +Expected serial logs: + +```text +[BTN] LEFT / previous mode +[RF-Clown] changed | Mode: NRF24 | State: DEACTIVE + +[BTN] RIGHT / next mode +[RF-Clown] changed | Mode: WiFi | State: DEACTIVE + +[BTN] SELECT / active-deactive +[RF-Clown] changed | Mode: WiFi | State: ACTIVE +``` + +--- + +## 7. SELECT Toggle Fix + +SELECT was detected but did not properly toggle `ACTIVE_MODE` / `DEACTIVE_MODE`. + +Fix logic: + +```cpp +if (lastS == HIGH && nowS == LOW) { + current = (current == ACTIVE_MODE) ? DEACTIVE_MODE : ACTIVE_MODE; + ChangeRequested2 = false; + lastEventMs = now; + Serial.println("[BTN] SELECT / active-deactive"); +} +``` + +After this fix, SELECT correctly changes state: + +```text +[BTN] SELECT / active-deactive +[RF-Clown] changed | Mode: BLE | State: ACTIVE + +[BTN] SELECT / active-deactive +[RF-Clown] changed | Mode: BLE | State: DEACTIVE +``` + +--- + +## 8. Mode UI Fix + +After the button polling patch, the OLED mode UI became usable. + +Confirmed mode navigation: + +```text +WiFi +Video TX +RC +BLE +Bluetooth +USB Wireless +Zigbee +NRF24 +``` + +--- + +## 9. RF24 Radio Detection + +Terminal inspection confirmed the nRF24L01+ radio initializes correctly: + +```text +SPI Frequency = 10 Mhz +Channel = 76 (~2476 MHz) +Model = nRF24L01+ +RF Data Rate = 2 MBPS +RF Power Amplifier = PA_MAX +RF Low Noise Amplifier = Enabled +Primary Mode = TX +TX address = 0xffffffffff +``` + +This confirms: + +```text +ESP32 to nRF24 SPI communication = OK +nRF24 module detection = OK +TX mode configuration = OK +PA level configuration = OK +``` + +--- + +## 10. Channel Verification + +The old RF24 details output repeatedly showed: + +```text +Channel = 76 (~2476 MHz) +``` + +This looked suspicious, so channel verification logging was added. + +Expected channel debug output: + +```text +[CHANNEL] Mode: NRF24 | requested=78 (~2478 MHz) | A=78 B=78 C=78 +[CHANNEL] Mode: NRF24 | requested=76 (~2476 MHz) | A=76 B=76 C=76 +[CHANNEL] Mode: NRF24 | requested=79 (~2479 MHz) | A=79 B=79 C=79 +``` + +This confirms: + +```text +RadioA channel update = OK +RadioB channel update = OK +RadioC channel update = OK +``` + +--- + +## 11. Reduce Serial Flood + +Channel debug and RF24 `printDetails()` can flood the terminal. + +Fix: + +```text +Disable repeated printDetails() +Throttle channel verification logs +Print only useful button/mode/state logs +``` + +Expected clean output: + +```text +[RF-Clown] Boot diagnostic patch active +[RF-Clown] boot | Mode: WiFi | State: DEACTIVE + +[BTN] RIGHT / next mode +[RF-Clown] changed | Mode: BLE | State: DEACTIVE + +[BTN] SELECT / active-deactive +[RF-Clown] changed | Mode: BLE | State: ACTIVE + +[CHANNEL] Mode: BLE | requested=26 (~2426 MHz) | A=26 B=26 C=26 +``` + +--- + +## 12. LED Notes + +The bright blue LED near the USB port appears to be a hardware power/charging LED. + +Observed behavior: + +```text +USB connected = blue LED bright +Battery low = blue LED dim +Power on = blue LED on +``` + +This LED is not necessarily controlled by firmware. + +If the firmware NeoPixel/status LED does not change, possible reasons: + +```text +NeoPixel GPIO mismatch +M5-Shark board revision uses a different LED pin +Firmware LED setting disabled +Board only exposes a hardware power LED +``` + +This does not mean the RF module is broken. + +--- + +## 13. Terminal Inspection + +Open serial: + +```bash +picocom -b 115200 /dev/ttyUSB0 +``` + +Exit serial: + +```text +Ctrl+A, then Ctrl+X +``` + +Check USB device: + +```bash +ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null +lsusb | grep -i -E "silicon|cp210|uart|esp" +``` + +Kill anything using the serial port: + +```bash +sudo fuser -k /dev/ttyUSB0 2>/dev/null || true +``` + +Stop ModemManager if needed: + +```bash +sudo systemctl stop ModemManager 2>/dev/null || true +``` + +--- + +## 14. Current Working Status + +```text +ESP32 detected = OK +CP2102 USB serial = OK +OLED mode UI = OK +LEFT/RIGHT buttons = OK +SELECT Active/Deactive = OK +nRF24L01+ detected = OK +RadioA channel update = OK +RadioB channel update = OK +RadioC channel update = OK +Serial flood = reduced +``` + +--- + +## 15. Limitations + +Terminal logs can confirm: + +```text +ESP32 boot +OLED UI +Button detection +Mode switching +Active/Deactive state +nRF24 SPI initialization +RF24 channel configuration +TX mode configuration +``` + +Terminal logs cannot fully confirm: + +```text +Actual RF emission strength +Antenna quality +External spectrum activity +Effect on Bluetooth/WiFi devices +``` + +For passive RF verification, use: + +```text +2.4GHz spectrum analyzer +HackRF or other SDR with 2.4GHz support +Another nRF24 scanner +nRF52840 BLE sniffer +``` + +--- + +## 16. Safety Notice + +Use this firmware only for: + +```text +Authorized lab testing +Firmware debugging +Hardware validation +Defensive RF research +Education in a controlled environment +``` + +Do not use RF-active modes against public devices, office devices, neighbors, or unknown networks. + +--- + +## 17. Git Commands + +Create branch: + +```bash +cd ~/rf-clown-backup/RF-Clown + +git switch -c fix/m5shark-rfclown-ui-led-debug +``` + +Add docs and source fixes: + +```bash +git add RfClown/ docs/M5SHARK_RF_CLOWN_FIX.md +``` + +Commit: + +```bash +git commit -m "Fix M5-Shark RF-Clown UI buttons and diagnostics" +``` + +Push: + +```bash +git push -u origin fix/m5shark-rfclown-ui-led-debug +``` + +--- + +## 18. Final Note + +This fix was prepared and tested by: + +```text +Aung Myat Thu [w01f] +``` + +The main goal was to make the M5-Shark RF-Clown V2 firmware usable for controlled lab debugging by fixing: + +```text +Compilation +OLED mode navigation +Button handling +Active/Deactive toggle +Serial diagnostics +RF24 channel verification +``` \ No newline at end of file diff --git a/RF-Clown-M5Shark-Fix/globals.cpp b/RF-Clown-M5Shark-Fix/globals.cpp new file mode 100644 index 0000000..ccd4054 --- /dev/null +++ b/RF-Clown-M5Shark-Fix/globals.cpp @@ -0,0 +1,25 @@ +// RF_CLOWN_GLOBAL_DEFINITIONS_PATCH +// Global definitions moved out of headers to fix Arduino CLI multiple-definition linker errors. + +#include "config.h" +#include "setting.h" + +U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); +Adafruit_NeoPixel pixels(1, 14, NEO_GRB + NEO_KHZ800); +OperationMode current_Mode = WiFi_MODULE; +volatile Operation current = DEACTIVE_MODE; +byte channelGroup_1[] = {2, 5, 8, 11}; +byte channelGroup_2[] = {26, 29, 32, 35}; +byte channelGroup_3[] = {80, 83, 86, 89}; +volatile bool ChangeRequested = false; +volatile bool ChangeRequested1 = false; +volatile bool ChangeRequested2 = false; +unsigned long lastPressTime = 0; +bool neoPixelActive = false; +uint8_t oledBrightness = 100; + + +// Channel group lengths for extern arrays. +extern const size_t channelGroup_1_len = sizeof(channelGroup_1); +extern const size_t channelGroup_2_len = sizeof(channelGroup_2); +extern const size_t channelGroup_3_len = sizeof(channelGroup_3); diff --git a/RF-Clown-M5Shark-Fix/neopixel.cpp b/RF-Clown-M5Shark-Fix/neopixel.cpp new file mode 100644 index 0000000..7e7ff1f --- /dev/null +++ b/RF-Clown-M5Shark-Fix/neopixel.cpp @@ -0,0 +1,62 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#include "setting.h" +#include "config.h" + +extern Adafruit_NeoPixel pixels; + +void neopixelSetup() { + EEPROM.begin(512); + neoPixelActive = EEPROM.read(0); + + if (neoPixelActive) { + pixels.begin(); + pixels.clear(); + //pixels.show(); + } +} + +void neopixelLoop(); + +void setNeoPixelColour(const std::string& colour) { + uint32_t colorValue = 0; + + if (colour == "red") { + colorValue = pixels.Color(5, 0, 0); + } else if (colour == "green") { + colorValue = pixels.Color(0, 5, 0); + } else if (colour == "blue") { + colorValue = pixels.Color(0, 0, 5); + } else if (colour == "yellow") { + colorValue = pixels.Color(5, 5, 0); + } else if (colour == "purple") { + colorValue = pixels.Color(5, 0, 5); + } else if (colour == "cyan") { + colorValue = pixels.Color(0, 5, 5); + } else if (colour == "white") { + colorValue = pixels.Color(5, 5, 5); + } else if (colour == "null") { + colorValue = pixels.Color(0, 0, 0); + } + + pixels.setPixelColor(0, colorValue); + pixels.show(); +} + +void flash(int numberOfFlashes, const std::vector& colors, const std::string& finalColour) { + if (numberOfFlashes <= 0 || colors.empty()) { + Serial.println("Invalid parameters for flash: Check numberOfFlashes or colors vector."); + return; + } + + for (int i = 0; i < numberOfFlashes; ++i) { + for (const auto& color : colors) { + setNeoPixelColour(color); + delay(500); + } + } + setNeoPixelColour(finalColour); +} diff --git a/RF-Clown-M5Shark-Fix/setting.cpp b/RF-Clown-M5Shark-Fix/setting.cpp new file mode 100644 index 0000000..4ab2ace --- /dev/null +++ b/RF-Clown-M5Shark-Fix/setting.cpp @@ -0,0 +1,98 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#include "setting.h" +#include "config.h" + +RF24 RadioA(NRF_CE_PIN_A, NRF_CSN_PIN_A); +RF24 RadioB(NRF_CE_PIN_B, NRF_CSN_PIN_B); +RF24 RadioC(NRF_CE_PIN_C, NRF_CSN_PIN_C); + +void setRadiosNeutralState() { + RadioA.stopListening(); + RadioA.setAutoAck(false); + RadioA.setRetries(0, 0); + RadioA.powerDown(); + digitalWrite(NRF_CE_PIN_A, LOW); + + RadioB.stopListening(); + RadioB.setAutoAck(false); + RadioB.setRetries(0, 0); + RadioB.powerDown(); + digitalWrite(NRF_CE_PIN_B, LOW); + + RadioC.stopListening(); + RadioC.setAutoAck(false); + RadioC.setRetries(0, 0); + RadioC.powerDown(); + digitalWrite(NRF_CE_PIN_C, LOW); +} + +void configureNrf(RF24 &radio) { + radio.begin(); + radio.setAutoAck(false); + radio.stopListening(); + radio.setRetries(0, 0); + radio.setPALevel(RF24_PA_MAX, true); + radio.setDataRate(RF24_2MBPS); + radio.setCRCLength(RF24_CRC_DISABLED); +} + +void setupRadioA() { + configureNrf(RadioA); +} + +void setupRadioB() { + configureNrf(RadioB); +} + +void setupRadioC() { + configureNrf(RadioC); +} + +void initAllRadios() { + setupRadioA(); + setupRadioB(); + setupRadioC(); +} + +void Str(uint8_t x, uint8_t y, const uint8_t* asciiArray, size_t len) { + char buf[64]; + for (size_t i = 0; i < len && i < sizeof(buf) - 1; i++) { + buf[i] = (char)asciiArray[i]; + } + buf[len] = '\0'; + + u8g2.drawStr(x, y, buf); +} + +void CenteredStr(uint8_t screenWidth, uint8_t y, const uint8_t* asciiArray, size_t len, const uint8_t* font) { + char buf[64]; + for (size_t i = 0; i < len && i < sizeof(buf) - 1; i++) { + buf[i] = (char)asciiArray[i]; + } + buf[len] = '\0'; + + u8g2.setFont((const uint8_t*)font); + int16_t w = u8g2.getUTF8Width(buf); + u8g2.setCursor((screenWidth - w) / 2, y); + u8g2.print(buf); +} + +void conf() { + u8g2.setBitmapMode(1); + u8g2.clearBuffer(); + CenteredStr(128, 15, txt_n, sizeof(txt_n), u8g2_font_ncenB14_tr); + CenteredStr(120, 35, txt_c, sizeof(txt_c), u8g2_font_ncenB08_tr); + CenteredStr(128, 50, txt_v, sizeof(txt_v), u8g2_font_6x10_tf); + u8g2.sendBuffer(); + delay(3000); + u8g2.clearBuffer(); + u8g2.drawXBMP(0, 0, 128, 64, cred); + u8g2.sendBuffer(); + delay(250); +} + + diff --git a/RF-Clown-M5Shark-Fix/setting.h b/RF-Clown-M5Shark-Fix/setting.h new file mode 100644 index 0000000..537b09a --- /dev/null +++ b/RF-Clown-M5Shark-Fix/setting.h @@ -0,0 +1,121 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#ifndef setting_H +#define setting_H + +#include +#include +#include +#include +#include +#include +#include +#include + +void neopixelSetup(); +void neopixelLoop(); + +void setNeoPixelColour(const std::string& colour); +void flash(int numberOfFlashes, const std::vector& colors, const std::string& finalColour); + +extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; +extern Adafruit_NeoPixel pixels; + +//extern bool neoPixelActive; + +extern bool neoPixelActive; +extern uint8_t oledBrightness; + +extern RF24 RadioA; +extern RF24 RadioB; +extern RF24 RadioC; + +void configureNrf(RF24 &radio); + +void setRadiosNeutralState(); + +void setupRadioA(); +void setupRadioB(); +void setupRadioC(); + +void initAllRadios(); + +void Str(uint8_t x, uint8_t y, const uint8_t* asciiArray, size_t len); +void CenteredStr(uint8_t screenWidth, uint8_t y, const uint8_t* asciiArray, size_t len, const uint8_t* font); +void conf(); + +const uint8_t txt_n[] = {82, 102, 67, 108, 111, 119, 110}; +const uint8_t txt_c[] = {98, 121, 32, 67, 105, 102, 101, 114, 84, 101, 99, 104}; +const uint8_t txt_v[] = {118, 50, 46, 48, 46, 48}; + +const unsigned char cred [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xf0, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x78, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x0c, 0x7f, 0xfe, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0xc0, 0x7f, 0xfe, 0x07, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0xe0, 0x7f, 0xfe, 0x1f, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf8, 0x7f, 0xfe, 0x3f, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x7f, 0xfe, 0x7f, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0xfe, 0x7f, 0xfe, 0xff, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x80, 0x7f, 0xff, 0x7f, 0xfe, 0xff, 0xf9, 0x03, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xc1, 0x3f, 0xff, 0x7f, 0xfe, 0xff, 0xfb, 0x87, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xe7, 0xbf, 0xff, 0x7f, 0xfe, 0xff, 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xff, 0xdf, 0xff, 0x7f, 0xfe, 0xff, 0xf7, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xdf, 0xff, 0x7f, 0xfe, 0xff, 0xe7, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0xff, 0x7f, 0xfe, 0xff, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xef, 0xff, 0x7f, 0xfe, 0xff, 0xcf, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xff, 0x7f, 0xfe, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x1e, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x0e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x06, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x3f, 0x7f, 0x1e, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0xee, 0x0f, 0x7e, 0x1e, 0x00, 0xee, 0x39, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xef, 0xe7, 0x7c, 0x3e, 0x00, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcf, 0xf7, 0x79, 0x7e, 0x80, 0xef, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xdf, 0xf7, 0x7b, 0xfe, 0xc0, 0xe7, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xff, 0x9f, 0xe7, 0x77, 0xfe, 0xf3, 0xf7, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xcf, 0xbf, 0xe7, 0x6f, 0x8e, 0xff, 0xf3, 0xc7, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x83, 0x3f, 0xcf, 0x4f, 0x06, 0xff, 0xfb, 0x03, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x3f, 0x9e, 0x1f, 0x72, 0xfe, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xb0, 0x3f, 0xf8, 0x3c, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x60, 0x7f, 0xfe, 0x0d, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0xc0, 0xfe, 0xff, 0x0c, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xc0, 0xfd, 0x7f, 0x06, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x80, 0xfb, 0x3f, 0x07, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x80, 0xf3, 0x9f, 0x03, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#endif diff --git a/RF-Clown-M5Shark-Fix/setting.h.bak.2569-05-25-1305 b/RF-Clown-M5Shark-Fix/setting.h.bak.2569-05-25-1305 new file mode 100644 index 0000000..8b8a6a6 --- /dev/null +++ b/RF-Clown-M5Shark-Fix/setting.h.bak.2569-05-25-1305 @@ -0,0 +1,121 @@ +/* ____________________________ + This software is licensed under the MIT License: + https://github.com/cifertech/rfclown + ________________________________________ */ + +#ifndef setting_H +#define setting_H + +#include +#include +#include +#include +#include +#include +#include +#include + +void neopixelSetup(); +void neopixelLoop(); + +void setNeoPixelColour(const std::string& colour); +void flash(int numberOfFlashes, const std::vector& colors, const std::string& finalColour); + +extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; +extern Adafruit_NeoPixel pixels; + +//extern bool neoPixelActive; + +bool neoPixelActive = false; +uint8_t oledBrightness = 100; + +extern RF24 RadioA; +extern RF24 RadioB; +extern RF24 RadioC; + +void configureNrf(RF24 &radio); + +void setRadiosNeutralState(); + +void setupRadioA(); +void setupRadioB(); +void setupRadioC(); + +void initAllRadios(); + +void Str(uint8_t x, uint8_t y, const uint8_t* asciiArray, size_t len); +void CenteredStr(uint8_t screenWidth, uint8_t y, const uint8_t* asciiArray, size_t len, const uint8_t* font); +void conf(); + +const uint8_t txt_n[] = {82, 102, 67, 108, 111, 119, 110}; +const uint8_t txt_c[] = {98, 121, 32, 67, 105, 102, 101, 114, 84, 101, 99, 104}; +const uint8_t txt_v[] = {118, 50, 46, 48, 46, 48}; + +const unsigned char cred [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xf0, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x78, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x0c, 0x7f, 0xfe, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0xc0, 0x7f, 0xfe, 0x07, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0xe0, 0x7f, 0xfe, 0x1f, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf8, 0x7f, 0xfe, 0x3f, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x7f, 0xfe, 0x7f, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0xfe, 0x7f, 0xfe, 0xff, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x80, 0x7f, 0xff, 0x7f, 0xfe, 0xff, 0xf9, 0x03, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xc1, 0x3f, 0xff, 0x7f, 0xfe, 0xff, 0xfb, 0x87, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xe7, 0xbf, 0xff, 0x7f, 0xfe, 0xff, 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xff, 0xdf, 0xff, 0x7f, 0xfe, 0xff, 0xf7, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xdf, 0xff, 0x7f, 0xfe, 0xff, 0xe7, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0xff, 0x7f, 0xfe, 0xff, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xef, 0xff, 0x7f, 0xfe, 0xff, 0xcf, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xff, 0x7f, 0xfe, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x1e, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x0e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x06, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x3f, 0x7f, 0x1e, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0xee, 0x0f, 0x7e, 0x1e, 0x00, 0xee, 0x39, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xef, 0xe7, 0x7c, 0x3e, 0x00, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcf, 0xf7, 0x79, 0x7e, 0x80, 0xef, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xdf, 0xf7, 0x7b, 0xfe, 0xc0, 0xe7, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xff, 0x9f, 0xe7, 0x77, 0xfe, 0xf3, 0xf7, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xcf, 0xbf, 0xe7, 0x6f, 0x8e, 0xff, 0xf3, 0xc7, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x83, 0x3f, 0xcf, 0x4f, 0x06, 0xff, 0xfb, 0x03, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x3f, 0x9e, 0x1f, 0x72, 0xfe, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xb0, 0x3f, 0xf8, 0x3c, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x60, 0x7f, 0xfe, 0x0d, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0xc0, 0xfe, 0xff, 0x0c, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xc0, 0xfd, 0x7f, 0x06, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x80, 0xfb, 0x3f, 0x07, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x80, 0xf3, 0x9f, 0x03, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#endif