commit
202c71c5b2
4 changed files with 324 additions and 0 deletions
122
examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino
Normal file
122
examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
RadioLib FSK4 Transmit Example
|
||||
|
||||
This example sends an example FSK-4 'Horus Binary' message using SX1278's
|
||||
FSK modem.
|
||||
|
||||
This signal can be demodulated using a SSB demodulator (SDR or otherwise), and
|
||||
horusdemodlib: https://github.com/projecthorus/horusdemodlib/wiki
|
||||
|
||||
Other modules that can be used for FSK4:
|
||||
(Untested, but work with RTTY to are likely to work here too)
|
||||
- SX127x/RFM9x
|
||||
- RF69
|
||||
- SX1231
|
||||
- CC1101
|
||||
- SX126x
|
||||
- nRF24
|
||||
- Si443x/RFM2x
|
||||
- SX128x
|
||||
|
||||
For default module settings, see the wiki page
|
||||
https://github.com/jgromes/RadioLib/wiki/Default-configuration
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// RESET pin: 9
|
||||
// DIO1 pin: 3
|
||||
SX1278 radio = new Module(10, 2, 9, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 radio = RadioShield.ModuleA;
|
||||
|
||||
// create FAK4 client instance using the FSK module
|
||||
FSK4Client fsk4(&radio);
|
||||
|
||||
// A 'canned' encoded Horus Binary telemetry packet.
|
||||
// Refer here for packet format information:
|
||||
// https://github.com/projecthorus/horusdemodlib/wiki/2---Modem-Details#horus-binary-v1-mode-4-fsk
|
||||
// After demodulation, deinterleaving, and descrambling, this results in a packet: 00000001172D0000000000000000D20463010AFF2780
|
||||
// This decodes to the Habitat-compatible telemetry string: $$4FSKTEST,0,01:23:45,0.00000,0.00000,1234,99,1,10,5.00*ABCD
|
||||
uint8_t sample_packet[] = {
|
||||
0x45, 0x24, 0x24, 0x48, 0x2F, 0x12, 0x16, 0x08, 0x15, 0xC1,
|
||||
0x49, 0xB2, 0x06, 0xFC, 0x92, 0xEB, 0x93, 0xD7, 0xEE, 0x5D,
|
||||
0x35, 0xA0, 0x91, 0xDA, 0x8D, 0x5F, 0x85, 0x6B, 0x63, 0x03,
|
||||
0x6B, 0x60, 0xEA, 0xFE, 0x55, 0x9D, 0xF1, 0xAB, 0xE5, 0x5E,
|
||||
0xDB, 0x7C, 0xDB, 0x21, 0x5A, 0x19
|
||||
};
|
||||
uint8_t sample_packet_len = 45;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize SX1278 with default settings
|
||||
Serial.print(F("[SX1278] Initializing ... "));
|
||||
int state = radio.beginFSK();
|
||||
|
||||
// when using one of the non-LoRa modules for FSK4
|
||||
// (RF69, CC1101, Si4432 etc.), use the basic begin() method
|
||||
// int state = radio.begin();
|
||||
|
||||
if(state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
|
||||
// initialize FSK4 client
|
||||
// NOTE: FSK4 frequency shift will be rounded
|
||||
// to the nearest multiple of frequency step size.
|
||||
// The exact value depends on the module:
|
||||
// SX127x/RFM9x - 61 Hz
|
||||
// RF69 - 61 Hz
|
||||
// CC1101 - 397 Hz
|
||||
// SX126x - 1 Hz
|
||||
// nRF24 - 1000000 Hz
|
||||
// Si443x/RFM2x - 156 Hz
|
||||
// SX128x - 198 Hz
|
||||
Serial.print(F("[FSK4] Initializing ... "));
|
||||
// low ("space") frequency: 434.0 MHz
|
||||
// frequency shift: 270 Hz (actually results in a shift of 244 Hz)
|
||||
// baud rate: 100 baud
|
||||
state = fsk4.begin(434.0, 270, 100);
|
||||
if(state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.print(F("[FSK4] Sending FSK4 data packet ... "));
|
||||
|
||||
// send out idle condition for 1000 ms
|
||||
fsk4.idle();
|
||||
delay(1000);
|
||||
|
||||
// FSK4Client supports the write(uint8_t b) and write(uint8_t* buff, size_t len) method.
|
||||
// We use the write(uint8_t b) method to send a few bytes of preamble to allow the demodulator
|
||||
// to lock on to the signal.
|
||||
fsk4.write(0x1B); fsk4.write(0x1B); fsk4.write(0x1B); fsk4.write(0x1B);
|
||||
fsk4.write(0x1B); fsk4.write(0x1B); fsk4.write(0x1B); fsk4.write(0x1B);
|
||||
|
||||
// We then send the encoded packet.
|
||||
fsk4.write(sample_packet, sample_packet_len);
|
||||
|
||||
Serial.println(F("done!"));
|
||||
|
||||
}
|
|
@ -98,6 +98,7 @@
|
|||
#include "protocols/Morse/Morse.h"
|
||||
#include "protocols/RTTY/RTTY.h"
|
||||
#include "protocols/SSTV/SSTV.h"
|
||||
#include "protocols/FSK4/FSK4.h"
|
||||
|
||||
// transport layer protocols
|
||||
#include "protocols/TransportLayer/TransportLayer.h"
|
||||
|
|
119
src/protocols/FSK4/FSK4.cpp
Normal file
119
src/protocols/FSK4/FSK4.cpp
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include "FSK4.h"
|
||||
#if !defined(RADIOLIB_EXCLUDE_FSK4)
|
||||
|
||||
|
||||
|
||||
FSK4Client::FSK4Client(PhysicalLayer* phy) {
|
||||
_phy = phy;
|
||||
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
||||
_audio = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
//#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
||||
// FSK4Client::FSK4Client(AFSKClient* audio) {
|
||||
// _phy = audio->_phy;
|
||||
// _audio = audio;
|
||||
// }
|
||||
//#endif
|
||||
|
||||
int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) {
|
||||
// save configuration
|
||||
_baseHz = base;
|
||||
_shiftHz = shift;
|
||||
|
||||
|
||||
// calculate duration of 1 bit
|
||||
_bitDuration = (uint32_t)1000000/rate;
|
||||
|
||||
// calculate module carrier frequency resolution
|
||||
uint32_t step = round(_phy->getFreqStep());
|
||||
|
||||
// check minimum shift value
|
||||
if(shift < step / 2) {
|
||||
return(ERR_INVALID_RTTY_SHIFT);
|
||||
}
|
||||
|
||||
// round shift to multiples of frequency step size
|
||||
if(shift % step < (step / 2)) {
|
||||
_shift = shift / step;
|
||||
} else {
|
||||
_shift = (shift / step) + 1;
|
||||
}
|
||||
|
||||
// Write resultant tones into arrays for quick lookup when modulating.
|
||||
_tones[0] = 0;
|
||||
_tones[1] = _shift;
|
||||
_tones[2] = _shift*2;
|
||||
_tones[3] = _shift*3;
|
||||
|
||||
_tonesHz[0] = 0;
|
||||
_tonesHz[1] = _shiftHz;
|
||||
_tonesHz[2] = _shiftHz*2;
|
||||
_tonesHz[3] = _shiftHz*3;
|
||||
|
||||
// calculate 24-bit frequency
|
||||
_base = (base * 1000000.0) / _phy->getFreqStep();
|
||||
|
||||
// configure for direct mode
|
||||
return(_phy->startDirect());
|
||||
}
|
||||
|
||||
void FSK4Client::idle() {
|
||||
// Idle at Tone 0.
|
||||
tone(0);
|
||||
}
|
||||
|
||||
size_t FSK4Client::write(uint8_t* buff, size_t len) {
|
||||
size_t n = 0;
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
n += FSK4Client::write(buff[i]);
|
||||
}
|
||||
FSK4Client::standby();
|
||||
return(n);
|
||||
}
|
||||
|
||||
size_t FSK4Client::write(uint8_t b) {
|
||||
|
||||
int k;
|
||||
// Send symbols MSB first.
|
||||
for (k=0;k<4;k++)
|
||||
{
|
||||
// Extract 4FSK symbol (2 bits)
|
||||
uint8_t symbol = (b & 0xC0) >> 6;
|
||||
// Modulate
|
||||
FSK4Client::tone(symbol);
|
||||
// Shift to next symbol.
|
||||
b = b << 2;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void FSK4Client::tone(uint8_t i) {
|
||||
uint32_t start = Module::micros();
|
||||
transmitDirect(_base + _tones[i], _baseHz + _tonesHz[i]);
|
||||
while(Module::micros() - start < _bitDuration) {
|
||||
Module::yield();
|
||||
}
|
||||
}
|
||||
|
||||
int16_t FSK4Client::transmitDirect(uint32_t freq, uint32_t freqHz) {
|
||||
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
||||
if(_audio != nullptr) {
|
||||
return(_audio->tone(freqHz));
|
||||
}
|
||||
#endif
|
||||
return(_phy->transmitDirect(freq));
|
||||
}
|
||||
|
||||
int16_t FSK4Client::standby() {
|
||||
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
||||
if(_audio != nullptr) {
|
||||
return(_audio->noTone());
|
||||
}
|
||||
#endif
|
||||
return(_phy->standby());
|
||||
}
|
||||
|
||||
#endif
|
82
src/protocols/FSK4/FSK4.h
Normal file
82
src/protocols/FSK4/FSK4.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
#if !defined(_RADIOLIB_FSK4_H)
|
||||
#define _RADIOLIB_FSK4_H
|
||||
|
||||
#include "../../TypeDef.h"
|
||||
|
||||
#if !defined(RADIOLIB_EXCLUDE_FSK4)
|
||||
|
||||
#include "../PhysicalLayer/PhysicalLayer.h"
|
||||
#include "../AFSK/AFSK.h"
|
||||
|
||||
|
||||
/*!
|
||||
\class FSK4Client
|
||||
|
||||
\brief Client for FSK-4 communication. The public interface is the same as Arduino Serial.
|
||||
*/
|
||||
class FSK4Client {
|
||||
public:
|
||||
/*!
|
||||
\brief Constructor for FSK-4 mode.
|
||||
|
||||
\param phy Pointer to the wireless module providing PhysicalLayer communication.
|
||||
*/
|
||||
explicit FSK4Client(PhysicalLayer* phy);
|
||||
|
||||
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
||||
/*!
|
||||
\brief Constructor for AFSK mode.
|
||||
|
||||
\param audio Pointer to the AFSK instance providing audio.
|
||||
*/
|
||||
//explicit FSK4Client(AFSKClient* audio);
|
||||
#endif
|
||||
|
||||
// basic methods
|
||||
|
||||
/*!
|
||||
\brief Initialization method.
|
||||
|
||||
\param base Base (space) frequency to be used in MHz (in FSK-4 mode), or the space tone frequency in Hz (in AFSK mode)
|
||||
|
||||
\param shift Frequency shift between each tone in Hz.
|
||||
|
||||
\param rate Baud rate to be used during transmission.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t begin(float base, uint32_t shift, uint16_t rate);
|
||||
|
||||
/*!
|
||||
\brief Send out idle condition (RF tone at mark frequency).
|
||||
*/
|
||||
void idle();
|
||||
|
||||
size_t write(uint8_t* buff, size_t len);
|
||||
size_t write(uint8_t b);
|
||||
|
||||
|
||||
#ifndef RADIOLIB_GODMODE
|
||||
private:
|
||||
#endif
|
||||
PhysicalLayer* _phy;
|
||||
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
||||
AFSKClient* _audio;
|
||||
#endif
|
||||
|
||||
uint32_t _base = 0, _baseHz = 0;
|
||||
uint32_t _shift = 0, _shiftHz = 0;
|
||||
uint32_t _bitDuration = 0;
|
||||
uint32_t _tones[4];
|
||||
uint32_t _tonesHz[4];
|
||||
|
||||
void tone(uint8_t i);
|
||||
|
||||
int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0);
|
||||
int16_t standby();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue