/* stupid atenna matrix firmware - by DL3SD * FIXME: * - replace delay in loop by interrupt handling * - maybe implement sleep mode to avoid hf issues by arduino clock */ #include #define USE_I2C_LCD //#define USE_I2C_OLED //#define USE_SPI_EINK #define pin_K1 8 //2 #define pin_K2 7//3 #define pin_K3 6//4 #define pin_K4 5//5 #define pin_K5 4//6 #define pin_K6 3//12 #define pin_T 2//14 #define VERSION "v0.2" #define MODES 6 struct state { char name[4]; bool K1; bool K2; bool K3; bool K4; bool K5; bool K6; }; struct identifier { char signature[16]; char ant[3][16]; char trx[3][16]; }; struct identifier names; // = { "samcfg", "ant1", "ant2", "ant3", "trx1", "trx2", "trx3" }; const struct state matrix[] = { {"123", 0, 0, 0, 0, 0, 0}, // ANT1->TRX1 ANT2->TRX2 ANT3->TRX3 {"213", 1, 0, 1, 0, 0, 0}, // ANT1->TRX2 ANT2->TRX1 ANT3->TRX3 {"312", 1 ,1, 1, 0, 1, 0}, // ANT1->TRX3 ANT2->TRX1 ANT3->TRX2 {"132", 0 ,0, 1, 1, 1, 0}, // ANT1->TRX1 ANT2->TRX3 ANT3->TRX2 {"231", 1 ,0 ,1, 1, 1, 1}, // ANT1->TRX2 ANT2->TRX3 ANT3->TRX1 {"321", 1 ,1 ,0, 0, 1, 1}, // ANT1->TRX3 ANT2->TRX2 ANT3->TRX1 }; int mode; /*###########################################*/ #if defined(USE_I2C_LCD) /*###########################################*/ #include #include LiquidCrystal_I2C lcd(0x27, 20, 4); void initDisplay() { lcd.init(); lcd.backlight(); lcd.setCursor(8,0); lcd.print(F("stupid")); delay(350); lcd.setCursor(7,1); lcd.print(F("antenna")); delay(350); lcd.setCursor(8,2); lcd.print(F("matrix")); delay(350); lcd.setCursor(4,3); lcd.print(VERSION); lcd.print(F(" by DL3SD")); delay(3000); lcd.clear(); lcd.setCursor(8,0); lcd.print(F("visit")); lcd.setCursor(0,1); lcd.print(F("github.com/denzs/sam")); lcd.setCursor(0,2); lcd.print(F("for more information")); delay(5000); } void updateDisplay() { char m[4], out[32]; int c; strcpy(m, matrix[mode].name); lcd.clear(); lcd.setCursor(3,0); lcd.print(F("S.A.M. by DL3SD")); for(int i=0; i < MODES/2; i++) { c = m[i]-48; lcd.setCursor(0, i+1); lcd.print(names.trx[i]); lcd.setCursor(10, i+1); sprintf(out, "%s", names.ant[c-1]); lcd.print(out); } } /*###########################################*/ #endif /*###########################################*/ /*###########################################*/ #if defined(USE_I2C_OLED) /*###########################################*/ #include #include #include #include "DejaVuSansMono5pt7b.h" #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); void updateDisplay() { char m[4], out[32]; int c; strcpy(m, matrix[mode].name); display.clearDisplay(); //lcd.setCursor(3,0); //lcd.print(F("S.A.M. by DL3SD")); for(int i=0; i < MODES/2; i++) { c = m[i]-48; display.setCursor(0, (i+1)*10); display.print(names.trx[i]); display.setCursor(64, (i+1)*10); sprintf(out, "%s", names.ant[c-1]); display.print(out); } display.display(); } void initDisplay() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.display(); //display.setFont(&FreeSans9pt7b); display.setFont(&DejaVuSansMono5pt7b); //display.setTextSize(1); delay(1000); display.clearDisplay(); display.setTextColor(WHITE); } /*###########################################*/ #endif /*###########################################*/ /*###########################################*/ #if defined(USE_SPI_EINK) /*###########################################*/ #define ENABLE_GxEPD2_GFX 0 #include // including both doesn't hurt #include // including both doesn't hurt FIXME remove??? #include #define MAX_DISPLAY_BUFFER_SIZE 600 #define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) GxEPD2_BW display(GxEPD2_290(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); void updateDisplay() { char out[256]; sprintf(out, " s.a.m. by DL3SD\n github.com/denzs/sam\n\n %s %s\n %s %s\n %s %s", names.trx[0], names.ant[matrix[mode].name[0]-49], names.trx[1], names.ant[matrix[mode].name[1]-49], names.trx[2], names.ant[matrix[mode].name[2]-49]); Serial.println(out); display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; display.getTextBounds(out , 0, 0, &tbx, &tby, &tbw, &tbh); // center the bounding box by transposition of the origin: uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2) - tby; display.setFullWindow(); display.firstPage(); do { Serial.println("[I] refresh eink screen.."); display.fillScreen(GxEPD_WHITE); display.setCursor(x, y); display.print(out); } while (display.nextPage()); display.hibernate(); } void initDisplay() { display.init(); char out[] = " s.a.m. by DL3SD\n github.com/denzs/sam\n\n"; display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; display.getTextBounds(out , 0, 0, &tbx, &tby, &tbw, &tbh); // center the bounding box by transposition of the origin: uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2); // - tby; display.setFullWindow(); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(x, y); display.print(out); } while (display.nextPage()); display.hibernate(); } /*###########################################*/ #endif /*###########################################*/ void setup() { Serial.begin(9600); Serial.print(F("[S] configuring pins..")); pinMode(pin_K1, OUTPUT); pinMode(pin_K2, OUTPUT); pinMode(pin_K3, OUTPUT); pinMode(pin_K4, OUTPUT); pinMode(pin_K5, OUTPUT); pinMode(pin_K6, OUTPUT); pinMode(pin_T, INPUT); Serial.println(F("done")); Serial.print(F("[S] trying to read identifiers from EEPROM..")); EEPROM.get(0, names); Serial.println(F("done")); if(strcmp(names.signature, "samcfg") == 0) { Serial.println(F("[S] configuration found")); } else { Serial.println(F("[S] configuration not found.. using defaults")); strcpy(names.signature, "samcfg"); strcpy(names.ant[0], "ant1"); strcpy(names.ant[1], "ant2"); strcpy(names.ant[2], "ant3"); strcpy(names.trx[0], "trx1"); strcpy(names.trx[1], "trx2"); strcpy(names.trx[2], "trx3"); } Serial.print(F("[S] init relays with mode 123..")); setMode("123"); setRelays(0); Serial.println(F("done")); Serial.print(F("[S] initializing display..")); initDisplay(); Serial.println(F("done")); updateDisplay(); Serial.println(F("[S] setup finished")); } void storeName(char *dst, char *src) { strncpy(dst, src, strlen(src)); dst[strlen(src) - 1] = '\0'; } void setRelays(bool display) { digitalWrite(pin_K1, matrix[mode].K1); digitalWrite(pin_K2, matrix[mode].K2); digitalWrite(pin_K3, matrix[mode].K3); digitalWrite(pin_K4, matrix[mode].K4); digitalWrite(pin_K5, matrix[mode].K5); digitalWrite(pin_K6, matrix[mode].K6); if (display) { updateDisplay(); } } void nextMode() { if(mode == MODES - 1) { mode = 0; } else { mode++; } Serial.print("[M] "); Serial.println(matrix[mode].name); setRelays(1); } void setMode(char *m) { char debug[32]; m[3] = '\0'; for(int i=0 ; i < MODES; i++) { //sprintf(debug, "[D] comparing %s against %s", m, matrix[i].name); //Serial.println(debug); if(strcmp(matrix[i].name, m) == 0) { mode = i; //sprintf(debug, "found mode %s at index %d", m, i); //Serial.println(debug); return; } } sprintf(debug, "[E] cant find mode %s", m); Serial.println(debug); return; } void parseCommand(String s) { switch (s[0]) { case 'a': switch (s[1]) { case '1': case '2': case '3': storeName(names.ant[(int)s[1] - 49], &s[2]); updateDisplay(); break; default: Serial.println("unsupported option"); //Serial.println(); break; } break; case 't': switch (s[1]) { case '1': case '2': case '3': storeName(names.trx[(int)s[1] - 49], &s[2]); updateDisplay(); break; default: Serial.println("unsupported option"); //Serial.println(); break; } break; case 'm': if(s.length() == 5) { setMode(&s[1]); setRelays(1); } Serial.print("[M] "); Serial.println(matrix[mode].name); //Serial.println(); break; case 'n': nextMode(); break; case 'h': Serial.print(F("[I] commands available in ")); Serial.println(VERSION); Serial.println(F("[I] a1mygreatantenna1 - sets name of ANT1 to mygreatantenna1")); Serial.println(F("[I] a2mygreatantenna2 - sets name of ANT2 to mygreatantenna2")); Serial.println(F("[I] a3mygreatantenna3 - sets name of ANT3 to mygreatantenna3")); Serial.println(F("[I] t1mygreatrig1 - sets name of TRX1 to mygreatrig1")); Serial.println(F("[I] t2mygreatrig2 - sets name of TRX2 to mygreatrig2")); Serial.println(F("[I] t3mygreatrig3 - sets name of TRX3 to mygreatrig3")); Serial.println(F("[I] m312 - activate matrix 312 (I1->O3 I2->O1 I3->O2)")); Serial.println(F("[I] m - print current matrix")); Serial.println(F("[I] n - goto next matrix entry")); Serial.println(F("[I] r - print runtime settings")); Serial.println(F("[I] w - store runtime settings to EEPROM")); Serial.println(F("[I] h - print this help text")); //Serial.println(); break; case 'w': EEPROM.put(0, names); Serial.println(F("[S] runtime settings stored in EEPROM")); break; case 'r': Serial.println(F("[I] current runtime settings:")); Serial.print(F("[R] ANT1: ")); Serial.println(names.ant[0]); Serial.print(F("[R] ANT2: ")); Serial.println(names.ant[1]); Serial.print(F("[R] ANT3: ")); Serial.println(names.ant[2]); Serial.print(F("[R] TRX1: ")); Serial.println(names.trx[0]); Serial.print(F("[R] TRX2: ")); Serial.println(names.trx[1]); Serial.print(F("[R] TRX3: ")); Serial.println(names.trx[2]); Serial.println(F("[I] -> dont forget to write to EEPROM with 'w' after modifying")); //Serial.println(); break; default: Serial.println(F("[E] command not found - enter 'h' for help")); //Serial.println(); break; } } void loop() { String s; if (Serial.available() > 0) { s = Serial.readString(); parseCommand(s); } if(digitalRead(pin_T) == HIGH) { //Serial.println("button pressed.."); nextMode(); } delay(300); }