diff --git a/README.md b/README.md index 49268e2..03a88c6 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ There are several features that can be added to the rig if you want to. This is done by adding and removing `#define` lines to `settings.h`. - `OPT_BAND_SELECT`: change the band by pressing RIT for 2s. +- `OPT_AUTO_BAND`: auto-select bands using a PCA9536 PIO (thanks VK3IL). - `OPT_ERASE_EEPROM`: erase the EEPROM by holding RIT for 8s. - `OPT_STORE_CW_SPEED`: store the CW speed in EEPROM. - `OPT_DFE`: direct frequency entry by holding the encoder button for 1s. @@ -209,6 +210,8 @@ Some images of the connections: ## Changelog +- 2017-05-16: + - `OPT_AUTO_BAND` (PR [#22](/../../pull/22) by VK3IL) - 2017-05-12: - VK band plans (PR [#21](/../../pull/21) by VK3IL) - 2017-05-04: diff --git a/SODA_POP/SODA_POP.h b/SODA_POP/SODA_POP.h index 03beeb5..85c251f 100644 --- a/SODA_POP/SODA_POP.h +++ b/SODA_POP/SODA_POP.h @@ -87,6 +87,11 @@ byte memory_index_character; #define EEPROM_CW_SPEED 7 // 1 byte #endif +#ifdef OPT_AUTO_BAND +#define PCA9536_BUS_ADDR 0x41 // I2C address for PCA9536 +#undef OPT_BAND_SELECT +#endif + #endif // vim: tabstop=2 shiftwidth=2 expandtab: diff --git a/SODA_POP/SODA_POP.ino b/SODA_POP/SODA_POP.ino index b84841b..1e8eeb5 100644 --- a/SODA_POP/SODA_POP.ino +++ b/SODA_POP/SODA_POP.ino @@ -70,6 +70,7 @@ Si5351 si5351; #define IF_DEFAULT 491480000 byte memory_pointer; +byte errno; // Global error number for S_ERROR const int MUTE = A3; const int TXEN = 13; // production A0 @@ -142,11 +143,18 @@ void setup() TIMSK1 |= 1 << OCIE1A; interrupts(); +#ifdef OPT_AUTO_BAND + state.state = EEPROM.read(6) == 0xff ? S_CALIBRATION_CORRECTION : S_DEFAULT; + read_module_band(); +#else state.band = (enum band) EEPROM.read(6); // check for operating band if (state.band == BAND_UNKNOWN) { state.band = (enum band) 0; state.state = S_CALIBRATION_CORRECTION; + } else { + state.state = S_DEFAULT; } +#endif fetch_calibration_data(); //load calibration data si5351.set_correction(cal_value); //correct the clock chip error @@ -155,7 +163,6 @@ void setup() invalidate_display(); delay(1000); - state.state = S_DEFAULT; invalidate_display(); digitalWrite(MUTE, LOW); @@ -194,7 +201,7 @@ void loop() case S_CALIBRATION_PEAK_RX: loop_calibration_peak_rx(); break; case S_ERROR: loop_error(); break; default: - error(); + error(1); break; } @@ -237,6 +244,11 @@ void loop_default() state.idle_for = DISABLE_DISPLAY_AFTER - 500; #endif +#ifdef OPT_AUTO_BAND + if (tcount % 5000 == 0) // Check the band module for changes every 5s + read_module_band(); +#endif + if (key_active()) { state.state = S_KEYING; // Tuning with the rotary encoder @@ -795,8 +807,12 @@ void loop_calibration_peak_if() EEPROM.write(EEPROM_IF_FREQ + 1, state.op_freq >> 8); EEPROM.write(EEPROM_IF_FREQ + 2, state.op_freq >> 16); EEPROM.write(EEPROM_IF_FREQ + 3, state.op_freq >> 24); - + #ifdef OPT_AUTO_BAND + EEPROM.write(6, 0); // Reset the "not calibrated" flag now that we've written the cal values + state.state = S_CALIBRATION_PEAK_RX; +#else state.state = S_CALIBRATION_CHANGE_BAND; +#endif invalidate_frequencies(); invalidate_display(); @@ -865,7 +881,7 @@ void key_handle_end() state.state = S_DEFAULT; } else if (state.state == S_MEM_ENTER) { if (memory_pointer == MEMORY_LENGTH) { - error(); + error(2); return; } buffer[memory_pointer++] = morse_char; @@ -1089,10 +1105,78 @@ void ee_erase() * Enter the error state. This error is non-recoverable and should only be used * in very rare cases. */ -void error() +void error(byte er) { + errno = er; state.state = S_ERROR; +} + +#ifdef OPT_AUTO_BAND +/* + * Read the input latch of the PCA9536 and return a 4-bit value + * If the band module can't be read or the value is out of range, display an error and wait for a valid band module + */ +byte PCA9536_read() +{ + for (boolean err = true; err; err = false) { + Wire.beginTransmission(PCA9536_BUS_ADDR); + Wire.write(byte(0x00)); // We read only from register 0, the input latch + Wire.endTransmission(false); // Transmit repeated start rather than stop at end of transmission + Wire.requestFrom(PCA9536_BUS_ADDR, 1); + if (Wire.available() != 1) { // Unable to read the band module ID (most + // likely it's not plugged in properly, or being changed!) + err = true; + } else { + byte reg_val = Wire.read() & 0x0f; + if(reg_val < 2 || reg_val > 11) // Module has an un-supported configuration + err = true; + } + if (err) { + state.display.digits[3] = LED_N_6; + state.display.digits[2] = LED_n; + state.display.digits[1] = LED_E; + state.display.digits[0] = LED_r; + state.display.dots = 0x0; + delay(500); + } + } invalidate_display(); + return reg_val; +} + +/* + * Check if the band module has changed and if it has, reset bandlimits and operating frequency + */ +void read_module_band() +{ + enum band new_band; + + switch (PCA9536_read()) { // Map returned value to current band table range + case 2: new_band = BAND_160; break; + case 3: new_band = BAND_80; break; +#ifdef BAND_60 + case 4: new_band = BAND_60; break; +#endif + case 5: new_band = BAND_40; break; + case 6: new_band = BAND_30; break; + case 7: new_band = BAND_20; break; + case 8: new_band = BAND_17; break; + case 9: new_band = BAND_15; break; + case 10: new_band = BAND_12; break; + case 11: new_band = BAND_10; break; + default: new_band = BAND_UNKNOWN; error(3); break; + } + + if (new_band != state.band) { + digitalWrite(MUTE, LOW); // Make sure we are in receive mode + state.band = new_band; + setup_band(); // Set the band limits and default + // operating frequency for the selected band + display_band(); + delay(2000); // Allow time to view the band on the display + invalidate_display(); + } } +#endif // vim: tabstop=2 shiftwidth=2 expandtab: diff --git a/SODA_POP/buttons.ino b/SODA_POP/buttons.ino index 1d0fced..b486b38 100644 --- a/SODA_POP/buttons.ino +++ b/SODA_POP/buttons.ino @@ -150,7 +150,7 @@ unsigned int time_encoder_button() } /** - * Debounche the keyer button. + * Debounce the keyer button. */ void debounce_keyer() { diff --git a/SODA_POP/display.ino b/SODA_POP/display.ino index ad56ec1..249f013 100644 --- a/SODA_POP/display.ino +++ b/SODA_POP/display.ino @@ -165,8 +165,8 @@ void invalidate_display() case S_ERROR: state.display.digits[3] = LED_E; state.display.digits[2] = LED_r; - state.display.digits[1] = LED_r; - state.display.digits[0] = 0x00; + state.display.digits[0] = LED_DIGITS[errno / 10]; + state.display.digits[0] = LED_DIGITS[errno % 10]; state.display.dots = 0x2; break; } diff --git a/SODA_POP/settings.h b/SODA_POP/settings.h index df867b7..8ab9125 100644 --- a/SODA_POP/settings.h +++ b/SODA_POP/settings.h @@ -38,6 +38,9 @@ /* Band selection by pressing RIT for 2s */ #define OPT_BAND_SELECT +/* Autoband selection based on plugged in module with PCA9536 PIO */ +//#define OPT_AUTO_BAND + /* Erase EEPROM by pressing RIT for 8s */ #define OPT_ERASE_EEPROM @@ -48,7 +51,7 @@ #define OPT_DFE /* Disable display when idle */ -#define OPT_DISABLE_DISPLAY +//#define OPT_DISABLE_DISPLAY #define DISABLE_DISPLAY_AFTER 2500 /* Time to disable display after, in ms */ /* More message memories. Select using the rotary encoder. */