Compare commits

..

23 Commits
RPi ... master

Author SHA1 Message Date
morgan 753ca34560 increment version 2021-04-19 13:23:23 -04:00
morgan 888697bb79 bugfixes for nRF examples 2021-04-19 13:20:54 -04:00
Morgan Redfield 1500d07213 adding nRF52840 (feather) example 2021-04-19 10:49:34 -04:00
Morgan Redfield 70bd364473 update reset comments for HSMini 2019-12-23 11:14:37 -05:00
Morgan Redfield ef2268ca22 fix serial rx flush in examples 2019-09-07 19:43:11 -07:00
Morgan Redfield aa14035c94 stabilize comms timing 2019-09-07 19:40:22 -07:00
Morgan Redfield 777a56d131 fix I2C comments 2019-08-20 14:34:20 -07:00
spaceneedle 0e520d74f9
Update README.md 2019-08-07 09:53:55 -04:00
Morgan Redfield f630fc8d88 loop speech 2019-07-18 18:08:02 -07:00
Morgan Redfield 4006afff64 make speechTX more polite and more verbose 2019-07-18 18:06:38 -07:00
Morgan Redfield 3d3f6a36b6 update dtmf, morse, and examples 2019-07-14 13:37:14 -07:00
Morgan Redfield 71acbbb975 update DTMF tx and rx 2019-06-01 18:09:15 -07:00
Morgan Redfield 6472b103b4 update Morse 2019-06-01 15:25:56 -07:00
Morgan Redfield 7e509ca0fc minor morse updates 2019-05-11 15:32:13 -07:00
Morgan Redfield 12fd074aed let HSTone be generated by HamShield itself 2019-04-28 11:41:29 -07:00
Morgan Redfield 1d0eb281e2 serial messenger bug fixes 2019-04-12 11:50:17 -07:00
Morgan Redfield 7941388980 adding in HandyTalkie_nrf52840 2019-04-06 14:00:45 -07:00
Morgan Redfield f83b547de4 merge RPi branch in, add Feather nRF52840 Express example BLE sketch 2019-04-06 14:00:03 -07:00
Morgan Redfield b147edfcfa minor bug fix 2019-03-24 15:17:45 -07:00
Morgan Redfield 3c3d83c057 unify pin naming scheme 2019-03-15 10:43:15 -07:00
Morgan Redfield 9d708e4046 update afsk_messenger example 2019-02-10 12:01:09 -08:00
Morgan Redfield 250dd330b7 noTone bugfixes 2019-02-04 17:41:35 -08:00
Morgan Redfield 289d1f73a8 removing duration from tone calls 2019-02-04 15:25:29 -08:00
23 changed files with 2140 additions and 647 deletions

View File

@ -1,5 +1,7 @@
# HamShield # HamShield
You can purchase HamShield (as well as smaller variants or LoRa version) at http://www.enhancedradio.com/
The master branch is intended for use with HamShield hardware -09 and above. The master branch is intended for use with HamShield hardware -09 and above.
WARNING: The dev branch is not guaranteed to work. Please use caution if you choose to use that branch. WARNING: The dev branch is not guaranteed to work. Please use caution if you choose to use that branch.

View File

@ -12,7 +12,7 @@
* To send a message: connect to the Arduino over a Serial link. * To send a message: connect to the Arduino over a Serial link.
* Send the following over the serial link: * Send the following over the serial link:
* `from,to,:message * `from,to,:message
* example: * `KG7OGM,KG7OGM,:Hi there * example: * KG7OGM,KG7OGM,:Hi there`
*/ */
@ -22,7 +22,7 @@
#include <packet.h> #include <packet.h>
#include <avr/wdt.h> #include <avr/wdt.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -37,10 +37,11 @@ int msgptr = 0;
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
@ -52,14 +53,14 @@ 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);
radio.setSQHiThresh(-100); radio.setSQHiThresh(-100);
radio.setSQLoThresh(-100); radio.setSQLoThresh(-100);
radio.setSQOn(); //radio.setSQOn();
//radio.bypassPreDeEmph(); radio.bypassPreDeEmph();
dds.start(); dds.start();
afsk.start(&dds); afsk.start(&dds);
delay(100); delay(100);
@ -74,6 +75,7 @@ void loop() {
//Serial.println(messagebuff); //Serial.println(messagebuff);
prepMessage(); prepMessage();
msgptr = 0; msgptr = 0;
messagebuff = "";
Serial.print("!!"); Serial.print("!!");
} }
else { else {

View File

@ -5,7 +5,7 @@
#include <HamShield.h> #include <HamShield.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -17,13 +17,14 @@ uint8_t pl_rx_buffer[32];
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -36,7 +37,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

@ -29,7 +29,7 @@ HamShield radio;
#define LED_PIN 13 #define LED_PIN 13
#define RSSI_REPORT_RATE_MS 5000 #define RSSI_REPORT_RATE_MS 5000
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -43,13 +43,14 @@ unsigned long rssi_timeout;
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, LOW); digitalWrite(RESET_PIN, LOW);
@ -68,20 +69,18 @@ void setup() {
// verify connection // verify connection
Serial.println("Testing device connections..."); Serial.println("Testing device connections...");
Serial.println(radio.testConnection() ? "RDA radio connection successful" : "RDA radio connection failed"); Serial.println(radio.testConnection() ? "radio connection successful" : "radio connection failed");
// initialize device // initialize device
Serial.println("Initializing I2C devices..."); Serial.println("Initializing radio device...");
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 +91,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
@ -163,7 +167,7 @@ void loop() {
} else { } else {
Serial.setTimeout(40); Serial.setTimeout(40);
freq = Serial.parseInt(); freq = Serial.parseInt();
Serial.flush(); while (Serial.available()) Serial.read();
radio.frequency(freq); radio.frequency(freq);
Serial.print("set frequency: "); Serial.print("set frequency: ");
Serial.println(freq); Serial.println(freq);

View File

@ -14,7 +14,7 @@
#include <HamShield.h> #include <HamShield.h>
#include <DDS.h> #include <DDS.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -26,13 +26,14 @@ DDS dds;
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
// turn on radio // turn on radio
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);

View File

@ -20,7 +20,7 @@ HamShield radio;
#define LED_PIN 13 #define LED_PIN 13
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -28,13 +28,14 @@ uint32_t freq;
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, LOW); digitalWrite(RESET_PIN, LOW);
@ -72,7 +73,7 @@ void setup() {
//radio.setSQOff(); //radio.setSQOff();
Serial.println("setting frequency to: "); Serial.println("setting frequency to: ");
freq = 420000; 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,33 +105,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++;
}
delay(10);
}
} 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()) {
uint8_t code = char2code(Serial.read()); // get first code
uint8_t code = radio.DTMFchar2code(Serial.read());
// start transmitting // start transmitting
radio.setDTMFCode(code); // set first radio.setDTMFCode(code); // set first
@ -145,56 +131,23 @@ void loop() {
// wait until we're ready for a new code // wait until we're ready for a new code
delay(10); delay(10);
} }
if (Serial.available()) {
code = radio.DTMFchar2code(Serial.read());
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;
}
while (radio.getDTMFTxActive() != 0) { while (radio.getDTMFTxActive() != 0) {
// wait until this code is done // wait until this code is done
delay(10); delay(10);
} }
if (Serial.available()) {
code = char2code(Serial.read());
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;
}
} }
// done with tone // done with tone
radio.setModeReceive(); radio.setModeReceive();
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

@ -16,7 +16,7 @@
#define DDS_REFCLK_DEFAULT 9600 #define DDS_REFCLK_DEFAULT 9600
#include <HamShield.h> #include <HamShield.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -25,13 +25,14 @@ HamShield radio;
// 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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -57,8 +58,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

@ -15,7 +15,7 @@
#include <HamShield.h> #include <HamShield.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -29,13 +29,14 @@ 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, it should be held low to avoid tx noise
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -61,8 +62,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.");
} }
@ -79,7 +80,7 @@ void loop() {
radio.setModeTransmit(); radio.setModeTransmit();
// Generate a 600Hz tone for TRANSMITLENGTH time // Generate a 600Hz tone for TRANSMITLENGTH time
tone(PWM_PIN, 600, TRANSMITLENGTH); tone(MIC_PIN, 600, TRANSMITLENGTH);
delay(TRANSMITLENGTH); delay(TRANSMITLENGTH);
// Identify the transmitter // Identify the transmitter

View File

@ -26,7 +26,7 @@ HamShield radio;
#define LED_PIN 13 #define LED_PIN 13
#define RSSI_REPORT_RATE_MS 5000 #define RSSI_REPORT_RATE_MS 5000
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -39,13 +39,14 @@ unsigned long rssi_timeout;
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, LOW); digitalWrite(RESET_PIN, LOW);
@ -57,7 +58,8 @@ void setup() {
while (digitalRead(SWITCH_PIN) && !Serial.available()); while (digitalRead(SWITCH_PIN) && !Serial.available());
Serial.read(); // flush Serial.read(); // flush
// let the AU ot of reset // let the radio out of reset
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -65,20 +67,19 @@ void setup() {
// verify connection // verify connection
Serial.println("Testing device connections..."); Serial.println("Testing device connections...");
Serial.println(radio.testConnection() ? "RDA radio connection successful" : "RDA radio connection failed"); Serial.println(radio.testConnection() ? "radio connection successful" : "radio connection failed");
// initialize device // initialize device
Serial.println("Initializing I2C devices..."); Serial.println("Initializing radio device...");
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
@ -136,7 +137,7 @@ void loop() {
} else { } else {
Serial.setTimeout(40); Serial.setTimeout(40);
freq = Serial.parseInt(); freq = Serial.parseInt();
Serial.flush(); while (Serial.available()) Serial.read();
radio.frequency(freq); radio.frequency(freq);
Serial.print("set frequency: "); Serial.print("set frequency: ");
Serial.println(freq); Serial.println(freq);

View File

@ -0,0 +1,283 @@
/* Hamshield
* Example: HandyTalkie_nRF52840
* This is a simple example to demonstrate the HamShield working
* with an Adafruit Feather nRF52840 Express
*
* HamShield to Feather Connections:
* SPKR - Feather A0
* MIC - Feather D11
* CLK - Feather D5
* nCS - Feather D6
* DAT - Feather D9
* GND - Feather GND
* VCC - Feather 3.3V
*
* Connect the HamShield to your Feather as above.
* Screw the antenna into the HamShield RF jack. Plug a pair
* of headphones into the HamShield.
*
* Connect the Feather nRF52840 Express to your computer via
* a USB Micro B cable. After uploading this program to
* your Feather, open the Serial Monitor. You should see some
* text displayed that documents the setup process.
*
* Once the Feather is set up and talking to the HamShield,
* you can control it over USB-Serial or BLE-Serial(UART).
*
* Try using Adafruit's Bluefruit app to connect to the Feather.
* Once you're connected, you can control the HamShield using
* the same commands you'd use over USB-Serial. The response to
* all commands will be echoed to both USB-Serial and BLE-Serial(UART).
*
* Serial UART commands:
* t - change from Tx to Rx (or vice versa)
* F123400 - set frequency to 123400 kHz
*/
#include <bluefruit.h>
// BLE Service
BLEDis bledis; // device information
BLEUart bleuart; // uart over ble
BLEBas blebas; // battery
#include <HamShield.h>
// create object for radio
HamShield radio(6,5,9);
// To use non-standard pins, use the following initialization
//HamShield radio(ncs_pin, clk_pin, dat_pin);
#define LED_PIN 3
#define RSSI_REPORT_RATE_MS 5000
#define MIC_PIN A1
bool blinkState = false;
bool currently_tx;
uint32_t freq;
unsigned long rssi_timeout;
void setup() {
// NOTE: if not using PWM out, it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// initialize serial communication
Serial.begin(115200);
while (!Serial) delay(10);
Serial.println("Setting up BLE");
// Setup the BLE LED to be enabled on CONNECT
// Note: This is actually the default behaviour, but provided
// here in case you want to control this LED manually via PIN 19
Bluefruit.autoConnLed(true);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin();
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Bluefruit.setTxPower(4);
Bluefruit.setName("MyBlueHam");
//Bluefruit.setName(getMcuUniqueID()); // useful testing with multiple central connections
Bluefruit.setConnectCallback(connect_callback);
Bluefruit.setDisconnectCallback(disconnect_callback);
// Configure and Start Device Information Service
bledis.setManufacturer("Enhanced Radio Devices");
bledis.setModel("BlueHam");
bledis.begin();
// Configure and Start BLE Uart Service
bleuart.begin();
// Start BLE Battery Service
blebas.begin();
blebas.write(100);
// Set up and start advertising
startAdv();
delay(100);
Serial.println("beginning Ham radio setup");
// verify connection
Serial.println("Testing device connections...");
if (radio.testConnection()) {
Serial.println("HamShield connection successful");
} else {
Serial.print("HamShield connection failed");
while(1) delay(100);
}
// initialize device
Serial.println("Initializing radio device...");
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration");
// set frequency
Serial.println("changing frequency");
radio.setSQOff();
freq = 432100; // 70cm calling frequency
radio.frequency(freq);
// set to receive
radio.setModeReceive();
currently_tx = false;
Serial.print("config register is: ");
Serial.println(radio.readCtlReg());
Serial.println(radio.readRSSI());
/*
// set to transmit
radio.setModeTransmit();
// maybe set PA bias voltage
Serial.println("configured for transmit");
radio.setTxSourceMic();
*/
radio.setRfPower(0);
// configure Arduino LED for
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
rssi_timeout = 0;
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 128-bit uuid
Bluefruit.Advertising.addService(bleuart);
// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
* For recommended advertising interval
* https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
// for serial output buffer on both interfaces
#define TEXT_BUF_LEN 64
char text_buf[TEXT_BUF_LEN];
void loop() {
char c = 0;
bool ble_serial = false;
if (Serial.available()) {
Serial.readBytes(&c, 1);
} else if (bleuart.available()) {
c = (char) bleuart.read();
ble_serial = true;
}
if (c != 0) {
if (c == 't')
{
if (!currently_tx)
{
currently_tx = true;
// set to transmit
radio.setModeTransmit();
Serial.println("Tx");
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "Tx\n");
bleuart.write(text_buf, str_len);
//radio.setTxSourceMic();
//radio.setRfPower(1);
} else {
radio.setModeReceive();
currently_tx = false;
Serial.println("Rx");
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "Rx\n");
bleuart.write(text_buf, str_len);
}
} else if (c == 'F') {
if (ble_serial == false) {
Serial.setTimeout(40);
freq = Serial.parseInt();
Serial.flush();
} else {
int idx = 0;
while (bleuart.available() &&
bleuart.peek() >= '0' &&
bleuart.peek() <= '9' &&
idx < TEXT_BUF_LEN) {
text_buf[idx] = bleuart.read();
idx++;
}
text_buf[idx] = 0; // null terminate
freq = atoi(text_buf);
}
radio.frequency(freq);
Serial.print("set frequency: ");
Serial.println(freq);
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "set frequency: %d\n", freq);
bleuart.write(text_buf, str_len);
}
}
if (!currently_tx && (millis() - rssi_timeout) > RSSI_REPORT_RATE_MS)
{
int rssi = radio.readRSSI();
Serial.println(rssi);
int str_len = snprintf(text_buf, TEXT_BUF_LEN, "rssi: %d\n", rssi);
bleuart.write(text_buf, str_len);
rssi_timeout = millis();
}
}
// callback invoked when central connects
void connect_callback(uint16_t conn_handle)
{
char central_name[32] = { 0 };
Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
Serial.print("Connected to ");
Serial.println(central_name);
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
* https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.println();
Serial.println("Disconnected");
}

View File

@ -35,19 +35,20 @@ DDS dds;
AFSK afsk; AFSK afsk;
KISS kiss(&Serial, &radio, &dds, &afsk); KISS kiss(&Serial, &radio, &dds, &afsk);
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up

View File

@ -10,51 +10,46 @@
* monitor the status of the beacon. To test, set a HandyTalkie * monitor the status of the beacon. To test, set a HandyTalkie
* to 438MHz. You should hear the message " CALLSIGN HAMSHIELD" * to 438MHz. You should hear the message " CALLSIGN HAMSHIELD"
* in morse code. * in morse code.
*
*
* Note: only upper case letters, numbers, and a few symbols
* are supported.
* Supported symbols: &/+(=:?";@`-._),!$
*
* If you're having trouble accurately decoding, you may want to
* tweak the min/max . and - times. You can also uncomment
* the Serial.print debug statements that can tell you when tones
* are being detected, how long they're detected for, and whether
* the tones are decoded as a . or -.
*
*/ */
#define DDS_REFCLK_DEFAULT 9600 #define DDS_REFCLK_DEFAULT 9600
#include <HamShield.h> #include <HamShield.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
#define MORSE_FREQ 600 #define MORSE_FREQ 600
#define MORSE_DOT 100 // ms #define MORSE_DOT 150 // ms
// 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.3)
#define MESSAGE_END_TIME (MORSE_DOT*15)
#define MIN_DOT_TIME (MORSE_DOT*0.7)
#define MAX_DOT_TIME (MORSE_DOT*1.3)
#define MIN_DASH_TIME (MORSE_DOT*2.7)
#define MAX_DASH_TIME (MORSE_DOT*3.3)
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;
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -80,63 +75,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((uint32_t) 438000); 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;
} }
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();
}
} 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;
handleTone(tone_time);
}
}
// we might be done with a character if the space is long enough
if ((millis() - space_in_progress) > CHAR_END_TIME) {
char m = parseMorse();
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
@ -145,9 +96,11 @@ void loop() {
// We'll wait up to 30 seconds for a clear channel, requiring that the channel is clear for 2 seconds before we transmit // We'll wait up to 30 seconds for a clear channel, requiring that the channel is clear for 2 seconds before we transmit
if (radio.waitForChannel(30000,2000,-5)) { if (radio.waitForChannel(30000,2000,-5)) {
// If we get here, the channel is clear. // If we get here, the channel is clear.
Serial.println("sending");
// Start transmitting by putting the radio into transmit mode. // Start transmitting by putting the radio into transmit mode.
radio.setModeTransmit(); radio.setModeTransmit();
Serial.println("tx");
unsigned int MORSE_BUF_SIZE = 128; unsigned int MORSE_BUF_SIZE = 128;
char morse_buf[MORSE_BUF_SIZE]; char morse_buf[MORSE_BUF_SIZE];
unsigned int morse_idx; unsigned int morse_idx;
@ -161,8 +114,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.
radio.setModeReceive();
Serial.println("sent"); Serial.println("sent");
radio.setModeReceive();
radio.lookForTone(MORSE_FREQ);
} 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: ");
@ -171,33 +125,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(".");
//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("-");
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

@ -10,7 +10,7 @@
* 446MHz to receive the image output. * 446MHz to receive the image output.
*/ */
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -28,13 +28,14 @@ int16_t rssi;
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up

View File

@ -16,7 +16,7 @@
#include <HamShield.h> #include <HamShield.h>
#include <DDS.h> #include <DDS.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -32,13 +32,14 @@ ddsAccumulator_t freqTable[3];
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -54,7 +55,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 PWM_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,20 +98,18 @@ 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(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
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,137 +119,444 @@ 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
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
state = TX;
Serial.println("#TX,ON;");
timer = millis();
break;
case 32: // space - transmit case '?': // ? - RSSI
if(repeater == 1) { radio.frequency(tx); } Serial.print(":");
radio.setModeTransmit(); Serial.print(radio.readRSSI(),DEC);
state = 10; Serial.println(";");
Serial.println("#TX,ON;"); break;
timer = millis();
break;
case 63: // ? - RSSI case '^': // ^ - VSSI (voice) level
Serial.print(":"); Serial.print(":");
Serial.print(radio.readRSSI(),DEC); Serial.print(radio.readVSSI(),DEC);
Serial.println(";"); Serial.println(";");
break; break;
case 65: // A - CTCSS In case 'F': // F - frequency
getValue(); getValue();
ctcssin = atof(cmdbuff); freq = atol(cmdbuff);
radio.setCtcss(ctcssin); if(radio.frequency(freq) == true) {
break; Serial.print("@");
Serial.print(freq,DEC);
Serial.println(";!;");
} else {
Serial.println("X1;");
}
break;
case 66: // B - CTCSS Out case 'P': // P - power level
break; getValue();
temp = atol(cmdbuff);
radio.setRfPower(temp);
Serial.println("!;");
break;
case 67: // C - CTCSS Enable case 'S': // S - squelch
break; 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 68: // D - CDCSS Enable case 'R': // R - repeater offset mode
break; getValue();
temp = atol(cmdbuff);
if(temp == 0) { repeater = 0; }
if(temp == 1) { repeater = 1; }
Serial.println("!;");
break;
case 70: // F - frequency case 'T': // T - transmit offset
getValue(); getValue();
freq = atol(cmdbuff); tx_freq = atol(cmdbuff);
if(radio.frequency(freq) == true) { Serial.print("@"); Serial.print(freq,DEC); Serial.println(";!;"); } else { Serial.println("X1;"); } Serial.println("!;");
break; break;
case 'M': case 'M': // M - Morse
getValue(); getValue();
radio.setModeTransmit(); if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
delay(300); muted = false; // can't mute (for PL tones) during tx
radio.morseOut(cmdbuff); radio.setUnmute();
state = 10; radio.setModeTransmit();
break; delay(300);
radio.morseOut(cmdbuff);
if(repeater == true) { radio.frequency(freq); }
radio.setModeReceive();
Serial.println("!;");
break;
case 80: // P - power level case 'N': // N - set to Morse in Mode
getValue(); morse_rx_setup();
temp = atol(cmdbuff); state = MORSE;
radio.setRfPower(temp); Serial.println("!;");
break; break;
case 82: // R - repeater offset mode case 'D': // D - DTMF Out
getValue(); dtmfSetup();
temp = atol(cmdbuff); getValue();
if(temp == 0) { repeater = 0; } dtmf_out(cmdbuff);
if(temp == 1) { repeater = 1; } Serial.println("!;");
break; break;
case 83: // S - squelch case 'B': // B - set to DTMF in Mode
getValue(); dtmfSetup();
temp = atol(cmdbuff); radio.enableDTMFReceive();
radio.setSQLoThresh(temp); state = DTMF;
break; Serial.println("!;");
break;
case 84: // T - transmit offset case 'A': // A - TX PL Tone configuration command
getValue(); pl_tone_tx();
tx = atol(cmdbuff); Serial.println("!;");
break; break;
case 'C': // C - RX PL Tone configuration command
pl_tone_rx();
Serial.println("!;");
break;
case 94: // ^ - VSSI (voice) level case 'V': // V - set volume
Serial.print(":"); getValue();
Serial.print(radio.readVSSI(),DEC); temp = cmdbuff[0];
Serial.println(";"); 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;
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; 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();
} }
}
} }
void getValue() { void getValue() {
int p = 0; int p = 0;
char temp; char temp;
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) { cmdbuff[0] = 0;
Serial.print("@"); return;
for(int x = 0; x < 32; x++) { }
Serial.println(cmdbuff[x]); }
}
cmdbuff[0] = 0;
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

@ -0,0 +1,704 @@
/* Hamshield
* Example: AppSerialController_nRF52840
* This is a simple example to demonstrate the HamShield working
* with an Adafruit Feather nRF52840 Express
*
* HamShield to Feather Connections:
* SPKR - Feather A0
* MIC - Feather D11
* CLK - Feather D5
* nCS - Feather D6
* DAT - Feather D9
* GND - Feather GND
* VCC - Feather 3.3V
*
* Connect the HamShield to your Feather as above.
* Screw the antenna into the HamShield RF jack. Plug a pair
* of headphones into the HamShield.
*
* Connect the Feather nRF52840 Express to your computer via
* a USB Micro B cable. After uploading this program to
* your Feather, open the Serial Monitor. You should see some
* text displayed that documents the setup process.
*
* Once the Feather is set up and talking to the HamShield,
* you can control it over USB-Serial or BLE-Serial(UART).
*
* Try using Adafruit's Bluefruit app to connect to the Feather.
* Once you're connected, you can control the HamShield using
* the same commands you'd use over USB-Serial. The response to
* all commands will be echoed to both USB-Serial and BLE-Serial(UART).
*
Commands:
Mode ASCII Description
-------------- ----------- --------------------------------------------------------------------------------------------------------------------------------------------
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
Frequency F<freq>; Set the receive frequency in KHz, if offset is disabled, this is the transmit frequency
Morse Out M<text>; A small buffer for morse code (32 chars)
Morse In N; Sets mode to Morse In, listening for Morse
Power level P<level>; Set the power amp level, 0 = lowest, 15 = highest
Enable Offset R<state>; 1 turns on repeater offset mode, 0 turns off repeater offset mode
Squelch S<level>; Set the squelch level
TX Offset T<freq>; The absolute frequency of the repeater offset to transmit on in KHz
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:
Condition ASCII Description
------------ ---------- -----------------------------------------------------------------
Startup *<code>; Startup and shield connection status
Success !; Generic success message for command that returns no value
Error X<code>; Indicates an error code. The numerical value is the type of error
Value :<value>; In response to a query
Status #<value>; Unsolicited status 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 <bluefruit.h>
#include <stdarg.h>
#include <stdio.h>
#include <HamShield.h>
// BLE Service
BLEDis bledis; // device information
BLEUart bleuart; // uart over ble
BLEBas blebas; // battery
// create object for radio
HamShield radio(6,5,9);
// To use non-standard pins, use the following initialization
//HamShield radio(ncs_pin, clk_pin, dat_pin);
#define LED_PIN 3
#define MIC_PIN A1
enum {TX, NORMAL, DTMF, MORSE, KISS};
int state = NORMAL;
bool rx_ctcss = false;
bool muted = false;
int txcount = 0;
long timer = 0; // Transmit timer to track timeout (send space to reset)
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] = "";
int temp = 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 ctcssout = 0;
int cdcssin = 0;
int cdcssout = 0;
void setup() {
// NOTE: if not using PWM out (MIC pin), it should be held low to avoid tx noise
pinMode(MIC_PIN, OUTPUT);
digitalWrite(MIC_PIN, LOW);
// initialize serial communication
Serial.begin(115200);
while (!Serial) delay(10);
// Setup the BLE LED to be enabled on CONNECT
// Note: This is actually the default behaviour, but provided
// here in case you want to control this LED manually via PIN 19
Bluefruit.autoConnLed(true);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin();
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Bluefruit.setTxPower(4);
Bluefruit.setName("MyBlueHam");
//Bluefruit.setName(getMcuUniqueID()); // useful testing with multiple central connections
Bluefruit.setConnectCallback(connect_callback);
Bluefruit.setDisconnectCallback(disconnect_callback);
// Configure and Start Device Information Service
bledis.setManufacturer("Enhanced Radio Devices");
bledis.setModel("BlueHam");
bledis.begin();
// Configure and Start BLE Uart Service
bleuart.begin();
// Start BLE Battery Service
blebas.begin();
blebas.write(100);
// Set up and start advertising
startAdv();
delay(100);
SerialWrite(";;;;;;;;;;;;;;;;;;;;;;;;;;\n");
int result = radio.testConnection();
SerialWrite("*%d;\n", result);
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
radio.frequency(freq);
radio.setVolume1(0xF);
radio.setVolume2(0xF);
radio.setModeReceive();
radio.setTxSourceMic();
radio.setRfPower(pwr);
radio.setSQLoThresh(-80);
radio.setSQHiThresh(-70);
radio.setSQOn();
SerialWrite("*START;\n");
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 128-bit uuid
Bluefruit.Advertising.addService(bleuart);
// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
* For recommended advertising interval
* https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void loop() {
// TODO: loop fixing based on serialtransciever!
char c = 0;
bool ble_serial = false;
if (Serial.available()) {
Serial.readBytes(&c, 1);
} else if (bleuart.available()) {
c = (char) bleuart.read();
ble_serial = true;
}
// TODO: BLE
if(c != 0) {
int text = c; // get the first char to see what the upcoming command is
switch (state) {
// we handle commands differently based on what state we're in
case TX:
// we're currently transmitting
// if we got a space, reset our transmit timeout
if(text == ' ') { timer = millis();}
break;
case NORMAL:
switch(text) {
case ' ': // space - transmit
if(repeater == true && tx_freq != 0) { radio.frequency(tx_freq); }
muted = false; // can't mute (for PL tones) during tx
radio.setUnmute();
radio.setModeTransmit();
state = TX;
SerialWrite("#TX,ON;\n");
timer = millis();
break;
case '?': // ? - RSSI
SerialWrite(":%d;\n", radio.readRSSI());
break;
case '^': // ^ - VSSI (voice) level
SerialWrite(":%d;\n", radio.readVSSI());
break;
case 'F': // F - frequency
getValue(ble_serial);
freq = atol(cmdbuff);
if(radio.frequency(freq) == true) {
SerialWrite("@%d;!;\n", freq);
} else {
SerialWrite("X1;\n");
}
break;
case 'P': // P - power level
getValue(ble_serial);
temp = atol(cmdbuff);
radio.setRfPower(temp);
SerialWrite("!;\n");
break;
case 'S': // S - squelch
getValue(ble_serial);
temp = atol(cmdbuff);
if (temp < -2 && temp > -130) {
radio.setSQLoThresh(temp);
radio.setSQHiThresh(temp+2);
radio.setSQOn();
SerialWrite("%d!;\n", temp);
} else {
SerialWrite("X!;\n");
}
break;
case 'R': // R - repeater offset mode
getValue(ble_serial);
temp = atol(cmdbuff);
if(temp == 0) { repeater = 0; }
if(temp == 1) { repeater = 1; }
SerialWrite("!;\n");
break;
case 'T': // T - transmit offset
getValue(ble_serial);
tx_freq = atol(cmdbuff);
SerialWrite("!;\n");
break;
case 'M': // M - Morse
getValue(ble_serial);
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();
SerialWrite("!;\n");
break;
case 'N': // N - set to Morse in Mode
morse_rx_setup();
state = MORSE;
SerialWrite("!;\n");
break;
case 'D': // D - DTMF Out
dtmfSetup();
getValue(ble_serial);
dtmf_out(cmdbuff);
SerialWrite("!;\n");
break;
case 'B': // B - set to DTMF in Mode
dtmfSetup();
radio.enableDTMFReceive();
state = DTMF;
SerialWrite("!;\n");
break;
case 'A': // A - TX PL Tone configuration command
pl_tone_tx();
SerialWrite("!;\n");
break;
case 'C': // C - RX PL Tone configuration command
pl_tone_rx();
SerialWrite("!;\n");
break;
case 'V': // V - set volume
getValue(ble_serial);
temp = cmdbuff[0];
if (temp == 0x31) {
temp = atol(cmdbuff + 1);
radio.setVolume1(temp);
SerialWrite("!;\n");
} else if (temp == 0x32) {
temp = atol(cmdbuff + 1);
radio.setVolume2(temp);
SerialWrite("!;\n");
} else {
// not a valid volume command, flush buffers
SerialFlush(ble_serial);
SerialWrite("X!;\n");
}
break;
case 'K': // K - switch to KISS TNC mode
//state = KISS;
//TODO: set up KISS
SerialWrite("X1;\n");
break;
default:
// unknown command, flush the input buffer and wait for next one
SerialWrite("X1;\n");
SerialFlush(ble_serial);
break;
}
break;
case KISS:
if ((ble_serial && bleuart.peek() == '_') || (!ble_serial && 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(ble_serial);
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
SerialFlush(ble_serial);
}
break;
case DTMF:
if (text == '_') { state = NORMAL; }
if (text == 'D') { // tx message
getValue(ble_serial);
dtmf_out(cmdbuff);
} else {
// not a valid cmd
SerialFlush(ble_serial);
}
break;
default:
// we're in an invalid state, reset to safe settings
SerialFlush(ble_serial);
radio.frequency(freq);
radio.setModeReceive();
state = NORMAL;
break;
}
}
// now handle any state related functions
switch (state) {
case TX:
if(millis() > (timer + 500)) {
SerialWrite("#TX,OFF;\n");
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
SerialFlushWhitespace(ble_serial);
}
// callback invoked when central connects
void connect_callback(uint16_t conn_handle)
{
char central_name[32] = { 0 };
Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
Serial.print("Connected to ");
Serial.println(central_name);
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
* https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.println();
Serial.println("Disconnected");
}
void getValue(bool ble_serial) {
int p = 0;
char temp;
for(;;) {
if((!ble_serial && Serial.available()) || (ble_serial && bleuart.available())) {
if (ble_serial) {
temp = bleuart.read();
} else {
temp = Serial.read();
}
if(temp == 59) {
cmdbuff[p] = 0;
return;
}
cmdbuff[p] = temp;
p++;
if(p == 32) {
cmdbuff[0] = 0;
return;
}
}
}
}
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
SerialWrite("R%d;\n", m);
}
}
// 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
SerialWrite("R%c;\n",m);
}
}
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();
}
}
#define TEXT_BUF_LEN 64
char text_buf[TEXT_BUF_LEN];
void SerialWrite(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int str_len = vsnprintf(text_buf, TEXT_BUF_LEN, fmt, args);
va_end(args);
bleuart.write(text_buf, str_len);
Serial.write(text_buf, str_len);
}
void SerialFlush(bool ble_serial) {
if (ble_serial) {
while (bleuart.available()) { bleuart.read(); }
} else {
while (Serial.available()) { Serial.read(); }
}
}
void SerialFlushWhitespace(bool ble_serial) {
if (!ble_serial && Serial.available()) {
char cpeek = Serial.peek();
while (cpeek == ' ' || cpeek == '\r' || cpeek == '\n')
{
Serial.read();
cpeek = Serial.peek();
}
} else if (ble_serial && bleuart.available()) {
char cpeek = bleuart.peek();
while (cpeek == ' ' || cpeek == '\r' || cpeek == '\n')
{
bleuart.read();
cpeek = bleuart.peek();
}
}
}

View File

@ -25,7 +25,7 @@ char CALLSIGN[] = "1ZZ9ZZ/B";
#include <HamShield.h> #include <HamShield.h>
#include <PCM.h> #include <PCM.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -90,13 +90,14 @@ const unsigned char dbm[] PROGMEM = {
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, LOW); digitalWrite(MIC_PIN, LOW);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -106,7 +107,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

@ -2,6 +2,10 @@
* Example: SpeechTX - This example used the basic JustTransmit example from the above site * Example: SpeechTX - This example used the basic JustTransmit example from the above site
* This example uses the Talkie Arduino speech library. It transmits pre-encoded speech over the air. * This example uses the Talkie Arduino speech library. It transmits pre-encoded speech over the air.
* More info at: https://github.com/going-digital/Talkie * More info at: https://github.com/going-digital/Talkie
*
* Make sure you're using an Arduino Uno or equivalent. The Talkie library doesn't work
* with hardware that doesn't use the ATMega328 or ATMega168.
*
* Connect the HamShield to your Arduino. Screw the antenna * Connect the HamShield to your Arduino. Screw the antenna
* into the HamShield RF jack. Connect the Arduino to * into the HamShield RF jack. Connect the Arduino to
* wall power and then to your computer via USB. After * wall power and then to your computer via USB. After
@ -12,7 +16,7 @@
#include <HamShield.h> #include <HamShield.h>
#define PWM_PIN 3 #define MIC_PIN 3
#define RESET_PIN A3 #define RESET_PIN A3
#define SWITCH_PIN 2 #define SWITCH_PIN 2
@ -230,13 +234,14 @@ const uint8_t spYELLOW[] PROGMEM = {0x69,0xBD,0x56,0x15,0xAC,0x67,0xE5,0x
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
pinMode(PWM_PIN, OUTPUT); pinMode(MIC_PIN, OUTPUT);
digitalWrite(PWM_PIN, HIGH); digitalWrite(MIC_PIN, HIGH);
// prep the switch // prep the switch
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
// set up the reset control pin // set up the reset control pin
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
pinMode(RESET_PIN, OUTPUT); pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, HIGH); digitalWrite(RESET_PIN, HIGH);
delay(5); // wait for device to come up delay(5); // wait for device to come up
@ -249,9 +254,16 @@ 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);
}
void loop() {
radio.waitForChannel(); // wait for the channel to be empty
radio.setModeTransmit(); radio.setModeTransmit();
delay(100); // wait for PA to come up
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
voice.say(spSIX); // more word choices can be found at the talkie github site voice.say(spSIX); // more word choices can be found at the talkie github site
voice.say(spALPHA); voice.say(spALPHA);
@ -267,10 +279,6 @@ void setup() {
voice.say(spON); voice.say(spON);
voice.say(spFIRE); voice.say(spFIRE);
} radio.setModeReceive();
delay(10000);
void loop() {
radio.frequency(144025);
radio.setModeTransmit();
for(;;) { }
} }

View File

@ -1,5 +1,5 @@
name=HamShield name=HamShield
version=1.1.2 version=1.1.4
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

@ -18,6 +18,7 @@
/* don't change this regulatory value, use dangerMode() and safeMode() instead */ /* don't change this regulatory value, use dangerMode() and safeMode() instead */
bool restrictions = true; bool restrictions = true;
uint16_t old_dtmf_reg;
/* channel lookup tables */ /* channel lookup tables */
@ -125,11 +126,11 @@ const unsigned char AFSK_space[] PROGMEM = { 140, 228, 250, 166, 53, 0, 53, 166,
* @see A1846S_ADDRESS_AD0_LOW * @see A1846S_ADDRESS_AD0_LOW
* @see A1846S_ADDRESS_AD0_HIGH * @see A1846S_ADDRESS_AD0_HIGH
*/ */
HamShield::HamShield(uint8_t cs_pin, uint8_t clk_pin, uint8_t dat_pin, uint8_t pwm_pin) { HamShield::HamShield(uint8_t ncs_pin, uint8_t clk_pin, uint8_t dat_pin, uint8_t mic_pin) {
devAddr = cs_pin; devAddr = ncs_pin;
hs_pwm_pin = pwm_pin; hs_mic_pin = mic_pin;
HSsetPins(cs_pin, clk_pin, dat_pin); HSsetPins(ncs_pin, clk_pin, dat_pin);
} }
@ -192,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
@ -226,12 +227,15 @@ void HamShield::initialize(bool narrowBand) {
setModeReceive(); setModeReceive();
setTxSourceMic(); setTxSourceMic();
setRfPower(0); setRfPower(0);
setSQLoThresh(80); setSQLoThresh(-80);
setSQOn(); setSQOn();
*/ */
setDTMFIdleTime(50); setDTMFIdleTime(50);
setDTMFTxTime(60); setDTMFTxTime(60);
setDTMFDetectTime(24); setDTMFDetectTime(24);
HSreadWord(devAddr, A1846S_DTMF_ENABLE_REG, radio_dat_buf);
old_dtmf_reg = radio_dat_buf[0];
} }
@ -252,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);
@ -384,13 +388,13 @@ void HamShield::setupWideBand() {
// end AGC table // end AGC table
} }
/** Verify the I2C connection. /** Verify the data connection.
* Make sure the device is connected and responds as expected. * Make sure the device is connected and responds as expected.
* @return True if connection is valid, false otherwise * @return True if connection is valid, false otherwise
*/ */
bool HamShield::testConnection() { bool HamShield::testConnection() {
HSreadWord(devAddr, 0x00, radio_i2c_buf); HSreadWord(devAddr, 0x00, radio_dat_buf);
return radio_i2c_buf[0] == 0x1846; return radio_dat_buf[0] == 0x1846;
} }
@ -410,8 +414,8 @@ bool HamShield::testConnection() {
*/ */
uint16_t HamShield::readCtlReg() { uint16_t HamShield::readCtlReg() {
HSreadWord(devAddr, A1846S_CTL_REG, radio_i2c_buf); HSreadWord(devAddr, A1846S_CTL_REG, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::softReset() { void HamShield::softReset() {
@ -499,8 +503,8 @@ void HamShield::setClkMode(bool LFClk){
HSwriteWord(devAddr, A1846S_CLK_MODE_REG, tx_data); HSwriteWord(devAddr, A1846S_CLK_MODE_REG, tx_data);
} }
bool HamShield::getClkMode(){ bool HamShield::getClkMode(){
HSreadBitW(devAddr, A1846S_CLK_MODE_REG, A1846S_CLK_MODE_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CLK_MODE_REG, A1846S_CLK_MODE_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
// TODO: create a 25kHz setup option as well as 12.5kHz (as is implemented now) // TODO: create a 25kHz setup option as well as 12.5kHz (as is implemented now)
@ -513,8 +517,8 @@ void HamShield::setChanMode(uint16_t mode){
HSwriteBitsW(devAddr, A1846S_CTL_REG, A1846S_CHAN_MODE_BIT, A1846S_CHAN_MODE_LENGTH, mode); HSwriteBitsW(devAddr, A1846S_CTL_REG, A1846S_CHAN_MODE_BIT, A1846S_CHAN_MODE_LENGTH, mode);
} }
uint16_t HamShield::getChanMode(){ uint16_t HamShield::getChanMode(){
HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_CHAN_MODE_BIT, A1846S_CHAN_MODE_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_CHAN_MODE_BIT, A1846S_CHAN_MODE_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
*/ */
@ -547,8 +551,8 @@ void HamShield::setTX(bool on_noff){
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_TX_MODE_BIT, on_noff); HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_TX_MODE_BIT, on_noff);
} }
bool HamShield::getTX(){ bool HamShield::getTX(){
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TX_MODE_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TX_MODE_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
void HamShield::setRX(bool on_noff){ void HamShield::setRX(bool on_noff){
@ -569,8 +573,8 @@ void HamShield::setRX(bool on_noff){
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_RX_MODE_BIT, on_noff); HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_RX_MODE_BIT, on_noff);
} }
bool HamShield::getRX(){ bool HamShield::getRX(){
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_RX_MODE_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_RX_MODE_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
void HamShield::setModeTransmit(){ void HamShield::setModeTransmit(){
@ -630,8 +634,8 @@ void HamShield::setTxSourceNone(){
setTxSource(0); setTxSource(0);
} }
uint16_t HamShield::getTxSource(){ uint16_t HamShield::getTxSource(){
HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_VOICE_SEL_BIT, A1846S_VOICE_SEL_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_VOICE_SEL_BIT, A1846S_VOICE_SEL_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
/* /*
@ -648,8 +652,8 @@ void HamShield::setPABiasVoltage(uint16_t voltage){
HSwriteBitsW(devAddr, A1846S_PABIAS_REG, A1846S_PABIAS_BIT, A1846S_PABIAS_LENGTH, voltage); HSwriteBitsW(devAddr, A1846S_PABIAS_REG, A1846S_PABIAS_BIT, A1846S_PABIAS_LENGTH, voltage);
} }
uint16_t HamShield::getPABiasVoltage(){ uint16_t HamShield::getPABiasVoltage(){
HSreadBitsW(devAddr, A1846S_PABIAS_REG, A1846S_PABIAS_BIT, A1846S_PABIAS_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_PABIAS_REG, A1846S_PABIAS_BIT, A1846S_PABIAS_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
*/ */
// Subaudio settings // Subaudio settings
@ -668,8 +672,8 @@ void HamShield::setCtcssCdcssMode(uint16_t mode){
HSwriteBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTDCSS_DTEN_BIT, A1846S_CTDCSS_DTEN_LEN, mode); HSwriteBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTDCSS_DTEN_BIT, A1846S_CTDCSS_DTEN_LEN, mode);
} }
uint16_t HamShield::getCtcssCdcssMode(){ uint16_t HamShield::getCtcssCdcssMode(){
HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTDCSS_DTEN_BIT, A1846S_CTDCSS_DTEN_BIT, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTDCSS_DTEN_BIT, A1846S_CTDCSS_DTEN_BIT, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setDetPhaseShift() { void HamShield::setDetPhaseShift() {
@ -707,16 +711,16 @@ void HamShield::setCdcssSel(bool long_nshort){
HSwriteBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_SEL_BIT, long_nshort); HSwriteBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_SEL_BIT, long_nshort);
} }
bool HamShield::getCdcssSel(){ bool HamShield::getCdcssSel(){
HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_SEL_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_SEL_BIT, radio_dat_buf);
return (radio_i2c_buf[0] == 1); return (radio_dat_buf[0] == 1);
} }
void HamShield::setCdcssInvert(bool invert) { void HamShield::setCdcssInvert(bool invert) {
HSwriteBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_INVERT_BIT, invert); HSwriteBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_INVERT_BIT, invert);
} }
bool HamShield::getCdcssInvert() { bool HamShield::getCdcssInvert() {
HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_INVERT_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_INVERT_BIT, radio_dat_buf);
return (radio_i2c_buf[0] == 1); return (radio_dat_buf[0] == 1);
} }
// Cdcss neg_det_en // Cdcss neg_det_en
@ -759,8 +763,8 @@ float HamShield::getCtcssFreqHz() {
//y = mx + b //y = mx + b
float m = 1.678; float m = 1.678;
float b = -3.3; float b = -3.3;
HSreadWord(devAddr, A1846S_CTCSS_FREQ_REG, radio_i2c_buf); HSreadWord(devAddr, A1846S_CTCSS_FREQ_REG, radio_dat_buf);
float f = (float) radio_i2c_buf[0]; float f = (float) radio_dat_buf[0];
return (f/m-b)/100; return (f/m-b)/100;
} }
@ -769,28 +773,45 @@ 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() {
HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 0); void HamShield::enableCtcss() {
// enable TX
enableCtcssTx();
// enable RX
enableCtcssRx();
}
void HamShield::disableCtcssTx() {
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) {
HSwriteBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 15, 8, thresh); HSwriteBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 15, 8, thresh);
} }
uint8_t HamShield::getCtcssDetThreshIn() { uint8_t HamShield::getCtcssDetThreshIn() {
HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 15, 8, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 15, 8, radio_dat_buf);
return (uint8_t) radio_i2c_buf[0]; return (uint8_t) radio_dat_buf[0];
} }
// unmatch threshold // unmatch threshold
@ -798,13 +819,13 @@ void HamShield::setCtcssDetThreshOut(uint8_t thresh) {
HSwriteBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 7, 8, thresh); HSwriteBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 7, 8, thresh);
} }
uint8_t HamShield::getCtcssDetThreshOut() { uint8_t HamShield::getCtcssDetThreshOut() {
HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 7, 8, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 7, 8, radio_dat_buf);
return (uint8_t) radio_i2c_buf[0]; return (uint8_t) radio_dat_buf[0];
} }
bool HamShield::getCtcssToneDetected() { bool HamShield::getCtcssToneDetected() {
HSreadBitW(devAddr, A1846S_FLAG_REG, A1846S_CTCSS1_FLAG_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_FLAG_REG, A1846S_CTCSS1_FLAG_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
// cdcss codes // cdcss codes
@ -835,10 +856,10 @@ void HamShield::setCdcssCode(uint16_t code) {
} }
uint16_t HamShield::getCdcssCode() { uint16_t HamShield::getCdcssCode() {
uint32_t oct_code; uint32_t oct_code;
HSreadWord(devAddr, A1846S_CDCSS_CODE_HI_REG, radio_i2c_buf); HSreadWord(devAddr, A1846S_CDCSS_CODE_HI_REG, radio_dat_buf);
oct_code = ((uint32_t)radio_i2c_buf[0] << 16); oct_code = ((uint32_t)radio_dat_buf[0] << 16);
HSreadWord(devAddr, A1846S_CDCSS_CODE_LO_REG, radio_i2c_buf); HSreadWord(devAddr, A1846S_CDCSS_CODE_LO_REG, radio_dat_buf);
oct_code += radio_i2c_buf[0]; oct_code += radio_dat_buf[0];
oct_code = oct_code >> 12; oct_code = oct_code >> 12;
uint16_t code = (oct_code & 0x3); uint16_t code = (oct_code & 0x3);
@ -858,32 +879,38 @@ void HamShield::setSQOff(){
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_SQ_ON_BIT, 0); HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_SQ_ON_BIT, 0);
} }
bool HamShield::getSQState(){ bool HamShield::getSQState(){
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_SQ_ON_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_SQ_ON_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
// SQ threshold // SQ threshold
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_dat_buf);
return radio_i2c_buf[0] - 137; return radio_dat_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_dat_buf);
return radio_i2c_buf[0] - 137; return radio_dat_buf[0] - 137;
} }
bool HamShield::getSquelching() {
HSreadBitW(devAddr, A1846S_FLAG_REG, A1846S_SQ_FLAG_BIT, radio_dat_buf);
return (radio_dat_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);
@ -892,8 +919,8 @@ void HamShield::clearSQOutSel(){
HSwriteBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, 0); HSwriteBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, 0);
} }
bool HamShield::getSQOutSel(){ bool HamShield::getSQOutSel(){
HSreadBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
// VOX // VOX
@ -904,8 +931,8 @@ void HamShield::setVoxOff(){
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_VOX_ON_BIT, 0); HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_VOX_ON_BIT, 0);
} }
bool HamShield::getVoxOn(){ bool HamShield::getVoxOn(){
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_VOX_ON_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_VOX_ON_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
// Vox Threshold // Vox Threshold
@ -915,16 +942,16 @@ void HamShield::setVoxOpenThresh(uint16_t vox_open_thresh){
} }
uint16_t HamShield::getVoxOpenThresh(){ uint16_t HamShield::getVoxOpenThresh(){
HSreadBitsW(devAddr, A1846S_TH_H_VOX_REG, A1846S_TH_H_VOX_BIT, A1846S_TH_H_VOX_LEN, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_TH_H_VOX_REG, A1846S_TH_H_VOX_BIT, A1846S_TH_H_VOX_LEN, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setVoxShutThresh(uint16_t vox_shut_thresh){ void HamShield::setVoxShutThresh(uint16_t vox_shut_thresh){
// When vssi < th_l_vox && time delay meet, then vox will be 0 (unit mV ) // When vssi < th_l_vox && time delay meet, then vox will be 0 (unit mV )
HSwriteBitsW(devAddr, A1846S_TH_L_VOX_REG, A1846S_TH_L_VOX_BIT, A1846S_TH_L_VOX_LEN, vox_shut_thresh); HSwriteBitsW(devAddr, A1846S_TH_L_VOX_REG, A1846S_TH_L_VOX_BIT, A1846S_TH_L_VOX_LEN, vox_shut_thresh);
} }
uint16_t HamShield::getVoxShutThresh(){ uint16_t HamShield::getVoxShutThresh(){
HSreadBitsW(devAddr, A1846S_TH_L_VOX_REG, A1846S_TH_L_VOX_BIT, A1846S_TH_L_VOX_LEN, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_TH_L_VOX_REG, A1846S_TH_L_VOX_BIT, A1846S_TH_L_VOX_LEN, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
// Tail Noise // Tail Noise
@ -935,8 +962,8 @@ void HamShield::disableTailNoiseElim(){
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_TAIL_ELIM_EN_BIT, 1); HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_TAIL_ELIM_EN_BIT, 1);
} }
bool HamShield::getTailNoiseElimEnabled(){ bool HamShield::getTailNoiseElimEnabled(){
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TAIL_ELIM_EN_BIT, radio_i2c_buf); HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TAIL_ELIM_EN_BIT, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
// tail noise shift select // tail noise shift select
@ -949,8 +976,8 @@ void HamShield::setShiftSelect(uint16_t shift_sel){
HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_SHIFT_SEL_BIT, A1846S_SHIFT_SEL_LEN, shift_sel); HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_SHIFT_SEL_BIT, A1846S_SHIFT_SEL_LEN, shift_sel);
} }
uint16_t HamShield::getShiftSelect(){ uint16_t HamShield::getShiftSelect(){
HSreadBitsW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_SHIFT_SEL_BIT, A1846S_SHIFT_SEL_LEN, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_SHIFT_SEL_BIT, A1846S_SHIFT_SEL_LEN, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
// DTMF // DTMF
@ -979,8 +1006,8 @@ void HamShield::setDTMFDetectTime(uint16_t detect_time) {
} }
uint16_t HamShield::getDTMFDetectTime() { uint16_t HamShield::getDTMFDetectTime() {
HSreadBitsW(devAddr, A1846S_DTMF_ENABLE_REG, A18462_DTMF_DET_TIME_BIT, A18462_DTMF_DET_TIME_LEN, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_DTMF_ENABLE_REG, A18462_DTMF_DET_TIME_BIT, A18462_DTMF_DET_TIME_LEN, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setDTMFIdleTime(uint16_t idle_time) { void HamShield::setDTMFIdleTime(uint16_t idle_time) {
@ -990,10 +1017,71 @@ void HamShield::setDTMFIdleTime(uint16_t idle_time) {
} }
uint16_t HamShield::getDTMFIdleTime() { uint16_t HamShield::getDTMFIdleTime() {
HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DTMF_IDLE_TIME_BIT, A1846S_DTMF_IDLE_TIME_LEN, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DTMF_IDLE_TIME_BIT, A1846S_DTMF_IDLE_TIME_LEN, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_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
@ -1001,8 +1089,8 @@ void HamShield::setDTMFTxTime(uint16_t tx_time) {
} }
uint16_t HamShield::getDTMFTxTime() { uint16_t HamShield::getDTMFTxTime() {
HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DUALTONE_TX_TIME_BIT, A1846S_DUALTONE_TX_TIME_LEN, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DUALTONE_TX_TIME_BIT, A1846S_DUALTONE_TX_TIME_LEN, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
uint16_t HamShield::disableDTMF(){ uint16_t HamShield::disableDTMF(){
@ -1010,18 +1098,18 @@ uint16_t HamShield::disableDTMF(){
} }
uint16_t HamShield::getDTMFSample(){ uint16_t HamShield::getDTMFSample(){
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
uint16_t HamShield::getDTMFTxActive(){ uint16_t HamShield::getDTMFTxActive(){
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_TX_IDLE_BIT, 1, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_TX_IDLE_BIT, 1, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
uint16_t HamShield::getDTMFCode(){ uint16_t HamShield::getDTMFCode(){
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_CODE_BIT, A1846S_DTMF_CODE_LEN, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_CODE_BIT, A1846S_DTMF_CODE_LEN, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setDTMFCode(uint16_t code){ void HamShield::setDTMFCode(uint16_t code){
@ -1062,9 +1150,44 @@ void HamShield::setDTMFCode(uint16_t code){
} }
// Tone Transmission
void HamShield::HStone(uint8_t pin, unsigned int frequency) {
// store old dtmf reg for noTone
// HSreadWord(devAddr, A1846S_DTMF_ENABLE_REG, radio_dat_buf);
// old_dtmf_reg = radio_dat_buf[0];
// set frequency
HSwriteWord(devAddr, A1846S_TONE1_FREQ, frequency*10);
// set 0x79 dtmf control
HSwriteBitsW(devAddr, 0x79, 15, 2, 0x3); // transmit single tone (not dtmf)
// HSwriteBitsW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_DTMF_ENABLE_BIT, 2, 0x2); // transmit single tone (not dtmf)
// bypass pre/de-emphasis
HSwriteBitsW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, 1, 1);
// set source for tx
setTxSourceTone1(); // writes to 3A
//tone(pin, frequency);
}
void HamShield::HSnoTone(uint8_t pin) {
setTxSourceMic();
//HSwriteWord(devAddr, A1846S_DTMF_ENABLE_REG, old_dtmf_reg); // disable tone and dtmf
// noTone(pin);
}
// Tone detection // Tone detection
void HamShield::lookForTone(uint16_t t_hz) { void HamShield::lookForTone(uint16_t t_hz) {
float tone_hz = (float) t_hz; // set 0x79 dtmf control
HSwriteBitsW(devAddr, 0x79, 15, 2, 0x3); // transmit single tone (not dtmf)
// bypass pre/de-emphasis
HSwriteBitsW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, 1, 1);
float tone_hz = (float) t_hz;
float Fs = 6400000/1024; float Fs = 6400000/1024;
float k = floor(tone_hz/Fs*127 + 0.5); float k = floor(tone_hz/Fs*127 + 0.5);
uint16_t t = (uint16_t) (round(2.0*cos(2.0*M_PI*k/127)*1024)); uint16_t t = (uint16_t) (round(2.0*cos(2.0*M_PI*k/127)*1024));
@ -1072,24 +1195,38 @@ void HamShield::lookForTone(uint16_t t_hz) {
float k2 = floor(2*tone_hz/Fs*127+0.5); float k2 = floor(2*tone_hz/Fs*127+0.5);
uint16_t h = (uint16_t) (round(2.0*cos(2.0*M_PI*k2/127)*1024)); uint16_t h = (uint16_t) (round(2.0*cos(2.0*M_PI*k2/127)*1024));
// set tone // set tone
HSwriteWord(devAddr, 0x68, t); HSwriteWord(devAddr, 0x67, t); // looking for tone 1
// set second harmonic // set second harmonic
HSwriteWord(devAddr, 0x70, h); HSwriteWord(devAddr, 0x6F, h); // looking for tone
// turn on tone detect // turn on tone detect
HSwriteBitW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_TONE_DETECT, 1); HSwriteBitW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_TONE_DETECT, 1);
HSwriteBitW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_DTMF_ENABLE_BIT, 1); HSwriteBitW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_DTMF_ENABLE_BIT, 1);
} }
bool redetect = false;
uint8_t last_tone_detected = 0;
uint8_t HamShield::toneDetected() { uint8_t HamShield::toneDetected() {
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_dat_buf);
if (radio_i2c_buf[0] != 0) { if (radio_dat_buf[0] != 0) {
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_CODE_BIT, A1846S_DTMF_CODE_LEN, radio_i2c_buf); if (!redetect) {
if (radio_i2c_buf[0] == 1) { redetect = true;
return 1; HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_CODE_BIT, A1846S_DTMF_CODE_LEN, radio_dat_buf);
} last_tone_detected = radio_dat_buf[0];
} //Serial.print("t: ");
//Serial.println(last_tone_detected);
}
if (last_tone_detected == 0) {
return 1;
}
} else if (redetect) {
// re-enable detect
redetect = false;
HSwriteBitW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_TONE_DETECT, 1);
HSwriteBitW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_DTMF_ENABLE_BIT, 1);
}
return 0; return 0;
} }
@ -1098,15 +1235,15 @@ void HamShield::setFMVoiceCssDeviation(uint16_t deviation){
HSwriteBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_VOICE_BIT, A1846S_FM_DEV_VOICE_LENGTH, deviation); HSwriteBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_VOICE_BIT, A1846S_FM_DEV_VOICE_LENGTH, deviation);
} }
uint16_t HamShield::getFMVoiceCssDeviation(){ uint16_t HamShield::getFMVoiceCssDeviation(){
HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_VOICE_BIT, A1846S_FM_DEV_VOICE_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_VOICE_BIT, A1846S_FM_DEV_VOICE_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setFMCssDeviation(uint16_t deviation){ void HamShield::setFMCssDeviation(uint16_t deviation){
HSwriteBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_CSS_BIT, A1846S_FM_DEV_CSS_LENGTH, deviation); HSwriteBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_CSS_BIT, A1846S_FM_DEV_CSS_LENGTH, deviation);
} }
uint16_t HamShield::getFMCssDeviation(){ uint16_t HamShield::getFMCssDeviation(){
HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_CSS_BIT, A1846S_FM_DEV_CSS_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_CSS_BIT, A1846S_FM_DEV_CSS_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
// RX voice range // RX voice range
@ -1121,15 +1258,15 @@ void HamShield::setVolume1(uint16_t volume){
HSwriteBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_1_BIT, A1846S_RX_VOL_1_LENGTH, volume); HSwriteBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_1_BIT, A1846S_RX_VOL_1_LENGTH, volume);
} }
uint16_t HamShield::getVolume1(){ uint16_t HamShield::getVolume1(){
HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_1_BIT, A1846S_RX_VOL_1_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_1_BIT, A1846S_RX_VOL_1_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setVolume2(uint16_t volume){ void HamShield::setVolume2(uint16_t volume){
HSwriteBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_2_BIT, A1846S_RX_VOL_2_LENGTH, volume); HSwriteBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_2_BIT, A1846S_RX_VOL_2_LENGTH, volume);
} }
uint16_t HamShield::getVolume2(){ uint16_t HamShield::getVolume2(){
HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_2_BIT, A1846S_RX_VOL_2_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_2_BIT, A1846S_RX_VOL_2_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
// GPIO // GPIO
@ -1155,8 +1292,8 @@ uint16_t HamShield::getGpioMode(uint16_t gpio){
uint16_t mode_len = 2; uint16_t mode_len = 2;
uint16_t bit = gpio*2 + 1; uint16_t bit = gpio*2 + 1;
HSreadBitsW(devAddr, A1846S_GPIO_MODE_REG, bit, mode_len, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_GPIO_MODE_REG, bit, mode_len, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setGpios(uint16_t mode){ void HamShield::setGpios(uint16_t mode){
@ -1164,8 +1301,8 @@ void HamShield::setGpios(uint16_t mode){
} }
uint16_t HamShield::getGpios(){ uint16_t HamShield::getGpios(){
HSreadWord(devAddr, A1846S_GPIO_MODE_REG, radio_i2c_buf); HSreadWord(devAddr, A1846S_GPIO_MODE_REG, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
// Int // Int
@ -1176,8 +1313,8 @@ void HamShield::disableInterrupt(uint16_t interrupt){
HSwriteBitW(devAddr, A1846S_INT_MODE_REG, interrupt, 0); HSwriteBitW(devAddr, A1846S_INT_MODE_REG, interrupt, 0);
} }
bool HamShield::getInterruptEnabled(uint16_t interrupt){ bool HamShield::getInterruptEnabled(uint16_t interrupt){
HSreadBitW(devAddr, A1846S_INT_MODE_REG, interrupt, radio_i2c_buf); HSreadBitW(devAddr, A1846S_INT_MODE_REG, interrupt, radio_dat_buf);
return (radio_i2c_buf[0] != 0); return (radio_dat_buf[0] != 0);
} }
// ST mode // ST mode
@ -1185,8 +1322,8 @@ void HamShield::setStMode(uint16_t mode){
HSwriteBitsW(devAddr, A1846S_CTL_REG, A1846S_ST_MODE_BIT, A1846S_ST_MODE_LENGTH, mode); HSwriteBitsW(devAddr, A1846S_CTL_REG, A1846S_ST_MODE_BIT, A1846S_ST_MODE_LENGTH, mode);
} }
uint16_t HamShield::getStMode(){ uint16_t HamShield::getStMode(){
HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_ST_MODE_BIT, A1846S_ST_MODE_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_ST_MODE_BIT, A1846S_ST_MODE_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
void HamShield::setStFullAuto(){ void HamShield::setStFullAuto(){
setStMode(2); setStMode(2);
@ -1206,8 +1343,8 @@ void HamShield::usePreDeEmph(){
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, 0); HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, 0);
} }
bool HamShield::getPreDeEmphEnabled(){ bool HamShield::getPreDeEmphEnabled(){
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, radio_i2c_buf); HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, radio_dat_buf);
return (radio_i2c_buf[0] == 0); return (radio_dat_buf[0] == 0);
} }
// Voice Filters // Voice Filters
@ -1218,8 +1355,8 @@ void HamShield::useVoiceHpf(){
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VHPF_FILTER_EN, 0); HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VHPF_FILTER_EN, 0);
} }
bool HamShield::getVoiceHpfEnabled(){ bool HamShield::getVoiceHpfEnabled(){
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VHPF_FILTER_EN, radio_i2c_buf); HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VHPF_FILTER_EN, radio_dat_buf);
return (radio_i2c_buf[0] == 0); return (radio_dat_buf[0] == 0);
} }
void HamShield::bypassVoiceLpf(){ void HamShield::bypassVoiceLpf(){
@ -1229,8 +1366,8 @@ void HamShield::useVoiceLpf(){
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VLPF_FILTER_EN, 0); HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VLPF_FILTER_EN, 0);
} }
bool HamShield::getVoiceLpfEnabled(){ bool HamShield::getVoiceLpfEnabled(){
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VLPF_FILTER_EN, radio_i2c_buf); HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VLPF_FILTER_EN, radio_dat_buf);
return (radio_i2c_buf[0] == 0); return (radio_dat_buf[0] == 0);
} }
// Vox filters // Vox filters
@ -1242,8 +1379,8 @@ void HamShield::useVoxHpf(){
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VXHPF_FILTER_EN, 0); HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VXHPF_FILTER_EN, 0);
} }
bool HamShield::getVoxHpfEnabled(){ bool HamShield::getVoxHpfEnabled(){
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXHPF_FILTER_EN, radio_i2c_buf); HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXHPF_FILTER_EN, radio_dat_buf);
return (radio_i2c_buf[0] == 0); return (radio_dat_buf[0] == 0);
} }
void HamShield::bypassVoxLpf(){ void HamShield::bypassVoxLpf(){
@ -1253,28 +1390,28 @@ void HamShield::useVoxLpf(){
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VXLPF_FILTER_EN, 0); HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VXLPF_FILTER_EN, 0);
} }
bool HamShield::getVoxLpfEnabled(){ bool HamShield::getVoxLpfEnabled(){
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXLPF_FILTER_EN, radio_i2c_buf); HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXLPF_FILTER_EN, radio_dat_buf);
return (radio_i2c_buf[0] == 0); return (radio_dat_buf[0] == 0);
} }
// Read Only Status Registers // Read Only Status Registers
int16_t HamShield::readRSSI(){ int16_t HamShield::readRSSI(){
HSreadBitsW(devAddr, A1846S_RSSI_REG, A1846S_RSSI_BIT, A1846S_RSSI_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_RSSI_REG, A1846S_RSSI_BIT, A1846S_RSSI_LENGTH, radio_dat_buf);
int16_t rssi = (radio_i2c_buf[0] & 0xFF) - 137; int16_t rssi = (radio_dat_buf[0] & 0xFF) - 137;
return rssi; return rssi;
} }
uint16_t HamShield::readVSSI(){ uint16_t HamShield::readVSSI(){
HSreadBitsW(devAddr, A1846S_VSSI_REG, A1846S_VSSI_BIT, A1846S_VSSI_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_VSSI_REG, A1846S_VSSI_BIT, A1846S_VSSI_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
uint16_t HamShield::readMSSI(){ uint16_t HamShield::readMSSI(){
HSreadBitsW(devAddr, A1846S_VSSI_REG, A1846S_MSSI_BIT, A1846S_MSSI_LENGTH, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_VSSI_REG, A1846S_MSSI_BIT, A1846S_MSSI_LENGTH, radio_dat_buf);
return radio_i2c_buf[0]; return radio_dat_buf[0];
} }
@ -1545,7 +1682,7 @@ Does not take in account the millis() overflow
*/ */
bool HamShield::waitForChannel(long timeout = 0, long breakwindow = 0, int setRSSI = HAMSHIELD_EMPTY_CHANNEL_RSSI) { bool HamShield::waitForChannel(long timeout, long breakwindow, int setRSSI) {
int16_t rssi = 0; // Set RSSI to max received signal int16_t rssi = 0; // Set RSSI to max received signal
for(int x = 0; x < 20; x++) { rssi = readRSSI(); } // "warm up" to get past RSSI hysteresis for(int x = 0; x < 20; x++) { rssi = readRSSI(); } // "warm up" to get past RSSI hysteresis
long timer = HSmillis() + timeout; // Setup the timeout value long timer = HSmillis() + timeout; // Setup the timeout value
@ -1563,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() {
@ -1593,18 +1734,21 @@ void HamShield::morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]) {
int i; int i;
char prev = 0; char prev = 0;
for(i = 0; buffer[i] != '\0' && i < HAMSHIELD_MORSE_BUFFER_SIZE; prev = buffer[i], i++) { for(i = 0; buffer[i] != '\0' && i < HAMSHIELD_MORSE_BUFFER_SIZE; prev = buffer[i], i++) {
// On a space, delay 7 dots // On a space, delay 7 dots
if(buffer[i] == ' ') { if(buffer[i] == ' ') {
// We delay by 4 here, if we previously sent a symbol. Otherwise 7. // We delay by 4 here, if we previously sent a symbol. Otherwise 7.
// This could probably just be always 7 and go relatively unnoticed. // This could probably just be always 7 and go relatively unnoticed.
if(prev == 0 || prev == ' '){ if(prev == 0 || prev == ' '){
//tone(hs_pwm_pin, 6000, morse_dot_millis * 7); //tone(hs_mic_pin, 6000, morse_dot_millis * 7);
HSnoTone(hs_pwm_pin); HSnoTone(hs_mic_pin);
HSdelay(morse_dot_millis*7); HSdelay(morse_dot_millis*7);
//Serial.print(" ");
} else { } else {
//tone(hs_pwm_pin, 6000, morse_dot_millis * 4); //tone(hs_mic_pin, 6000, morse_dot_millis * 4);
HSnoTone(hs_pwm_pin); HSnoTone(hs_mic_pin);
HSdelay(morse_dot_millis*4); HSdelay(morse_dot_millis*4);
//Serial.print(" ");
} }
continue; continue;
} }
@ -1613,28 +1757,128 @@ void HamShield::morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]) {
if(bits) { // If it is a valid character... if(bits) { // If it is a valid character...
do { do {
if(bits & 1) { if(bits & 1) {
HStone(hs_pwm_pin, morse_freq); //, morse_dot_millis * 3); HStone(hs_mic_pin, morse_freq);//, morse_dot_millis * 3);
HSdelay(morse_dot_millis*3); HSdelay(morse_dot_millis*3);
HSnoTone(hs_pwm_pin); HSnoTone(hs_mic_pin);
//Serial.print('-');
} else { } else {
HStone(hs_pwm_pin, morse_freq); //, morse_dot_millis); HStone(hs_mic_pin, morse_freq);//, morse_dot_millis);
HSdelay(morse_dot_millis); HSdelay(morse_dot_millis);
HSnoTone(hs_pwm_pin); HSnoTone(hs_mic_pin);
//Serial.print('.');
} }
//tone(hs_pwm_pin, 6000, morse_dot_millis); //tone(hs_mic_pin, 6000, morse_dot_millis);
HSnoTone(hs_pwm_pin); HSnoTone(hs_mic_pin);
HSdelay(morse_dot_millis); HSdelay(morse_dot_millis);
bits >>= 1; // Shift into the next symbol bits >>= 1; // Shift into the next symbol
} while(bits != 1); // Wait for 1 termination to be all we have left } while(bits != 1); // Wait for 1 termination to be all we have left
} }
// End of character // End of character
//tone(hs_pwm_pin, 6000, morse_dot_millis * 3); //tone(hs_mic_pin, 6000, morse_dot_millis * 3);
HSnoTone(hs_pwm_pin); HSnoTone(hs_mic_pin);
HSdelay(morse_dot_millis * 3); HSdelay(morse_dot_millis * 3);
} }
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) {
@ -1760,20 +2004,20 @@ void HamShield::SSTVTestPattern(int code) {
/* wait for tone to complete */ /* wait for tone to complete */
void HamShield::toneWait(uint16_t freq, long timer) { void HamShield::toneWait(uint16_t freq, long timer) {
HStone(hs_pwm_pin,freq); //,timer); HStone(hs_mic_pin,freq);//,timer);
HSdelay(timer); HSdelay(timer);
HSnoTone(hs_pwm_pin); HSnoTone(hs_mic_pin);
} }
/* wait microseconds for tone to complete */ /* wait microseconds for tone to complete */
void HamShield::toneWaitU(uint16_t freq, long timer) { void HamShield::toneWaitU(uint16_t freq, long timer) {
if(freq < 16383) { if(freq < 16383) {
HStone(hs_pwm_pin,freq); HStone(hs_mic_pin,freq);
HSdelayMicroseconds(timer); HSnoTone(hs_pwm_pin); return; HSdelayMicroseconds(timer); HSnoTone(hs_mic_pin); return;
} }
HStone(hs_pwm_pin,freq); HStone(hs_mic_pin,freq);
HSdelay(timer / 1000); HSnoTone(hs_pwm_pin); return; HSdelay(timer / 1000); HSnoTone(hs_mic_pin); return;
} }

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,10 +217,24 @@
#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:
HamShield(uint8_t cs_pin = nSEN, uint8_t clk_pin = CLK, uint8_t dat_pin = DAT, uint8_t pwm_pin = HAMSHIELD_PWM_PIN); HamShield(uint8_t ncs_pin = nCS, uint8_t clk_pin = CLK, uint8_t dat_pin = DAT, uint8_t mic_pin = MIC);
void initialize(); // defaults to 12.5kHz void initialize(); // defaults to 12.5kHz
void initialize(bool narrowBand); // select 12.5kHz if true or 25kHz if false void initialize(bool narrowBand); // select 12.5kHz if true or 25kHz if false
@ -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();
@ -398,6 +420,8 @@ class HamShield {
void setDTMFCode(uint16_t code); void setDTMFCode(uint16_t code);
// Tone // Tone
void HStone(uint8_t pin, unsigned int frequency);
void HSnoTone(uint8_t pin);
void lookForTone(uint16_t tone_hz); void lookForTone(uint16_t tone_hz);
uint8_t toneDetected(); uint8_t toneDetected();
@ -480,14 +504,18 @@ 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 = 0, long breakwindow = 0, int setRSSI = HAMSHIELD_EMPTY_CHANNEL_RSSI);
void SSTVVISCode(int code); void SSTVVISCode(int code);
void SSTVTestPattern(int code); void SSTVTestPattern(int code);
void toneWait(uint16_t freq, long timer); void toneWait(uint16_t freq, long timer);
@ -498,8 +526,8 @@ class HamShield {
private: private:
uint8_t devAddr; uint8_t devAddr;
uint8_t hs_pwm_pin; uint8_t hs_mic_pin;
uint16_t radio_i2c_buf[4]; uint16_t radio_dat_buf[4];
bool tx_active; bool tx_active;
bool rx_active; bool rx_active;
float radio_frequency; float radio_frequency;

View File

@ -1,10 +1,16 @@
/* /*
* Based loosely on I2Cdev by Jeff Rowberg, except for all kludgy bit-banging * Based loosely on I2Cdev by Jeff Rowberg, except for all kludgy bit-banging
*
* Note that while the Radio IC (AU1846) does have an I2C interface, we've found
* it to be a bit buggy. Instead, we are using a secondary interface to communicate
* with it. The secondary interface is a bit of a hybrid between I2C and SPI.
* uses a Chip-Select pin like SPI, but has bi-directional data like I2C. In order
* to deal with this, we bit-bang the interface.
*/ */
#include "HamShield_comms.h" #include "HamShield_comms.h"
uint8_t ncs_pin = nSEN; uint8_t ncs_pin = nCS;
uint8_t clk_pin = CLK; uint8_t clk_pin = CLK;
uint8_t dat_pin = DAT; uint8_t dat_pin = DAT;
@ -63,16 +69,20 @@ int8_t HSreadWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data)
temp = ((regAddr & (0x80 >> i)) != 0); temp = ((regAddr & (0x80 >> i)) != 0);
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); // digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
digitalWrite(dat_pin, temp); digitalWrite(dat_pin, temp);
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); //PORTC |= (1<<5); // digitalWrite(clk_pin, 1); //PORTC |= (1<<5); //
HSdelayMicroseconds(1);
} }
// change direction of dat_pin // change direction of dat_pin
pinMode(dat_pin, INPUT); // DDRC &= ~(1<<4); // pinMode(dat_pin, INPUT); // DDRC &= ~(1<<4); //
for (int i = 15; i >= 0; i--) { for (int i = 15; i >= 0; i--) {
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); // digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); //PORTC |= (1<<5); // digitalWrite(clk_pin, 1); //PORTC |= (1<<5); //
temp_dat = digitalRead(dat_pin); //((PINC & (1<<4)) != 0); temp_dat = digitalRead(dat_pin); //((PINC & (1<<4)) != 0);
temp_dat = temp_dat << i; temp_dat = temp_dat << i;
*data |= temp_dat; *data |= temp_dat;
HSdelayMicroseconds(1);
} }
digitalWrite(devAddr, 1); //PORTC |= (1<<1);// CS digitalWrite(devAddr, 1); //PORTC |= (1<<1);// CS
@ -121,13 +131,17 @@ bool HSwriteWord(uint8_t devAddr, uint8_t regAddr, uint16_t data)
temp_reg = ((regAddr & (0x80 >> i)) != 0); temp_reg = ((regAddr & (0x80 >> i)) != 0);
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); // digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
digitalWrite(dat_pin, regAddr & (0x80 >> i)); digitalWrite(dat_pin, regAddr & (0x80 >> i));
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); // PORTC |= (1<<5); // digitalWrite(clk_pin, 1); // PORTC |= (1<<5); //
HSdelayMicroseconds(1);
} }
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
temp_dat = ((data & (0x8000 >> i)) != 0); temp_dat = ((data & (0x8000 >> i)) != 0);
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); // digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
digitalWrite(dat_pin, temp_dat); digitalWrite(dat_pin, temp_dat);
HSdelayMicroseconds(1);
digitalWrite(clk_pin, 1); // PORTC |= (1<<5); // digitalWrite(clk_pin, 1); // PORTC |= (1<<5); //
HSdelayMicroseconds(1);
} }
digitalWrite(devAddr, 1); //PORTC |= (1<<1); //CS digitalWrite(devAddr, 1); //PORTC |= (1<<1); //CS
@ -145,19 +159,3 @@ void HSdelay(unsigned long ms) {
void HSdelayMicroseconds(unsigned int us) { void HSdelayMicroseconds(unsigned int us) {
delayMicroseconds(us); delayMicroseconds(us);
} }
void HStone(uint8_t pin, unsigned int frequency) {
#if defined(ARDUINO)
tone(pin, frequency);
#else
softToneCreate(pin);
softToneWrite(pin, frequency);
#endif
}
void HSnoTone(uint8_t pin) {
#if defined(ARDUINO)
noTone(pin);
#else
softToneWrite(pin, 0);
#endif
}

View File

@ -8,19 +8,19 @@
#if defined(ARDUINO) #if defined(ARDUINO)
#include "Arduino.h" #include "Arduino.h"
#define nSEN A1 //15 // #define nCS A1 //15 //
#define CLK A5 //19 // #define CLK A5 //19 //
#define DAT A4 //18 // #define DAT A4 //18 //
#define HAMSHIELD_PWM_PIN 3 #define MIC 3
#else // assume Raspberry Pi #else // assume Raspberry Pi
#include "stdint.h" #include "stdint.h"
#include <wiringPi.h> #include <wiringPi.h>
#include <softTone.h> #include <softTone.h>
#define nSEN 0 //BCM17, HW pin 11 #define nCS 0 //BCM17, HW pin 11
#define CLK 3 //BCM22, HW pin 15 #define CLK 3 //BCM22, HW pin 15
#define DAT 2 //BCM27, HW pin 13 #define DAT 2 //BCM27, HW pin 13
#define HAMSHIELD_PWM_PIN 1 //BCM18, HW pin 12 #define MIC 1 //BCM18, HW pin 12
#endif #endif
@ -41,8 +41,5 @@ unsigned long HSmillis();
void HSdelay(unsigned long ms); void HSdelay(unsigned long ms);
void HSdelayMicroseconds(unsigned int us); void HSdelayMicroseconds(unsigned int us);
void HStone(uint8_t pin, unsigned int frequency);
void HSnoTone(uint8_t pin);
#endif /* _HAMSHIELD_COMMS_H_ */ #endif /* _HAMSHIELD_COMMS_H_ */