From d8813c244259a58e175241213aff3ef65dec0dca Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:02:25 +0100 Subject: [PATCH 1/9] added RSSI reading --- RichWave.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/RichWave.h b/RichWave.h index 617a264..7192b92 100644 --- a/RichWave.h +++ b/RichWave.h @@ -7,14 +7,17 @@ class RichWave { public: - RichWave(uint8_t dataPin, uint8_t lePin, uint8_t clkPin); + RichWave(uint8_t dataPin, uint8_t lePin, uint8_t clkPin, uint8_t rssiPin); void setFrequency(int frequency); void setRegister(byte address, unsigned long data); + uint16_t readRSSI(); private: uint8_t dataPin; uint8_t lePin; uint8_t clkPin; + uint8_t rssiPin; + uint16_t lastTuned; void sendBit(boolean isOne); }; -#endif \ No newline at end of file +#endif From 449b47bed5d852b138858fc889ce0e681c523735 Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:03:42 +0100 Subject: [PATCH 2/9] Added RSSI Pin and RSSI Reading. --- RichWave.cpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/RichWave.cpp b/RichWave.cpp index bc016c2..df13a61 100644 --- a/RichWave.cpp +++ b/RichWave.cpp @@ -13,16 +13,21 @@ DO WHATEVER YOU WANT PUBLIC LICENSE Version 1.0: - initial version - set Register and setFrequency support + + Modified by der-Frickler.net + - Added RSSI Pin and RSSI Reading. + */ #include "RichWave.h" // SPIDATA = CS0; SPILE = CS1; SPICLK = CS2 -RichWave::RichWave(uint8_t spiDataPin, uint8_t spiLePin, uint8_t spiClkPin) +RichWave::RichWave(uint8_t spiDataPin, uint8_t spiLePin, uint8_t spiClkPin, uint8_t rSSIPin) { dataPin = spiDataPin; lePin = spiLePin; clkPin = spiClkPin; + rssiPin = rSSIPin; pinMode(spiDataPin, OUTPUT); pinMode(spiLePin, OUTPUT); @@ -39,6 +44,7 @@ void RichWave::setFrequency(int freq) { // A Part int a = (freq%64)/2; setRegister(0x01, a | (n << 7)); + lastTuned = millis(); } void RichWave::setRegister(byte address, unsigned long data) { @@ -68,4 +74,29 @@ void RichWave::sendBit(boolean isOne) { // generate clock pulse digitalWrite(clkPin, HIGH); digitalWrite(clkPin, LOW); -} \ No newline at end of file +} + + +// ---------------------------------------------------------------------------- +// readRSSI read rssi of given module. +// ---------------------------------------------------------------------------- +uint16_t RichWave::readRSSI() +{ + // check if RSSI is stable after tune by checking the time + uint16_t tune_time = millis() - lastTuned; + // module need >20ms to tune. + if (tune_time < 30) + { + // wait until tune time is full filled + delay(30 - tune_time); + } + + uint16_t rssi = 0; + for (uint8_t i = 0; i < 10; i++) + { + rssi += analogRead(rssiPin); + } + rssi = rssi / 10; // average + + return rssi; +} From c8120d34bb038efa9fb6bd14a551925b6c453555 Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:43:02 +0100 Subject: [PATCH 3/9] Added 4x Richwave RX5808 Video Receiver Example --- examples/rx5808_4x_splitter.ino | 423 ++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 examples/rx5808_4x_splitter.ino diff --git a/examples/rx5808_4x_splitter.ino b/examples/rx5808_4x_splitter.ino new file mode 100644 index 0000000..8c08a90 --- /dev/null +++ b/examples/rx5808_4x_splitter.ino @@ -0,0 +1,423 @@ +/* + * 4x Richwave RX5808 Video Receiver for use with a + * Video Splitscreen processor and optional HMDVR + * + * 4 Buttons to trigger a channelsearch on each module. + * Search is done by scanning channel 1-8 of each band one after the other + * If valid signal is found, the tuner locks on to that channel. + * + * Oled is used to display all 4 tunes Channels, Freq. and RSSI val. + * + * requires a patched version of the Richwave lib by Timo Witte + * + * https://github.com/derFrickler/RichWave + * + * + * + * http://der-Frickler.net + * + * +*/ + +//#define DEBUG + +#include +#include +#include +#include +#include + +// Debug output on serial +#define DEBUG + +// Choose if you wish to use 8 additional Channels +// 5362 MHz 5399 MHz 5436 MHz 5473 MHz 5510 MHz 5547 MHz 5584 MHz 5621 MHz +// Local laws may prohibit the use of these frequencies use at your own risk! +//#define USE_LBAND + +// Recording Pin of the HMDVR/EachineDVR +#define P_REC A0 + +// RSSI default raw range +#define RSSI_REC_ON 160 +#define RSSI_REC_OFF 140 +#define RSSI_SEEK_TRESHOLD 160 + +#define rssiPin0 A1 +#define rssiPin1 A3 +#define rssiPin2 A6 +#define rssiPin3 A7 +//const uint8_t rssiPin[] = {rssiPin0, rssiPin1, rssiPin2, rssiPin3}; + +#define spiLatch0 7 +#define spiLatch1 8 +#define spiLatch2 9 +#define spiLatch3 10 +//const uint8_t slaveSelectPin[] = {spiLatch0, spiLatch1, spiLatch2, spiLatch3}; +#define spiDataPin 11 +#define spiClockPin 12 + +// DATA PIN; LATCH PIN; CLK PIN; RSSI PIN +RichWave rx0(spiDataPin, spiLatch0, spiClockPin, rssiPin0); +RichWave rx1(spiDataPin, spiLatch1, spiClockPin, rssiPin1); +RichWave rx2(spiDataPin, spiLatch2, spiClockPin, rssiPin2); +RichWave rx3(spiDataPin, spiLatch3, spiClockPin, rssiPin3); + +// Pretuned Channels at startup. +uint8_t channel[] = {2, 5, 18, 0}; + +#define S_TUNED 0 +#define S_SCAN 1 +uint8_t state[] = {S_TUNED, S_TUNED, S_TUNED, S_SCAN}; +//uint16_t tuneTime[] = {0, 0, 0, 0}; + +#define BUTTON0 2 +#define BUTTON1 4 +#define BUTTON2 5 +#define BUTTON3 6 +const uint8_t buttons[] = {BUTTON0, BUTTON1, BUTTON2, BUTTON3}; + + +// Channels with their Mhz Values +const uint16_t channelFreqTable[] PROGMEM = { + // Channel 1 - 8 + 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725, // Band A + 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866, // Band B + 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945, // Band E + 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880, // Band F / Airwave +#ifdef USE_LBAND + 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917, // Band C / Immersion Raceband + 5362, 5399, 5436, 5473, 5510, 5547, 5584, 5621 // Band D / 5.3 +#else + 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 // Band C / Immersion Raceband +#endif +}; + +// do coding as simpl#define P_REC 3e hex value to save memory. +const uint8_t channelNames[] PROGMEM = { + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, // Band A + 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, // Band B + 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, // Band E + 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, // Band F / Airwave +#ifdef USE_LBAND + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, // Band C / Immersion Raceband + 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8 // BAND D / 5.3 +#else + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 // Band C / Immersion Raceband +#endif +}; + +// All Channels of the above List ordered by Mhz +const uint8_t channelList[] PROGMEM = { +#ifdef USE_LBAND + 40, 41, 42, 43, 44, 45, 46, 47, 19, 18, 32, 17, 33, 16, 7, 34, 8, 24, 6, 9, 25, 5, 35, 10, 26, 4, 11, 27, 3, 36, 12, 28, 2, 13, 29, 37, 1, 14, 30, 0, 15, 31, 38, 20, 21, 39, 22, 23 +#else + 19, 18, 32, 17, 33, 16, 7, 34, 8, 24, 6, 9, 25, 5, 35, 10, 26, 4, 11, 27, 3, 36, 12, 28, 2, 13, 29, 37, 1, 14, 30, 0, 15, 31, 38, 20, 21, 39, 22, 23 +#endif +}; + + +GOFi2cOLED oled;// default slave address is 0x3D + +boolean recording = false; + + +// ---------------------------------------------------------------------------- +// SETUP +// ---------------------------------------------------------------------------- +void setup() { + oled.init(0x3C); //initialze OLED display + oled.display(); // show splashscreen + delay(2000); + oled.clearDisplay(); + + oled.drawFastHLine(0, 0, 128, WHITE); + oled.drawFastHLine(0, 14, 128, WHITE); + oled.setCursor(3, 4); + oled.setTextSize(1); + oled.print("4X Video Splitter RX"); + + pinMode(LED_BUILTIN, OUTPUT); + + for (uint8_t i = 0; i <= sizeof(buttons); i++) { + pinMode (buttons[i], INPUT_PULLUP); + } + + +#ifdef DEBUG + Serial.begin(115200); + Serial.println(F("START:")); +#endif + +for (int mod = 0; mod < 4; mod++) { + // if modul is in tuned mode, tune to channel + if (state[mod] == S_TUNED) { + setChannelModule(mod, channel[mod]); + } +} + + // Setup Done - LED ON + digitalWrite(13, HIGH); + +} + +// ---------------------------------------------------------------------------- +// MAIN LOOP +// ---------------------------------------------------------------------------- +void loop() +{ + + // check Scan Buttons, and set module to scan if set. + for (int mod = 0; mod < 4; mod++) { + if (! digitalRead(buttons[mod])) { + state[mod] = S_SCAN; +#ifdef DEBUG + Serial.print(F("Setting Module" )); + Serial.print(mod); + Serial.println(F(" to Scan Mode")); +#endif + } + } + + // for each module, scan channels if in scan mode. + int rssi = 0; + int maxRSSI = 0; + for (int mod = 0; mod < 4; mod++) { + // if modul is in scan mode, skip to next ch. + if (state[mod] == S_SCAN) { + rssi = nextChannel(mod); + // if something found on that ch, change mode to tuned. + if (!hasChannel(mod) && rssi > RSSI_SEEK_TRESHOLD) { + state[mod] = S_TUNED; + } + } else { + rssi = readRSSI(mod); + } + displayChannel(mod, rssi); + maxRSSI = max(maxRSSI, rssi); + } + + // if highest RSSI of all Modules is over Treshhold -> Rec, else Rec Off + if (maxRSSI < RSSI_REC_OFF) { + rec(false); + } else if (maxRSSI > RSSI_REC_ON) { + rec(true); + } + + // delay(20); + +} + + +/*###########################################################################*/ +/* SUB ROUTINES +/*###########################################################################*/ + +// ---------------------------------------------------------------------------- +// nextChannel tune to next channel on given module +// ---------------------------------------------------------------------------- +uint16_t nextChannel(uint8_t module) { + uint8_t currChannel = channel[module]; + + currChannel++; + if (currChannel >= sizeof(channelList) ) { + currChannel = 0; + } + + setChannelModule(module, currChannel); + channel[module] = currChannel; +// wait_rssi_ready(module); + int rssi = readRSSI(module); + +#ifdef DEBUG + Serial.print(F("Mod: ")); Serial.print(module); + Serial.print(F(" tuned to CH: ")); Serial.print(currChannel); + Serial.print(F(": ")); Serial.print(channelName(currChannel)); + Serial.print(F(": ")); Serial.print(pgm_read_word_near(channelFreqTable + currChannel)); + Serial.print(F(" RSSI: ")); Serial.println(rssi); +#endif + + return rssi; +} + +// ---------------------------------------------------------------------------- +// hasCHannel check if current channel is already tuned on other module. +// ---------------------------------------------------------------------------- +boolean hasChannel(uint8_t module) { + int currChannel = channel[module]; + +#ifdef DEBUG + Serial.print(F("Check CHANNEL: ")); Serial.print(currChannel); + Serial.print(F(" IS IN ")); Serial.print(channel[0]); + Serial.print(F(" ")); Serial.print(channel[1]); + Serial.print(F(" ")); Serial.print(channel[2]); + Serial.print(F(" ")); Serial.print(channel[3]); +#endif + + int mod = 0; + for (mod = 0; mod <= 4; mod++) { + //if (mod != module && (channel[mod] - 1 <= currChannel) && currChannel <= channel[mod] + 1) { + + if (mod != module && channel[mod] == currChannel) { +#ifdef DEBUG + Serial.println(F(" -> TRUE")); +#endif + return true; + } + } + +#ifdef DEBUG + Serial.println(F(" -> FALSE")); +#endif + return false; +} + +// ---------------------------------------------------------------------------- +// displayChannel display the given channel, freq and rssi on the oled +// ---------------------------------------------------------------------------- +void displayChannel(int module, int rssi) { + + if (state[module] == S_SCAN) { + oled.setTextColor(BLACK, WHITE); // 'inverted' text + } else { + oled.setTextColor(WHITE); + } + + int ch = channel[module]; + switch (module) { + case 0: + oled.fillRect(5, 16, 63, 26, BLACK); + oled.setCursor(5, 16); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(40, 27); + break; + case 1: + oled.fillRect(68, 16, 63, 26, BLACK); + oled.setCursor(68, 16); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(103, 27); + break; + case 2: + oled.fillRect(5, 42, 63, 26, BLACK); + oled.setCursor(5, 42); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(40, 53); + break; + case 3: + oled.fillRect(68, 42, 63, 26, BLACK); + oled.setCursor(68, 42); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(103, 53); + break; + + default: + break; + } + oled.print(rssi); + oled.display(); +} + +// ---------------------------------------------------------------------------- +// readRSSI read rssi of given module. +// ---------------------------------------------------------------------------- +uint16_t readRSSI(uint8_t module) +{ + switch (module) { + case 0: + return rx0.readRSSI(); + case 1: + return rx1.readRSSI(); + case 2: + return rx2.readRSSI(); + case 3: + return rx3.readRSSI(); + } + return 0; +} + + +// ---------------------------------------------------------------------------- +// channelName return channel name from list. +// ---------------------------------------------------------------------------- +String channelName(uint8_t ch) { + String name = String(pgm_read_byte_near(channelNames + ch), HEX); + name.toUpperCase(); + if (name.charAt(0) == 'C') { + name.setCharAt(0, 'R'); + } + return name; +} + + +// ---------------------------------------------------------------------------- +// channel_from_index +// ---------------------------------------------------------------------------- +uint8_t channel_from_index(uint8_t channelIndex) +{ + uint8_t loop = 0; + uint8_t channel = 0; + for (loop = 0; loop <= sizeof(channelList); loop++) + { + if (pgm_read_byte_near(channelList + loop) == channelIndex) + { + channel = loop; + break; + } + } + return (channel); +} + + +// ---------------------------------------------------------------------------- +// setChannelModule tune given module to given channel +// ---------------------------------------------------------------------------- +void setChannelModule(uint8_t module, uint8_t channel) { + + uint16_t channelFreq = pgm_read_word_near(channelFreqTable + channel); + + switch (module) { + case 0: + rx0.setFrequency(channelFreq); + break; + case 1: + rx1.setFrequency(channelFreq); + break; + case 2: + rx2.setFrequency(channelFreq); + break; + case 3: + rx3.setFrequency(channelFreq); + break; + default: + break; + } + +// tuneTime[module] = millis(); +} + +void rec(boolean rec) { + if (rec == recording) + return + + digitalWrite(P_REC, HIGH); + delay(1000); + digitalWrite(P_REC, LOW); + recording = !recording; +} + From 6ec24864c18b676bd0d2e7b4bf29eafac5d82edb Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:44:01 +0100 Subject: [PATCH 4/9] Added 4x Richwave RX5808 Video Receiver Example --- .../rx5808_4x_splitter/rx5808_4x_splitter.ino | 423 ++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 examples/rx5808_4x_splitter/rx5808_4x_splitter.ino diff --git a/examples/rx5808_4x_splitter/rx5808_4x_splitter.ino b/examples/rx5808_4x_splitter/rx5808_4x_splitter.ino new file mode 100644 index 0000000..8c08a90 --- /dev/null +++ b/examples/rx5808_4x_splitter/rx5808_4x_splitter.ino @@ -0,0 +1,423 @@ +/* + * 4x Richwave RX5808 Video Receiver for use with a + * Video Splitscreen processor and optional HMDVR + * + * 4 Buttons to trigger a channelsearch on each module. + * Search is done by scanning channel 1-8 of each band one after the other + * If valid signal is found, the tuner locks on to that channel. + * + * Oled is used to display all 4 tunes Channels, Freq. and RSSI val. + * + * requires a patched version of the Richwave lib by Timo Witte + * + * https://github.com/derFrickler/RichWave + * + * + * + * http://der-Frickler.net + * + * +*/ + +//#define DEBUG + +#include +#include +#include +#include +#include + +// Debug output on serial +#define DEBUG + +// Choose if you wish to use 8 additional Channels +// 5362 MHz 5399 MHz 5436 MHz 5473 MHz 5510 MHz 5547 MHz 5584 MHz 5621 MHz +// Local laws may prohibit the use of these frequencies use at your own risk! +//#define USE_LBAND + +// Recording Pin of the HMDVR/EachineDVR +#define P_REC A0 + +// RSSI default raw range +#define RSSI_REC_ON 160 +#define RSSI_REC_OFF 140 +#define RSSI_SEEK_TRESHOLD 160 + +#define rssiPin0 A1 +#define rssiPin1 A3 +#define rssiPin2 A6 +#define rssiPin3 A7 +//const uint8_t rssiPin[] = {rssiPin0, rssiPin1, rssiPin2, rssiPin3}; + +#define spiLatch0 7 +#define spiLatch1 8 +#define spiLatch2 9 +#define spiLatch3 10 +//const uint8_t slaveSelectPin[] = {spiLatch0, spiLatch1, spiLatch2, spiLatch3}; +#define spiDataPin 11 +#define spiClockPin 12 + +// DATA PIN; LATCH PIN; CLK PIN; RSSI PIN +RichWave rx0(spiDataPin, spiLatch0, spiClockPin, rssiPin0); +RichWave rx1(spiDataPin, spiLatch1, spiClockPin, rssiPin1); +RichWave rx2(spiDataPin, spiLatch2, spiClockPin, rssiPin2); +RichWave rx3(spiDataPin, spiLatch3, spiClockPin, rssiPin3); + +// Pretuned Channels at startup. +uint8_t channel[] = {2, 5, 18, 0}; + +#define S_TUNED 0 +#define S_SCAN 1 +uint8_t state[] = {S_TUNED, S_TUNED, S_TUNED, S_SCAN}; +//uint16_t tuneTime[] = {0, 0, 0, 0}; + +#define BUTTON0 2 +#define BUTTON1 4 +#define BUTTON2 5 +#define BUTTON3 6 +const uint8_t buttons[] = {BUTTON0, BUTTON1, BUTTON2, BUTTON3}; + + +// Channels with their Mhz Values +const uint16_t channelFreqTable[] PROGMEM = { + // Channel 1 - 8 + 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725, // Band A + 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866, // Band B + 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945, // Band E + 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880, // Band F / Airwave +#ifdef USE_LBAND + 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917, // Band C / Immersion Raceband + 5362, 5399, 5436, 5473, 5510, 5547, 5584, 5621 // Band D / 5.3 +#else + 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 // Band C / Immersion Raceband +#endif +}; + +// do coding as simpl#define P_REC 3e hex value to save memory. +const uint8_t channelNames[] PROGMEM = { + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, // Band A + 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, // Band B + 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, // Band E + 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, // Band F / Airwave +#ifdef USE_LBAND + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, // Band C / Immersion Raceband + 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8 // BAND D / 5.3 +#else + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 // Band C / Immersion Raceband +#endif +}; + +// All Channels of the above List ordered by Mhz +const uint8_t channelList[] PROGMEM = { +#ifdef USE_LBAND + 40, 41, 42, 43, 44, 45, 46, 47, 19, 18, 32, 17, 33, 16, 7, 34, 8, 24, 6, 9, 25, 5, 35, 10, 26, 4, 11, 27, 3, 36, 12, 28, 2, 13, 29, 37, 1, 14, 30, 0, 15, 31, 38, 20, 21, 39, 22, 23 +#else + 19, 18, 32, 17, 33, 16, 7, 34, 8, 24, 6, 9, 25, 5, 35, 10, 26, 4, 11, 27, 3, 36, 12, 28, 2, 13, 29, 37, 1, 14, 30, 0, 15, 31, 38, 20, 21, 39, 22, 23 +#endif +}; + + +GOFi2cOLED oled;// default slave address is 0x3D + +boolean recording = false; + + +// ---------------------------------------------------------------------------- +// SETUP +// ---------------------------------------------------------------------------- +void setup() { + oled.init(0x3C); //initialze OLED display + oled.display(); // show splashscreen + delay(2000); + oled.clearDisplay(); + + oled.drawFastHLine(0, 0, 128, WHITE); + oled.drawFastHLine(0, 14, 128, WHITE); + oled.setCursor(3, 4); + oled.setTextSize(1); + oled.print("4X Video Splitter RX"); + + pinMode(LED_BUILTIN, OUTPUT); + + for (uint8_t i = 0; i <= sizeof(buttons); i++) { + pinMode (buttons[i], INPUT_PULLUP); + } + + +#ifdef DEBUG + Serial.begin(115200); + Serial.println(F("START:")); +#endif + +for (int mod = 0; mod < 4; mod++) { + // if modul is in tuned mode, tune to channel + if (state[mod] == S_TUNED) { + setChannelModule(mod, channel[mod]); + } +} + + // Setup Done - LED ON + digitalWrite(13, HIGH); + +} + +// ---------------------------------------------------------------------------- +// MAIN LOOP +// ---------------------------------------------------------------------------- +void loop() +{ + + // check Scan Buttons, and set module to scan if set. + for (int mod = 0; mod < 4; mod++) { + if (! digitalRead(buttons[mod])) { + state[mod] = S_SCAN; +#ifdef DEBUG + Serial.print(F("Setting Module" )); + Serial.print(mod); + Serial.println(F(" to Scan Mode")); +#endif + } + } + + // for each module, scan channels if in scan mode. + int rssi = 0; + int maxRSSI = 0; + for (int mod = 0; mod < 4; mod++) { + // if modul is in scan mode, skip to next ch. + if (state[mod] == S_SCAN) { + rssi = nextChannel(mod); + // if something found on that ch, change mode to tuned. + if (!hasChannel(mod) && rssi > RSSI_SEEK_TRESHOLD) { + state[mod] = S_TUNED; + } + } else { + rssi = readRSSI(mod); + } + displayChannel(mod, rssi); + maxRSSI = max(maxRSSI, rssi); + } + + // if highest RSSI of all Modules is over Treshhold -> Rec, else Rec Off + if (maxRSSI < RSSI_REC_OFF) { + rec(false); + } else if (maxRSSI > RSSI_REC_ON) { + rec(true); + } + + // delay(20); + +} + + +/*###########################################################################*/ +/* SUB ROUTINES +/*###########################################################################*/ + +// ---------------------------------------------------------------------------- +// nextChannel tune to next channel on given module +// ---------------------------------------------------------------------------- +uint16_t nextChannel(uint8_t module) { + uint8_t currChannel = channel[module]; + + currChannel++; + if (currChannel >= sizeof(channelList) ) { + currChannel = 0; + } + + setChannelModule(module, currChannel); + channel[module] = currChannel; +// wait_rssi_ready(module); + int rssi = readRSSI(module); + +#ifdef DEBUG + Serial.print(F("Mod: ")); Serial.print(module); + Serial.print(F(" tuned to CH: ")); Serial.print(currChannel); + Serial.print(F(": ")); Serial.print(channelName(currChannel)); + Serial.print(F(": ")); Serial.print(pgm_read_word_near(channelFreqTable + currChannel)); + Serial.print(F(" RSSI: ")); Serial.println(rssi); +#endif + + return rssi; +} + +// ---------------------------------------------------------------------------- +// hasCHannel check if current channel is already tuned on other module. +// ---------------------------------------------------------------------------- +boolean hasChannel(uint8_t module) { + int currChannel = channel[module]; + +#ifdef DEBUG + Serial.print(F("Check CHANNEL: ")); Serial.print(currChannel); + Serial.print(F(" IS IN ")); Serial.print(channel[0]); + Serial.print(F(" ")); Serial.print(channel[1]); + Serial.print(F(" ")); Serial.print(channel[2]); + Serial.print(F(" ")); Serial.print(channel[3]); +#endif + + int mod = 0; + for (mod = 0; mod <= 4; mod++) { + //if (mod != module && (channel[mod] - 1 <= currChannel) && currChannel <= channel[mod] + 1) { + + if (mod != module && channel[mod] == currChannel) { +#ifdef DEBUG + Serial.println(F(" -> TRUE")); +#endif + return true; + } + } + +#ifdef DEBUG + Serial.println(F(" -> FALSE")); +#endif + return false; +} + +// ---------------------------------------------------------------------------- +// displayChannel display the given channel, freq and rssi on the oled +// ---------------------------------------------------------------------------- +void displayChannel(int module, int rssi) { + + if (state[module] == S_SCAN) { + oled.setTextColor(BLACK, WHITE); // 'inverted' text + } else { + oled.setTextColor(WHITE); + } + + int ch = channel[module]; + switch (module) { + case 0: + oled.fillRect(5, 16, 63, 26, BLACK); + oled.setCursor(5, 16); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(40, 27); + break; + case 1: + oled.fillRect(68, 16, 63, 26, BLACK); + oled.setCursor(68, 16); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(103, 27); + break; + case 2: + oled.fillRect(5, 42, 63, 26, BLACK); + oled.setCursor(5, 42); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(40, 53); + break; + case 3: + oled.fillRect(68, 42, 63, 26, BLACK); + oled.setCursor(68, 42); + oled.setTextSize(3); + oled.print(channelName(ch)); + oled.setTextColor(WHITE); + oled.setTextSize(1); + oled.print(pgm_read_word_near(channelFreqTable + ch)); + oled.setCursor(103, 53); + break; + + default: + break; + } + oled.print(rssi); + oled.display(); +} + +// ---------------------------------------------------------------------------- +// readRSSI read rssi of given module. +// ---------------------------------------------------------------------------- +uint16_t readRSSI(uint8_t module) +{ + switch (module) { + case 0: + return rx0.readRSSI(); + case 1: + return rx1.readRSSI(); + case 2: + return rx2.readRSSI(); + case 3: + return rx3.readRSSI(); + } + return 0; +} + + +// ---------------------------------------------------------------------------- +// channelName return channel name from list. +// ---------------------------------------------------------------------------- +String channelName(uint8_t ch) { + String name = String(pgm_read_byte_near(channelNames + ch), HEX); + name.toUpperCase(); + if (name.charAt(0) == 'C') { + name.setCharAt(0, 'R'); + } + return name; +} + + +// ---------------------------------------------------------------------------- +// channel_from_index +// ---------------------------------------------------------------------------- +uint8_t channel_from_index(uint8_t channelIndex) +{ + uint8_t loop = 0; + uint8_t channel = 0; + for (loop = 0; loop <= sizeof(channelList); loop++) + { + if (pgm_read_byte_near(channelList + loop) == channelIndex) + { + channel = loop; + break; + } + } + return (channel); +} + + +// ---------------------------------------------------------------------------- +// setChannelModule tune given module to given channel +// ---------------------------------------------------------------------------- +void setChannelModule(uint8_t module, uint8_t channel) { + + uint16_t channelFreq = pgm_read_word_near(channelFreqTable + channel); + + switch (module) { + case 0: + rx0.setFrequency(channelFreq); + break; + case 1: + rx1.setFrequency(channelFreq); + break; + case 2: + rx2.setFrequency(channelFreq); + break; + case 3: + rx3.setFrequency(channelFreq); + break; + default: + break; + } + +// tuneTime[module] = millis(); +} + +void rec(boolean rec) { + if (rec == recording) + return + + digitalWrite(P_REC, HIGH); + delay(1000); + digitalWrite(P_REC, LOW); + recording = !recording; +} + From 7bdde75356e4acb44ce13d823e7cdfe5aeae989d Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:44:15 +0100 Subject: [PATCH 5/9] Delete rx5808_4x_splitter.ino --- examples/rx5808_4x_splitter.ino | 423 -------------------------------- 1 file changed, 423 deletions(-) delete mode 100644 examples/rx5808_4x_splitter.ino diff --git a/examples/rx5808_4x_splitter.ino b/examples/rx5808_4x_splitter.ino deleted file mode 100644 index 8c08a90..0000000 --- a/examples/rx5808_4x_splitter.ino +++ /dev/null @@ -1,423 +0,0 @@ -/* - * 4x Richwave RX5808 Video Receiver for use with a - * Video Splitscreen processor and optional HMDVR - * - * 4 Buttons to trigger a channelsearch on each module. - * Search is done by scanning channel 1-8 of each band one after the other - * If valid signal is found, the tuner locks on to that channel. - * - * Oled is used to display all 4 tunes Channels, Freq. and RSSI val. - * - * requires a patched version of the Richwave lib by Timo Witte - * - * https://github.com/derFrickler/RichWave - * - * - * - * http://der-Frickler.net - * - * -*/ - -//#define DEBUG - -#include -#include -#include -#include -#include - -// Debug output on serial -#define DEBUG - -// Choose if you wish to use 8 additional Channels -// 5362 MHz 5399 MHz 5436 MHz 5473 MHz 5510 MHz 5547 MHz 5584 MHz 5621 MHz -// Local laws may prohibit the use of these frequencies use at your own risk! -//#define USE_LBAND - -// Recording Pin of the HMDVR/EachineDVR -#define P_REC A0 - -// RSSI default raw range -#define RSSI_REC_ON 160 -#define RSSI_REC_OFF 140 -#define RSSI_SEEK_TRESHOLD 160 - -#define rssiPin0 A1 -#define rssiPin1 A3 -#define rssiPin2 A6 -#define rssiPin3 A7 -//const uint8_t rssiPin[] = {rssiPin0, rssiPin1, rssiPin2, rssiPin3}; - -#define spiLatch0 7 -#define spiLatch1 8 -#define spiLatch2 9 -#define spiLatch3 10 -//const uint8_t slaveSelectPin[] = {spiLatch0, spiLatch1, spiLatch2, spiLatch3}; -#define spiDataPin 11 -#define spiClockPin 12 - -// DATA PIN; LATCH PIN; CLK PIN; RSSI PIN -RichWave rx0(spiDataPin, spiLatch0, spiClockPin, rssiPin0); -RichWave rx1(spiDataPin, spiLatch1, spiClockPin, rssiPin1); -RichWave rx2(spiDataPin, spiLatch2, spiClockPin, rssiPin2); -RichWave rx3(spiDataPin, spiLatch3, spiClockPin, rssiPin3); - -// Pretuned Channels at startup. -uint8_t channel[] = {2, 5, 18, 0}; - -#define S_TUNED 0 -#define S_SCAN 1 -uint8_t state[] = {S_TUNED, S_TUNED, S_TUNED, S_SCAN}; -//uint16_t tuneTime[] = {0, 0, 0, 0}; - -#define BUTTON0 2 -#define BUTTON1 4 -#define BUTTON2 5 -#define BUTTON3 6 -const uint8_t buttons[] = {BUTTON0, BUTTON1, BUTTON2, BUTTON3}; - - -// Channels with their Mhz Values -const uint16_t channelFreqTable[] PROGMEM = { - // Channel 1 - 8 - 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725, // Band A - 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866, // Band B - 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945, // Band E - 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880, // Band F / Airwave -#ifdef USE_LBAND - 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917, // Band C / Immersion Raceband - 5362, 5399, 5436, 5473, 5510, 5547, 5584, 5621 // Band D / 5.3 -#else - 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 // Band C / Immersion Raceband -#endif -}; - -// do coding as simpl#define P_REC 3e hex value to save memory. -const uint8_t channelNames[] PROGMEM = { - 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, // Band A - 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, // Band B - 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, // Band E - 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, // Band F / Airwave -#ifdef USE_LBAND - 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, // Band C / Immersion Raceband - 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8 // BAND D / 5.3 -#else - 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 // Band C / Immersion Raceband -#endif -}; - -// All Channels of the above List ordered by Mhz -const uint8_t channelList[] PROGMEM = { -#ifdef USE_LBAND - 40, 41, 42, 43, 44, 45, 46, 47, 19, 18, 32, 17, 33, 16, 7, 34, 8, 24, 6, 9, 25, 5, 35, 10, 26, 4, 11, 27, 3, 36, 12, 28, 2, 13, 29, 37, 1, 14, 30, 0, 15, 31, 38, 20, 21, 39, 22, 23 -#else - 19, 18, 32, 17, 33, 16, 7, 34, 8, 24, 6, 9, 25, 5, 35, 10, 26, 4, 11, 27, 3, 36, 12, 28, 2, 13, 29, 37, 1, 14, 30, 0, 15, 31, 38, 20, 21, 39, 22, 23 -#endif -}; - - -GOFi2cOLED oled;// default slave address is 0x3D - -boolean recording = false; - - -// ---------------------------------------------------------------------------- -// SETUP -// ---------------------------------------------------------------------------- -void setup() { - oled.init(0x3C); //initialze OLED display - oled.display(); // show splashscreen - delay(2000); - oled.clearDisplay(); - - oled.drawFastHLine(0, 0, 128, WHITE); - oled.drawFastHLine(0, 14, 128, WHITE); - oled.setCursor(3, 4); - oled.setTextSize(1); - oled.print("4X Video Splitter RX"); - - pinMode(LED_BUILTIN, OUTPUT); - - for (uint8_t i = 0; i <= sizeof(buttons); i++) { - pinMode (buttons[i], INPUT_PULLUP); - } - - -#ifdef DEBUG - Serial.begin(115200); - Serial.println(F("START:")); -#endif - -for (int mod = 0; mod < 4; mod++) { - // if modul is in tuned mode, tune to channel - if (state[mod] == S_TUNED) { - setChannelModule(mod, channel[mod]); - } -} - - // Setup Done - LED ON - digitalWrite(13, HIGH); - -} - -// ---------------------------------------------------------------------------- -// MAIN LOOP -// ---------------------------------------------------------------------------- -void loop() -{ - - // check Scan Buttons, and set module to scan if set. - for (int mod = 0; mod < 4; mod++) { - if (! digitalRead(buttons[mod])) { - state[mod] = S_SCAN; -#ifdef DEBUG - Serial.print(F("Setting Module" )); - Serial.print(mod); - Serial.println(F(" to Scan Mode")); -#endif - } - } - - // for each module, scan channels if in scan mode. - int rssi = 0; - int maxRSSI = 0; - for (int mod = 0; mod < 4; mod++) { - // if modul is in scan mode, skip to next ch. - if (state[mod] == S_SCAN) { - rssi = nextChannel(mod); - // if something found on that ch, change mode to tuned. - if (!hasChannel(mod) && rssi > RSSI_SEEK_TRESHOLD) { - state[mod] = S_TUNED; - } - } else { - rssi = readRSSI(mod); - } - displayChannel(mod, rssi); - maxRSSI = max(maxRSSI, rssi); - } - - // if highest RSSI of all Modules is over Treshhold -> Rec, else Rec Off - if (maxRSSI < RSSI_REC_OFF) { - rec(false); - } else if (maxRSSI > RSSI_REC_ON) { - rec(true); - } - - // delay(20); - -} - - -/*###########################################################################*/ -/* SUB ROUTINES -/*###########################################################################*/ - -// ---------------------------------------------------------------------------- -// nextChannel tune to next channel on given module -// ---------------------------------------------------------------------------- -uint16_t nextChannel(uint8_t module) { - uint8_t currChannel = channel[module]; - - currChannel++; - if (currChannel >= sizeof(channelList) ) { - currChannel = 0; - } - - setChannelModule(module, currChannel); - channel[module] = currChannel; -// wait_rssi_ready(module); - int rssi = readRSSI(module); - -#ifdef DEBUG - Serial.print(F("Mod: ")); Serial.print(module); - Serial.print(F(" tuned to CH: ")); Serial.print(currChannel); - Serial.print(F(": ")); Serial.print(channelName(currChannel)); - Serial.print(F(": ")); Serial.print(pgm_read_word_near(channelFreqTable + currChannel)); - Serial.print(F(" RSSI: ")); Serial.println(rssi); -#endif - - return rssi; -} - -// ---------------------------------------------------------------------------- -// hasCHannel check if current channel is already tuned on other module. -// ---------------------------------------------------------------------------- -boolean hasChannel(uint8_t module) { - int currChannel = channel[module]; - -#ifdef DEBUG - Serial.print(F("Check CHANNEL: ")); Serial.print(currChannel); - Serial.print(F(" IS IN ")); Serial.print(channel[0]); - Serial.print(F(" ")); Serial.print(channel[1]); - Serial.print(F(" ")); Serial.print(channel[2]); - Serial.print(F(" ")); Serial.print(channel[3]); -#endif - - int mod = 0; - for (mod = 0; mod <= 4; mod++) { - //if (mod != module && (channel[mod] - 1 <= currChannel) && currChannel <= channel[mod] + 1) { - - if (mod != module && channel[mod] == currChannel) { -#ifdef DEBUG - Serial.println(F(" -> TRUE")); -#endif - return true; - } - } - -#ifdef DEBUG - Serial.println(F(" -> FALSE")); -#endif - return false; -} - -// ---------------------------------------------------------------------------- -// displayChannel display the given channel, freq and rssi on the oled -// ---------------------------------------------------------------------------- -void displayChannel(int module, int rssi) { - - if (state[module] == S_SCAN) { - oled.setTextColor(BLACK, WHITE); // 'inverted' text - } else { - oled.setTextColor(WHITE); - } - - int ch = channel[module]; - switch (module) { - case 0: - oled.fillRect(5, 16, 63, 26, BLACK); - oled.setCursor(5, 16); - oled.setTextSize(3); - oled.print(channelName(ch)); - oled.setTextColor(WHITE); - oled.setTextSize(1); - oled.print(pgm_read_word_near(channelFreqTable + ch)); - oled.setCursor(40, 27); - break; - case 1: - oled.fillRect(68, 16, 63, 26, BLACK); - oled.setCursor(68, 16); - oled.setTextSize(3); - oled.print(channelName(ch)); - oled.setTextColor(WHITE); - oled.setTextSize(1); - oled.print(pgm_read_word_near(channelFreqTable + ch)); - oled.setCursor(103, 27); - break; - case 2: - oled.fillRect(5, 42, 63, 26, BLACK); - oled.setCursor(5, 42); - oled.setTextSize(3); - oled.print(channelName(ch)); - oled.setTextColor(WHITE); - oled.setTextSize(1); - oled.print(pgm_read_word_near(channelFreqTable + ch)); - oled.setCursor(40, 53); - break; - case 3: - oled.fillRect(68, 42, 63, 26, BLACK); - oled.setCursor(68, 42); - oled.setTextSize(3); - oled.print(channelName(ch)); - oled.setTextColor(WHITE); - oled.setTextSize(1); - oled.print(pgm_read_word_near(channelFreqTable + ch)); - oled.setCursor(103, 53); - break; - - default: - break; - } - oled.print(rssi); - oled.display(); -} - -// ---------------------------------------------------------------------------- -// readRSSI read rssi of given module. -// ---------------------------------------------------------------------------- -uint16_t readRSSI(uint8_t module) -{ - switch (module) { - case 0: - return rx0.readRSSI(); - case 1: - return rx1.readRSSI(); - case 2: - return rx2.readRSSI(); - case 3: - return rx3.readRSSI(); - } - return 0; -} - - -// ---------------------------------------------------------------------------- -// channelName return channel name from list. -// ---------------------------------------------------------------------------- -String channelName(uint8_t ch) { - String name = String(pgm_read_byte_near(channelNames + ch), HEX); - name.toUpperCase(); - if (name.charAt(0) == 'C') { - name.setCharAt(0, 'R'); - } - return name; -} - - -// ---------------------------------------------------------------------------- -// channel_from_index -// ---------------------------------------------------------------------------- -uint8_t channel_from_index(uint8_t channelIndex) -{ - uint8_t loop = 0; - uint8_t channel = 0; - for (loop = 0; loop <= sizeof(channelList); loop++) - { - if (pgm_read_byte_near(channelList + loop) == channelIndex) - { - channel = loop; - break; - } - } - return (channel); -} - - -// ---------------------------------------------------------------------------- -// setChannelModule tune given module to given channel -// ---------------------------------------------------------------------------- -void setChannelModule(uint8_t module, uint8_t channel) { - - uint16_t channelFreq = pgm_read_word_near(channelFreqTable + channel); - - switch (module) { - case 0: - rx0.setFrequency(channelFreq); - break; - case 1: - rx1.setFrequency(channelFreq); - break; - case 2: - rx2.setFrequency(channelFreq); - break; - case 3: - rx3.setFrequency(channelFreq); - break; - default: - break; - } - -// tuneTime[module] = millis(); -} - -void rec(boolean rec) { - if (rec == recording) - return - - digitalWrite(P_REC, HIGH); - delay(1000); - digitalWrite(P_REC, LOW); - recording = !recording; -} - From b3a30239ba7363d5f4f0756d5780ec69c27077a9 Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:45:24 +0100 Subject: [PATCH 6/9] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 942af5d..3a954e2 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,9 @@ A Arduino library to control the RTC6715 RichWave 5.8 GHz RX Chip. This chip is commonly used in Foxtech/Boscam Receiver modules for example the RX5808 which is in turn is used inside receivers like the RC305 or can be used stand-alone. + +Created by Timo Witte + + Modified by der-Frickler.net + - Added RSSI Pin and RSSI Reading. + - Added 4x Richwave RX5808 Video Receiver as Example. From 69613716a5971c8bcf5d5f14fafaf8cde84b41fd Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:45:53 +0100 Subject: [PATCH 7/9] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a954e2..c4eecae 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ A Arduino library to control the RTC6715 RichWave 5.8 GHz RX Chip. This chip is commonly used in Foxtech/Boscam Receiver modules for example the RX5808 which is in turn is used inside receivers like the RC305 or can be used stand-alone. -Created by Timo Witte +Created by Timo Witte - Modified by der-Frickler.net +Modified by der-Frickler.net - Added RSSI Pin and RSSI Reading. - Added 4x Richwave RX5808 Video Receiver as Example. From f248113d6708ba26d06560996297ffa8447171b4 Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:53:18 +0100 Subject: [PATCH 8/9] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c4eecae..f7c25e4 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,6 @@ Created by Timo Witte Modified by der-Frickler.net - Added RSSI Pin and RSSI Reading. - - Added 4x Richwave RX5808 Video Receiver as Example. + + - Added 4x Richwave RX5808 Video Receiver as Example. Attach the 4 RX modules to a video processor: http://www.banggood.com/de/4-CH-Channel-DVR-CCTV-Quad-Video-Camera-Processor-System-kit-Splitter-Switcher-p-1032225.html and you get a nice splitscreen view of 4 different FPV Channels: https://www.youtube.com/watch?v=YXnQFq7hVz4 + From 2d9c20768fdbffab5efc8108546a007e74126a4d Mon Sep 17 00:00:00 2001 From: derFrickler Date: Thu, 1 Dec 2016 09:53:36 +0100 Subject: [PATCH 9/9] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f7c25e4..ee3a8cf 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,8 @@ Created by Timo Witte Modified by der-Frickler.net - Added RSSI Pin and RSSI Reading. - - Added 4x Richwave RX5808 Video Receiver as Example. Attach the 4 RX modules to a video processor: http://www.banggood.com/de/4-CH-Channel-DVR-CCTV-Quad-Video-Camera-Processor-System-kit-Splitter-Switcher-p-1032225.html and you get a nice splitscreen view of 4 different FPV Channels: https://www.youtube.com/watch?v=YXnQFq7hVz4 + - Added 4x Richwave RX5808 Video Receiver as Example. Attach the 4 RX modules to a video processor: + http://www.banggood.com/de/4-CH-Channel-DVR-CCTV-Quad-Video-Camera-Processor-System-kit-Splitter-Switcher-p-1032225.html + and you get a nice splitscreen view of 4 different FPV Channels: + https://www.youtube.com/watch?v=YXnQFq7hVz4