update dtmf, morse, and examples

This commit is contained in:
Morgan Redfield 2019-07-14 13:37:14 -07:00
parent 71acbbb975
commit 3d3f6a36b6
16 changed files with 727 additions and 331 deletions

View File

@ -52,7 +52,7 @@ void setup() {
Serial.begin(9600); Serial.begin(9600);
radio.initialize(); radio.initialize();
radio.frequency(145570); radio.frequency(144390); // default aprs frequency in North America
radio.setRfPower(0); radio.setRfPower(0);
radio.setVolume1(0xFF); radio.setVolume1(0xFF);
radio.setVolume2(0xFF); radio.setVolume2(0xFF);

View File

@ -36,7 +36,7 @@ void setup() {
Serial.println("Setting radio to its defaults.."); Serial.println("Setting radio to its defaults..");
radio.initialize(); radio.initialize();
radio.setRfPower(0); radio.setRfPower(0);
radio.frequency(146520); radio.frequency(432100); // 70cm calling frequency
radio.setModeReceive(); radio.setModeReceive();
} }

View File

@ -75,13 +75,11 @@ void setup() {
radio.initialize(); // initializes automatically for UHF 12.5kHz channel radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration"); Serial.println("setting default Radio configuration");
radio.dangerMode();
// set frequency // set frequency
Serial.println("changing frequency"); Serial.println("changing frequency");
radio.setSQOff(); freq = 432100; // 70cm calling frequency
freq = 446000;
radio.frequency(freq); radio.frequency(freq);
// set to receive // set to receive
@ -92,6 +90,11 @@ void setup() {
Serial.println(radio.readCtlReg()); Serial.println(radio.readCtlReg());
Serial.println(radio.readRSSI()); Serial.println(radio.readRSSI());
// set up squelch
radio.setSQLoThresh(-80);
radio.setSQHiThresh(-70);
radio.setSQOn();
radio.setRfPower(0); radio.setRfPower(0);
// CTCSS Setup code // CTCSS Setup code

View File

@ -72,7 +72,7 @@ void setup() {
//radio.setSQOff(); //radio.setSQOff();
Serial.println("setting frequency to: "); Serial.println("setting frequency to: ");
freq = 432250; freq = 432100; // 70cm calling frequency
radio.frequency(freq); radio.frequency(freq);
Serial.print(radio.getFrequency()); Serial.print(radio.getFrequency());
Serial.println("kHz"); Serial.println("kHz");
@ -104,38 +104,18 @@ void setup() {
Serial.println("ready"); Serial.println("ready");
} }
char rx_dtmf_buf[255];
int rx_dtmf_idx = 0;
void loop() { void loop() {
// look for tone // look for tone
if (radio.getDTMFSample() != 0) { char m = radio.DTMFRxLoop();
uint16_t code = radio.getDTMFCode(); if (m != 0) {
Serial.print(m);
rx_dtmf_buf[rx_dtmf_idx++] = code2char(code);
// reset after this tone
int j = 0;
while (j < 4) {
if (radio.getDTMFSample() == 0) {
j++;
} else {
j = 1;
}
delay(10);
}
// reset read
//radio.enableDTMFReceive();
} else if (rx_dtmf_idx > 0) {
rx_dtmf_buf[rx_dtmf_idx] = '\0'; // NULL terminate the string
Serial.println(rx_dtmf_buf);
rx_dtmf_idx = 0;
} }
// Is it time to send tone? // Is it time to send tone?
if (Serial.available()) { if (Serial.available()) {
// get first code // get first code
uint8_t code = char2code(Serial.read()); uint8_t code = radio.DTMFchar2code(Serial.read());
// start transmitting // start transmitting
radio.setDTMFCode(code); // set first radio.setDTMFCode(code); // set first
@ -151,7 +131,7 @@ void loop() {
delay(10); delay(10);
} }
if (Serial.available()) { if (Serial.available()) {
code = char2code(Serial.read()); code = radio.DTMFchar2code(Serial.read());
if (code == 255) code = 0xE; // throw a * in there so we don't break things with an invalid code if (code == 255) code = 0xE; // throw a * in there so we don't break things with an invalid code
radio.setDTMFCode(code); // set first radio.setDTMFCode(code); // set first
} else { } else {
@ -170,38 +150,3 @@ void loop() {
radio.setTxSourceMic(); radio.setTxSourceMic();
} }
} }
uint8_t char2code(char c) {
uint8_t code;
if (c == '#') {
code = 0xF;
} else if (c=='*') {
code = 0xE;
} else if (c >= 'A' && c <= 'D') {
code = c - 'A' + 0xA;
} else if (c >= '0' && c <= '9') {
code = c - '0';
} else {
// invalid code, skip it
code = 255;
}
return code;
}
char code2char(uint16_t code) {
char c;
if (code < 10) {
c = '0' + code;
} else if (code < 0xE) {
c = 'A' + code - 10;
} else if (code == 0xE) {
c = '*';
} else if (code == 0xF) {
c = '#';
} else {
c = '?'; // invalid code
}
return c;
}

View File

@ -57,8 +57,8 @@ void setup() {
radio.setMorseFreq(600); radio.setMorseFreq(600);
radio.setMorseDotMillis(100); radio.setMorseDotMillis(100);
// Configure the HamShield to operate on 438.000MHz // Configure the HamShield
radio.frequency(438000); radio.frequency(432300); // 70cm beacon frequency
Serial.println("Radio Configured."); Serial.println("Radio Configured.");
} }

View File

@ -61,8 +61,8 @@ void setup() {
radio.setMorseFreq(600); radio.setMorseFreq(600);
radio.setMorseDotMillis(100); radio.setMorseDotMillis(100);
// Configure the HamShield to operate on 438.000Mhz // Configure the HamShield frequency
radio.frequency(438000); radio.frequency(432400);
Serial.println("Radio configured."); Serial.println("Radio configured.");
} }

View File

@ -72,13 +72,12 @@ void setup() {
radio.initialize(); // initializes automatically for UHF 12.5kHz channel radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration"); Serial.println("setting default Radio configuration");
radio.dangerMode();
// set frequency // set frequency
Serial.println("changing frequency"); Serial.println("changing frequency");
radio.setSQOff(); radio.setSQOff();
freq = 446000; freq = 432100; // 70cm calling frequency
radio.frequency(freq); radio.frequency(freq);
// set to receive // set to receive

View File

@ -126,7 +126,7 @@ void setup() {
Serial.println("changing frequency"); Serial.println("changing frequency");
radio.setSQOff(); radio.setSQOff();
freq = 446000; freq = 432100; // 70cm calling frequency
radio.frequency(freq); radio.frequency(freq);
// set to receive // set to receive

View File

@ -36,28 +36,9 @@
// Note that all timing is defined in terms of MORSE_DOT relative durations // Note that all timing is defined in terms of MORSE_DOT relative durations
// You may want to tweak those timings below // You may want to tweak those timings below
#define SYMBOL_END_TIME 5 //millis
#define CHAR_END_TIME (MORSE_DOT*2.7)
#define MESSAGE_END_TIME (MORSE_DOT*8)
#define MIN_DOT_TIME (MORSE_DOT-30)
#define MAX_DOT_TIME (MORSE_DOT+55)
#define MIN_DASH_TIME (MORSE_DOT*3-30)
#define MAX_DASH_TIME (MORSE_DOT*3+55)
HamShield radio; HamShield radio;
uint32_t last_tone_check; // track how often we check for morse tones
uint32_t tone_in_progress; // track how long the current tone lasts
uint32_t space_in_progress; // track how long since the last tone
uint8_t rx_morse_char;
uint8_t rx_morse_bit;
bool bits_to_process;
char rx_msg[128];
uint8_t rx_idx;
// Run our start up things here // Run our start up things here
void setup() { void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise // NOTE: if not using PWM out, it should be held low to avoid tx noise
@ -93,68 +74,19 @@ void setup() {
radio.setMorseDotMillis(MORSE_DOT); radio.setMorseDotMillis(MORSE_DOT);
radio.lookForTone(MORSE_FREQ); radio.lookForTone(MORSE_FREQ);
radio.setupMorseRx();
// Configure the HamShield to operate on 438.000MHz // Configure the HamShield frequency
radio.frequency(432000); radio.frequency(432100); // 70cm calling frequency
radio.setModeReceive(); radio.setModeReceive();
Serial.println("Radio Configured."); Serial.println("Radio Configured.");
last_tone_check = millis();
space_in_progress = 0; // haven't checked yet
tone_in_progress = 0; // not currently listening to a tone
rx_morse_char = 0; // haven't found any tones yet
rx_idx = 0;
rx_morse_bit = 1;
bits_to_process = false;
} }
void loop() { void loop() {
// are we receiving anything char rx_char = radio.morseRxLoop();
if (radio.toneDetected()) { if (rx_char != 0) {
space_in_progress = 0; Serial.print(rx_char);
if (tone_in_progress == 0) {
// start a new tone
tone_in_progress = millis();
//Serial.print('t');
}
} else {
// keep track of how long the silence is
if (space_in_progress == 0) space_in_progress = millis();
// we wait for a bit of silence before ending the last
// symbol in order to smooth out the detector
if ((millis() - space_in_progress) > SYMBOL_END_TIME)
{
if (tone_in_progress != 0) {
// end the last tone
uint16_t tone_time = millis() - tone_in_progress;
tone_in_progress = 0;
//Serial.println(tone_time);
handleTone(tone_time);
}
}
// we might be done with a character if the space is long enough
if (((millis() - space_in_progress) > CHAR_END_TIME) && bits_to_process) {
char m = parseMorse();
bits_to_process = false;
if (m != 0) {
rx_msg[rx_idx++] = m;
}
}
// we might be done with a message if the space is long enough
if ((millis() - space_in_progress) > MESSAGE_END_TIME) {
if (rx_idx > 0) {
// we got a message, print it now
rx_msg[rx_idx] = '\0'; // null terminate
Serial.println(rx_msg);
rx_idx = 0; // reset message buffer
}
rx_morse_char = 0;
rx_morse_bit = 1;
}
} }
// should we send anything // should we send anything
@ -181,9 +113,9 @@ void loop() {
radio.morseOut(morse_buf); radio.morseOut(morse_buf);
// We're done sending the message, set the radio back into recieve mode. // We're done sending the message, set the radio back into recieve mode.
Serial.println("sent");
radio.setModeReceive(); radio.setModeReceive();
radio.lookForTone(MORSE_FREQ); radio.lookForTone(MORSE_FREQ);
Serial.println("sent");
} else { } else {
// If we get here, the channel is busy. Let's also print out the RSSI. // If we get here, the channel is busy. Let's also print out the RSSI.
Serial.print("The channel was busy. RSSI: "); Serial.print("The channel was busy. RSSI: ");
@ -192,34 +124,4 @@ void loop() {
} }
} }
void handleTone(uint16_t tone_time) {
//Serial.println(tone_time);
if (tone_time > MIN_DOT_TIME && tone_time < MAX_DOT_TIME) {
// add a dot
//Serial.print(".");
bits_to_process = true;
//nothing to do for this bit position, since . = 0
} else if (tone_time > MIN_DASH_TIME && tone_time < MAX_DASH_TIME) {
// add a dash
//Serial.print("-");
bits_to_process = true;
rx_morse_char += rx_morse_bit;
}
// prep for the next bit
rx_morse_bit = rx_morse_bit << 1;
}
char parseMorse() {
// if morse_char is a valid morse character, return the character
// if morse_char is an invalid (incomplete) morse character, return 0
//if (rx_morse_bit != 1) Serial.println(rx_morse_char, BIN);
rx_morse_char += rx_morse_bit; // add the terminator bit
// if we got a char, then print it
char c = radio.morseReverseLookup(rx_morse_char);
rx_morse_char = 0;
rx_morse_bit = 1;
return c;
}

View File

@ -54,7 +54,7 @@ void setup() {
// Tell the HamShield to start up // Tell the HamShield to start up
radio.initialize(); radio.initialize();
radio.setRfPower(0); radio.setRfPower(0);
radio.frequency(145500); radio.frequency(446000);
// put your setup code here, to run once: // put your setup code here, to run once:
//dds.setReferenceClock(34965/4); //dds.setReferenceClock(34965/4);
dds.start(); dds.start();

View File

@ -15,22 +15,32 @@
* R1; * R1;
* [Just a space] * [Just a space]
// see also: https://github.com/EnhancedRadioDevices/HamShield/wiki/HamShield-Serial-Mode
Commands: Commands:
Mode ASCII Description Implemented Mode ASCII Description
-------------- ----------- -------------------------------------------------------------------------------------------------------------------------------------------- ----------------- -------------- ----------- --------------------------------------------------------------------------------------------------------------------------------------------
Transmit space Space must be received at least every 500 mS Yes Transmit space Space must be received at least every 500 mS
Receive not space If space is not received and/or 500 mS timeout of space occurs, unit will go into receive mode Yes Receive not space If space is not received and/or 500 mS timeout of space occurs, unit will go into receive mode
Bandwidth E<mode>; for 12.5KHz mode is 0, for 25KHz, mode is 1 No Frequency F<freq>; Set the receive frequency in KHz, if offset is disabled, this is the transmit frequency
Frequency F<freq>; Set the receive frequency in KHz, if offset is disabled, this is the transmit frequency No
Morse Out M<text>; A small buffer for morse code (32 chars) Morse Out M<text>; A small buffer for morse code (32 chars)
Power level P<level>; Set the power amp level, 0 = lowest, 15 = highest No Morse In N; Sets mode to Morse In, listening for Morse
Enable Offset R<state>; 1 turns on repeater offset mode, 0 turns off repeater offset mode No Power level P<level>; Set the power amp level, 0 = lowest, 15 = highest
Squelch S<level>; Set the squelch level No Enable Offset R<state>; 1 turns on repeater offset mode, 0 turns off repeater offset mode
TX Offset T<freq>; The absolute frequency of the repeater offset to transmit on in KHz No Squelch S<level>; Set the squelch level
RSSI ?; Respond with the current receive level in - dBm (no sign provided on numerical response) No TX Offset T<freq>; The absolute frequency of the repeater offset to transmit on in KHz
Voice Level ^; Respond with the current voice level (VSSI) RSSI ? Respond with the current receive level in - dBm (no sign provided on numerical response)
Voice Level ^ Respond with the current voice level (VSSI), only valid when transmitting
DTMF Out D<vals>; A small buffer for DTMF out (only 0-9,A,B,C,D,*,# accepted)
DTMF In B; Sets mode to DTMF In, listening for DTMF
PL Tone Tx A<val>; Sets PL tone for TX, value is tone frequency in Hz (float), set to 0 to disable
PL Tone Rx C<val>; Sets PL tone for RX, value is tone frequency in Hz (float), set to 0 to disable
Volume 1 V1<val>; Set volume 1 (value between 0 and 15)
Volume 2 V2<val>; Set volume 2 (value between 0 and 15)
KISS TNC K; Move to KISS TNC mode (send ^; to move back to normal mode). NOT IMPELEMENTED YET
Normal Mode _ Move to Normal mode from any other mode (except TX)
Responses: Responses:
@ -42,23 +52,44 @@ Error X<code>; Indicates an error code. The numerical value is the type
Value :<value>; In response to a query Value :<value>; In response to a query
Status #<value>; Unsolicited status message Status #<value>; Unsolicited status message
Debug Msg @<text>; 32 character debug message Debug Msg @<text>; 32 character debug message
Rx Msg R<text>; up to 32 characters of received message, only if device is in DTMF or Morse Rx modes
*/ */
// Note that the following are not yet implemented
// TODO: change get_value so it's intuitive
// TODO: Squelch open and squelch shut independently controllable
// TODO: pre/de emph filter
// TODO: walkie-talkie
// TODO: KISS TNC
#include "HamShield.h" #include "HamShield.h"
#define MIC_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
int state; enum {TX, NORMAL, DTMF, MORSE, KISS};
int state = NORMAL;
bool rx_ctcss = false;
bool muted = false;
int txcount = 0; int txcount = 0;
long timer = 0; long timer = 0; // Transmit timer to track timeout (send space to reset)
long freq = 144390;
long tx = 0; long freq = 432100; // 70cm calling frequency, receive frequency and default transmit frequency
long tx_freq = 0; // transmit frequency if repeater is on
int pwr = 0; // tx power
char cmdbuff[32] = ""; char cmdbuff[32] = "";
int temp = 0; int temp = 0;
int repeater = 0;
bool repeater = false; // true if transmit and receive operate on different frequencies
char pl_rx_buffer[32]; // pl tone rx buffer
char pl_tx_buffer[32]; // pl tone tx buffer
float ctcssin = 0; float ctcssin = 0;
float ctcssout = 0; float ctcssout = 0;
int cdcssin = 0; int cdcssin = 0;
@ -67,10 +98,8 @@ int cdcssout = 0;
HamShield radio; HamShield radio;
void setup() { void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise // NOTE: if not using PWM out (MIC pin), it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW); digitalWrite(MIC_PIN, LOW);
@ -80,7 +109,6 @@ void setup() {
// set up the reset control pin // set up the reset control pin
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up
Serial.begin(9600); Serial.begin(9600);
Serial.println(";;;;;;;;;;;;;;;;;;;;;;;;;;"); Serial.println(";;;;;;;;;;;;;;;;;;;;;;;;;;");
@ -90,111 +118,282 @@ void setup() {
Serial.print(result,DEC); Serial.print(result,DEC);
Serial.println(";"); Serial.println(";");
radio.initialize(); // initializes automatically for UHF 12.5kHz channel radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("*START;");
radio.frequency(freq); radio.frequency(freq);
radio.setVolume1(0xF); radio.setVolume1(0xF);
radio.setVolume2(0xF); radio.setVolume2(0xF);
radio.setModeReceive(); radio.setModeReceive();
radio.setTxSourceMic(); radio.setTxSourceMic();
radio.setRfPower(0); radio.setRfPower(pwr);
radio.setSQLoThresh(80); radio.setSQLoThresh(-80);
radio.setSQHiThresh(-70);
radio.setSQOn(); radio.setSQOn();
Serial.println("*START;");
} }
void loop() { void loop() {
if(Serial.available()) { if(Serial.available()) {
int text = Serial.read(); int text = Serial.read(); // get the first char to see what the upcoming command is
switch (state) { switch (state) {
// we handle commands differently based on what state we're in
case 10: case TX:
if(text == 32) { timer = millis();} // we're currently transmitting
// if we got a space, reset our transmit timeout
if(text == ' ') { timer = millis();}
break; break;
case 0: case NORMAL:
switch(text) { switch(text) {
case ' ': // space - transmit
case 32: // space - transmit if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
if(repeater == 1) { radio.frequency(tx); } muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit(); radio.setModeTransmit();
state = 10; state = TX;
Serial.println("#TX,ON;"); Serial.println("#TX,ON;");
timer = millis(); timer = millis();
break; break;
case 63: // ? - RSSI case '?': // ? - RSSI
Serial.print(":"); Serial.print(":");
Serial.print(radio.readRSSI(),DEC); Serial.print(radio.readRSSI(),DEC);
Serial.println(";"); Serial.println(";");
break; break;
case 65: // A - CTCSS In case '^': // ^ - VSSI (voice) level
getValue(); Serial.print(":");
ctcssin = atof(cmdbuff); Serial.print(radio.readVSSI(),DEC);
radio.setCtcss(ctcssin); Serial.println(";");
break; break;
case 66: // B - CTCSS Out case 'F': // F - frequency
break;
case 67: // C - CTCSS Enable
break;
case 68: // D - CDCSS Enable
break;
case 70: // F - frequency
getValue(); getValue();
freq = atol(cmdbuff); freq = atol(cmdbuff);
if(radio.frequency(freq) == true) { Serial.print("@"); Serial.print(freq,DEC); Serial.println(";!;"); } else { Serial.println("X1;"); } if(radio.frequency(freq) == true) {
Serial.print("@");
Serial.print(freq,DEC);
Serial.println(";!;");
} else {
Serial.println("X1;");
}
break; break;
case 'M': case 'P': // P - power level
getValue();
radio.setModeTransmit();
delay(300);
radio.morseOut(cmdbuff);
state = 10;
break;
case 80: // P - power level
getValue(); getValue();
temp = atol(cmdbuff); temp = atol(cmdbuff);
radio.setRfPower(temp); radio.setRfPower(temp);
Serial.println("!;");
break; break;
case 82: // R - repeater offset mode case 'S': // S - squelch
getValue();
temp = atol(cmdbuff);
if (temp < -2 && temp > -130) {
radio.setSQLoThresh(temp);
radio.setSQHiThresh(temp+2);
radio.setSQOn();
Serial.print(temp);
Serial.println("!;");
} else {
Serial.println("X!;");
}
break;
case 'R': // R - repeater offset mode
getValue(); getValue();
temp = atol(cmdbuff); temp = atol(cmdbuff);
if(temp == 0) { repeater = 0; } if(temp == 0) { repeater = 0; }
if(temp == 1) { repeater = 1; } if(temp == 1) { repeater = 1; }
Serial.println("!;");
break; break;
case 83: // S - squelch case 'T': // T - transmit offset
getValue(); getValue();
temp = atol(cmdbuff); tx_freq = atol(cmdbuff);
radio.setSQLoThresh(temp); Serial.println("!;");
break; break;
case 84: // T - transmit offset case 'M': // M - Morse
getValue(); getValue();
tx = atol(cmdbuff); if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
delay(300);
radio.morseOut(cmdbuff);
if(repeater == true) { radio.frequency(freq); }
radio.setModeReceive();
Serial.println("!;");
break; break;
case 'N': // N - set to Morse in Mode
morse_rx_setup();
state = MORSE;
Serial.println("!;");
break;
case 94: // ^ - VSSI (voice) level case 'D': // D - DTMF Out
Serial.print(":"); dtmfSetup();
Serial.print(radio.readVSSI(),DEC); getValue();
Serial.println(";"); dtmf_out(cmdbuff);
Serial.println("!;");
break;
case 'B': // B - set to DTMF in Mode
dtmfSetup();
radio.enableDTMFReceive();
state = DTMF;
Serial.println("!;");
break;
case 'A': // A - TX PL Tone configuration command
pl_tone_tx();
Serial.println("!;");
break;
case 'C': // C - RX PL Tone configuration command
pl_tone_rx();
Serial.println("!;");
break;
case 'V': // V - set volume
getValue();
temp = cmdbuff[0];
if (temp == 0x31) {
temp = atol(cmdbuff + 1);
radio.setVolume1(temp);
Serial.println("!;");
} else if (temp == 0x32) {
temp = atol(cmdbuff + 1);
radio.setVolume2(temp);
Serial.println("!;");
} else {
// not a valid volume command
while (Serial.available()) { Serial.read(); }
Serial.println("X!;");
} }
break; break;
case 'K': // K - switch to KISS TNC mode
//state = KISS;
//TODO: set up KISS
Serial.println("X1;");
break;
default:
// unknown command, flush the input buffer and wait for next one
Serial.println("X1;");
while (Serial.available()) { Serial.read(); }
break;
}
break;
case KISS:
if (Serial.peek() == '_') {
state = NORMAL;
if (rx_ctcss) {
radio.enableCtcss();
muted = true; // can't mute (for PL tones) during tx
radio.setMute();
}
}
// TODO: handle KISS TNC
break;
case MORSE:
if (text == '_') { state = NORMAL; }
if (text == 'M') { // tx message
getValue();
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
delay(300);
radio.morseOut(cmdbuff);
if(repeater == true) { radio.frequency(freq); }
radio.setModeReceive();
} else {
// not a valid cmd
while (Serial.available()) { Serial.read(); }
}
break;
case DTMF:
if (text == '_') { state = NORMAL; }
if (text == 'D') { // tx message
getValue();
dtmf_out(cmdbuff);
} else {
// not a valid cmd
while (Serial.available()) { Serial.read(); }
}
break;
default:
// we're in an invalid state, reset to safe settings
while (Serial.available()) { Serial.read(); }
radio.frequency(freq);
radio.setModeReceive();
state = NORMAL;
break;
} }
} }
if(state == 10) {
if(millis() > (timer + 500)) { Serial.println("#TX,OFF;");radio.setModeReceive(); if(repeater == 1) { radio.frequency(freq); } state = 0; txcount = 0; } // now handle any state related functions
switch (state) {
case TX:
if(millis() > (timer + 500)) {
Serial.println("#TX,OFF;");
radio.setModeReceive();
if(repeater == true) { radio.frequency(freq); }
if (rx_ctcss) {
radio.setMute();
muted = true;
}
txcount = 0;
state = NORMAL;
}
break;
case NORMAL:
// deal with rx ctccs if necessary
if (rx_ctcss) {
if (radio.getCtcssToneDetected()) {
if (muted) {
muted = false;
radio.setUnmute();
}
} else {
if (!muted) {
muted = true;
radio.setMute();
}
}
}
break;
case DTMF:
dtmf_rx(); // wait for DTMF reception
break;
case MORSE:
morse_rx(); // wait for Morse reception
break;
}
// get rid of any trailing whitespace in the serial buffer
if (Serial.available()) {
char cpeek = Serial.peek();
while (cpeek == ' ' || cpeek == '\r' || cpeek == '\n')
{
Serial.read();
cpeek = Serial.peek();
}
} }
} }
@ -204,23 +403,159 @@ void getValue() {
for(;;) { for(;;) {
if(Serial.available()) { if(Serial.available()) {
temp = Serial.read(); temp = Serial.read();
if(temp == 59) { cmdbuff[p] = 0; Serial.print("@"); if(temp == 59) {
for(int x = 0; x < 32; x++) { Serial.print(cmdbuff[x]);} cmdbuff[p] = 0;
Serial.println();
return; return;
} }
cmdbuff[p] = temp; cmdbuff[p] = temp;
p++; p++;
if(p == 32) { if(p == 32) {
Serial.print("@");
for(int x = 0; x < 32; x++) {
Serial.println(cmdbuff[x]);
}
cmdbuff[0] = 0; cmdbuff[0] = 0;
return;
Serial.println("X0;"); return; } // some sort of alignment issue? lets not feed junk into whatever takes this string in }
} }
} }
} }
void dtmfSetup() {
radio.setVolume1(6);
radio.setVolume2(0);
radio.setDTMFDetectTime(24); // time to detect a DTMF code, units are 2.5ms
radio.setDTMFIdleTime(50); // time between transmitted DTMF codes, units are 2.5ms
radio.setDTMFTxTime(60); // duration of transmitted DTMF codes, units are 2.5ms
}
void dtmf_out(char * out_buf) {
if (out_buf[0] == ';' || out_buf[0] == 0) return; // empty message
uint8_t i = 0;
uint8_t code = radio.DTMFchar2code(out_buf[i]);
// start transmitting
radio.setDTMFCode(code); // set first
radio.setTxSourceTones();
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute during transmit
radio.setUnmute();
radio.setModeTransmit();
delay(300); // wait for TX to come to full power
bool dtmf_to_tx = true;
while (dtmf_to_tx) {
// wait until ready
while (radio.getDTMFTxActive() != 1) {
// wait until we're ready for a new code
delay(10);
}
if (i < 32 && out_buf[i] != ';' && out_buf[i] != 0) {
code = radio.DTMFchar2code(out_buf[i]);
if (code == 255) code = 0xE; // throw a * in there so we don't break things with an invalid code
radio.setDTMFCode(code); // set first
} else {
dtmf_to_tx = false;
break;
}
i++;
while (radio.getDTMFTxActive() != 0) {
// wait until this code is done
delay(10);
}
}
// done with tone
radio.setModeReceive();
if (repeater == true) {radio.frequency(freq);}
radio.setTxSourceMic();
}
void dtmf_rx() {
char m = radio.DTMFRxLoop();
if (m != 0) {
// Note: not doing buffering of messages,
// we just send a single morse character
// whenever we get it
Serial.print('R');
Serial.print(m);
Serial.println(';');
}
}
// TODO: morse config info
void morse_rx_setup() {
// Set the morse code characteristics
radio.setMorseFreq(MORSE_FREQ);
radio.setMorseDotMillis(MORSE_DOT);
radio.lookForTone(MORSE_FREQ);
radio.setupMorseRx();
}
void morse_rx() {
char m = radio.morseRxLoop();
if (m != 0) {
// Note: not doing buffering of messages,
// we just send a single morse character
// whenever we get it
Serial.print('R');
Serial.print(m);
Serial.println(';');
}
}
void pl_tone_tx() {
memset(pl_tx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
if(buf == 'X') { return; }
if(buf == ';') { pl_tx_buffer[ptr] = 0; program_pl_tx(); return; }
if(ptr == 31) { return; }
pl_tx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_tx() {
float pl_tx = atof(pl_tx_buffer);
radio.setCtcss(pl_tx);
if (pl_tx == 0) {
radio.disableCtcssTx();
} else {
radio.enableCtcssTx();
}
}
void pl_tone_rx() {
memset(pl_rx_buffer,0,32);
uint8_t ptr = 0;
while(1) {
if(Serial.available()) {
uint8_t buf = Serial.read();
if(buf == 'X') { return; }
if(buf == ';') { pl_rx_buffer[ptr] = 0; program_pl_rx(); return; }
if(ptr == 31) { return; }
pl_rx_buffer[ptr] = buf; ptr++;
}
}
}
void program_pl_rx() {
float pl_rx = atof(pl_rx_buffer);
radio.setCtcss(pl_rx);
if (pl_rx == 0) {
rx_ctcss = false;
radio.setUnmute();
muted = false;
radio.disableCtcssRx();
} else {
rx_ctcss = true;
radio.setMute();
muted = true;
radio.enableCtcssRx();
}
}

View File

@ -106,7 +106,7 @@ void setup() {
int result = radio.testConnection(); int result = radio.testConnection();
Serial.println(result); Serial.println(result);
radio.initialize(); radio.initialize();
radio.frequency(446000); radio.frequency(432400);
radio.setVolume1(0xF); radio.setVolume1(0xF);
radio.setVolume2(0xF); radio.setVolume2(0xF);
radio.setModeReceive(); radio.setModeReceive();

View File

@ -249,7 +249,7 @@ void setup() {
Serial.println("Setting radio to its defaults.."); Serial.println("Setting radio to its defaults..");
radio.initialize(); radio.initialize();
radio.setRfPower(0); radio.setRfPower(0);
radio.frequency(144025); radio.frequency(145010);
radio.setModeTransmit(); radio.setModeTransmit();
voice.say(spKILO); // to change these to the words you would like to say, or a ham radio call sign - uncomment above encoded words voice.say(spKILO); // to change these to the words you would like to say, or a ham radio call sign - uncomment above encoded words

View File

@ -1,5 +1,5 @@
name=HamShield name=HamShield
version=1.1.2 version=1.1.3
author=Morgan Redfield <morgan@enhancedradio.com>, Casey Halverson <casey@enhancedradio.com> author=Morgan Redfield <morgan@enhancedradio.com>, Casey Halverson <casey@enhancedradio.com>
maintainer=Morgan Redfield <morgan@enhancedradio.com> maintainer=Morgan Redfield <morgan@enhancedradio.com>
sentence=A library for use with HamShield by Enhanced Radio Devices. sentence=A library for use with HamShield by Enhanced Radio Devices.

View File

@ -193,7 +193,7 @@ void HamShield::initialize(bool narrowBand) {
HSwriteWord(devAddr, 0x57, tx_data); HSwriteWord(devAddr, 0x57, tx_data);
tx_data = 0x800D; tx_data = 0x800D;
HSwriteWord(devAddr, 0x58, tx_data); HSwriteWord(devAddr, 0x58, tx_data);
tx_data = 0x0EDD; tx_data = 0x0EDB;
HSwriteWord(devAddr, 0x5A, tx_data); // sq and noise detect times HSwriteWord(devAddr, 0x5A, tx_data); // sq and noise detect times
tx_data = 0x3FFF; tx_data = 0x3FFF;
HSwriteWord(devAddr, 0x63, tx_data); // pre-emphasis bypass HSwriteWord(devAddr, 0x63, tx_data); // pre-emphasis bypass
@ -227,7 +227,7 @@ void HamShield::initialize(bool narrowBand) {
setModeReceive(); setModeReceive();
setTxSourceMic(); setTxSourceMic();
setRfPower(0); setRfPower(0);
setSQLoThresh(80); setSQLoThresh(-80);
setSQOn(); setSQOn();
*/ */
setDTMFIdleTime(50); setDTMFIdleTime(50);
@ -256,11 +256,11 @@ void HamShield::setupNarrowBand() {
HSwriteWord(devAddr, 0x34, tx_data); HSwriteWord(devAddr, 0x34, tx_data);
tx_data = 0x40C3; tx_data = 0x40C3;
HSwriteWord(devAddr, 0x3A, tx_data); // modu_det_sel sq setting HSwriteWord(devAddr, 0x3A, tx_data); // modu_det_sel sq setting
tx_data = 0x0407; tx_data = 0x0F1E;
HSwriteWord(devAddr, 0x3C, tx_data); // pk_det_th sq setting [8:7] HSwriteWord(devAddr, 0x3C, tx_data); // pk_det_th sq setting [8:7]
tx_data = 0x28D0; tx_data = 0x28D0;
HSwriteWord(devAddr, 0x3F, tx_data); // rssi3_th sq setting HSwriteWord(devAddr, 0x3F, tx_data); // rssi3_th sq setting
tx_data = 0x203E; tx_data = 0x20BE;
HSwriteWord(devAddr, 0x48, tx_data); HSwriteWord(devAddr, 0x48, tx_data);
tx_data = 0x1BB7; tx_data = 0x1BB7;
HSwriteWord(devAddr, 0x60, tx_data); HSwriteWord(devAddr, 0x60, tx_data);
@ -773,20 +773,37 @@ void HamShield::setCtcssFreqToStandard(){
setCtcssFreq(13440); setCtcssFreq(13440);
} }
void HamShield::enableCtcss() { void HamShield::enableCtcssTx() {
// enable TX
HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 3); HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 3);
}
// enable RX void HamShield::enableCtcssRx() {
setCtcssGpioSel(1); setCtcssGpioSel(1);
HSwriteBitW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTCSS_DET_BIT, 0); HSwriteBitW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTCSS_DET_BIT, 0);
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_CTCSS_FILTER_BYPASS, 0); HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_CTCSS_FILTER_BYPASS, 0);
setDetCtcss(); setDetCtcss();
} }
void HamShield::disableCtcss() {
void HamShield::enableCtcss() {
// enable TX
enableCtcssTx();
// enable RX
enableCtcssRx();
}
void HamShield::disableCtcssTx() {
HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 0); HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 0);
}
void HamShield::disableCtcssRx() {
setCtcssGpioSel(0);
disableCtcssCdcss(); disableCtcssCdcss();
} }
void HamShield::disableCtcss() {
disableCtcssTx();
disableCtcssRx();
}
// match threshold // match threshold
void HamShield::setCtcssDetThreshIn(uint8_t thresh) { void HamShield::setCtcssDetThreshIn(uint8_t thresh) {
@ -870,24 +887,30 @@ bool HamShield::getSQState(){
void HamShield::setSQHiThresh(int16_t sq_hi_threshold){ void HamShield::setSQHiThresh(int16_t sq_hi_threshold){
// Sq detect high th, rssi_cmp will be 1 when rssi>th_h_sq, unit 1dB // Sq detect high th, rssi_cmp will be 1 when rssi>th_h_sq, unit 1dB
uint16_t sq = 137 + sq_hi_threshold; uint16_t sq = 137 + sq_hi_threshold;
HSwriteWord(devAddr, A1846S_SQ_OPEN_THRESH_REG, sq); HSwriteBitsW(devAddr, A1846S_SQ_OPEN_THRESH_REG, A1846S_SQ_OPEN_THRESH_BIT, A1846S_SQ_OPEN_THRESH_LENGTH, sq);
} }
int16_t HamShield::getSQHiThresh(){ int16_t HamShield::getSQHiThresh(){
HSreadWord(devAddr, A1846S_SQ_OPEN_THRESH_REG, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_SQ_OPEN_THRESH_REG, A1846S_SQ_OPEN_THRESH_BIT, A1846S_SQ_OPEN_THRESH_LENGTH, radio_i2c_buf);
return radio_i2c_buf[0] - 137; return radio_i2c_buf[0] - 137;
} }
void HamShield::setSQLoThresh(int16_t sq_lo_threshold){ void HamShield::setSQLoThresh(int16_t sq_lo_threshold){
// Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1 dB // Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1 dB
uint16_t sq = 137 + sq_lo_threshold; uint16_t sq = 137 + sq_lo_threshold;
HSwriteWord(devAddr, A1846S_SQ_SHUT_THRESH_REG, sq); HSwriteBitsW(devAddr, A1846S_SQ_SHUT_THRESH_REG, A1846S_SQ_SHUT_THRESH_BIT, A1846S_SQ_SHUT_THRESH_LENGTH, sq);
} }
int16_t HamShield::getSQLoThresh(){ int16_t HamShield::getSQLoThresh(){
HSreadWord(devAddr, A1846S_SQ_SHUT_THRESH_REG, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_SQ_SHUT_THRESH_REG, A1846S_SQ_SHUT_THRESH_BIT, A1846S_SQ_SHUT_THRESH_LENGTH, radio_i2c_buf);
return radio_i2c_buf[0] - 137; return radio_i2c_buf[0] - 137;
} }
bool HamShield::getSquelching() {
HSreadBitW(devAddr, A1846S_FLAG_REG, A1846S_SQ_FLAG_BIT, radio_i2c_buf);
return (radio_i2c_buf[0] != 0);
}
// SQ out select // SQ out select
void HamShield::setSQOutSel(){ void HamShield::setSQOutSel(){
HSwriteBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, 1); HSwriteBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, 1);
@ -998,6 +1021,67 @@ uint16_t HamShield::getDTMFIdleTime() {
return radio_i2c_buf[0]; return radio_i2c_buf[0];
} }
char HamShield::DTMFRxLoop() {
char m = 0;
if (getDTMFSample() != 0) {
uint16_t code = getDTMFCode();
m = DTMFcode2char(code);
// reset after this tone
int j = 0;
while (j < 4) {
if (getDTMFSample() == 0) {
j++;
} else {
j = 1;
}
delay(10);
}
// reset read
//enableDTMFReceive();
}
return m;
}
char HamShield::DTMFcode2char(uint16_t code) {
char c;
if (code < 10) {
c = '0' + code;
} else if (code < 0xE) {
c = 'A' + code - 10;
} else if (code == 0xE) {
c = '*';
} else if (code == 0xF) {
c = '#';
} else {
c = '?'; // invalid code
}
return c;
}
uint8_t HamShield::DTMFchar2code(char c) {
uint8_t code;
if (c == '#') {
code = 0xF;
} else if (c=='*') {
code = 0xE;
} else if (c >= 'A' && c <= 'D') {
code = c - 'A' + 0xA;
} else if (c >= '0' && c <= '9') {
code = c - '0';
} else {
// invalid code, skip it
code = 255;
}
return code;
}
void HamShield::setDTMFTxTime(uint16_t tx_time) { void HamShield::setDTMFTxTime(uint16_t tx_time) {
if (tx_time > 63) {tx_time = 63;} // maxed out if (tx_time > 63) {tx_time = 63;} // maxed out
// tx time is duration of DTMF Tone // tx time is duration of DTMF Tone
@ -1616,6 +1700,10 @@ bool HamShield::waitForChannel(long timeout = 0, long breakwindow = 0, int setRS
return false; return false;
} }
void HamShield::setupMorseRx() {
// TODO: morse timing config (e.g. dot time, dash time, etc)
}
// Get current morse code tone frequency (in Hz) // Get current morse code tone frequency (in Hz)
unsigned int HamShield::getMorseFreq() { unsigned int HamShield::getMorseFreq() {
@ -1693,6 +1781,104 @@ void HamShield::morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]) {
return; return;
} }
// returns '\0' if no valid morse char found yet
char HamShield::morseRxLoop() {
static uint32_t last_tone_check = 0; // track how often we check for morse tones
static uint32_t tone_in_progress; // track how long the current tone lasts
static uint32_t space_in_progress; // track how long since the last tone
static uint8_t rx_morse_char;
static uint8_t rx_morse_bit;
static bool bits_to_process;
if (last_tone_check == 0) {
last_tone_check = millis();
space_in_progress = 0; // haven't checked yet
tone_in_progress = 0; // not currently listening to a tone
rx_morse_char = 0; // haven't found any tones yet
rx_morse_bit = 1;
bits_to_process = false;
}
char m = 0;
// are we receiving anything
if (toneDetected()) {
space_in_progress = 0;
if (tone_in_progress == 0) {
// start a new tone
tone_in_progress = millis();
//Serial.print('t');
}
} else {
// keep track of how long the silence is
if (space_in_progress == 0) space_in_progress = millis();
// we wait for a bit of silence before ending the last
// symbol in order to smooth out the detector
if ((millis() - space_in_progress) > SYMBOL_END_TIME)
{
if (tone_in_progress != 0) {
// end the last tone
uint16_t tone_time = millis() - tone_in_progress;
tone_in_progress = 0;
//Serial.println(tone_time);
bits_to_process = handleMorseTone(tone_time, bits_to_process, &rx_morse_char, &rx_morse_bit);
}
}
// we might be done with a character if the space is long enough
if (((millis() - space_in_progress) > CHAR_END_TIME) && bits_to_process) {
m = parseMorse(rx_morse_char, rx_morse_bit);
bits_to_process = false;
rx_morse_char = 0;
rx_morse_bit = 1;
}
// we might be done with a message if the space is long enough
if ((millis() - space_in_progress) > MESSAGE_END_TIME) {
rx_morse_char = 0;
rx_morse_bit = 1;
}
}
return m;
}
bool HamShield::handleMorseTone(uint16_t tone_time, bool bits_to_process,
uint8_t * rx_morse_char, uint8_t * rx_morse_bit) {
//Serial.println(tone_time);
if (tone_time > MIN_DOT_TIME && tone_time < MAX_DOT_TIME) {
// add a dot
//Serial.print(".");
bits_to_process = true;
//nothing to do for this bit position, since . = 0
} else if (tone_time > MIN_DASH_TIME && tone_time < MAX_DASH_TIME) {
// add a dash
//Serial.print("-");
bits_to_process = true;
*rx_morse_char += *rx_morse_bit;
}
// prep for the next bit
*rx_morse_bit = *rx_morse_bit << 1;
return bits_to_process;
}
char HamShield::parseMorse(uint8_t rx_morse_char, uint8_t rx_morse_bit) {
// if morse_char is a valid morse character, return the character
// if morse_char is an invalid (incomplete) morse character, return 0
//if (rx_morse_bit != 1) Serial.println(rx_morse_char, BIN);
rx_morse_char += rx_morse_bit; // add the terminator bit
// if we got a char, then print it
char c = morseReverseLookup(rx_morse_char);
return c;
}
/* Morse code lookup table */ /* Morse code lookup table */
uint8_t HamShield::morseLookup(char letter) { uint8_t HamShield::morseLookup(char letter) {

View File

@ -32,7 +32,7 @@
#define A1846S_TH_L_VOX_REG 0x64 // register holds vox low (shut) threshold bits #define A1846S_TH_L_VOX_REG 0x64 // register holds vox low (shut) threshold bits
#define A1846S_FM_DEV_REG 0x43 // register holds fm deviation settings #define A1846S_FM_DEV_REG 0x43 // register holds fm deviation settings
#define A1846S_RX_VOLUME_REG 0x44 // register holds RX volume settings #define A1846S_RX_VOLUME_REG 0x44 // register holds RX volume settings
#define A1846S_SQ_OPEN_THRESH_REG 0x48 // see sq #define A1846S_SQ_OPEN_THRESH_REG 0x49 // see sq
#define A1846S_SQ_SHUT_THRESH_REG 0x49 // see sq #define A1846S_SQ_SHUT_THRESH_REG 0x49 // see sq
#define A1846S_CTCSS_FREQ_REG 0x4A // ctcss_freq<15:0> #define A1846S_CTCSS_FREQ_REG 0x4A // ctcss_freq<15:0>
#define A1846S_CDCSS_CODE_HI_REG 0x4B // cdcss_code<23:16> #define A1846S_CDCSS_CODE_HI_REG 0x4B // cdcss_code<23:16>
@ -145,12 +145,12 @@
#define A1846S_SHIFT_SEL_LEN 2 #define A1846S_SHIFT_SEL_LEN 2
// Bitfields for A1846S_SQ_THRESH_REG // Bitfields for A1846S_SQ_THRESH_REG
#define A1846S_SQ_OPEN_THRESH_BIT 9 // sq open threshold <9:0> #define A1846S_SQ_OPEN_THRESH_BIT 13 // sq open threshold <6:0>
#define A1846S_SQ_OPEN_THRESH_LENGTH 10 #define A1846S_SQ_OPEN_THRESH_LENGTH 7
// Bitfields for A1846S_SQ_SHUT_THRESH_REG // Bitfields for A1846S_SQ_SHUT_THRESH_REG
#define A1846S_SQ_SHUT_THRESH_BIT 9 // sq shut threshold <9:0> #define A1846S_SQ_SHUT_THRESH_BIT 6 // sq shut threshold <6:0>
#define A1846S_SQ_SHUT_THRESH_LENGTH 10 #define A1846S_SQ_SHUT_THRESH_LENGTH 7
// Bitfields for A1846S_SQ_OUT_SEL_REG // Bitfields for A1846S_SQ_OUT_SEL_REG
#define A1846S_SQ_OUT_SEL_BIT 7 // sq_out_sel #define A1846S_SQ_OUT_SEL_BIT 7 // sq_out_sel
@ -168,8 +168,8 @@
#define A1846S_CTCSS2_FLAG_BIT 8 // 1 when txon is enabled #define A1846S_CTCSS2_FLAG_BIT 8 // 1 when txon is enabled
#define A1846S_INVERT_DET_FLAG_BIT 7 // ctcss phase shift detect #define A1846S_INVERT_DET_FLAG_BIT 7 // ctcss phase shift detect
#define A1846S_CSS_CMP_FLAG_BIT 2 // ctcss/cdcss compared #define A1846S_CSS_CMP_FLAG_BIT 2 // ctcss/cdcss compared
#define A1846S_SQ_FLAG_BIT 1 // sq final signal out from dsp #define A1846S_SQ_FLAG_BIT 0 // sq final signal out from dsp
#define A1846S_VOX_FLAG_BIT 0 // vox out from dsp #define A1846S_VOX_FLAG_BIT 1 // vox out from dsp
// Bitfields for A1846S_RSSI_REG // Bitfields for A1846S_RSSI_REG
#define A1846S_RSSI_BIT 15 // RSSI readings <7:0> #define A1846S_RSSI_BIT 15 // RSSI readings <7:0>
@ -217,6 +217,20 @@
#define HAMSHIELD_PSK31_FREQ 1000 #define HAMSHIELD_PSK31_FREQ 1000
// Morse Configuration
#define MORSE_FREQ 600
#define MORSE_DOT 150 // ms
#define SYMBOL_END_TIME 5 //millis
#define CHAR_END_TIME (MORSE_DOT*2.7)
#define MESSAGE_END_TIME (MORSE_DOT*8)
#define MIN_DOT_TIME (MORSE_DOT-30)
#define MAX_DOT_TIME (MORSE_DOT+55)
#define MIN_DASH_TIME (MORSE_DOT*3-30)
#define MAX_DASH_TIME (MORSE_DOT*3+55)
class HamShield { class HamShield {
public: public:
@ -299,7 +313,11 @@ class HamShield {
uint16_t getCtcssFreqMilliHz(); uint16_t getCtcssFreqMilliHz();
float getCtcssFreqHz(); float getCtcssFreqHz();
void setCtcssFreqToStandard(); // freq must be 134.4Hz for standard cdcss mode void setCtcssFreqToStandard(); // freq must be 134.4Hz for standard cdcss mode
void enableCtcssTx();
void enableCtcssRx();
void enableCtcss(); void enableCtcss();
void disableCtcssTx();
void disableCtcssRx();
void disableCtcss(); void disableCtcss();
void setCtcssDetThreshIn(uint8_t thresh); void setCtcssDetThreshIn(uint8_t thresh);
uint8_t getCtcssDetThreshIn(); uint8_t getCtcssDetThreshIn();
@ -344,6 +362,7 @@ class HamShield {
int16_t getSQHiThresh(); int16_t getSQHiThresh();
void setSQLoThresh(int16_t sq_lo_threshold); // Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1dB void setSQLoThresh(int16_t sq_lo_threshold); // Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1dB
int16_t getSQLoThresh(); int16_t getSQLoThresh();
bool getSquelching();
// SQ out select // SQ out select
void setSQOutSel(); void setSQOutSel();
@ -389,6 +408,9 @@ class HamShield {
uint16_t getDTMFDetectTime(); uint16_t getDTMFDetectTime();
void setDTMFIdleTime(uint16_t idle_time); // idle time is time between DTMF Tone void setDTMFIdleTime(uint16_t idle_time); // idle time is time between DTMF Tone
uint16_t getDTMFIdleTime(); uint16_t getDTMFIdleTime();
char DTMFRxLoop();
char DTMFcode2char(uint16_t code);
uint8_t DTMFchar2code(char c);
void setDTMFTxTime(uint16_t tx_time); // tx time is duration of DTMF Tone void setDTMFTxTime(uint16_t tx_time); // tx time is duration of DTMF Tone
uint16_t getDTMFTxTime(); uint16_t getDTMFTxTime();
uint16_t disableDTMF(); uint16_t disableDTMF();
@ -482,11 +504,15 @@ class HamShield {
uint32_t scanChannels(uint32_t buffer[],uint8_t buffsize, uint8_t speed, uint16_t threshold); uint32_t scanChannels(uint32_t buffer[],uint8_t buffsize, uint8_t speed, uint16_t threshold);
uint32_t findWhitespaceChannels(uint32_t buffer[],uint8_t buffsize, uint8_t dwell, uint16_t threshold); uint32_t findWhitespaceChannels(uint32_t buffer[],uint8_t buffsize, uint8_t dwell, uint16_t threshold);
void setupMorseRx();
unsigned int getMorseFreq(); unsigned int getMorseFreq();
void setMorseFreq(unsigned int morse_freq_hz); void setMorseFreq(unsigned int morse_freq_hz);
unsigned int getMorseDotMillis(); unsigned int getMorseDotMillis();
void setMorseDotMillis(unsigned int morse_dot_dur_millis); void setMorseDotMillis(unsigned int morse_dot_dur_millis);
void morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]); void morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]);
char morseRxLoop();
bool handleMorseTone(uint16_t tone_time, bool bits_to_process, uint8_t * rx_morse_char, uint8_t * rx_morse_bit);
char parseMorse(uint8_t rx_morse_char, uint8_t rx_morse_bit);
uint8_t morseLookup(char letter); uint8_t morseLookup(char letter);
uint8_t morseReverseLookup(uint8_t itu); uint8_t morseReverseLookup(uint8_t itu);
bool waitForChannel(long timeout, long breakwindow, int setRSSI); bool waitForChannel(long timeout, long breakwindow, int setRSSI);