diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2015-12-03 19:49:18 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2015-12-03 19:49:18 +0100 |
commit | d9a1643b1ad937259c6ebebd43ce3101c3e2b8f6 (patch) | |
tree | fa79f57f1fdd48ef76ba17ba868d153366096220 /src | |
parent | 225b3a3742ab60473503fdb707c6fe941a4bb88f (diff) | |
download | glutte-o-matic-d9a1643b1ad937259c6ebebd43ce3101c3e2b8f6.tar.gz glutte-o-matic-d9a1643b1ad937259c6ebebd43ce3101c3e2b8f6.tar.bz2 glutte-o-matic-d9a1643b1ad937259c6ebebd43ce3101c3e2b8f6.zip |
Add fsm logic
Diffstat (limited to 'src')
-rw-r--r-- | src/fsm/src/common.h | 7 | ||||
-rw-r--r-- | src/fsm/src/fsm.c | 308 | ||||
-rw-r--r-- | src/fsm/src/fsm.h | 14 |
3 files changed, 323 insertions, 6 deletions
diff --git a/src/fsm/src/common.h b/src/fsm/src/common.h index 5381be0..45ba854 100644 --- a/src/fsm/src/common.h +++ b/src/fsm/src/common.h @@ -27,5 +27,12 @@ #ifndef _COMMON_H_ #define _COMMON_H_ +// Return the current timestamp in milliseconds. Timestamps are monotonic, and not +// wall clock time. +uint64_t timestamp_now(void); + +// Return either 0 or 1, somewhat randomly +int random_bool(void); + #endif // _COMMON_H_ diff --git a/src/fsm/src/fsm.c b/src/fsm/src/fsm.c index 6de1fe4..a6d2bcb 100644 --- a/src/fsm/src/fsm.c +++ b/src/fsm/src/fsm.c @@ -29,13 +29,315 @@ static struct fsm_input_signals_t fsm_in; static struct fsm_output_signals_t fsm_out; -// Keep track of when we last entered a given state -static uint64_t time_state[_NUM_FSM_STATES]; +static fsm_state_t current_state; + +// Keep track of when we last entered a given state, measured +// in ms using the timestamp_now() function +static uint64_t timestamp_state[_NUM_FSM_STATES]; void fsm_init() { memset(&fsm_in, 0, sizeof(fsm_in)); memset(&fsm_out, 0, sizeof(fsm_out)); - memset(time_state, 0, _NUM_FSM_STATES * sizeof(*time_state)); + memset(timestamp_state, 0, _NUM_FSM_STATES * sizeof(*timestamp_state)); + + current_state = FSM_OISIF; +} + +// Calculate the time spent in the current state +uint64_t fsm_current_state_time_ms(void) { + return timestamp_now() - timestamp_state[current_state]; +} + +uint64_t fsm_current_state_time_s(void) { + return fsm_current_state_time_ms() / 1000; +} + +// Between turns in a QSO, the repeater sends a letter in CW, +// different messages are possible. They are sorted here from +// low to high priority. +const char* letter_all_ok = "k"; +const char* letter_sstv = "s"; +const char* letter_qrp = "g"; +const char* letter_freq_high = "u"; +const char* letter_freq_low = "d"; +const char* letter_swr_high = "r"; + +const char* fsm_select_letter(void) { + if (fsm_in.swr_high) { + return letter_swr_high; + } + else if (fsm_in.discrim_d) { + return letter_freq_low; + } + else if (fsm_in.discrim_u) { + return letter_freq_high; + } + else if (fsm_in.qrp) { + return letter_qrp; + } + else if (fsm_in.sstv_mode) { + return letter_sstv; + } + + return letter_all_ok; +} + +void fsm_update() { + + fsm_state_t next_state = current_state; + + // Some defaults for the outgoing signals + fsm_out.tx_on = 0; + fsm_out.modulation = 0; + fsm_out.cw_trigger = 0; + // other output signals keep their value + + switch (current_state) { + case FSM_OISIF: + if (fsm_in.tone_1750 && fsm_in.sq) { + next_state = FSM_OPEN1; + } + else if (fsm_in.start_tm) { + if (fsm_in.qrp || fsm_in.swr_high) { + next_state = FSM_BALISE_SPECIALE; + } + else { + next_state = FSM_BALISE_LONGUE; + } + } + else if (!fsm_in.qrp && fsm_current_state_time_s() > 20 * 60) { + next_state = FSM_BALISE_COURTE; + } + break; + + case FSM_OPEN1: + fsm_out.tx_on = 1; + + if (!fsm_in.sq) { + next_state = FSM_OPEN2; + } + break; + + case FSM_OPEN2: + fsm_out.tx_on = 1; + fsm_out.modulation = 1; + + if (fsm_current_state_time_ms() > 200) { + next_state = FSM_LETTRE; + } + break; + + case FSM_LETTRE: + fsm_out.tx_on = 1; + fsm_out.modulation = 1; + fsm_out.cw_msg = fsm_select_letter(); + fsm_out.cw_trigger = 1; + + if (fsm_in.cw_done) { + next_state = FSM_ECOUTE; + } + break; + + case FSM_ECOUTE: + fsm_out.tx_on = 1; + fsm_out.modulation = 1; + + if (fsm_in.sq) { + next_state = FSM_QSO; + } + else if (fsm_current_state_time_s() > 6 && + timestamp_state[FSM_ECOUTE] - timestamp_state[FSM_OPEN2] < + 1000ul * 5) { + next_state = FSM_ATTENTE; + } + else if (fsm_current_state_time_s() > 5 && + timestamp_state[FSM_ECOUTE] - timestamp_state[FSM_OPEN2] < + 1000ul * 5 * 60) { + next_state = FSM_OISIF; + } + else if (fsm_current_state_time_s() > 5 && + timestamp_state[FSM_ECOUTE] - timestamp_state[FSM_OPEN2] < + 1000ul * 10 * 60) { + next_state = FSM_TEXTE_73; + } + else if (fsm_current_state_time_s() > 5 && + timestamp_state[FSM_ECOUTE] - timestamp_state[FSM_OPEN2] < + 1000ul * 15 * 60) { + next_state = FSM_TEXTE_HB9G; + } + else if (fsm_current_state_time_s() > 5 && + timestamp_state[FSM_ECOUTE] - timestamp_state[FSM_OPEN2] >= + 1000ul * 15 * 60) { + next_state = FSM_TEXTE_LONG; + } + break; + + case FSM_ATTENTE: + if (fsm_in.sq) { + next_state = FSM_ECOUTE; + } + else if (fsm_current_state_time_s() > 15) { + next_state = FSM_OISIF; + } + break; + + case FSM_QSO: + fsm_out.tx_on = 1; + fsm_out.modulation = 1; + + if (!fsm_in.sq) { + next_state = FSM_LETTRE; + } + else if (fsm_current_state_time_s() > 5 * 60) { + next_state = FSM_ANTI_BAVARD; + } + break; + + case FSM_ANTI_BAVARD: + fsm_out.tx_on = 1; + // No modulation! + fsm_out.cw_msg = "hi hi"; + fsm_out.cw_trigger = 1; + + if (fsm_in.cw_done) { + next_state = FSM_BLOQUE; + } + break; + + case FSM_BLOQUE: + if (fsm_current_state_time_s() > 10) { + next_state = FSM_OISIF; + } + break; + + case FSM_TEXTE_73: + fsm_out.tx_on = 1; + fsm_out.modulation = 1; + fsm_out.cw_msg = "73"; + fsm_out.cw_trigger = 1; + + if (fsm_in.sq) { + next_state = FSM_QSO; + } + else if (fsm_in.cw_done) { + next_state = FSM_OISIF; + } + break; + + case FSM_TEXTE_HB9G: + fsm_out.tx_on = 1; + fsm_out.modulation = 1; + fsm_out.cw_msg = "hb9g"; + fsm_out.cw_trigger = 1; + + if (fsm_in.sq) { + next_state = FSM_QSO; + } + else if (fsm_in.cw_done) { + next_state = FSM_OISIF; + } + break; + + case FSM_TEXTE_LONG: + fsm_out.tx_on = 1; + fsm_out.modulation = 1; + + if (random_bool()) { + fsm_out.cw_msg = "hb9g 1628m"; + } + else { + fsm_out.cw_msg = "hb9g jn36bk"; + } + fsm_out.cw_trigger = 1; + + if (fsm_in.sq) { + next_state = FSM_QSO; + } + else if (fsm_in.cw_done) { + next_state = FSM_OISIF; + } + break; + + case FSM_BALISE_LONGUE: + fsm_out.tx_on = 1; + + // TODO transmit humidity + // TODO read voltage + if (fsm_in.wind_generator_ok) { + fsm_out.cw_msg = "hb9g jn36bk 1628m u 10v5 = T 11 73"; + // = means same voltage as previous + // + means higher + // - means lower + } + else { + fsm_out.cw_msg = "hb9g jn36bk 1628m u 10v5 = T 11 #"; + // The # is the SK digraph + } + fsm_out.cw_trigger = 1; + + if (fsm_in.sq) { + next_state = FSM_OPEN2; + } + else if (fsm_in.cw_done) { + next_state = FSM_OISIF; + } + break; + + case FSM_BALISE_SPECIALE: + fsm_out.tx_on = 1; + // TODO read voltage + if (fsm_in.wind_generator_ok) { + fsm_out.cw_msg = "hb9g u 10v5 73"; + } + else { + fsm_out.cw_msg = "hb9g u 10v5 #"; // The # is the SK digraph + } + fsm_out.cw_trigger = 1; + + if (fsm_in.sq) { + next_state = FSM_OPEN2; + } + else if (fsm_in.cw_done) { + next_state = FSM_OISIF; + } + break; + + case FSM_BALISE_COURTE: + fsm_out.tx_on = 1; + + { + int rand = random_bool() * 2 + random_bool(); + + if (rand == 0) { + fsm_out.cw_msg = "hb9g"; + } + else if (rand == 1) { + fsm_out.cw_msg = "hb9g jn36bk"; + } + else if (rand == 2) { + fsm_out.cw_msg = "hb9g 1628m"; + } + else { + fsm_out.cw_msg = "hb9g jn36bk 1628m"; + } + } + fsm_out.cw_trigger = 1; + + if (fsm_in.sq) { + next_state = FSM_OPEN2; + } + else if (fsm_in.cw_done) { + next_state = FSM_OISIF; + } + break; + default: + // Should never happen + next_state = FSM_OISIF; + break; + } + + current_state = next_state; + timestamp_state[next_state] = timestamp_now(); } diff --git a/src/fsm/src/fsm.h b/src/fsm/src/fsm.h index 869c2c1..16e864a 100644 --- a/src/fsm/src/fsm.h +++ b/src/fsm/src/fsm.h @@ -26,7 +26,7 @@ #define _FSM_H_ // List of all states the FSM of the relay can be in -enum fsm_state_t { +enum fsm_state_e { FSM_OISIF = 0, // Idle FSM_OPEN1, // 1750 Hz received and squelch open FSM_OPEN2, // Squelch closed @@ -36,14 +36,17 @@ enum fsm_state_t { FSM_QSO, // QSO ongoing FSM_ANTI_BAVARD, // QSO too long, cut transmission FSM_BLOQUE, // Backoff after ANTI_BAVARD - FSM_LONG_TEXTE, // Transmit long notice after QSO - FSM_TEXTE_HB9G, // Transmit short notice after QSO + FSM_TEXTE_73, // Transmit 73 after QSO + FSM_TEXTE_HB9G, // Transmit HB9G after QSO + FSM_TEXTE_LONG, // Transmit either HB9G JN36BK or HB9G 1628M after QSO FSM_BALISE_LONGUE, // Full-length 2-hour beacon FSM_BALISE_SPECIALE, // 2-hour beacon when in QRP or with high power return mode FSM_BALISE_COURTE, // Short intermittent beacon _NUM_FSM_STATES // Dummy state to count the number of states }; +typedef enum fsm_state_e fsm_state_t; + // All signals that the FSM can read, most of them are actually booleans struct fsm_input_signals_t { /* Signals coming from repeater electronics */ @@ -57,9 +60,14 @@ struct fsm_input_signals_t { int wind_generator_ok; // false if the generator is folded out of the wind int discrim_d; // FM discriminator says RX is too low in frequency int tone_1750; // Detect 1750Hz tone + int sstv_mode; // The 1750Hz filter is disabled, permitting SSTV usage /* Signals coming from CW generator */ int cw_done; // The CW generator has finished transmitting the message + + /* Signal coming from the standing wave ratio meter */ + int swr_high; // We see a lot of return power + }; // All signals the FSM has to control |