[Morse] Added support for Morse code transmissions
This commit is contained in:
parent
2101203d07
commit
344afee97a
5 changed files with 476 additions and 0 deletions
98
examples/Morse_Transmit/Morse_Transmit.ino
Normal file
98
examples/Morse_Transmit/Morse_Transmit.ino
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
RadioLib Morse Transmit Example
|
||||||
|
|
||||||
|
This example sends Morse code message using
|
||||||
|
SX1278's FSK modem.
|
||||||
|
|
||||||
|
Other modules that can be used for Morse:
|
||||||
|
- SX1272/73/76/77/79
|
||||||
|
- RF69
|
||||||
|
- SX1231
|
||||||
|
- CC1101
|
||||||
|
*/
|
||||||
|
|
||||||
|
// include the library
|
||||||
|
#include <RadioLib.h>
|
||||||
|
|
||||||
|
// SX1278 module is in slot A on the shield
|
||||||
|
SX1278 fsk = RadioShield.ModuleA;
|
||||||
|
|
||||||
|
// create Morse client instance using the FSK module
|
||||||
|
MorseClient morse(&fsk);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// initialize SX1278
|
||||||
|
Serial.print(F("[SX1278] Initializing ... "));
|
||||||
|
// carrier frequency: 434.0 MHz
|
||||||
|
// bit rate: 48.0 kbps
|
||||||
|
// frequency deviation: 50.0 kHz
|
||||||
|
// Rx bandwidth: 125.0 kHz
|
||||||
|
// output power: 13 dBm
|
||||||
|
// current limit: 100 mA
|
||||||
|
// sync word: 0x2D 0x01
|
||||||
|
int state = fsk.beginFSK();
|
||||||
|
if(state == ERR_NONE) {
|
||||||
|
Serial.println(F("success!"));
|
||||||
|
} else {
|
||||||
|
Serial.print(F("failed, code "));
|
||||||
|
Serial.println(state);
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize Morse client
|
||||||
|
Serial.print(F("[Morse] Initializing ... "));
|
||||||
|
// base frequency: 434.0 MHz
|
||||||
|
// speed: 20 words per minute
|
||||||
|
state = morse.begin(434.0);
|
||||||
|
if(state == ERR_NONE) {
|
||||||
|
Serial.println(F("success!"));
|
||||||
|
} else {
|
||||||
|
Serial.print(F("failed, code "));
|
||||||
|
Serial.println(state);
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Serial.print(F("[Morse] Sending Morse data ... "));
|
||||||
|
|
||||||
|
// MorseClient supports all methods of the Serial class
|
||||||
|
// NOTE: Characters that do not have ITU-R M.1677-1
|
||||||
|
// representation will not be sent! Lower case
|
||||||
|
// letters will be capitalized.
|
||||||
|
|
||||||
|
// send start signal first
|
||||||
|
morse.startSignal();
|
||||||
|
|
||||||
|
// Arduino String class
|
||||||
|
String aStr = "Arduino String";
|
||||||
|
morse.print(aStr);
|
||||||
|
|
||||||
|
// character array (C-String)
|
||||||
|
morse.print("C-String");
|
||||||
|
|
||||||
|
// character
|
||||||
|
morse.print('c');
|
||||||
|
|
||||||
|
// byte
|
||||||
|
// formatting DEC/HEX/OCT/BIN is supported for
|
||||||
|
// any integer type (byte/int/long)
|
||||||
|
morse.print(255, HEX);
|
||||||
|
|
||||||
|
// integer number
|
||||||
|
int i = 1000;
|
||||||
|
morse.print(i);
|
||||||
|
|
||||||
|
// floating point number
|
||||||
|
// NOTE: When using println(), the transmission will be
|
||||||
|
// terminated with cross signal (.-.-.).
|
||||||
|
float f = -3.1415;
|
||||||
|
morse.println(f, 3);
|
||||||
|
|
||||||
|
Serial.println(F("done!"));
|
||||||
|
|
||||||
|
// wait for a second before transmitting again
|
||||||
|
delay(1000);
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ XBeeSerial KEYWORD1
|
||||||
MQTTClient KEYWORD1
|
MQTTClient KEYWORD1
|
||||||
HTTPClient KEYWORD1
|
HTTPClient KEYWORD1
|
||||||
RTTYClient KEYWORD1
|
RTTYClient KEYWORD1
|
||||||
|
MorseClient KEYWORD1
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
|
@ -113,6 +114,9 @@ check KEYWORD2
|
||||||
idle KEYWORD2
|
idle KEYWORD2
|
||||||
byteArr KEYWORD2
|
byteArr KEYWORD2
|
||||||
|
|
||||||
|
# Morse
|
||||||
|
startSignal KEYWORD2
|
||||||
|
|
||||||
# TransportLayer
|
# TransportLayer
|
||||||
openTransportConnection KEYWORD2
|
openTransportConnection KEYWORD2
|
||||||
closeTransportConnection KEYWORD2
|
closeTransportConnection KEYWORD2
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "modules/XBee.h"
|
#include "modules/XBee.h"
|
||||||
|
|
||||||
#include "protocols/PhysicalLayer.h"
|
#include "protocols/PhysicalLayer.h"
|
||||||
|
#include "protocols/Morse.h"
|
||||||
#include "protocols/RTTY.h"
|
#include "protocols/RTTY.h"
|
||||||
|
|
||||||
#include "protocols/TransportLayer.h"
|
#include "protocols/TransportLayer.h"
|
||||||
|
|
322
src/protocols/Morse.cpp
Normal file
322
src/protocols/Morse.cpp
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
#include "Morse.h"
|
||||||
|
|
||||||
|
// structure to save data about character Morse code
|
||||||
|
struct Morse_t {
|
||||||
|
char c; // ASCII character
|
||||||
|
const char* m; // Morse code representation
|
||||||
|
};
|
||||||
|
|
||||||
|
// array of all Morse code characters
|
||||||
|
static const Morse_t MorseTable[MORSE_LENGTH] = {
|
||||||
|
{.c = 'A', .m = ".-"},
|
||||||
|
{.c = 'B', .m = "-..."},
|
||||||
|
{.c = 'C', .m = "-.-."},
|
||||||
|
{.c = 'D', .m = "-.."},
|
||||||
|
{.c = 'E', .m = "."},
|
||||||
|
{.c = 'F', .m = "..-."},
|
||||||
|
{.c = 'G', .m = "--."},
|
||||||
|
{.c = 'H', .m = "...."},
|
||||||
|
{.c = 'I', .m = ".."},
|
||||||
|
{.c = 'J', .m = ".---"},
|
||||||
|
{.c = 'K', .m = "-.-"},
|
||||||
|
{.c = 'L', .m = ".-.."},
|
||||||
|
{.c = 'M', .m = "--"},
|
||||||
|
{.c = 'N', .m = "-."},
|
||||||
|
{.c = 'O', .m = "---"},
|
||||||
|
{.c = 'P', .m = ".--."},
|
||||||
|
{.c = 'Q', .m = "--.-"},
|
||||||
|
{.c = 'R', .m = ".-."},
|
||||||
|
{.c = 'S', .m = "..."},
|
||||||
|
{.c = 'T', .m = "-"},
|
||||||
|
{.c = 'U', .m = "..-"},
|
||||||
|
{.c = 'V', .m = "...-"},
|
||||||
|
{.c = 'W', .m = ".--"},
|
||||||
|
{.c = 'X', .m = "-..-"},
|
||||||
|
{.c = 'Y', .m = "-.--"},
|
||||||
|
{.c = 'Z', .m = "--.."},
|
||||||
|
{.c = '1', .m = ".----"},
|
||||||
|
{.c = '2', .m = "..---"},
|
||||||
|
{.c = '3', .m = "...--"},
|
||||||
|
{.c = '4', .m = "....-"},
|
||||||
|
{.c = '5', .m = "....."},
|
||||||
|
{.c = '6', .m = "-...."},
|
||||||
|
{.c = '7', .m = "--..."},
|
||||||
|
{.c = '8', .m = "---.."},
|
||||||
|
{.c = '9', .m = "----."},
|
||||||
|
{.c = '0', .m = "-----"},
|
||||||
|
{.c = '.', .m = ".-.-.-"},
|
||||||
|
{.c = ',', .m = "--..--"},
|
||||||
|
{.c = ':', .m = "---..."},
|
||||||
|
{.c = '?', .m = "..--.."},
|
||||||
|
{.c = '\'', .m = ".----."},
|
||||||
|
{.c = '-', .m = "-....-"},
|
||||||
|
{.c = '/', .m = "-..-."},
|
||||||
|
{.c = '(', .m = "-.--."},
|
||||||
|
{.c = ')', .m = "-.--.-"},
|
||||||
|
{.c = '\"', .m = ".-..-."},
|
||||||
|
{.c = '=', .m = "-...-"},
|
||||||
|
{.c = '+', .m = ".-.-."},
|
||||||
|
{.c = '@', .m = ".--.-."},
|
||||||
|
{.c = ' ', .m = "_"}, // space is used to separate words
|
||||||
|
{.c = 0x01, .m = "-.-.-"}, // ASCII SOH (start of heading) is used as alias for start signal
|
||||||
|
{.c = 0x02, .m = ".-.-."} // ASCII EOT (end of transmission) is used as alias for stop signal
|
||||||
|
};
|
||||||
|
|
||||||
|
MorseClient::MorseClient(PhysicalLayer* phy) {
|
||||||
|
_phy = phy;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t MorseClient::begin(float base, uint8_t speed) {
|
||||||
|
// calculate 24-bit frequency
|
||||||
|
_base = (base * (uint32_t(1) << _phy->getDivExponent())) / _phy->getCrystalFreq();
|
||||||
|
|
||||||
|
// calculate dot length (assumes PARIS as typical word)
|
||||||
|
_dotLength = 1200 / speed;
|
||||||
|
|
||||||
|
// set module frequency deviation to 0
|
||||||
|
int16_t state = _phy->setFrequencyDeviation(0);
|
||||||
|
|
||||||
|
return(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::write(const char* str) {
|
||||||
|
if(str == NULL) {
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(MorseClient::write((uint8_t*)str, strlen(str)));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::write(uint8_t* buff, size_t len) {
|
||||||
|
size_t n = 0;
|
||||||
|
for(size_t i = 0; i < len; i++) {
|
||||||
|
n += MorseClient::write(buff[i]);
|
||||||
|
}
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::write(uint8_t b) {
|
||||||
|
// find the correct Morse code in array
|
||||||
|
uint8_t pos;
|
||||||
|
bool found = false;
|
||||||
|
for(pos = 0; pos < MORSE_LENGTH; pos++) {
|
||||||
|
if(MorseTable[pos].c == toupper(b)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.print((char)b);
|
||||||
|
Serial.print('\t');
|
||||||
|
// check if the requested code was found in the array
|
||||||
|
if(found) {
|
||||||
|
// iterate over Morse code representation and output appropriate tones
|
||||||
|
for(uint8_t i = 0; i < strlen(MorseTable[pos].m); i++) {
|
||||||
|
Serial.print(MorseTable[pos].m[i]);
|
||||||
|
switch(MorseTable[pos].m[i]) {
|
||||||
|
case '.':
|
||||||
|
_phy->transmitDirect(_base);
|
||||||
|
delay(_dotLength);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
_phy->transmitDirect(_base);
|
||||||
|
delay(_dotLength * 3);
|
||||||
|
break;
|
||||||
|
case '_':
|
||||||
|
// do nothing (word space)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// symbol space
|
||||||
|
_phy->receiveDirect();
|
||||||
|
delay(_dotLength);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// letter space
|
||||||
|
delay(_dotLength * 3);
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::startSignal() {
|
||||||
|
return(MorseClient::write(0x01));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(const String& str) {
|
||||||
|
return(MorseClient::write((uint8_t*)str.c_str(), str.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(const char* str) {
|
||||||
|
return(MorseClient::write((uint8_t*)str, strlen(str)));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(char c) {
|
||||||
|
return(MorseClient::write(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(unsigned char b, int base) {
|
||||||
|
return(MorseClient::print((unsigned long)b, base));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(int n, int base) {
|
||||||
|
return(MorseClient::print((long)n, base));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(unsigned int n, int base) {
|
||||||
|
return(MorseClient::print((unsigned long)n, base));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(long n, int base) {
|
||||||
|
if(base == 0) {
|
||||||
|
return(MorseClient::write(n));
|
||||||
|
} else if(base == DEC) {
|
||||||
|
if (n < 0) {
|
||||||
|
int t = MorseClient::print('-');
|
||||||
|
n = -n;
|
||||||
|
return(MorseClient::printNumber(n, DEC) + t);
|
||||||
|
}
|
||||||
|
return(MorseClient::printNumber(n, DEC));
|
||||||
|
} else {
|
||||||
|
return(MorseClient::printNumber(n, base));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(unsigned long n, int base) {
|
||||||
|
if(base == 0) {
|
||||||
|
return(MorseClient::write(n));
|
||||||
|
} else {
|
||||||
|
return(MorseClient::printNumber(n, base));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::print(double n, int digits) {
|
||||||
|
return(MorseClient::printFloat(n, digits));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(void) {
|
||||||
|
return(MorseClient::write(0x02));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(const String& str) {
|
||||||
|
size_t n = MorseClient::print(str);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(const char* str) {
|
||||||
|
size_t n = MorseClient::print(str);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(char c) {
|
||||||
|
size_t n = MorseClient::print(c);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(unsigned char b, int base) {
|
||||||
|
size_t n = MorseClient::print(b, base);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(int num, int base) {
|
||||||
|
size_t n = MorseClient::print(num, base);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(unsigned int num, int base) {
|
||||||
|
size_t n = MorseClient::print(num, base);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(long num, int base) {
|
||||||
|
size_t n = MorseClient::print(num, base);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(unsigned long num, int base) {
|
||||||
|
size_t n = MorseClient::print(num, base);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::println(double d, int digits) {
|
||||||
|
size_t n = MorseClient::print(d, digits);
|
||||||
|
n += MorseClient::println();
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::printNumber(unsigned long n, uint8_t base) {
|
||||||
|
char buf[8 * sizeof(long) + 1];
|
||||||
|
char *str = &buf[sizeof(buf) - 1];
|
||||||
|
|
||||||
|
*str = '\0';
|
||||||
|
|
||||||
|
if(base < 2) {
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
char c = n % base;
|
||||||
|
n /= base;
|
||||||
|
|
||||||
|
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||||
|
} while(n);
|
||||||
|
|
||||||
|
return(MorseClient::write(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MorseClient::printFloat(double number, uint8_t digits) {
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
char code[] = {0x00, 0x00, 0x00, 0x00};
|
||||||
|
if (isnan(number)) strcpy(code, "nan");
|
||||||
|
if (isinf(number)) strcpy(code, "inf");
|
||||||
|
if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically
|
||||||
|
if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically
|
||||||
|
|
||||||
|
if(code[0] != 0x00) {
|
||||||
|
return(MorseClient::write(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle negative numbers
|
||||||
|
if (number < 0.0) {
|
||||||
|
n += MorseClient::print('-');
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||||
|
double rounding = 0.5;
|
||||||
|
for(uint8_t i = 0; i < digits; ++i) {
|
||||||
|
rounding /= 10.0;
|
||||||
|
}
|
||||||
|
number += rounding;
|
||||||
|
|
||||||
|
// Extract the integer part of the number and print it
|
||||||
|
unsigned long int_part = (unsigned long)number;
|
||||||
|
double remainder = number - (double)int_part;
|
||||||
|
n += MorseClient::print(int_part);
|
||||||
|
|
||||||
|
// Print the decimal point, but only if there are digits beyond
|
||||||
|
if(digits > 0) {
|
||||||
|
n += MorseClient::print('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract digits from the remainder one at a time
|
||||||
|
while(digits-- > 0) {
|
||||||
|
remainder *= 10.0;
|
||||||
|
unsigned int toPrint = (unsigned int)(remainder);
|
||||||
|
n += MorseClient::print(toPrint);
|
||||||
|
remainder -= toPrint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
51
src/protocols/Morse.h
Normal file
51
src/protocols/Morse.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef _RADIOLIB_MORSE_H
|
||||||
|
#define _RADIOLIB_MORSE_H
|
||||||
|
|
||||||
|
#include "TypeDef.h"
|
||||||
|
#include "PhysicalLayer.h"
|
||||||
|
|
||||||
|
#define MORSE_LENGTH 52
|
||||||
|
|
||||||
|
class MorseClient {
|
||||||
|
public:
|
||||||
|
MorseClient(PhysicalLayer* phy);
|
||||||
|
|
||||||
|
// basic methods
|
||||||
|
int16_t begin(float base, uint8_t speed = 20);
|
||||||
|
size_t write(const char* str);
|
||||||
|
size_t write(uint8_t* buff, size_t len);
|
||||||
|
size_t write(uint8_t b);
|
||||||
|
|
||||||
|
size_t startSignal();
|
||||||
|
|
||||||
|
size_t print(const String &);
|
||||||
|
size_t print(const char[]);
|
||||||
|
size_t print(char);
|
||||||
|
size_t print(unsigned char, int = DEC);
|
||||||
|
size_t print(int, int = DEC);
|
||||||
|
size_t print(unsigned int, int = DEC);
|
||||||
|
size_t print(long, int = DEC);
|
||||||
|
size_t print(unsigned long, int = DEC);
|
||||||
|
size_t print(double, int = 2);
|
||||||
|
|
||||||
|
size_t println(void);
|
||||||
|
size_t println(const String &s);
|
||||||
|
size_t println(const char[]);
|
||||||
|
size_t println(char);
|
||||||
|
size_t println(unsigned char, int = DEC);
|
||||||
|
size_t println(int, int = DEC);
|
||||||
|
size_t println(unsigned int, int = DEC);
|
||||||
|
size_t println(long, int = DEC);
|
||||||
|
size_t println(unsigned long, int = DEC);
|
||||||
|
size_t println(double, int = 2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PhysicalLayer* _phy;
|
||||||
|
uint32_t _base;
|
||||||
|
uint16_t _dotLength;
|
||||||
|
|
||||||
|
size_t printNumber(unsigned long, uint8_t);
|
||||||
|
size_t printFloat(double, uint8_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Reference in a new issue