This commit is contained in:
Jim Colderwood 2024-04-01 18:21:09 +01:00
commit 8c790fa4e0
6 changed files with 362 additions and 0 deletions

129
GB3TX/GB3TX.ino Normal file
View File

@ -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);
}
}

34
GB3TX/config.h Normal file
View File

@ -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

44
GB3TX/cw.h Normal file
View File

@ -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

50
GB3TX/cw.ino Normal file
View File

@ -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);
}
}

62
GB3TX/repeater.h Normal file
View File

@ -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

43
GB3TX/repeater.ino Normal file
View File

@ -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);
}