13 Commits
RPi ... 1.1.3

Author SHA1 Message Date
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
21 changed files with 1182 additions and 433 deletions

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,8 +37,8 @@ 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
pinMode(SWITCH_PIN, INPUT_PULLUP); pinMode(SWITCH_PIN, INPUT_PULLUP);
@@ -52,14 +52,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 +74,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,8 +17,8 @@ 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);
@@ -36,7 +36,7 @@ void setup() {
Serial.println("Setting radio to its defaults.."); Serial.println("Setting radio to its defaults..");
radio.initialize(); radio.initialize();
radio.setRfPower(0); radio.setRfPower(0);
radio.frequency(146520); radio.frequency(432100); // 70cm calling frequency
radio.setModeReceive(); radio.setModeReceive();
} }

View File

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

View File

@@ -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,8 +26,8 @@ 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);

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,8 +28,8 @@ 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);
@@ -72,7 +72,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 +104,18 @@ void setup() {
Serial.println("ready"); Serial.println("ready");
} }
char rx_dtmf_buf[255];
int rx_dtmf_idx = 0;
void loop() { void loop() {
// look for tone // look for tone
if (radio.getDTMFSample() != 0) { char m = radio.DTMFRxLoop();
uint16_t code = radio.getDTMFCode(); if (m != 0) {
Serial.print(m);
rx_dtmf_buf[rx_dtmf_idx++] = code2char(code);
// reset after this tone
int j = 0;
while (j < 4) {
if (radio.getDTMFSample() == 0) {
j++;
}
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 +130,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,8 +25,8 @@ 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);
@@ -57,8 +57,8 @@ void setup() {
radio.setMorseFreq(600); radio.setMorseFreq(600);
radio.setMorseDotMillis(100); radio.setMorseDotMillis(100);
// Configure the HamShield to operate on 438.000MHz // Configure the HamShield
radio.frequency(438000); radio.frequency(432300); // 70cm beacon frequency
Serial.println("Radio Configured."); Serial.println("Radio Configured.");
} }

View File

@@ -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,8 +29,8 @@ 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);
@@ -61,8 +61,8 @@ void setup() {
radio.setMorseFreq(600); radio.setMorseFreq(600);
radio.setMorseDotMillis(100); radio.setMorseDotMillis(100);
// Configure the HamShield to operate on 438.000Mhz // Configure the HamShield frequency
radio.frequency(438000); radio.frequency(432400);
Serial.println("Radio configured."); Serial.println("Radio configured.");
} }
@@ -79,7 +79,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,8 +39,8 @@ 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);
@@ -72,13 +72,12 @@ void setup() {
radio.initialize(); // initializes automatically for UHF 12.5kHz channel radio.initialize(); // initializes automatically for UHF 12.5kHz channel
Serial.println("setting default Radio configuration"); Serial.println("setting default Radio configuration");
radio.dangerMode();
// set frequency // set frequency
Serial.println("changing frequency"); Serial.println("changing frequency");
radio.setSQOff(); radio.setSQOff();
freq = 446000; freq = 432100; // 70cm calling frequency
radio.frequency(freq); radio.frequency(freq);
// set to receive // set to receive

View File

@@ -0,0 +1,282 @@
/* 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(9,5,6);
// 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 I2C devices...");
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
}
#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,14 +35,14 @@ 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);

View File

@@ -10,46 +10,40 @@
* 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);
@@ -80,63 +74,19 @@ void setup() {
radio.setMorseDotMillis(MORSE_DOT); radio.setMorseDotMillis(MORSE_DOT);
radio.lookForTone(MORSE_FREQ); radio.lookForTone(MORSE_FREQ);
radio.setupMorseRx();
// Configure the HamShield to operate on 438.000MHz // Configure the HamShield frequency
radio.frequency((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 +95,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 +113,9 @@ void loop() {
radio.morseOut(morse_buf); radio.morseOut(morse_buf);
// We're done sending the message, set the radio back into recieve mode. // We're done sending the message, set the radio back into recieve mode.
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 +124,4 @@ void loop() {
} }
} }
void handleTone(uint16_t tone_time) {
//Serial.println(tone_time);
if (tone_time > MIN_DOT_TIME && tone_time < MAX_DOT_TIME) {
// add a dot
//Serial.print(".");
//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,8 +28,8 @@ 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);

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

View File

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

View File

@@ -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,8 +90,8 @@ 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);
@@ -106,7 +106,7 @@ void setup() {
int result = radio.testConnection(); int result = radio.testConnection();
Serial.println(result); Serial.println(result);
radio.initialize(); radio.initialize();
radio.frequency(446000); radio.frequency(432400);
radio.setVolume1(0xF); radio.setVolume1(0xF);
radio.setVolume2(0xF); radio.setVolume2(0xF);
radio.setModeReceive(); radio.setModeReceive();

View File

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

View File

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

View File

@@ -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_i2c_buf);
old_dtmf_reg = radio_i2c_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);
@@ -769,20 +773,37 @@ void HamShield::setCtcssFreqToStandard(){
setCtcssFreq(13440); setCtcssFreq(13440);
} }
void HamShield::enableCtcss() { void HamShield::enableCtcssTx() {
// enable TX
HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 3); HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 3);
}
// enable RX void HamShield::enableCtcssRx() {
setCtcssGpioSel(1); setCtcssGpioSel(1);
HSwriteBitW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTCSS_DET_BIT, 0); HSwriteBitW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTCSS_DET_BIT, 0);
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_CTCSS_FILTER_BYPASS, 0); HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_CTCSS_FILTER_BYPASS, 0);
setDetCtcss(); setDetCtcss();
} }
void HamShield::disableCtcss() {
void HamShield::enableCtcss() {
// enable TX
enableCtcssTx();
// enable RX
enableCtcssRx();
}
void HamShield::disableCtcssTx() {
HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 0); HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 0);
}
void HamShield::disableCtcssRx() {
setCtcssGpioSel(0);
disableCtcssCdcss(); disableCtcssCdcss();
} }
void HamShield::disableCtcss() {
disableCtcssTx();
disableCtcssRx();
}
// match threshold // match threshold
void HamShield::setCtcssDetThreshIn(uint8_t thresh) { void HamShield::setCtcssDetThreshIn(uint8_t thresh) {
@@ -866,24 +887,30 @@ bool HamShield::getSQState(){
void HamShield::setSQHiThresh(int16_t sq_hi_threshold){ void HamShield::setSQHiThresh(int16_t sq_hi_threshold){
// Sq detect high th, rssi_cmp will be 1 when rssi>th_h_sq, unit 1dB // Sq detect high th, rssi_cmp will be 1 when rssi>th_h_sq, unit 1dB
uint16_t sq = 137 + sq_hi_threshold; uint16_t sq = 137 + sq_hi_threshold;
HSwriteWord(devAddr, A1846S_SQ_OPEN_THRESH_REG, sq); HSwriteBitsW(devAddr, A1846S_SQ_OPEN_THRESH_REG, A1846S_SQ_OPEN_THRESH_BIT, A1846S_SQ_OPEN_THRESH_LENGTH, sq);
} }
int16_t HamShield::getSQHiThresh(){ int16_t HamShield::getSQHiThresh(){
HSreadWord(devAddr, A1846S_SQ_OPEN_THRESH_REG, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_SQ_OPEN_THRESH_REG, A1846S_SQ_OPEN_THRESH_BIT, A1846S_SQ_OPEN_THRESH_LENGTH, radio_i2c_buf);
return radio_i2c_buf[0] - 137; return radio_i2c_buf[0] - 137;
} }
void HamShield::setSQLoThresh(int16_t sq_lo_threshold){ void HamShield::setSQLoThresh(int16_t sq_lo_threshold){
// Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1 dB // Sq detect low th, rssi_cmp will be 0 when rssi<th_l_sq && time delay meet, unit 1 dB
uint16_t sq = 137 + sq_lo_threshold; uint16_t sq = 137 + sq_lo_threshold;
HSwriteWord(devAddr, A1846S_SQ_SHUT_THRESH_REG, sq); HSwriteBitsW(devAddr, A1846S_SQ_SHUT_THRESH_REG, A1846S_SQ_SHUT_THRESH_BIT, A1846S_SQ_SHUT_THRESH_LENGTH, sq);
} }
int16_t HamShield::getSQLoThresh(){ int16_t HamShield::getSQLoThresh(){
HSreadWord(devAddr, A1846S_SQ_SHUT_THRESH_REG, radio_i2c_buf); HSreadBitsW(devAddr, A1846S_SQ_SHUT_THRESH_REG, A1846S_SQ_SHUT_THRESH_BIT, A1846S_SQ_SHUT_THRESH_LENGTH, radio_i2c_buf);
return radio_i2c_buf[0] - 137; return radio_i2c_buf[0] - 137;
} }
bool HamShield::getSquelching() {
HSreadBitW(devAddr, A1846S_FLAG_REG, A1846S_SQ_FLAG_BIT, radio_i2c_buf);
return (radio_i2c_buf[0] != 0);
}
// SQ out select // SQ out select
void HamShield::setSQOutSel(){ void HamShield::setSQOutSel(){
HSwriteBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, 1); HSwriteBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, 1);
@@ -994,6 +1021,67 @@ uint16_t HamShield::getDTMFIdleTime() {
return radio_i2c_buf[0]; return radio_i2c_buf[0];
} }
char HamShield::DTMFRxLoop() {
char m = 0;
if (getDTMFSample() != 0) {
uint16_t code = getDTMFCode();
m = DTMFcode2char(code);
// reset after this tone
int j = 0;
while (j < 4) {
if (getDTMFSample() == 0) {
j++;
} else {
j = 1;
}
delay(10);
}
// reset read
//enableDTMFReceive();
}
return m;
}
char HamShield::DTMFcode2char(uint16_t code) {
char c;
if (code < 10) {
c = '0' + code;
} else if (code < 0xE) {
c = 'A' + code - 10;
} else if (code == 0xE) {
c = '*';
} else if (code == 0xF) {
c = '#';
} else {
c = '?'; // invalid code
}
return c;
}
uint8_t HamShield::DTMFchar2code(char c) {
uint8_t code;
if (c == '#') {
code = 0xF;
} else if (c=='*') {
code = 0xE;
} else if (c >= 'A' && c <= 'D') {
code = c - 'A' + 0xA;
} else if (c >= '0' && c <= '9') {
code = c - '0';
} else {
// invalid code, skip it
code = 255;
}
return code;
}
void HamShield::setDTMFTxTime(uint16_t tx_time) { void HamShield::setDTMFTxTime(uint16_t tx_time) {
if (tx_time > 63) {tx_time = 63;} // maxed out if (tx_time > 63) {tx_time = 63;} // maxed out
// tx time is duration of DTMF Tone // tx time is duration of DTMF Tone
@@ -1062,8 +1150,43 @@ 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_i2c_buf);
// old_dtmf_reg = radio_i2c_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) {
// 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 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);
@@ -1072,23 +1195,37 @@ 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_i2c_buf);
if (radio_i2c_buf[0] != 0) { if (radio_i2c_buf[0] != 0) {
if (!redetect) {
redetect = true;
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_i2c_buf);
if (radio_i2c_buf[0] == 1) { last_tone_detected = radio_i2c_buf[0];
//Serial.print("t: ");
//Serial.println(last_tone_detected);
}
if (last_tone_detected == 0) {
return 1; 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;
} }
@@ -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,11 +504,15 @@ class HamShield {
uint32_t scanChannels(uint32_t buffer[],uint8_t buffsize, uint8_t speed, uint16_t threshold); uint32_t scanChannels(uint32_t buffer[],uint8_t buffsize, uint8_t speed, uint16_t threshold);
uint32_t findWhitespaceChannels(uint32_t buffer[],uint8_t buffsize, uint8_t dwell, uint16_t threshold); uint32_t findWhitespaceChannels(uint32_t buffer[],uint8_t buffsize, uint8_t dwell, uint16_t threshold);
void setupMorseRx();
unsigned int getMorseFreq(); unsigned int getMorseFreq();
void setMorseFreq(unsigned int morse_freq_hz); void setMorseFreq(unsigned int morse_freq_hz);
unsigned int getMorseDotMillis(); unsigned int getMorseDotMillis();
void setMorseDotMillis(unsigned int morse_dot_dur_millis); void setMorseDotMillis(unsigned int morse_dot_dur_millis);
void morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]); void morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]);
char morseRxLoop();
bool handleMorseTone(uint16_t tone_time, bool bits_to_process, uint8_t * rx_morse_char, uint8_t * rx_morse_bit);
char parseMorse(uint8_t rx_morse_char, uint8_t rx_morse_bit);
uint8_t morseLookup(char letter); uint8_t morseLookup(char letter);
uint8_t morseReverseLookup(uint8_t itu); uint8_t morseReverseLookup(uint8_t itu);
bool waitForChannel(long timeout, long breakwindow, int setRSSI); bool waitForChannel(long timeout, long breakwindow, int setRSSI);
@@ -498,7 +526,7 @@ 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_i2c_buf[4];
bool tx_active; bool tx_active;
bool rx_active; bool rx_active;

View File

@@ -4,7 +4,7 @@
#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;
@@ -145,19 +145,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_ */