|
|
|
/* 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 <EEPROM.h>
|
|
|
|
|
|
|
|
#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 <Wire.h>
|
|
|
|
#include <LiquidCrystal_I2C.h>
|
|
|
|
|
|
|
|
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 <Adafruit_GFX.h>
|
|
|
|
#include <Adafruit_SSD1306.h>
|
|
|
|
#include <Fonts/FreeSans9pt7b.h>
|
|
|
|
#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 <GxEPD2_BW.h> // including both doesn't hurt
|
|
|
|
#include <GxEPD2_3C.h> // including both doesn't hurt FIXME remove???
|
|
|
|
#include <Fonts/FreeMonoBold9pt7b.h>
|
|
|
|
|
|
|
|
#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<GxEPD2_290, MAX_HEIGHT(GxEPD2_290)> 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);
|
|
|
|
}
|