Compare commits
23 Commits
Author | SHA1 | Date |
---|---|---|
morgan | 753ca34560 | |
morgan | 888697bb79 | |
Morgan Redfield | 1500d07213 | |
Morgan Redfield | 70bd364473 | |
Morgan Redfield | ef2268ca22 | |
Morgan Redfield | aa14035c94 | |
Morgan Redfield | 777a56d131 | |
spaceneedle | 0e520d74f9 | |
Morgan Redfield | f630fc8d88 | |
Morgan Redfield | 4006afff64 | |
Morgan Redfield | 3d3f6a36b6 | |
Morgan Redfield | 71acbbb975 | |
Morgan Redfield | 6472b103b4 | |
Morgan Redfield | 7e509ca0fc | |
Morgan Redfield | 12fd074aed | |
Morgan Redfield | 1d0eb281e2 | |
Morgan Redfield | 7941388980 | |
Morgan Redfield | f83b547de4 | |
Morgan Redfield | b147edfcfa | |
Morgan Redfield | 3c3d83c057 | |
Morgan Redfield | 9d708e4046 | |
Morgan Redfield | 250dd330b7 | |
Morgan Redfield | 289d1f73a8 |
|
@ -1,5 +1,7 @@
|
|||
# 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.
|
||||
|
||||
WARNING: The dev branch is not guaranteed to work. Please use caution if you choose to use that branch.
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* To send a message: connect to the Arduino over a Serial link.
|
||||
* Send the following over the serial link:
|
||||
* `from,to,:message
|
||||
* example: * `KG7OGM,KG7OGM,:Hi there
|
||||
* example: * KG7OGM,KG7OGM,:Hi there`
|
||||
*/
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
|||
#include <packet.h>
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -37,10 +37,11 @@ int msgptr = 0;
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
|
@ -52,14 +53,14 @@ void setup() {
|
|||
Serial.begin(9600);
|
||||
|
||||
radio.initialize();
|
||||
radio.frequency(145570);
|
||||
radio.frequency(144390); // default aprs frequency in North America
|
||||
radio.setRfPower(0);
|
||||
radio.setVolume1(0xFF);
|
||||
radio.setVolume2(0xFF);
|
||||
radio.setSQHiThresh(-100);
|
||||
radio.setSQLoThresh(-100);
|
||||
radio.setSQOn();
|
||||
//radio.bypassPreDeEmph();
|
||||
//radio.setSQOn();
|
||||
radio.bypassPreDeEmph();
|
||||
dds.start();
|
||||
afsk.start(&dds);
|
||||
delay(100);
|
||||
|
@ -74,6 +75,7 @@ void loop() {
|
|||
//Serial.println(messagebuff);
|
||||
prepMessage();
|
||||
msgptr = 0;
|
||||
messagebuff = "";
|
||||
Serial.print("!!");
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include <HamShield.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -17,13 +17,14 @@ uint8_t pl_rx_buffer[32];
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
@ -36,7 +37,7 @@ void setup() {
|
|||
Serial.println("Setting radio to its defaults..");
|
||||
radio.initialize();
|
||||
radio.setRfPower(0);
|
||||
radio.frequency(146520);
|
||||
radio.frequency(432100); // 70cm calling frequency
|
||||
radio.setModeReceive();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ HamShield radio;
|
|||
#define LED_PIN 13
|
||||
#define RSSI_REPORT_RATE_MS 5000
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -43,13 +43,14 @@ unsigned long rssi_timeout;
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, LOW);
|
||||
|
||||
|
@ -68,20 +69,18 @@ void setup() {
|
|||
|
||||
// verify connection
|
||||
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
|
||||
Serial.println("Initializing I2C devices...");
|
||||
Serial.println("Initializing radio device...");
|
||||
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
|
||||
|
||||
Serial.println("setting default Radio configuration");
|
||||
radio.dangerMode();
|
||||
|
||||
// set frequency
|
||||
Serial.println("changing frequency");
|
||||
|
||||
radio.setSQOff();
|
||||
freq = 446000;
|
||||
freq = 432100; // 70cm calling frequency
|
||||
radio.frequency(freq);
|
||||
|
||||
// set to receive
|
||||
|
@ -92,6 +91,11 @@ void setup() {
|
|||
Serial.println(radio.readCtlReg());
|
||||
Serial.println(radio.readRSSI());
|
||||
|
||||
// set up squelch
|
||||
radio.setSQLoThresh(-80);
|
||||
radio.setSQHiThresh(-70);
|
||||
radio.setSQOn();
|
||||
|
||||
radio.setRfPower(0);
|
||||
|
||||
// CTCSS Setup code
|
||||
|
@ -163,7 +167,7 @@ void loop() {
|
|||
} else {
|
||||
Serial.setTimeout(40);
|
||||
freq = Serial.parseInt();
|
||||
Serial.flush();
|
||||
while (Serial.available()) Serial.read();
|
||||
radio.frequency(freq);
|
||||
Serial.print("set frequency: ");
|
||||
Serial.println(freq);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <HamShield.h>
|
||||
#include <DDS.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -26,13 +26,14 @@ DDS dds;
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
// turn on radio
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
|
|
|
@ -20,7 +20,7 @@ HamShield radio;
|
|||
|
||||
#define LED_PIN 13
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -28,13 +28,14 @@ uint32_t freq;
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, LOW);
|
||||
|
||||
|
@ -72,7 +73,7 @@ void setup() {
|
|||
//radio.setSQOff();
|
||||
|
||||
Serial.println("setting frequency to: ");
|
||||
freq = 420000;
|
||||
freq = 432100; // 70cm calling frequency
|
||||
radio.frequency(freq);
|
||||
Serial.print(radio.getFrequency());
|
||||
Serial.println("kHz");
|
||||
|
@ -104,33 +105,18 @@ void setup() {
|
|||
Serial.println("ready");
|
||||
}
|
||||
|
||||
char rx_dtmf_buf[255];
|
||||
int rx_dtmf_idx = 0;
|
||||
void loop() {
|
||||
|
||||
// look for tone
|
||||
if (radio.getDTMFSample() != 0) {
|
||||
uint16_t code = radio.getDTMFCode();
|
||||
|
||||
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;
|
||||
char m = radio.DTMFRxLoop();
|
||||
if (m != 0) {
|
||||
Serial.print(m);
|
||||
}
|
||||
|
||||
// Is it time to send tone?
|
||||
if (Serial.available()) {
|
||||
uint8_t code = char2code(Serial.read());
|
||||
// get first code
|
||||
uint8_t code = radio.DTMFchar2code(Serial.read());
|
||||
|
||||
// start transmitting
|
||||
radio.setDTMFCode(code); // set first
|
||||
|
@ -145,56 +131,23 @@ void loop() {
|
|||
// wait until we're ready for a new code
|
||||
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) {
|
||||
// wait until this code is done
|
||||
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
|
||||
radio.setModeReceive();
|
||||
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;
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
#define DDS_REFCLK_DEFAULT 9600
|
||||
#include <HamShield.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -25,13 +25,14 @@ HamShield radio;
|
|||
// Run our start up things here
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
@ -57,8 +58,8 @@ void setup() {
|
|||
radio.setMorseFreq(600);
|
||||
radio.setMorseDotMillis(100);
|
||||
|
||||
// Configure the HamShield to operate on 438.000MHz
|
||||
radio.frequency(438000);
|
||||
// Configure the HamShield
|
||||
radio.frequency(432300); // 70cm beacon frequency
|
||||
|
||||
Serial.println("Radio Configured.");
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <HamShield.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -29,13 +29,14 @@ HamShield radio;
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
@ -61,8 +62,8 @@ void setup() {
|
|||
radio.setMorseFreq(600);
|
||||
radio.setMorseDotMillis(100);
|
||||
|
||||
// Configure the HamShield to operate on 438.000Mhz
|
||||
radio.frequency(438000);
|
||||
// Configure the HamShield frequency
|
||||
radio.frequency(432400);
|
||||
|
||||
Serial.println("Radio configured.");
|
||||
}
|
||||
|
@ -79,7 +80,7 @@ void loop() {
|
|||
radio.setModeTransmit();
|
||||
|
||||
// Generate a 600Hz tone for TRANSMITLENGTH time
|
||||
tone(PWM_PIN, 600, TRANSMITLENGTH);
|
||||
tone(MIC_PIN, 600, TRANSMITLENGTH);
|
||||
delay(TRANSMITLENGTH);
|
||||
|
||||
// Identify the transmitter
|
||||
|
|
|
@ -26,7 +26,7 @@ HamShield radio;
|
|||
#define LED_PIN 13
|
||||
#define RSSI_REPORT_RATE_MS 5000
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -39,13 +39,14 @@ unsigned long rssi_timeout;
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, LOW);
|
||||
|
||||
|
@ -57,7 +58,8 @@ void setup() {
|
|||
while (digitalRead(SWITCH_PIN) && !Serial.available());
|
||||
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);
|
||||
delay(5); // wait for device to come up
|
||||
|
||||
|
@ -65,20 +67,19 @@ void setup() {
|
|||
|
||||
// verify connection
|
||||
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
|
||||
Serial.println("Initializing I2C devices...");
|
||||
Serial.println("Initializing radio device...");
|
||||
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
|
||||
|
||||
Serial.println("setting default Radio configuration");
|
||||
radio.dangerMode();
|
||||
|
||||
// set frequency
|
||||
Serial.println("changing frequency");
|
||||
|
||||
radio.setSQOff();
|
||||
freq = 446000;
|
||||
freq = 432100; // 70cm calling frequency
|
||||
radio.frequency(freq);
|
||||
|
||||
// set to receive
|
||||
|
@ -136,7 +137,7 @@ void loop() {
|
|||
} else {
|
||||
Serial.setTimeout(40);
|
||||
freq = Serial.parseInt();
|
||||
Serial.flush();
|
||||
while (Serial.available()) Serial.read();
|
||||
radio.frequency(freq);
|
||||
Serial.print("set frequency: ");
|
||||
Serial.println(freq);
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -35,19 +35,20 @@ DDS dds;
|
|||
AFSK afsk;
|
||||
KISS kiss(&Serial, &radio, &dds, &afsk);
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
|
|
@ -10,51 +10,46 @@
|
|||
* monitor the status of the beacon. To test, set a HandyTalkie
|
||||
* to 438MHz. You should hear the message " CALLSIGN HAMSHIELD"
|
||||
* 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
|
||||
#include <HamShield.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
#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
|
||||
// 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;
|
||||
|
||||
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
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
@ -80,63 +75,19 @@ void setup() {
|
|||
radio.setMorseDotMillis(MORSE_DOT);
|
||||
|
||||
radio.lookForTone(MORSE_FREQ);
|
||||
radio.setupMorseRx();
|
||||
|
||||
// Configure the HamShield to operate on 438.000MHz
|
||||
radio.frequency((uint32_t) 438000);
|
||||
// Configure the HamShield frequency
|
||||
radio.frequency(432100); // 70cm calling frequency
|
||||
radio.setModeReceive();
|
||||
|
||||
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() {
|
||||
// are we receiving anything
|
||||
if (radio.toneDetected()) {
|
||||
space_in_progress = 0;
|
||||
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;
|
||||
}
|
||||
char rx_char = radio.morseRxLoop();
|
||||
if (rx_char != 0) {
|
||||
Serial.print(rx_char);
|
||||
}
|
||||
|
||||
// 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
|
||||
if (radio.waitForChannel(30000,2000,-5)) {
|
||||
// If we get here, the channel is clear.
|
||||
Serial.println("sending");
|
||||
|
||||
// Start transmitting by putting the radio into transmit mode.
|
||||
radio.setModeTransmit();
|
||||
Serial.println("tx");
|
||||
unsigned int MORSE_BUF_SIZE = 128;
|
||||
char morse_buf[MORSE_BUF_SIZE];
|
||||
unsigned int morse_idx;
|
||||
|
@ -161,8 +114,9 @@ void loop() {
|
|||
radio.morseOut(morse_buf);
|
||||
|
||||
// We're done sending the message, set the radio back into recieve mode.
|
||||
radio.setModeReceive();
|
||||
Serial.println("sent");
|
||||
radio.setModeReceive();
|
||||
radio.lookForTone(MORSE_FREQ);
|
||||
} else {
|
||||
// If we get here, the channel is busy. Let's also print out the 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* 446MHz to receive the image output.
|
||||
*/
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -28,13 +28,14 @@ int16_t rssi;
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <HamShield.h>
|
||||
#include <DDS.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -32,13 +32,14 @@ ddsAccumulator_t freqTable[3];
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
@ -54,7 +55,7 @@ void setup() {
|
|||
// Tell the HamShield to start up
|
||||
radio.initialize();
|
||||
radio.setRfPower(0);
|
||||
radio.frequency(145500);
|
||||
radio.frequency(446000);
|
||||
// put your setup code here, to run once:
|
||||
//dds.setReferenceClock(34965/4);
|
||||
dds.start();
|
||||
|
|
|
@ -15,22 +15,32 @@
|
|||
* R1;
|
||||
* [Just a space]
|
||||
|
||||
|
||||
// see also: https://github.com/EnhancedRadioDevices/HamShield/wiki/HamShield-Serial-Mode
|
||||
|
||||
Commands:
|
||||
|
||||
Mode ASCII Description Implemented
|
||||
-------------- ----------- -------------------------------------------------------------------------------------------------------------------------------------------- -----------------
|
||||
Transmit space Space must be received at least every 500 mS Yes
|
||||
Receive not space If space is not received and/or 500 mS timeout of space occurs, unit will go into receive mode Yes
|
||||
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 No
|
||||
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)
|
||||
Power level P<level>; Set the power amp level, 0 = lowest, 15 = highest No
|
||||
Enable Offset R<state>; 1 turns on repeater offset mode, 0 turns off repeater offset mode No
|
||||
Squelch S<level>; Set the squelch level No
|
||||
TX Offset T<freq>; The absolute frequency of the repeater offset to transmit on in KHz No
|
||||
RSSI ?; Respond with the current receive level in - dBm (no sign provided on numerical response) No
|
||||
Voice Level ^; Respond with the current voice level (VSSI)
|
||||
|
||||
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:
|
||||
|
||||
|
@ -42,23 +52,44 @@ Error X<code>; Indicates an error code. The numerical value is the type
|
|||
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 "HamShield.h"
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#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;
|
||||
long timer = 0;
|
||||
long freq = 144390;
|
||||
long tx = 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;
|
||||
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 ctcssout = 0;
|
||||
int cdcssin = 0;
|
||||
|
@ -67,20 +98,18 @@ int cdcssout = 0;
|
|||
|
||||
HamShield radio;
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
// 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);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
||||
Serial.begin(9600);
|
||||
Serial.println(";;;;;;;;;;;;;;;;;;;;;;;;;;");
|
||||
|
@ -90,111 +119,282 @@ void setup() {
|
|||
Serial.print(result,DEC);
|
||||
Serial.println(";");
|
||||
radio.initialize(); // initializes automatically for UHF 12.5kHz channel
|
||||
Serial.println("*START;");
|
||||
radio.frequency(freq);
|
||||
radio.setVolume1(0xF);
|
||||
radio.setVolume2(0xF);
|
||||
radio.setModeReceive();
|
||||
radio.setTxSourceMic();
|
||||
radio.setRfPower(0);
|
||||
radio.setSQLoThresh(80);
|
||||
radio.setRfPower(pwr);
|
||||
radio.setSQLoThresh(-80);
|
||||
radio.setSQHiThresh(-70);
|
||||
radio.setSQOn();
|
||||
Serial.println("*START;");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
if(Serial.available()) {
|
||||
|
||||
int text = Serial.read();
|
||||
int text = Serial.read(); // 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 10:
|
||||
if(text == 32) { timer = millis();}
|
||||
case TX:
|
||||
// we're currently transmitting
|
||||
// if we got a space, reset our transmit timeout
|
||||
if(text == ' ') { timer = millis();}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case NORMAL:
|
||||
switch(text) {
|
||||
|
||||
case 32: // space - transmit
|
||||
if(repeater == 1) { radio.frequency(tx); }
|
||||
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 = 10;
|
||||
state = TX;
|
||||
Serial.println("#TX,ON;");
|
||||
timer = millis();
|
||||
break;
|
||||
|
||||
case 63: // ? - RSSI
|
||||
case '?': // ? - RSSI
|
||||
Serial.print(":");
|
||||
Serial.print(radio.readRSSI(),DEC);
|
||||
Serial.println(";");
|
||||
break;
|
||||
|
||||
case 65: // A - CTCSS In
|
||||
getValue();
|
||||
ctcssin = atof(cmdbuff);
|
||||
radio.setCtcss(ctcssin);
|
||||
case '^': // ^ - VSSI (voice) level
|
||||
Serial.print(":");
|
||||
Serial.print(radio.readVSSI(),DEC);
|
||||
Serial.println(";");
|
||||
break;
|
||||
|
||||
case 66: // B - CTCSS Out
|
||||
break;
|
||||
|
||||
case 67: // C - CTCSS Enable
|
||||
break;
|
||||
|
||||
case 68: // D - CDCSS Enable
|
||||
break;
|
||||
|
||||
case 70: // F - frequency
|
||||
case 'F': // F - frequency
|
||||
getValue();
|
||||
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;
|
||||
|
||||
case 'M':
|
||||
getValue();
|
||||
radio.setModeTransmit();
|
||||
delay(300);
|
||||
radio.morseOut(cmdbuff);
|
||||
state = 10;
|
||||
break;
|
||||
|
||||
case 80: // P - power level
|
||||
case 'P': // P - power level
|
||||
getValue();
|
||||
temp = atol(cmdbuff);
|
||||
radio.setRfPower(temp);
|
||||
Serial.println("!;");
|
||||
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();
|
||||
temp = atol(cmdbuff);
|
||||
if(temp == 0) { repeater = 0; }
|
||||
if(temp == 1) { repeater = 1; }
|
||||
Serial.println("!;");
|
||||
break;
|
||||
|
||||
case 83: // S - squelch
|
||||
case 'T': // T - transmit offset
|
||||
getValue();
|
||||
temp = atol(cmdbuff);
|
||||
radio.setSQLoThresh(temp);
|
||||
tx_freq = atol(cmdbuff);
|
||||
Serial.println("!;");
|
||||
break;
|
||||
|
||||
case 84: // T - transmit offset
|
||||
case 'M': // M - Morse
|
||||
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;
|
||||
|
||||
case 'N': // N - set to Morse in Mode
|
||||
morse_rx_setup();
|
||||
state = MORSE;
|
||||
Serial.println("!;");
|
||||
break;
|
||||
|
||||
case 94: // ^ - VSSI (voice) level
|
||||
Serial.print(":");
|
||||
Serial.print(radio.readVSSI(),DEC);
|
||||
Serial.println(";");
|
||||
case 'D': // D - DTMF Out
|
||||
dtmfSetup();
|
||||
getValue();
|
||||
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;
|
||||
|
||||
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 +404,159 @@ void getValue() {
|
|||
for(;;) {
|
||||
if(Serial.available()) {
|
||||
temp = Serial.read();
|
||||
if(temp == 59) { cmdbuff[p] = 0; Serial.print("@");
|
||||
for(int x = 0; x < 32; x++) { Serial.print(cmdbuff[x]);}
|
||||
Serial.println();
|
||||
if(temp == 59) {
|
||||
cmdbuff[p] = 0;
|
||||
return;
|
||||
}
|
||||
cmdbuff[p] = temp;
|
||||
p++;
|
||||
if(p == 32) {
|
||||
Serial.print("@");
|
||||
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
|
||||
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
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ char CALLSIGN[] = "1ZZ9ZZ/B";
|
|||
#include <HamShield.h>
|
||||
#include <PCM.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -90,13 +90,14 @@ const unsigned char dbm[] PROGMEM = {
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, LOW);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, LOW);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
@ -106,7 +107,7 @@ void setup() {
|
|||
int result = radio.testConnection();
|
||||
Serial.println(result);
|
||||
radio.initialize();
|
||||
radio.frequency(446000);
|
||||
radio.frequency(432400);
|
||||
radio.setVolume1(0xF);
|
||||
radio.setVolume2(0xF);
|
||||
radio.setModeReceive();
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
* 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.
|
||||
* 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
|
||||
* into the HamShield RF jack. Connect the Arduino to
|
||||
* wall power and then to your computer via USB. After
|
||||
|
@ -12,7 +16,7 @@
|
|||
|
||||
#include <HamShield.h>
|
||||
|
||||
#define PWM_PIN 3
|
||||
#define MIC_PIN 3
|
||||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
|
@ -230,13 +234,14 @@ const uint8_t spYELLOW[] PROGMEM = {0x69,0xBD,0x56,0x15,0xAC,0x67,0xE5,0x
|
|||
|
||||
void setup() {
|
||||
// NOTE: if not using PWM out, it should be held low to avoid tx noise
|
||||
pinMode(PWM_PIN, OUTPUT);
|
||||
digitalWrite(PWM_PIN, HIGH);
|
||||
pinMode(MIC_PIN, OUTPUT);
|
||||
digitalWrite(MIC_PIN, HIGH);
|
||||
|
||||
// prep the switch
|
||||
pinMode(SWITCH_PIN, INPUT_PULLUP);
|
||||
|
||||
// set up the reset control pin
|
||||
// NOTE: HamShieldMini doesn't have a reset pin, so this has no effect
|
||||
pinMode(RESET_PIN, OUTPUT);
|
||||
digitalWrite(RESET_PIN, HIGH);
|
||||
delay(5); // wait for device to come up
|
||||
|
@ -249,9 +254,16 @@ void setup() {
|
|||
Serial.println("Setting radio to its defaults..");
|
||||
radio.initialize();
|
||||
radio.setRfPower(0);
|
||||
radio.frequency(144025);
|
||||
radio.frequency(145010);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
|
||||
radio.waitForChannel(); // wait for the channel to be empty
|
||||
|
||||
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(spSIX); // more word choices can be found at the talkie github site
|
||||
voice.say(spALPHA);
|
||||
|
@ -267,10 +279,6 @@ void setup() {
|
|||
voice.say(spON);
|
||||
voice.say(spFIRE);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
radio.frequency(144025);
|
||||
radio.setModeTransmit();
|
||||
for(;;) { }
|
||||
radio.setModeReceive();
|
||||
delay(10000);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=HamShield
|
||||
version=1.1.2
|
||||
version=1.1.4
|
||||
author=Morgan Redfield <morgan@enhancedradio.com>, Casey Halverson <casey@enhancedradio.com>
|
||||
maintainer=Morgan Redfield <morgan@enhancedradio.com>
|
||||
sentence=A library for use with HamShield by Enhanced Radio Devices.
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
/* don't change this regulatory value, use dangerMode() and safeMode() instead */
|
||||
bool restrictions = true;
|
||||
uint16_t old_dtmf_reg;
|
||||
|
||||
/* 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_HIGH
|
||||
*/
|
||||
HamShield::HamShield(uint8_t cs_pin, uint8_t clk_pin, uint8_t dat_pin, uint8_t pwm_pin) {
|
||||
devAddr = cs_pin;
|
||||
hs_pwm_pin = pwm_pin;
|
||||
HamShield::HamShield(uint8_t ncs_pin, uint8_t clk_pin, uint8_t dat_pin, uint8_t mic_pin) {
|
||||
devAddr = ncs_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);
|
||||
tx_data = 0x800D;
|
||||
HSwriteWord(devAddr, 0x58, tx_data);
|
||||
tx_data = 0x0EDD;
|
||||
tx_data = 0x0EDB;
|
||||
HSwriteWord(devAddr, 0x5A, tx_data); // sq and noise detect times
|
||||
tx_data = 0x3FFF;
|
||||
HSwriteWord(devAddr, 0x63, tx_data); // pre-emphasis bypass
|
||||
|
@ -226,12 +227,15 @@ void HamShield::initialize(bool narrowBand) {
|
|||
setModeReceive();
|
||||
setTxSourceMic();
|
||||
setRfPower(0);
|
||||
setSQLoThresh(80);
|
||||
setSQLoThresh(-80);
|
||||
setSQOn();
|
||||
*/
|
||||
setDTMFIdleTime(50);
|
||||
setDTMFTxTime(60);
|
||||
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);
|
||||
tx_data = 0x40C3;
|
||||
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]
|
||||
tx_data = 0x28D0;
|
||||
HSwriteWord(devAddr, 0x3F, tx_data); // rssi3_th sq setting
|
||||
tx_data = 0x203E;
|
||||
tx_data = 0x20BE;
|
||||
HSwriteWord(devAddr, 0x48, tx_data);
|
||||
tx_data = 0x1BB7;
|
||||
HSwriteWord(devAddr, 0x60, tx_data);
|
||||
|
@ -384,13 +388,13 @@ void HamShield::setupWideBand() {
|
|||
// end AGC table
|
||||
}
|
||||
|
||||
/** Verify the I2C connection.
|
||||
/** Verify the data connection.
|
||||
* Make sure the device is connected and responds as expected.
|
||||
* @return True if connection is valid, false otherwise
|
||||
*/
|
||||
bool HamShield::testConnection() {
|
||||
HSreadWord(devAddr, 0x00, radio_i2c_buf);
|
||||
return radio_i2c_buf[0] == 0x1846;
|
||||
HSreadWord(devAddr, 0x00, radio_dat_buf);
|
||||
return radio_dat_buf[0] == 0x1846;
|
||||
}
|
||||
|
||||
|
||||
|
@ -410,8 +414,8 @@ bool HamShield::testConnection() {
|
|||
*/
|
||||
|
||||
uint16_t HamShield::readCtlReg() {
|
||||
HSreadWord(devAddr, A1846S_CTL_REG, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadWord(devAddr, A1846S_CTL_REG, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
void HamShield::softReset() {
|
||||
|
@ -499,8 +503,8 @@ void HamShield::setClkMode(bool LFClk){
|
|||
HSwriteWord(devAddr, A1846S_CLK_MODE_REG, tx_data);
|
||||
}
|
||||
bool HamShield::getClkMode(){
|
||||
HSreadBitW(devAddr, A1846S_CLK_MODE_REG, A1846S_CLK_MODE_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_CLK_MODE_REG, A1846S_CLK_MODE_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
uint16_t HamShield::getChanMode(){
|
||||
HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_CHAN_MODE_BIT, A1846S_CHAN_MODE_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_CHAN_MODE_BIT, A1846S_CHAN_MODE_LENGTH, radio_dat_buf);
|
||||
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);
|
||||
}
|
||||
bool HamShield::getTX(){
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TX_MODE_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TX_MODE_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
bool HamShield::getRX(){
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_RX_MODE_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_RX_MODE_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
void HamShield::setModeTransmit(){
|
||||
|
@ -630,8 +634,8 @@ void HamShield::setTxSourceNone(){
|
|||
setTxSource(0);
|
||||
}
|
||||
uint16_t HamShield::getTxSource(){
|
||||
HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_VOICE_SEL_BIT, A1846S_VOICE_SEL_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_VOICE_SEL_BIT, A1846S_VOICE_SEL_LENGTH, radio_dat_buf);
|
||||
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);
|
||||
}
|
||||
uint16_t HamShield::getPABiasVoltage(){
|
||||
HSreadBitsW(devAddr, A1846S_PABIAS_REG, A1846S_PABIAS_BIT, A1846S_PABIAS_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_PABIAS_REG, A1846S_PABIAS_BIT, A1846S_PABIAS_LENGTH, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
*/
|
||||
// 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);
|
||||
}
|
||||
uint16_t HamShield::getCtcssCdcssMode(){
|
||||
HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTDCSS_DTEN_BIT, A1846S_CTDCSS_DTEN_BIT, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTDCSS_DTEN_BIT, A1846S_CTDCSS_DTEN_BIT, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
bool HamShield::getCdcssSel(){
|
||||
HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_SEL_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] == 1);
|
||||
HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_SEL_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] == 1);
|
||||
}
|
||||
|
||||
void HamShield::setCdcssInvert(bool invert) {
|
||||
HSwriteBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_INVERT_BIT, invert);
|
||||
}
|
||||
bool HamShield::getCdcssInvert() {
|
||||
HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_INVERT_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] == 1);
|
||||
HSreadBitW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_CDCSS_INVERT_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] == 1);
|
||||
}
|
||||
|
||||
// Cdcss neg_det_en
|
||||
|
@ -759,8 +763,8 @@ float HamShield::getCtcssFreqHz() {
|
|||
//y = mx + b
|
||||
float m = 1.678;
|
||||
float b = -3.3;
|
||||
HSreadWord(devAddr, A1846S_CTCSS_FREQ_REG, radio_i2c_buf);
|
||||
float f = (float) radio_i2c_buf[0];
|
||||
HSreadWord(devAddr, A1846S_CTCSS_FREQ_REG, radio_dat_buf);
|
||||
float f = (float) radio_dat_buf[0];
|
||||
return (f/m-b)/100;
|
||||
}
|
||||
|
||||
|
@ -769,28 +773,45 @@ void HamShield::setCtcssFreqToStandard(){
|
|||
setCtcssFreq(13440);
|
||||
}
|
||||
|
||||
void HamShield::enableCtcss() {
|
||||
// enable TX
|
||||
void HamShield::enableCtcssTx() {
|
||||
HSwriteBitsW(devAddr, A1846S_CTCSS_MODE_REG, 10, 2, 3);
|
||||
}
|
||||
|
||||
// enable RX
|
||||
void HamShield::enableCtcssRx() {
|
||||
setCtcssGpioSel(1);
|
||||
HSwriteBitW(devAddr, A1846S_TX_VOICE_REG, A1846S_CTCSS_DET_BIT, 0);
|
||||
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_CTCSS_FILTER_BYPASS, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
void HamShield::disableCtcssRx() {
|
||||
setCtcssGpioSel(0);
|
||||
disableCtcssCdcss();
|
||||
}
|
||||
void HamShield::disableCtcss() {
|
||||
disableCtcssTx();
|
||||
disableCtcssRx();
|
||||
}
|
||||
|
||||
// match threshold
|
||||
void HamShield::setCtcssDetThreshIn(uint8_t thresh) {
|
||||
HSwriteBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 15, 8, thresh);
|
||||
}
|
||||
uint8_t HamShield::getCtcssDetThreshIn() {
|
||||
HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 15, 8, radio_i2c_buf);
|
||||
return (uint8_t) radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 15, 8, radio_dat_buf);
|
||||
return (uint8_t) radio_dat_buf[0];
|
||||
}
|
||||
|
||||
// unmatch threshold
|
||||
|
@ -798,13 +819,13 @@ void HamShield::setCtcssDetThreshOut(uint8_t thresh) {
|
|||
HSwriteBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 7, 8, thresh);
|
||||
}
|
||||
uint8_t HamShield::getCtcssDetThreshOut() {
|
||||
HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 7, 8, radio_i2c_buf);
|
||||
return (uint8_t) radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_CTCSS_THRESH_REG, 7, 8, radio_dat_buf);
|
||||
return (uint8_t) radio_dat_buf[0];
|
||||
}
|
||||
|
||||
bool HamShield::getCtcssToneDetected() {
|
||||
HSreadBitW(devAddr, A1846S_FLAG_REG, A1846S_CTCSS1_FLAG_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_FLAG_REG, A1846S_CTCSS1_FLAG_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
// cdcss codes
|
||||
|
@ -835,10 +856,10 @@ void HamShield::setCdcssCode(uint16_t code) {
|
|||
}
|
||||
uint16_t HamShield::getCdcssCode() {
|
||||
uint32_t oct_code;
|
||||
HSreadWord(devAddr, A1846S_CDCSS_CODE_HI_REG, radio_i2c_buf);
|
||||
oct_code = ((uint32_t)radio_i2c_buf[0] << 16);
|
||||
HSreadWord(devAddr, A1846S_CDCSS_CODE_LO_REG, radio_i2c_buf);
|
||||
oct_code += radio_i2c_buf[0];
|
||||
HSreadWord(devAddr, A1846S_CDCSS_CODE_HI_REG, radio_dat_buf);
|
||||
oct_code = ((uint32_t)radio_dat_buf[0] << 16);
|
||||
HSreadWord(devAddr, A1846S_CDCSS_CODE_LO_REG, radio_dat_buf);
|
||||
oct_code += radio_dat_buf[0];
|
||||
|
||||
oct_code = oct_code >> 12;
|
||||
uint16_t code = (oct_code & 0x3);
|
||||
|
@ -858,32 +879,38 @@ void HamShield::setSQOff(){
|
|||
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_SQ_ON_BIT, 0);
|
||||
}
|
||||
bool HamShield::getSQState(){
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_SQ_ON_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_SQ_ON_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
// SQ 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
|
||||
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(){
|
||||
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){
|
||||
// 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;
|
||||
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(){
|
||||
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
|
||||
void HamShield::setSQOutSel(){
|
||||
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);
|
||||
}
|
||||
bool HamShield::getSQOutSel(){
|
||||
HSreadBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_SQ_OUT_SEL_REG, A1846S_SQ_OUT_SEL_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
// VOX
|
||||
|
@ -904,8 +931,8 @@ void HamShield::setVoxOff(){
|
|||
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_VOX_ON_BIT, 0);
|
||||
}
|
||||
bool HamShield::getVoxOn(){
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_VOX_ON_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_VOX_ON_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
// Vox Threshold
|
||||
|
@ -915,16 +942,16 @@ void HamShield::setVoxOpenThresh(uint16_t vox_open_thresh){
|
|||
|
||||
}
|
||||
uint16_t HamShield::getVoxOpenThresh(){
|
||||
HSreadBitsW(devAddr, A1846S_TH_H_VOX_REG, A1846S_TH_H_VOX_BIT, A1846S_TH_H_VOX_LEN, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_TH_H_VOX_REG, A1846S_TH_H_VOX_BIT, A1846S_TH_H_VOX_LEN, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
void HamShield::setVoxShutThresh(uint16_t vox_shut_thresh){
|
||||
// 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);
|
||||
}
|
||||
uint16_t HamShield::getVoxShutThresh(){
|
||||
HSreadBitsW(devAddr, A1846S_TH_L_VOX_REG, A1846S_TH_L_VOX_BIT, A1846S_TH_L_VOX_LEN, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_TH_L_VOX_REG, A1846S_TH_L_VOX_BIT, A1846S_TH_L_VOX_LEN, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
// Tail Noise
|
||||
|
@ -935,8 +962,8 @@ void HamShield::disableTailNoiseElim(){
|
|||
HSwriteBitW(devAddr, A1846S_CTL_REG, A1846S_TAIL_ELIM_EN_BIT, 1);
|
||||
}
|
||||
bool HamShield::getTailNoiseElimEnabled(){
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TAIL_ELIM_EN_BIT, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_CTL_REG, A1846S_TAIL_ELIM_EN_BIT, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
uint16_t HamShield::getShiftSelect(){
|
||||
HSreadBitsW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_SHIFT_SEL_BIT, A1846S_SHIFT_SEL_LEN, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_CTCSS_MODE_REG, A1846S_SHIFT_SEL_BIT, A1846S_SHIFT_SEL_LEN, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
// DTMF
|
||||
|
@ -979,8 +1006,8 @@ void HamShield::setDTMFDetectTime(uint16_t detect_time) {
|
|||
}
|
||||
|
||||
uint16_t HamShield::getDTMFDetectTime() {
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_ENABLE_REG, A18462_DTMF_DET_TIME_BIT, A18462_DTMF_DET_TIME_LEN, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_ENABLE_REG, A18462_DTMF_DET_TIME_BIT, A18462_DTMF_DET_TIME_LEN, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
void HamShield::setDTMFIdleTime(uint16_t idle_time) {
|
||||
|
@ -990,10 +1017,71 @@ void HamShield::setDTMFIdleTime(uint16_t idle_time) {
|
|||
}
|
||||
|
||||
uint16_t HamShield::getDTMFIdleTime() {
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DTMF_IDLE_TIME_BIT, A1846S_DTMF_IDLE_TIME_LEN, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DTMF_IDLE_TIME_BIT, A1846S_DTMF_IDLE_TIME_LEN, radio_dat_buf);
|
||||
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) {
|
||||
if (tx_time > 63) {tx_time = 63;} // maxed out
|
||||
// tx time is duration of DTMF Tone
|
||||
|
@ -1001,8 +1089,8 @@ void HamShield::setDTMFTxTime(uint16_t tx_time) {
|
|||
}
|
||||
|
||||
uint16_t HamShield::getDTMFTxTime() {
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DUALTONE_TX_TIME_BIT, A1846S_DUALTONE_TX_TIME_LEN, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_TIME_REG, A1846S_DUALTONE_TX_TIME_BIT, A1846S_DUALTONE_TX_TIME_LEN, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
uint16_t HamShield::disableDTMF(){
|
||||
|
@ -1010,18 +1098,18 @@ uint16_t HamShield::disableDTMF(){
|
|||
}
|
||||
|
||||
uint16_t HamShield::getDTMFSample(){
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
uint16_t HamShield::getDTMFTxActive(){
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_TX_IDLE_BIT, 1, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_TX_IDLE_BIT, 1, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
uint16_t HamShield::getDTMFCode(){
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_CODE_BIT, A1846S_DTMF_CODE_LEN, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_CODE_BIT, A1846S_DTMF_CODE_LEN, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
void HamShield::setDTMFCode(uint16_t code){
|
||||
|
@ -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_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
|
||||
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 Fs = 6400000/1024;
|
||||
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);
|
||||
uint16_t h = (uint16_t) (round(2.0*cos(2.0*M_PI*k2/127)*1024));
|
||||
// set tone
|
||||
HSwriteWord(devAddr, 0x68, t);
|
||||
HSwriteWord(devAddr, 0x67, t); // looking for tone 1
|
||||
|
||||
// set second harmonic
|
||||
HSwriteWord(devAddr, 0x70, h);
|
||||
HSwriteWord(devAddr, 0x6F, h); // looking for tone
|
||||
|
||||
// turn on tone detect
|
||||
HSwriteBitW(devAddr, A1846S_DTMF_ENABLE_REG, A1846S_TONE_DETECT, 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() {
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_i2c_buf);
|
||||
if (radio_i2c_buf[0] != 0) {
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_CODE_BIT, A1846S_DTMF_CODE_LEN, radio_i2c_buf);
|
||||
if (radio_i2c_buf[0] == 1) {
|
||||
HSreadBitsW(devAddr, A1846S_DTMF_CODE_REG, A1846S_DTMF_SAMPLE_BIT, 1, radio_dat_buf);
|
||||
if (radio_dat_buf[0] != 0) {
|
||||
if (!redetect) {
|
||||
redetect = true;
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
uint16_t HamShield::getFMVoiceCssDeviation(){
|
||||
HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_VOICE_BIT, A1846S_FM_DEV_VOICE_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_VOICE_BIT, A1846S_FM_DEV_VOICE_LENGTH, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
void HamShield::setFMCssDeviation(uint16_t deviation){
|
||||
HSwriteBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_CSS_BIT, A1846S_FM_DEV_CSS_LENGTH, deviation);
|
||||
}
|
||||
uint16_t HamShield::getFMCssDeviation(){
|
||||
HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_CSS_BIT, A1846S_FM_DEV_CSS_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_FM_DEV_REG, A1846S_FM_DEV_CSS_BIT, A1846S_FM_DEV_CSS_LENGTH, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
uint16_t HamShield::getVolume1(){
|
||||
HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_1_BIT, A1846S_RX_VOL_1_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_1_BIT, A1846S_RX_VOL_1_LENGTH, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
void HamShield::setVolume2(uint16_t volume){
|
||||
HSwriteBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_2_BIT, A1846S_RX_VOL_2_LENGTH, volume);
|
||||
}
|
||||
uint16_t HamShield::getVolume2(){
|
||||
HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_2_BIT, A1846S_RX_VOL_2_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_RX_VOLUME_REG, A1846S_RX_VOL_2_BIT, A1846S_RX_VOL_2_LENGTH, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
// GPIO
|
||||
|
@ -1155,8 +1292,8 @@ uint16_t HamShield::getGpioMode(uint16_t gpio){
|
|||
uint16_t mode_len = 2;
|
||||
uint16_t bit = gpio*2 + 1;
|
||||
|
||||
HSreadBitsW(devAddr, A1846S_GPIO_MODE_REG, bit, mode_len, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_GPIO_MODE_REG, bit, mode_len, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
void HamShield::setGpios(uint16_t mode){
|
||||
|
@ -1164,8 +1301,8 @@ void HamShield::setGpios(uint16_t mode){
|
|||
}
|
||||
|
||||
uint16_t HamShield::getGpios(){
|
||||
HSreadWord(devAddr, A1846S_GPIO_MODE_REG, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadWord(devAddr, A1846S_GPIO_MODE_REG, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
|
||||
// Int
|
||||
|
@ -1176,8 +1313,8 @@ void HamShield::disableInterrupt(uint16_t interrupt){
|
|||
HSwriteBitW(devAddr, A1846S_INT_MODE_REG, interrupt, 0);
|
||||
}
|
||||
bool HamShield::getInterruptEnabled(uint16_t interrupt){
|
||||
HSreadBitW(devAddr, A1846S_INT_MODE_REG, interrupt, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] != 0);
|
||||
HSreadBitW(devAddr, A1846S_INT_MODE_REG, interrupt, radio_dat_buf);
|
||||
return (radio_dat_buf[0] != 0);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
uint16_t HamShield::getStMode(){
|
||||
HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_ST_MODE_BIT, A1846S_ST_MODE_LENGTH, radio_i2c_buf);
|
||||
return radio_i2c_buf[0];
|
||||
HSreadBitsW(devAddr, A1846S_CTL_REG, A1846S_ST_MODE_BIT, A1846S_ST_MODE_LENGTH, radio_dat_buf);
|
||||
return radio_dat_buf[0];
|
||||
}
|
||||
void HamShield::setStFullAuto(){
|
||||
setStMode(2);
|
||||
|
@ -1206,8 +1343,8 @@ void HamShield::usePreDeEmph(){
|
|||
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, 0);
|
||||
}
|
||||
bool HamShield::getPreDeEmphEnabled(){
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] == 0);
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_EMPH_FILTER_EN, radio_dat_buf);
|
||||
return (radio_dat_buf[0] == 0);
|
||||
}
|
||||
|
||||
// Voice Filters
|
||||
|
@ -1218,8 +1355,8 @@ void HamShield::useVoiceHpf(){
|
|||
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VHPF_FILTER_EN, 0);
|
||||
}
|
||||
bool HamShield::getVoiceHpfEnabled(){
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VHPF_FILTER_EN, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] == 0);
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VHPF_FILTER_EN, radio_dat_buf);
|
||||
return (radio_dat_buf[0] == 0);
|
||||
}
|
||||
|
||||
void HamShield::bypassVoiceLpf(){
|
||||
|
@ -1229,8 +1366,8 @@ void HamShield::useVoiceLpf(){
|
|||
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VLPF_FILTER_EN, 0);
|
||||
}
|
||||
bool HamShield::getVoiceLpfEnabled(){
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VLPF_FILTER_EN, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] == 0);
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VLPF_FILTER_EN, radio_dat_buf);
|
||||
return (radio_dat_buf[0] == 0);
|
||||
}
|
||||
|
||||
// Vox filters
|
||||
|
@ -1242,8 +1379,8 @@ void HamShield::useVoxHpf(){
|
|||
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VXHPF_FILTER_EN, 0);
|
||||
}
|
||||
bool HamShield::getVoxHpfEnabled(){
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXHPF_FILTER_EN, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] == 0);
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXHPF_FILTER_EN, radio_dat_buf);
|
||||
return (radio_dat_buf[0] == 0);
|
||||
}
|
||||
|
||||
void HamShield::bypassVoxLpf(){
|
||||
|
@ -1253,28 +1390,28 @@ void HamShield::useVoxLpf(){
|
|||
HSwriteBitW(devAddr, A1846S_FILTER_REG, A1846S_VXLPF_FILTER_EN, 0);
|
||||
}
|
||||
bool HamShield::getVoxLpfEnabled(){
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXLPF_FILTER_EN, radio_i2c_buf);
|
||||
return (radio_i2c_buf[0] == 0);
|
||||
HSreadBitW(devAddr, A1846S_FILTER_REG, A1846S_VXLPF_FILTER_EN, radio_dat_buf);
|
||||
return (radio_dat_buf[0] == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read Only Status Registers
|
||||
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;
|
||||
}
|
||||
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(){
|
||||
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
|
||||
for(int x = 0; x < 20; x++) { rssi = readRSSI(); } // "warm up" to get past RSSI hysteresis
|
||||
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;
|
||||
}
|
||||
|
||||
void HamShield::setupMorseRx() {
|
||||
// TODO: morse timing config (e.g. dot time, dash time, etc)
|
||||
}
|
||||
|
||||
// Get current morse code tone frequency (in Hz)
|
||||
|
||||
unsigned int HamShield::getMorseFreq() {
|
||||
|
@ -1593,18 +1734,21 @@ void HamShield::morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]) {
|
|||
int i;
|
||||
char prev = 0;
|
||||
for(i = 0; buffer[i] != '\0' && i < HAMSHIELD_MORSE_BUFFER_SIZE; prev = buffer[i], i++) {
|
||||
|
||||
// On a space, delay 7 dots
|
||||
if(buffer[i] == ' ') {
|
||||
// We delay by 4 here, if we previously sent a symbol. Otherwise 7.
|
||||
// This could probably just be always 7 and go relatively unnoticed.
|
||||
if(prev == 0 || prev == ' '){
|
||||
//tone(hs_pwm_pin, 6000, morse_dot_millis * 7);
|
||||
HSnoTone(hs_pwm_pin);
|
||||
//tone(hs_mic_pin, 6000, morse_dot_millis * 7);
|
||||
HSnoTone(hs_mic_pin);
|
||||
HSdelay(morse_dot_millis*7);
|
||||
//Serial.print(" ");
|
||||
} else {
|
||||
//tone(hs_pwm_pin, 6000, morse_dot_millis * 4);
|
||||
HSnoTone(hs_pwm_pin);
|
||||
//tone(hs_mic_pin, 6000, morse_dot_millis * 4);
|
||||
HSnoTone(hs_mic_pin);
|
||||
HSdelay(morse_dot_millis*4);
|
||||
//Serial.print(" ");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1613,28 +1757,128 @@ void HamShield::morseOut(char buffer[HAMSHIELD_MORSE_BUFFER_SIZE]) {
|
|||
if(bits) { // If it is a valid character...
|
||||
do {
|
||||
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);
|
||||
HSnoTone(hs_pwm_pin);
|
||||
HSnoTone(hs_mic_pin);
|
||||
//Serial.print('-');
|
||||
} else {
|
||||
HStone(hs_pwm_pin, morse_freq); //, morse_dot_millis);
|
||||
HStone(hs_mic_pin, morse_freq);//, 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);
|
||||
HSnoTone(hs_pwm_pin);
|
||||
//tone(hs_mic_pin, 6000, morse_dot_millis);
|
||||
HSnoTone(hs_mic_pin);
|
||||
HSdelay(morse_dot_millis);
|
||||
bits >>= 1; // Shift into the next symbol
|
||||
} while(bits != 1); // Wait for 1 termination to be all we have left
|
||||
}
|
||||
// End of character
|
||||
//tone(hs_pwm_pin, 6000, morse_dot_millis * 3);
|
||||
HSnoTone(hs_pwm_pin);
|
||||
//tone(hs_mic_pin, 6000, morse_dot_millis * 3);
|
||||
HSnoTone(hs_mic_pin);
|
||||
HSdelay(morse_dot_millis * 3);
|
||||
}
|
||||
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 */
|
||||
|
||||
uint8_t HamShield::morseLookup(char letter) {
|
||||
|
@ -1760,20 +2004,20 @@ void HamShield::SSTVTestPattern(int code) {
|
|||
/* wait for tone to complete */
|
||||
|
||||
void HamShield::toneWait(uint16_t freq, long timer) {
|
||||
HStone(hs_pwm_pin,freq); //,timer);
|
||||
HStone(hs_mic_pin,freq);//,timer);
|
||||
HSdelay(timer);
|
||||
HSnoTone(hs_pwm_pin);
|
||||
HSnoTone(hs_mic_pin);
|
||||
}
|
||||
|
||||
/* wait microseconds for tone to complete */
|
||||
|
||||
void HamShield::toneWaitU(uint16_t freq, long timer) {
|
||||
if(freq < 16383) {
|
||||
HStone(hs_pwm_pin,freq);
|
||||
HSdelayMicroseconds(timer); HSnoTone(hs_pwm_pin); return;
|
||||
HStone(hs_mic_pin,freq);
|
||||
HSdelayMicroseconds(timer); HSnoTone(hs_mic_pin); return;
|
||||
}
|
||||
HStone(hs_pwm_pin,freq);
|
||||
HSdelay(timer / 1000); HSnoTone(hs_pwm_pin); return;
|
||||
HStone(hs_mic_pin,freq);
|
||||
HSdelay(timer / 1000); HSnoTone(hs_mic_pin); return;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#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_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_CTCSS_FREQ_REG 0x4A // ctcss_freq<15:0>
|
||||
#define A1846S_CDCSS_CODE_HI_REG 0x4B // cdcss_code<23:16>
|
||||
|
@ -145,12 +145,12 @@
|
|||
#define A1846S_SHIFT_SEL_LEN 2
|
||||
|
||||
// Bitfields for A1846S_SQ_THRESH_REG
|
||||
#define A1846S_SQ_OPEN_THRESH_BIT 9 // sq open threshold <9:0>
|
||||
#define A1846S_SQ_OPEN_THRESH_LENGTH 10
|
||||
#define A1846S_SQ_OPEN_THRESH_BIT 13 // sq open threshold <6:0>
|
||||
#define A1846S_SQ_OPEN_THRESH_LENGTH 7
|
||||
|
||||
// Bitfields for A1846S_SQ_SHUT_THRESH_REG
|
||||
#define A1846S_SQ_SHUT_THRESH_BIT 9 // sq shut threshold <9:0>
|
||||
#define A1846S_SQ_SHUT_THRESH_LENGTH 10
|
||||
#define A1846S_SQ_SHUT_THRESH_BIT 6 // sq shut threshold <6:0>
|
||||
#define A1846S_SQ_SHUT_THRESH_LENGTH 7
|
||||
|
||||
// Bitfields for A1846S_SQ_OUT_SEL_REG
|
||||
#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_INVERT_DET_FLAG_BIT 7 // ctcss phase shift detect
|
||||
#define A1846S_CSS_CMP_FLAG_BIT 2 // ctcss/cdcss compared
|
||||
#define A1846S_SQ_FLAG_BIT 1 // sq final signal out from dsp
|
||||
#define A1846S_VOX_FLAG_BIT 0 // vox out from dsp
|
||||
#define A1846S_SQ_FLAG_BIT 0 // sq final signal out from dsp
|
||||
#define A1846S_VOX_FLAG_BIT 1 // vox out from dsp
|
||||
|
||||
// Bitfields for A1846S_RSSI_REG
|
||||
#define A1846S_RSSI_BIT 15 // RSSI readings <7:0>
|
||||
|
@ -217,10 +217,24 @@
|
|||
#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 {
|
||||
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(bool narrowBand); // select 12.5kHz if true or 25kHz if false
|
||||
|
@ -299,7 +313,11 @@ class HamShield {
|
|||
uint16_t getCtcssFreqMilliHz();
|
||||
float getCtcssFreqHz();
|
||||
void setCtcssFreqToStandard(); // freq must be 134.4Hz for standard cdcss mode
|
||||
void enableCtcssTx();
|
||||
void enableCtcssRx();
|
||||
void enableCtcss();
|
||||
void disableCtcssTx();
|
||||
void disableCtcssRx();
|
||||
void disableCtcss();
|
||||
void setCtcssDetThreshIn(uint8_t thresh);
|
||||
uint8_t getCtcssDetThreshIn();
|
||||
|
@ -344,6 +362,7 @@ class HamShield {
|
|||
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
|
||||
int16_t getSQLoThresh();
|
||||
bool getSquelching();
|
||||
|
||||
// SQ out select
|
||||
void setSQOutSel();
|
||||
|
@ -389,6 +408,9 @@ class HamShield {
|
|||
uint16_t getDTMFDetectTime();
|
||||
void setDTMFIdleTime(uint16_t idle_time); // idle time is time between DTMF Tone
|
||||
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
|
||||
uint16_t getDTMFTxTime();
|
||||
uint16_t disableDTMF();
|
||||
|
@ -398,6 +420,8 @@ class HamShield {
|
|||
void setDTMFCode(uint16_t code);
|
||||
|
||||
// Tone
|
||||
void HStone(uint8_t pin, unsigned int frequency);
|
||||
void HSnoTone(uint8_t pin);
|
||||
void lookForTone(uint16_t tone_hz);
|
||||
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 findWhitespaceChannels(uint32_t buffer[],uint8_t buffsize, uint8_t dwell, uint16_t threshold);
|
||||
|
||||
void setupMorseRx();
|
||||
unsigned int getMorseFreq();
|
||||
void setMorseFreq(unsigned int morse_freq_hz);
|
||||
unsigned int getMorseDotMillis();
|
||||
void setMorseDotMillis(unsigned int morse_dot_dur_millis);
|
||||
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 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 SSTVTestPattern(int code);
|
||||
void toneWait(uint16_t freq, long timer);
|
||||
|
@ -498,8 +526,8 @@ class HamShield {
|
|||
|
||||
private:
|
||||
uint8_t devAddr;
|
||||
uint8_t hs_pwm_pin;
|
||||
uint16_t radio_i2c_buf[4];
|
||||
uint8_t hs_mic_pin;
|
||||
uint16_t radio_dat_buf[4];
|
||||
bool tx_active;
|
||||
bool rx_active;
|
||||
float radio_frequency;
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
uint8_t ncs_pin = nSEN;
|
||||
uint8_t ncs_pin = nCS;
|
||||
uint8_t clk_pin = CLK;
|
||||
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);
|
||||
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
|
||||
digitalWrite(dat_pin, temp);
|
||||
HSdelayMicroseconds(1);
|
||||
digitalWrite(clk_pin, 1); //PORTC |= (1<<5); //
|
||||
HSdelayMicroseconds(1);
|
||||
}
|
||||
// change direction of dat_pin
|
||||
pinMode(dat_pin, INPUT); // DDRC &= ~(1<<4); //
|
||||
for (int i = 15; i >= 0; i--) {
|
||||
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
|
||||
HSdelayMicroseconds(1);
|
||||
digitalWrite(clk_pin, 1); //PORTC |= (1<<5); //
|
||||
temp_dat = digitalRead(dat_pin); //((PINC & (1<<4)) != 0);
|
||||
temp_dat = temp_dat << i;
|
||||
*data |= temp_dat;
|
||||
HSdelayMicroseconds(1);
|
||||
}
|
||||
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);
|
||||
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
|
||||
digitalWrite(dat_pin, regAddr & (0x80 >> i));
|
||||
HSdelayMicroseconds(1);
|
||||
digitalWrite(clk_pin, 1); // PORTC |= (1<<5); //
|
||||
HSdelayMicroseconds(1);
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
temp_dat = ((data & (0x8000 >> i)) != 0);
|
||||
digitalWrite(clk_pin, 0); //PORTC &= ~(1<<5); //
|
||||
digitalWrite(dat_pin, temp_dat);
|
||||
HSdelayMicroseconds(1);
|
||||
digitalWrite(clk_pin, 1); // PORTC |= (1<<5); //
|
||||
HSdelayMicroseconds(1);
|
||||
}
|
||||
|
||||
digitalWrite(devAddr, 1); //PORTC |= (1<<1); //CS
|
||||
|
@ -145,19 +159,3 @@ void HSdelay(unsigned long ms) {
|
|||
void HSdelayMicroseconds(unsigned int 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
|
||||
}
|
|
@ -8,19 +8,19 @@
|
|||
#if defined(ARDUINO)
|
||||
#include "Arduino.h"
|
||||
|
||||
#define nSEN A1 //15 //
|
||||
#define nCS A1 //15 //
|
||||
#define CLK A5 //19 //
|
||||
#define DAT A4 //18 //
|
||||
#define HAMSHIELD_PWM_PIN 3
|
||||
#define MIC 3
|
||||
#else // assume Raspberry Pi
|
||||
#include "stdint.h"
|
||||
#include <wiringPi.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 DAT 2 //BCM27, HW pin 13
|
||||
#define HAMSHIELD_PWM_PIN 1 //BCM18, HW pin 12
|
||||
#define MIC 1 //BCM18, HW pin 12
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -41,8 +41,5 @@ unsigned long HSmillis();
|
|||
void HSdelay(unsigned long ms);
|
||||
void HSdelayMicroseconds(unsigned int us);
|
||||
|
||||
void HStone(uint8_t pin, unsigned int frequency);
|
||||
void HSnoTone(uint8_t pin);
|
||||
|
||||
|
||||
#endif /* _HAMSHIELD_COMMS_H_ */
|
||||
|
|
Loading…
Reference in New Issue