commit 8c790fa4e0cd78b98b22d0458386ed1459741a3c Author: Jim Colderwood Date: Mon Apr 1 18:21:09 2024 +0100 GB3TX diff --git a/GB3TX/GB3TX.ino b/GB3TX/GB3TX.ino new file mode 100644 index 0000000..3a2f685 --- /dev/null +++ b/GB3TX/GB3TX.ino @@ -0,0 +1,129 @@ +#include "config.h" +#include "repeater.h" + +#define PIP_OUT 13 + +void setup() { + pinMode(3, OUTPUT); + pinMode(8, OUTPUT); + pinMode(9, OUTPUT); + pinMode(7, INPUT); + pinMode(6, INPUT_PULLUP); +} + +void loop() { + repeater rpt; + repeater* myrpt; + myrpt = &rpt; + myrpt->callsign = ID; + myrpt->params.cw_pitch = CW_PITCH; + + /* Setup params */ + myrpt->params.cw_speed = 1200 / CW_SPEED; + myrpt->params.pip_length = RFPIPLEN; + myrpt->params.pip_pitch = RFPIP; + myrpt->params.pip_gw_length = GWPIPLEN; + myrpt->params.pip_gw_pitch = GWPIP; + myrpt->params.courtesy = COURTESY; + myrpt->params.pip_speed = 1200 / PIP_SPEED; + myrpt->params.pip_letter = PIP_LETTER; + myrpt->params.pip_gw_letter = PIP_GW_LETTER; + + delay(1000); + myrpt->state = SLEEP; + digitalWrite(PTT,HIGH); + digitalWrite(GWPTT, false); + + + unsigned long ht = millis(); + unsigned long tot = ht; + unsigned long kc; + unsigned long id = ht; + while (1) { + rx(myrpt); + + if (myrpt->state > SLEEP && millis() - id >= IDTIME) { + /* Repeater is IDLE, bring the transmitter up */ + if (myrpt->state == IDLE) { + myrpt->state = KEYCHUNK; + tx(myrpt); + myrpt->state = SLEEP; + } + sendID(myrpt); + id = millis(); + } + + if (((!myrpt->receiver.rx || !myrpt->gateway.receiver.rx)) && myrpt->state < 2) { + myrpt->state = KEYCHUNK; + if (!myrpt->receiver.rx) + kc = millis(); + } + + if (myrpt->state == KEYCHUNK && millis() - kc > KEYCHUNK_TIME) { + if (!myrpt->receiver.rx) { + myrpt->state = TT; + } else { + myrpt->state = GW; + } + tot = millis(); + } + + if ((myrpt->receiver.rx && myrpt->gateway.receiver.rx) && myrpt->state == KEYCHUNK) { + myrpt->state = IDLE; + } + + if ((myrpt->receiver.rx && myrpt->gateway.receiver.rx) && myrpt->state > HANG) { + myrpt->last = myrpt->state; + myrpt->state = HANG; + ht = millis(); + if (ht - tot < PIP_KEYCHUNK) + continue; + delay(350); + if (!digitalRead(COS)) { + continue; + } + courtesyTone(myrpt); + } + + if (myrpt->state == HANG && TAILPIPS) { + static unsigned long bc = millis(); + if (millis() - bc >= 1000) { + bc = millis(); + tone(3, myrpt->params.pip_pitch - 500, myrpt->params.pip_length * 1); + } + } + + if (!myrpt->receiver.rx && myrpt->state == HANG) { + myrpt->state = TT; + tot = millis(); + } + + if (!myrpt->gateway.receiver.rx && myrpt->state == HANG) { + myrpt->state = GW; + tot = millis(); + } + + if (myrpt->state == HANG && millis() - ht > HANGTIME) { + myrpt->state = IDLE; + } + + if (millis() - tot >= TIMEOUT && (myrpt->state == TT || myrpt->state == GW)) { + myrpt->state = TIMEOUT; + tone(3, 440, 1000); + delay(1000); + } + + if (myrpt->state == TIMEOUT) { + myrpt->state = IDLE; + tx(myrpt); + while (1) { + rx(myrpt); + if (myrpt->receiver.rx && myrpt->gateway.receiver.rx) + break; + } + } + + tx(myrpt); + } + +} \ No newline at end of file diff --git a/GB3TX/config.h b/GB3TX/config.h new file mode 100644 index 0000000..34a612b --- /dev/null +++ b/GB3TX/config.h @@ -0,0 +1,34 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* IO */ +#define GW_COS 6 +#define COS 7 +#define PTT 8 +#define GWPTT 9 +#define PIP 3 + +/* CW ID SETTINGS */ +#define ID "M0ZAH/R" +#define CW_SPEED 22 +#define CW_PITCH 875 + +/* PARAMS */ +#define COURTESY TONE +#define GWPIP 875 +#define GWPIPLEN 120 +#define PIP_LETTER 'K' +#define PIP_GW_LETTER 'R' +#define PIP_SPEED 18 +#define RFPIP 1200 +#define RFPIPLEN 80 +#define TAILPIPS false + +/* TIMERS */ +#define HANGTIME 2000 +#define KEYCHUNK_TIME 1000 +#define TIMEOUT 300000 +#define IDTIME 300000 +#define PIP_KEYCHUNK 1500 + +#endif \ No newline at end of file diff --git a/GB3TX/cw.h b/GB3TX/cw.h new file mode 100644 index 0000000..62aa6da --- /dev/null +++ b/GB3TX/cw.h @@ -0,0 +1,44 @@ +#ifndef CW_H +#define CW_H + +int morse[] = { + 0b00101001, // / + 0b00111111, // 0 + 0b00111110, // 1 + 0b00111100, // 2 + 0b00111000, // 3 + 0b00110000, // 4 + 0b00100000, // 5 + 0b00100001, // 6 + 0b00100011, // 7 + 0b00100111, // 8 + 0b00101111, // 9 + 0b00000110, // A + 0b00010001, // B + 0b00010101, // C + 0b00001001, // D + 0b00000010, // E + 0b00010100, // F + 0b00001011, // G + 0b00010000, // H + 0b00000100, // I + 0b00011110, // J + 0b00001101, // K + 0b00010010, // L + 0b00000111, // M + 0b00000101, // N + 0b00001111, // O + 0b00010110, // P + 0b00011011, // Q + 0b00001010, // R + 0b00001000, // S + 0b00000011, // T + 0b00001100, // U + 0b00011000, // V + 0b00001110, // W + 0b00011001, // X + 0b00011101, // Y + 0b00010011, // Z +}; + +#endif \ No newline at end of file diff --git a/GB3TX/cw.ino b/GB3TX/cw.ino new file mode 100644 index 0000000..7a78d84 --- /dev/null +++ b/GB3TX/cw.ino @@ -0,0 +1,50 @@ +#include "cw.h" + +void sendChar(int speed, int pitch, char c) { + if (c < 47 || c > 90) { + delay(speed * 3 * 2); + return; + } + + if (c > 57 && c < 65) { + return; + } + + int index = c - 47; + if (c >= 65) { + index = c - 54; + } + + if (index >= sizeof morse/sizeof morse[0]) + return; + + int dd = morse[index]; + + for (int i=0; i < 8; i++) { + if (dd == 1) { + return; + } + tone(3, pitch); + if (dd&1) { + delay(speed * 3); + } else { + delay(speed); + } + dd >>= 1; + noTone(3); + delay(speed); + } +} + +void sendID(repeater* myrpt) { + if (myrpt->callsign == NULL) { + return; + } + + for (int i=0; i < sizeof ID/sizeof ID[0]; i++) { + sendChar(myrpt->params.cw_speed, myrpt->params.cw_pitch, myrpt->callsign[i]); + delay(myrpt->params.cw_speed * 3); + } + +} + diff --git a/GB3TX/repeater.h b/GB3TX/repeater.h new file mode 100644 index 0000000..a41f60d --- /dev/null +++ b/GB3TX/repeater.h @@ -0,0 +1,62 @@ +#ifndef REPEATER_H +#define REPEATER_H + +typedef enum { + SLEEP, + IDLE, + KEYCHUNK, + HANG, + GW, + TT, + TOT, +}state; + +typedef enum { + TONE, + CW, +}c_type; + +typedef struct { + c_type courtesy; + int cw_pitch; + int cw_speed; + int pip_length; + char pip_letter; + int pip_pitch; + int pip_speed; + int pip_gw_length; + char pip_gw_letter; + int pip_gw_pitch; +}params; + +typedef struct { + bool tx; + unsigned long long tx_time; +}transmitter; + +typedef struct { + int id; + bool rx; + unsigned long long rx_time; +}receiver; + +typedef struct { + bool enable; + receiver receiver; + transmitter transmitter; +}gateway; + +typedef struct { + char* callsign; + int cw_pitch; + gateway gateway; + int hangtime; + unsigned long id_time; + state last; + params params; + receiver receiver; + state state; + transmitter transmitter; +}repeater; + +#endif \ No newline at end of file diff --git a/GB3TX/repeater.ino b/GB3TX/repeater.ino new file mode 100644 index 0000000..929c86a --- /dev/null +++ b/GB3TX/repeater.ino @@ -0,0 +1,43 @@ +void tx(repeater* myrpt) { + if (myrpt->state > 1 && !myrpt->transmitter.tx) { + myrpt->transmitter.tx = true; + digitalWrite(PTT,LOW); + delay(100); + return; + } + + if (!myrpt->transmitter.tx) + return; + + myrpt->transmitter.tx = false; + digitalWrite(PTT,HIGH); +} + +void rx(repeater* myrpt) { + myrpt->receiver.rx = digitalRead(COS); + myrpt->gateway.receiver.rx = digitalRead(GW_COS); + + if (!myrpt->receiver.rx && !myrpt->gateway.transmitter.tx) { + digitalWrite(GWPTT, true); + myrpt->gateway.transmitter.tx = true; + return; + } + + if (myrpt->gateway.transmitter.tx) { + digitalWrite(GWPTT, false); + myrpt->gateway.transmitter.tx = false; + } +} + +void courtesyTone(repeater* myrpt) { + switch(myrpt->params.courtesy) { + case 0: + myrpt->last == TT ? tone(3, myrpt->params.pip_pitch, myrpt->params.pip_length) : tone(3, myrpt->params.pip_gw_pitch, myrpt->params.pip_gw_length); + break; + case 1: + myrpt->last == TT ? sendChar(myrpt->params.pip_speed,myrpt->params.pip_pitch,myrpt->params.pip_letter) : sendChar(myrpt->params.pip_speed,myrpt->params.pip_gw_pitch, myrpt->params.pip_gw_letter); + break; + } + if (TAILPIPS) + delay(150); +} \ No newline at end of file