[SSTV] Added SSTV support

pull/142/head
jgromes 2020-03-31 17:31:10 +02:00
rodzic 75b9395349
commit c39c4f6b0d
6 zmienionych plików z 570 dodań i 0 usunięć

Wyświetl plik

@ -32,6 +32,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
* __SSTV__ for modules: SX127x, RFM9x, SX126x, RF69 and SX1231
### Supported platforms:
* __Arduino AVR__ - tested with hardware on Uno, Mega and Leonardo

Wyświetl plik

@ -0,0 +1,160 @@
/*
RadioLib SSTV Transmit Example
The following example sends SSTV picture using
SX1278's FSK modem.
Other modules that can be used for SSTV:
- SX127x/RFM9x
- RF69
- SX1231
- SX126x
NOTE: SSTV is an analog modulation, and
requires precise frequency control.
Some of the above modules can only
set their frequency in rough steps,
so the result can be distorted.
Using high-precision radio with TCXO
(like SX126x) is recommended.
NOTE: Some platforms (such as Arduino Uno)
might not be fast enough to correctly
send pictures via high-speed modes
like Scottie2 or Martin2. For those,
lower speed modes such as Wrasse,
Scottie1 or Martin1 are recommended.
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 fsk = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1278 fsk = RadioShield.ModuleA;
// create SSTV client instance using the FSK module
SSTVClient sstv(&fsk);
// test "image" - actually just a single 320px line
// will be sent over and over again, to create vertical color stripes at the receiver
uint32_t line[320] = {
// black
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
// blue
0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF,
0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF,
// green
0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00,
0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00,
// cyan
0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF,
0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF,
// red
0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000,
0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000,
// magenta
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
// yellow
0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00,
0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00,
// white
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF
};
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);
}
// when using one of the non-LoRa modules for SSTV
// (RF69, SX1231 etc.), use the basic begin() method
// int state = fsk.begin();
// initialize SSTV client
Serial.print(F("[SSTV] Initializing ... "));
// 0 Hz tone frequency: 434.0 MHz
// SSTV mode: Wrasse (SC2-180)
// correction factor: 0.95
// NOTE: Due to different speeds of various platforms
// supported by RadioLib (Arduino Uno, ESP32 etc),
// and because SSTV is analog protocol, incorrect
// timing of pulses can lead to distortions.
// To compensate, correction factor can be used
// to adjust the length of timing pulses
// (lower number = shorter pulses).
// The value is usually around 0.95 (95%).
state = sstv.begin(434.0, Wrasse, 0.95);
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// to help tune the receiver, SSTVClient can send
// continuous beep at the frequency corresponding to
// 1900 Hz in upper sideband (aka USB) modulation
// (SSTV header "leader tone")
/*
sstv.idle();
while(true);
*/
}
void loop() {
// send picture with 8 color stripes
Serial.print(F("[SSTV] Sending test picture ... "));
// send synchronization header first
sstv.sendHeader();
// send all picture lines
for(uint16_t i = 0; i < sstv.getPictureHeight(); i++) {
sstv.sendLine(line);
}
// turn off transmitter
fsk.standby();
Serial.println(F("done!"));
delay(30000);
}

Wyświetl plik

@ -10,6 +10,7 @@ RadioLib KEYWORD1
RadioShield KEYWORD1
Module KEYWORD1
# modules
CC1101 KEYWORD1
ESP8266 KEYWORD1
HC05 KEYWORD1
@ -39,6 +40,7 @@ SX1279 KEYWORD1
XBee KEYWORD1
XBeeSerial KEYWORD1
# protocols
MQTTClient KEYWORD1
HTTPClient KEYWORD1
RTTYClient KEYWORD1
@ -46,6 +48,18 @@ MorseClient KEYWORD1
PagerClient KEYWORD1
AX25Client KEYWORD1
AX25Frame KEYWORD1
SSTVClient KEYWORD1
# SSTV modes
Scottie1 KEYWORD1
Scottie2 KEYWORD1
ScottieDX KEYWORD1
Martin1 KEYWORD1
Martin2 KEYWORD1
Wrasse KEYWORD1
PasokonP3 KEYWORD1
PasokonP5 KEYWORD1
PasokonP7 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
@ -190,6 +204,11 @@ setRecvSequence KEYWORD2
setSendSequence KEYWORD2
sendFrame KEYWORD2
# SSTV
sendHeader KEYWORD2
sendLine KEYWORD2
getPictureHeight KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

Wyświetl plik

@ -75,6 +75,7 @@
#include "protocols/AX25/AX25.h"
#include "protocols/Morse/Morse.h"
#include "protocols/RTTY/RTTY.h"
#include "protocols/SSTV/SSTV.h"
// transport layer protocols
#include "protocols/TransportLayer/TransportLayer.h"

Wyświetl plik

@ -0,0 +1,266 @@
#include "SSTV.h"
const SSTVMode_t Scottie1 {
.visCode = SSTV_SCOTTIE_1,
.width = 320,
.height = 256,
.scanPixelLen = 432,
.numTones = 7,
.tones = {
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 9000, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }
}
};
const SSTVMode_t Scottie2 {
.visCode = SSTV_SCOTTIE_2,
.width = 320,
.height = 256,
.scanPixelLen = 275,
.numTones = 7,
.tones = {
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 9000, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }
}
};
const SSTVMode_t ScottieDX {
.visCode = SSTV_SCOTTIE_DX,
.width = 320,
.height = 256,
.scanPixelLen = 1080,
.numTones = 7,
.tones = {
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 9000, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 1500, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }
}
};
const SSTVMode_t Martin1 {
.visCode = SSTV_MARTIN_1,
.width = 320,
.height = 256,
.scanPixelLen = 458,
.numTones = 8,
.tones = {
{ .type = tone_t::GENERIC, .len = 4862, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 }
}
};
const SSTVMode_t Martin2 {
.visCode = SSTV_MARTIN_2,
.width = 320,
.height = 256,
.scanPixelLen = 229,
.numTones = 8,
.tones = {
{ .type = tone_t::GENERIC, .len = 4862, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 572, .freq = 1500 }
}
};
const SSTVMode_t Wrasse {
.visCode = SSTV_WRASSE_SC2_180,
.width = 320,
.height = 256,
.scanPixelLen = 734,
.numTones = 5,
.tones = {
{ .type = tone_t::GENERIC, .len = 5523, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 500, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }
}
};
const SSTVMode_t PasokonP3 {
.visCode = SSTV_PASOKON_P3,
.width = 640,
.height = 496,
.scanPixelLen = 208,
.numTones = 7,
.tones = {
{ .type = tone_t::GENERIC, .len = 5208, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 1042, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 1042, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 1042, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }
}
};
const SSTVMode_t PasokonP5 {
.visCode = SSTV_PASOKON_P5,
.width = 640,
.height = 496,
.scanPixelLen = 312,
.numTones = 7,
.tones = {
{ .type = tone_t::GENERIC, .len = 7813, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 1563, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 1563, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 1563, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }
}
};
const SSTVMode_t PasokonP7 {
.visCode = SSTV_PASOKON_P7,
.width = 640,
.height = 496,
.scanPixelLen = 417,
.numTones = 7,
.tones = {
{ .type = tone_t::GENERIC, .len = 10417, .freq = 1200 },
{ .type = tone_t::GENERIC, .len = 2083, .freq = 1500 },
{ .type = tone_t::SCAN_RED, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 2083, .freq = 1500 },
{ .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 },
{ .type = tone_t::GENERIC, .len = 2083, .freq = 1500 },
{ .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }
}
};
SSTVClient::SSTVClient(PhysicalLayer* phy) {
_phy = phy;
}
int16_t SSTVClient::begin(float base, SSTVMode_t mode, float correction) {
// save mode
_mode = mode;
// apply correction factor to all timings
_mode.scanPixelLen *= correction;
for(uint8_t i = 0; i < _mode.numTones; i++) {
_mode.tones[i].len *= correction;
}
// calculate 24-bit frequency
_base = (base * 1000000.0) / _phy->getFreqStep();
// set module frequency deviation to 0
int16_t state = _phy->setFrequencyDeviation(0);
return(state);
}
void SSTVClient::idle() {
tone(SSTV_TONE_LEADER);
}
void SSTVClient::sendHeader() {
// save first header flag for Scottie modes
_firstLine = true;
// send the first part of header (leader-break-leader)
tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH);
tone(SSTV_TONE_BREAK, SSTV_HEADER_BREAK_LENGTH);
tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH);
// VIS start bit
tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH);
// VIS code
uint8_t parityCount = 0;
for(uint8_t mask = 0x01; mask < 0x80; mask <<= 1) {
if(_mode.visCode & mask) {
tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH);
parityCount++;
} else {
tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH);
}
}
// VIS parity
if(parityCount % 2 == 0) {
// even parity
tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH);
} else {
// odd parity
tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH);
}
// VIS stop bit
tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH);
}
void SSTVClient::sendLine(uint32_t* imgLine) {
// check first line flag in Scottie modes
if(_firstLine && ((_mode.visCode == SSTV_SCOTTIE_1) || (_mode.visCode == SSTV_SCOTTIE_2) || (_mode.visCode == SSTV_SCOTTIE_DX))) {
_firstLine = false;
// send start sync tone
tone(SSTV_TONE_BREAK, 9000);
}
// send all tones in sequence
for(uint8_t i = 0; i < _mode.numTones; i++) {
if((_mode.tones[i].type == tone_t::GENERIC) && (_mode.tones[i].len > 0)) {
// sync/porch tones
tone(_mode.tones[i].freq, _mode.tones[i].len);
} else {
// scan lines
for(uint16_t j = 0; j < _mode.width; j++) {
uint32_t color = imgLine[j];
switch(_mode.tones[i].type) {
case(tone_t::SCAN_RED):
color &= 0x00FF0000;
color >>= 16;
break;
case(tone_t::SCAN_GREEN):
color &= 0x0000FF00;
color >>= 8;
break;
case(tone_t::SCAN_BLUE):
color &= 0x000000FF;
break;
case(tone_t::GENERIC):
break;
}
tone(SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), _mode.scanPixelLen);
}
}
}
}
uint16_t SSTVClient::getPictureHeight() {
return(_mode.height);
}
void SSTVClient::tone(float freq, uint32_t len) {
uint32_t start = micros();
_phy->transmitDirect(_base + (freq / _phy->getFreqStep()));
while(micros() - start < len);
}

Wyświetl plik

@ -0,0 +1,123 @@
#ifndef _RADIOLIB_SSTV_H
#define _RADIOLIB_SSTV_H
#include "../../TypeDef.h"
#include "../PhysicalLayer/PhysicalLayer.h"
// the following implementation is based on information from
// http://www.barberdsp.com/downloads/Dayton%20Paper.pdf
// VIS codes
#define SSTV_SCOTTIE_1 60
#define SSTV_SCOTTIE_2 56
#define SSTV_SCOTTIE_DX 76
#define SSTV_MARTIN_1 44
#define SSTV_MARTIN_2 40
#define SSTV_WRASSE_SC2_180 55
#define SSTV_PASOKON_P3 113
#define SSTV_PASOKON_P5 114
#define SSTV_PASOKON_P7 115
// SSTV tones in Hz
#define SSTV_TONE_LEADER 1900
#define SSTV_TONE_BREAK 1200
#define SSTV_TONE_VIS_1 1100
#define SSTV_TONE_VIS_0 1300
#define SSTV_TONE_BRIGHTNESS_MIN 1500
#define SSTV_TONE_BRIGHTNESS_MAX 2300
// calibration header timing in us
#define SSTV_HEADER_LEADER_LENGTH 300000
#define SSTV_HEADER_BREAK_LENGTH 10000
#define SSTV_HEADER_BIT_LENGTH 30000
// structure to save data about tone
struct tone_t {
enum {
GENERIC = 0,
SCAN_GREEN,
SCAN_BLUE,
SCAN_RED
} type;
uint32_t len;
uint16_t freq;
};
// structure to save data about SSTV mode
struct SSTVMode_t {
uint8_t visCode;
uint16_t width;
uint16_t height;
uint16_t scanPixelLen;
uint8_t numTones;
tone_t tones[8];
};
// all currently supported SSTV modes
extern const SSTVMode_t Scottie1;
extern const SSTVMode_t Scottie2;
extern const SSTVMode_t ScottieDX;
extern const SSTVMode_t Martin1;
extern const SSTVMode_t Martin2;
extern const SSTVMode_t Wrasse;
extern const SSTVMode_t PasokonP3;
extern const SSTVMode_t PasokonP5;
extern const SSTVMode_t PasokonP7;
class SSTVClient {
public:
/*!
\brief Default constructor.
\param phy Pointer to the wireless module providing PhysicalLayer communication.
*/
SSTVClient(PhysicalLayer* phy);
// basic methods
/*!
\brief Initialization method.
\param base Base RF frequency to be used in MHz. In USB modulation, this corresponds to "0 Hz tone".
\param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7.
*/
int16_t begin(float base, SSTVMode_t mode, float correction = 1.0);
/*!
\brief Sends out tone at 1900 Hz.
*/
void idle();
/*!
\brief Sends synchronization header for the SSTV mode set in begin method.
*/
void sendHeader();
/*!
\brief Sends single picture line in the currently configured SSTV mode.
\param imgLine Image line to send, in 24-bit RGB. It is up to the user to ensure that imgLine has enough pixels to send it in the current SSTV mode.
*/
void sendLine(uint32_t* imgLine);
/*!
\brief Get picture height of the currently configured SSTV mode.
\returns Picture height of the currently configured SSTV mode in pixels.
*/
uint16_t getPictureHeight();
#ifndef RADIOLIB_GODMODE
private:
#endif
PhysicalLayer* _phy;
uint32_t _base;
SSTVMode_t _mode;
bool _firstLine;
void tone(float freq, uint32_t len = 0);
};
#endif