Browse Source

Finally OSD + Composite is working!

master
Englebert 3 years ago
parent
commit
f80acbba3b
  1. 648
      BertFPVDiversity.ino
  2. 238
      SoftSPI.cpp
  3. 69
      SoftSPI.h
  4. 82
      rx5808.cpp
  5. 25
      rx5808.h

648
BertFPVDiversity.ino

@ -8,18 +8,470 @@
// 8-bits color code
// RRRGGGBB
#include "Arduino.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <Update.h>
#include "BertFPVDiversity.h"
#include "video.h"
#include "intro.h"
#include "menu.h"
#include "search.h"
#include "rx5808.h"
uint8_t display_screen = 0;
#define TOUCH_MODE T9
#define TOUCH_MODE T9
#define TOUCH_UP T7
#define TOUCH_DOWN T6
#define TOUCH_ENTER T8
#define INDICATOR_V1 2
#define INDICATOR_V2 15
#define BUZZER 23
#define VIDEO_SELECTOR 12
#define RSSI1 39
#define RSSI2 36
/* Buzzer sound limits */
uint32_t last_buzzer_seconds = 0;
bool last_buzzer_seconds_cron = false;
// Starting up WebServer
WebServer server(80);
// Replace with your network credentials
const char* ssid = "BERTFPV-Diversity";
const char* password = "LetMeIn1234"; // Must be >= 8 characters
/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
/* For the next check use */
uint32_t last_webserver_seconds = 0;
/*** Firmware Upgrade Page ***/
const char* firmware_upgrade_html PROGMEM = R"rawliteral(
<script>
var iBytesUploaded = 0;
var iBytesTotal = 0;
var iPreviousBytesLoaded = 0;
var iMaxFilesize = 1048576; // 1MB
var oTimer = 0;
var sResultFileSize = '';
function secondsToTime(secs) {
var hr = Math.floor(secs / 3600);
var min = Math.floor((secs - (hr * 3600))/60);
var sec = Math.floor(secs - (hr * 3600) - (min * 60));
if (hr < 10) {hr = "0" + hr; }
if (min < 10) {min = "0" + min;}
if (sec < 10) {sec = "0" + sec;}
if (hr) {hr = "00";}
return hr + ':' + min + ':' + sec;
};
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};
function fileSelected() {
document.getElementById('upload_response').style.display = 'none';
document.getElementById('error').style.display = 'none';
document.getElementById('error2').style.display = 'none';
document.getElementById('abort').style.display = 'none';
document.getElementById('warnsize').style.display = 'none';
var oFile = document.getElementById('image_file').files[0];
var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
if (! rFilter.test(oFile.type)) {
document.getElementById('error').style.display = 'block';
return;
}
if (oFile.size > iMaxFilesize) {
document.getElementById('warnsize').style.display = 'block';
return;
}
var oImage = document.getElementById('preview');
var oReader = new FileReader();
oReader.onload = function(e){
oImage.src = e.target.result;
oImage.onload = function () { // binding onload event
sResultFileSize = bytesToSize(oFile.size);
document.getElementById('fileinfo').style.display = 'block';
document.getElementById('filename').innerHTML = 'Name: ' + oFile.name;
document.getElementById('filesize').innerHTML = 'Size: ' + sResultFileSize;
document.getElementById('filetype').innerHTML = 'Type: ' + oFile.type;
document.getElementById('filedim').innerHTML = 'Dimension: ' + oImage.naturalWidth + ' x ' + oImage.naturalHeight;
};
};
oReader.readAsDataURL(oFile);
}
function startUploading() {
iPreviousBytesLoaded = 0;
document.getElementById('upload_response').style.display = 'none';
document.getElementById('error').style.display = 'none';
document.getElementById('error2').style.display = 'none';
document.getElementById('abort').style.display = 'none';
document.getElementById('warnsize').style.display = 'none';
document.getElementById('progress_percent').innerHTML = '';
var oProgress = document.getElementById('progress');
oProgress.style.display = 'block';
oProgress.style.width = '0px';
var vFD = new FormData(document.getElementById('upload_form'));
var oXHR = new XMLHttpRequest();
oXHR.upload.addEventListener('progress', uploadProgress, false);
oXHR.addEventListener('load', uploadFinish, false);
oXHR.addEventListener('error', uploadError, false);
oXHR.addEventListener('abort', uploadAbort, false);
oXHR.open('POST', '/update');
oXHR.send(vFD);
oTimer = setInterval(doInnerUpdates, 300);
}
function doInnerUpdates() {
var iCB = iBytesUploaded;
var iDiff = iCB - iPreviousBytesLoaded;
if (iDiff == 0)
return;
iPreviousBytesLoaded = iCB;
iDiff = iDiff * 2;
var iBytesRem = iBytesTotal - iPreviousBytesLoaded;
var secondsRemaining = iBytesRem / iDiff;
var iSpeed = iDiff.toString() + 'B/s';
if (iDiff > 1024 * 1024) {
iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s';
} else if (iDiff > 1024) {
iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s';
}
document.getElementById('speed').innerHTML = iSpeed;
document.getElementById('remaining').innerHTML = '| ' + secondsToTime(secondsRemaining);
}
function uploadProgress(e) {
if (e.lengthComputable) {
iBytesUploaded = e.loaded;
iBytesTotal = e.total;
var iPercentComplete = Math.round(e.loaded * 100 / e.total);
var iBytesTransfered = bytesToSize(iBytesUploaded);
document.getElementById('progress_percent').innerHTML = iPercentComplete.toString() + '%';
document.getElementById('progress').style.width = (iPercentComplete * 4).toString() + 'px';
document.getElementById('b_transfered').innerHTML = iBytesTransfered;
if (iPercentComplete == 100) {
var oUploadResponse = document.getElementById('upload_response');
oUploadResponse.innerHTML = '<h1>Please wait...processing</h1>';
oUploadResponse.style.display = 'block';
}
} else {
document.getElementById('progress').innerHTML = 'unable to compute';
}
}
function uploadFinish(e) {
var oUploadResponse = document.getElementById('upload_response');
oUploadResponse.innerHTML = e.target.responseText;
oUploadResponse.style.display = 'block';
document.getElementById('progress_percent').innerHTML = '100%';
document.getElementById('progress').style.width = '400px';
document.getElementById('filesize').innerHTML = sResultFileSize;
document.getElementById('remaining').innerHTML = '| 00:00:00';
clearInterval(oTimer);
}
function uploadError(e) {
document.getElementById('error2').style.display = 'block';
clearInterval(oTimer);
}
function uploadAbort(e) {
document.getElementById('abort').style.display = 'block';
clearInterval(oTimer);
}
</script>
<style>
.container {
margin: auto;
width: 50%;
}
.upload_form_cont {
background: -moz-linear-gradient(#ffffff, #f2f2f2);
background: -ms-linear-gradient(#ffffff, #f2f2f2);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2));
background: -webkit-linear-gradient(#ffffff, #f2f2f2);
background: -o-linear-gradient(#ffffff, #f2f2f2);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')";
background: linear-gradient(#ffffff, #f2f2f2);
color:#000;
overflow:hidden;
}
#upload_form {
float:center;
padding:20px;
width:700px;
}
#preview {
background-color:#fff;
display:block;
float:right;
width:200px;
}
#upload_form > div {
margin-bottom:10px;
}
#speed,#remaining {
float:left;
width:100px;
}
#b_transfered {
float:right;
text-align:right;
}
.clear_both {
clear:both;
}
input {
border-radius:10px;
-moz-border-radius:10px;
-ms-border-radius:10px;
-o-border-radius:10px;
-webkit-border-radius:10px;
border:1px solid #ccc;
font-size:14pt;
padding:5px 10px;
}
input[type=button] {
background: -moz-linear-gradient(#ffffff, #dfdfdf);
background: -ms-linear-gradient(#ffffff, #dfdfdf);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #dfdfdf));
background: -webkit-linear-gradient(#ffffff, #dfdfdf);
background: -o-linear-gradient(#ffffff, #dfdfdf);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf')";
background: linear-gradient(#ffffff, #dfdfdf);
}
#image_file {
width:400px;
}
#progress_info {
font-size:10pt;
}
#fileinfo,#error,#error2,#abort,#warnsize {
color:#aaa;
display:none;
font-size:10pt;
font-style:italic;
margin-top:10px;
}
#progress {
border:1px solid #ccc;
display:none;
float:left;
height:14px;
border-radius:10px;
-moz-border-radius:10px;
-ms-border-radius:10px;
-o-border-radius:10px;
-webkit-border-radius:10px;
background: -moz-linear-gradient(#66cc00, #4b9500);
background: -ms-linear-gradient(#66cc00, #4b9500);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #66cc00), color-stop(100%, #4b9500));
background: -webkit-linear-gradient(#66cc00, #4b9500);
background: -o-linear-gradient(#66cc00, #4b9500);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500')";
background: linear-gradient(#66cc00, #4b9500);
}
#progress_percent {
float:right;
}
#upload_response {
margin-top: 10px;
padding: 20px;
overflow: hidden;
display: none;
border: 1px solid #ccc;
border-radius:10px;
-moz-border-radius:10px;
-ms-border-radius:10px;
-o-border-radius:10px;
-webkit-border-radius:10px;
box-shadow: 0 0 5px #ccc;
background: -moz-linear-gradient(#bbb, #eee);
background: -ms-linear-gradient(#bbb, #eee);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #bbb), color-stop(100%, #eee));
background: -webkit-linear-gradient(#bbb, #eee);
background: -o-linear-gradient(#bbb, #eee);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee')";
background: linear-gradient(#bbb, #eee);
}
</style>
<body>
<header>
<h2 align='center'>*** BertFPV Diversity VTX Receiver - Firmware Uploader V1.0.0 ***</h2>
</header>
<div class='container'>
<div class='contr'><h2>Please select a file to upload the firmware.</h2></div>
<div class='upload_form_cont'>
<form method='POST' action='/update' enctype='multipart/form-data' id='upload_form'>
<div>
<div><label for='image_file'>Please select image file</label></div>
<div><input type='file' name='update' id='image_file' onchange='fileSelected();' /></div>
</div>
<div><input type='button' value='Upload' onclick='startUploading()' /></div>
<div id='fileinfo'>
<div id='filename'></div>
<div id='filesize'></div>
<div id='filetype'></div>
<div id='filedim'></div>
</div>
<div id='error'>You should select valid image files only!</div>
<div id='error2'>An error occurred while uploading the file</div>
<div id='abort'>The upload has been canceled by the user or the browser dropped the connection</div>
<div id='warnsize'>Your file is very big. We can't accept it. Please select more small file</div>
<div id='progress_info'>
<div id='progress'></div>
<div id='progress_percent'>&nbsp;</div>
<div class='clear_both'></div>
<div>
<div id='speed'>&nbsp;</div>
<div id='remaining'>&nbsp;</div>
<div id='b_transfered'>&nbsp;</div>
<div class='clear_both'></div>
</div>
<div id='upload_response'></div>
</div>
</form>
</div>
</div>
</div>
</body>
)rawliteral";
/*** Index Page ***/
const char* index_html PROGMEM = R"rawliteral(<pre><strong>BertFPV Diversity VTX Receiver v1.0</strong>
)rawliteral";
void setup_webserver(void) {
// Create HostAP
Serial.println(F("Starting SoftAP"));
WiFi.softAP(ssid, password);
Serial.println(F("Setting IP"));
WiFi.softAPConfig(local_ip, gateway, subnet);
delay(100); // Delay 100mS
IPAddress IP = WiFi.softAPIP();
Serial.print(F("AP IP address: "));
Serial.println(IP);
// init and get the time
// configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
/*
server.on("/status", HTTP_GET, []() {
server.sendHeader("Connection", "close");
String index_html_str = "CHANNEL: " + String(freq_channel);
if(signalNotOK) {
index_html_str = index_html_str + " Signal: KO";
} else {
index_html_str = index_html_str + " Signal: " + String(nrf_received_count);
}
server.send(200, "text/html", index_html_str);
});
*/
// Setting RX Channel
/*
server.on("/setchannel", HTTP_GET, []() {
server.sendHeader("Connection", "close");
if(!server.hasArg("c")) {
server.send(200, "text/html", "INVALID PARAMETERS");
}
String arg_freq_channel = server.arg("c");
int _freq_channel = arg_freq_channel.toInt();
if(_freq_channel < 0 || _freq_channel > 125) {
server.send(200, "text/html", "Channel is over the limit.");
} else {
freq_channel = _freq_channel;
save_settings();
String index_html_str = "CHANNEL SET: ";
index_html_str = index_html_str + String(freq_channel);
server.send(200, "text/html", index_html_str);
delay(500);
ESP.restart();
}
});
*/
server.on("/reboot", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", "REBOOTING...");
delay(2000);
ESP.restart();
});
// Setting up OTA
/*** Index Page ***/
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", firmware_upgrade_html);
});
/*** Firmware Upgrade Page ***/
server.on("/firmware_upgrade", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", firmware_upgrade_html);
});
// ################### HANDLING UPLOAD FIRMWARE HERE #########################
/*** handling uploading firmware file ***/
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK. Device is rebooting");
// Try to delay a bit...
delay(1000);
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START) {
// Serial.printf("Update: %s\n", upload.filename.c_str());
if(!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_WRITE) {
/*** flashing firmware to ESP ***/
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_END) {
if(Update.end(true)) {
//true to set the size to the current progress
// Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
// Starting up Server
server.begin();
// Just to debug...
// if(WiFi.status() == WL_CONNECTED)
// Serial.println(WiFi.localIP());
}
const int VALUE_THRESHOLD = 10;
const int VALUE_THRESHOLD = 1;
int touched_val = 0;
bool touched = false;
uint32_t last_touched = 0;
@ -86,6 +538,72 @@ void IRAM_ATTR onTimer(){
c++;
}
void io_setup() {
/* Indicators */
pinMode(INDICATOR_V1, OUTPUT);
pinMode(INDICATOR_V2, OUTPUT);
/* Buzzer */
pinMode(BUZZER, OUTPUT);
/* Video Selector - TEMPORARY */
pinMode(VIDEO_SELECTOR, OUTPUT);
digitalWrite(VIDEO_SELECTOR, LOW);
digitalWrite(INDICATOR_V1, HIGH);
digitalWrite(INDICATOR_V2, LOW);
}
void noTone() {
tone(BUZZER, 0);
}
void tone(byte pin, int freq) {
ledcSetup(0, 2000, 8); // setup beeper
ledcAttachPin(pin, 0); // attach beeper
ledcWriteTone(0, freq); // play tone
}
void touchBeep(uint8_t beep_type = 0) {
tone(BUZZER, 800);
// Instead of delay we use cronjob method
if(beep_type == 0) {
last_buzzer_seconds = millis() + 200;
} else {
last_buzzer_seconds = millis() + 500;
}
last_buzzer_seconds_cron = true;
}
void startupBeep() {
for(int i = 0; i < 10; i++) {
tone(BUZZER, random(1000, 2000));
delay(100);
noTone();
delay(10);
}
}
void setup_done() {
for(int i = 0; i < 10; i++) {
digitalWrite(INDICATOR_V1, HIGH);
digitalWrite(INDICATOR_V2, LOW);
delay(50);
digitalWrite(INDICATOR_V2, HIGH);
digitalWrite(INDICATOR_V1, LOW);
delay(50);
}
digitalWrite(INDICATOR_V1, LOW);
digitalWrite(INDICATOR_V2, LOW);
startupBeep();
digitalWrite(INDICATOR_V1, HIGH);
}
void setup_rx5808() {
RX5808::begin();
}
void setup() {
// Preparing Timer Hardware
/* 1 Aick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
@ -106,21 +624,98 @@ void setup() {
/* Standard serial baud rate */
Serial.begin(115200);
/* Setting up IO pins */
io_setup();
/* Setup RX5808 devices */
setup_rx5808();
/* Setup up Video Composite */
Video::begin();
/* Setup WebServer */
setup_webserver();
/* Setup Finish Routine */
setup_done();
}
void osd(uint8_t state) {
// 1 = ON, 0 = OFF
if(state == 0) {
dac_i2s_disable();
dac_output_disable(DAC_CHANNEL_1);
// Prevent distortion on the video composite
pinMode(GPIO_NUM_25, INPUT);
gpio_pulldown_dis(GPIO_NUM_25);
gpio_pullup_dis(GPIO_NUM_25);
gpio_set_pull_mode(GPIO_NUM_25, GPIO_FLOATING);
RX5808::setPowerDownRegister(0b00010000110000010011);
touchBeep(1);
} else {
RX5808::setPowerDownRegister(0b01010000110000010011);
dac_output_enable(DAC_CHANNEL_1);
dac_i2s_enable();
touchBeep(0);
}
}
void loop() {
// Handling web services every 100mS
if(millis() > last_webserver_seconds) {
server.handleClient();
last_webserver_seconds = millis() + 100;
}
// Handling cronjobs - BEGIN
if(millis() > last_buzzer_seconds && last_buzzer_seconds_cron == true) {
last_buzzer_seconds_cron = false;
noTone();
}
// Handling cronjobs - END
if(display_output_state)
display_output();
// Checking TouchPad - MODE
touched_val = touchRead(TOUCH_MODE);
if(touched_val < VALUE_THRESHOLD) {
if(millis() > last_touched) {
touched = !touched;
display_output_state = !display_output_state;
if(!display_output_state) {
osd(0);
} else {
osd(1);
}
last_touched = millis() + 500;
}
}
/****************
// Checking TouchPad - Up
touched_val = touchRead(TOUCH_UP);
if(touched_val < VALUE_THRESHOLD) {
if(millis() > last_touched) {
Menu::menu_position--;
last_touched = millis() + 500;
Menu::menu_position = (Menu::menu_position < 0) ? Menu::MAX_MENU_ITEMS - 1 : Menu::menu_position;
//Menu::menu_position = (Menu::menu_position >= Menu::MAX_MENU_ITEMS) ? 0 : Menu::menu_position;
}
}
// Checking TouchPad - DOWN
touched_val = touchRead(TOUCH_DOWN);
if(touched_val < VALUE_THRESHOLD) {
if(millis() > last_touched) {
Menu::menu_position++;
last_touched = millis() + 500;
//Menu::menu_position = (Menu::menu_position < 0) ? Menu::MAX_MENU_ITEMS - 1 : Menu::menu_position;
Menu::menu_position = (Menu::menu_position >= Menu::MAX_MENU_ITEMS) ? 0 : Menu::menu_position;
}
}
**********/
// Temporary
if(Serial.available() > 0) {
@ -129,7 +724,7 @@ void loop() {
// Making it cleaner??? not sure..
int key_type = -1;
if(serial_cmd_string == "prev")
if(serial_cmd_string == "prev")
key_type = 1;
else if(serial_cmd_string == "next")
key_type = 2;
@ -141,19 +736,42 @@ void loop() {
// Disable this screen and enable the RX5808 output
display_output_state = !display_output_state;
if(!display_output_state) {
dac_i2s_disable();
dac_output_disable(DAC_CHANNEL_1);
// Prevent distortion on the video composite
pinMode(GPIO_NUM_25, INPUT);
gpio_pulldown_dis(GPIO_NUM_25);
gpio_pullup_dis(GPIO_NUM_25);
gpio_set_pull_mode(GPIO_NUM_25, GPIO_FLOATING);
// OSD OFF
osd(0);
} else {
dac_output_enable(DAC_CHANNEL_1);
dac_i2s_enable();
// OSD ON
osd(1);
}
} else if(serial_cmd_string == "video1") {
digitalWrite(VIDEO_SELECTOR, LOW);
digitalWrite(INDICATOR_V1, HIGH);
digitalWrite(INDICATOR_V2, LOW);
Serial.println(F("Video 1"));
} else if(serial_cmd_string == "video2") {
digitalWrite(VIDEO_SELECTOR, HIGH);
digitalWrite(INDICATOR_V1, LOW);
digitalWrite(INDICATOR_V2, HIGH);
Serial.println(F("Video 2"));
} else if(serial_cmd_string == "receiveroff") {
RX5808::rxStandby(0);
touchBeep(0);
Serial.println(F("All Receiver standby mode"));
} else if(serial_cmd_string == "receiveron") {
RX5808::rxPowerOn(0);
Serial.println(F("All Receiver power on"));
} else if(serial_cmd_string == "reset") {
RX5808::rxReset(0);
Serial.println(F("All Receiver RESET"));
} else if(serial_cmd_string == "rssi") {
uint32_t rssi1 = analogRead(RSSI1);
uint32_t rssi2 = analogRead(RSSI2);
Serial.print(F("RSSI 1: "));
Serial.println(rssi1);
Serial.print(F("RSSI 2: "));
Serial.println(rssi2);
} else if(serial_cmd_string == "setfreq1") {
Serial.println("5845");
RX5808::setSynthRegisterB(5845);
}
switch(key_type) {

238
SoftSPI.cpp

@ -0,0 +1,238 @@
/*
* Copyright (c) 2014, Majenko Technologies
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Majenko Technologies nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "SoftSPI.h"
SoftSPI::SoftSPI(uint8_t mosi, uint8_t miso, uint8_t sck) {
_mosi = mosi;
_miso = miso;
_sck = sck;
_delay = 2;
_cke = 0;
_ckp = 0;
_order = MSBFIRST;
}
void SoftSPI::begin() {
pinMode(_mosi, OUTPUT);
pinMode(_miso, INPUT);
pinMode(_sck, OUTPUT);
}
void SoftSPI::end() {
pinMode(_mosi, INPUT);
pinMode(_miso, INPUT);
pinMode(_sck, INPUT);
}
void SoftSPI::setBitOrder(uint8_t order) {
_order = order & 1;
}
void SoftSPI::setDataMode(uint8_t mode) {
switch (mode) {
case SPI_MODE0:
_ckp = 0;
_cke = 0;
break;
case SPI_MODE1:
_ckp = 0;
_cke = 1;
break;
case SPI_MODE2:
_ckp = 1;
_cke = 0;
break;
case SPI_MODE3:
_ckp = 1;
_cke = 1;
break;
}
digitalWrite(_sck, _ckp ? HIGH : LOW);
}
void SoftSPI::setClockDivider(uint8_t div) {
switch (div) {
case SPI_CLOCK_DIV2:
_delay = 2;
break;
case SPI_CLOCK_DIV4:
_delay = 4;
break;
case SPI_CLOCK_DIV8:
_delay = 8;
break;
case SPI_CLOCK_DIV16:
_delay = 16;
break;
case SPI_CLOCK_DIV32:
_delay = 32;
break;
case SPI_CLOCK_DIV64:
_delay = 64;
break;
case SPI_CLOCK_DIV128:
_delay = 128;
break;
default:
_delay = 128;
break;
}
}
void SoftSPI::wait(uint_fast8_t del) {
for (uint_fast8_t i = 0; i < del; i++) {
asm volatile("nop");
}
}
uint32_t SoftSPI::transfer32(uint32_t data, uint8_t data_length) {
uint8_t out = 0;
uint8_t del = _delay >> 1;
uint8_t bval = 0;
int sck = (_ckp) ? HIGH : LOW;
for(uint8_t bit = 0; bit < data_length; bit++) {
// uint8_t sector = data >> (i * 8) & 0xFF;
// RX5808_SPI1.transfer(sector);
if (_cke) {
sck ^= 1;
digitalWrite(_sck, sck);
wait(del);
}
/* ... Write bit */
digitalWrite(_mosi, ((data >> bit) & 0x01) ? HIGH : LOW);
wait(del);
sck ^= 1u; digitalWrite(_sck, sck);
wait(del);
if (!_cke) {
sck ^= 1u;
digitalWrite(_sck, sck);
}
}
return 0;
}
uint8_t SoftSPI::transfer(uint8_t val) {
uint8_t out = 0;
if (_order == MSBFIRST) {
uint8_t v2 =
((val & 0x01) << 7) |
((val & 0x02) << 5) |
((val & 0x04) << 3) |
((val & 0x08) << 1) |
((val & 0x10) >> 1) |
((val & 0x20) >> 3) |
((val & 0x40) >> 5) |
((val & 0x80) >> 7);
val = v2;
}
uint8_t del = _delay >> 1;
uint8_t bval = 0;
/*
* CPOL := 0, CPHA := 0 => INIT = 0, PRE = Z|0, MID = 1, POST = 0
* CPOL := 1, CPHA := 0 => INIT = 1, PRE = Z|1, MID = 0, POST = 1
* CPOL := 0, CPHA := 1 => INIT = 0, PRE = 1 , MID = 0, POST = Z|0
* CPOL := 1, CPHA := 1 => INIT = 1, PRE = 0 , MID = 1, POST = Z|1
*/
int sck = (_ckp) ? HIGH : LOW;
for (uint8_t bit = 0u; bit < 8u; bit++)
{
if (_cke) {
sck ^= 1;
digitalWrite(_sck, sck);
wait(del);
}
/* ... Write bit */
digitalWrite(_mosi, ((val & (1<<bit)) ? HIGH : LOW));
wait(del);
sck ^= 1u; digitalWrite(_sck, sck);
/* ... Read bit */
{
bval = digitalRead(_miso);
if (_order == MSBFIRST) {
out <<= 1;
out |= bval;
} else {
out >>= 1;
out |= bval << 7;
}
}
wait(del);
if (!_cke) {
sck ^= 1u;
digitalWrite(_sck, sck);
}
}
return out;
}
uint16_t SoftSPI::transfer16(uint16_t data)
{
union {
uint16_t val;
struct {
uint8_t lsb;
uint8_t msb;
};
} in, out;
in.val = data;
if ( _order == MSBFIRST ) {
out.msb = transfer(in.msb);
out.lsb = transfer(in.lsb);
} else {
out.lsb = transfer(in.lsb);
out.msb = transfer(in.msb);
}
return out.val;
}

69
SoftSPI.h

@ -0,0 +1,69 @@
/*
* Copyright (c) 2014, Majenko Technologies
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Majenko Technologies nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SOFTSPI_H
#define _SOFTSPI_H
#if (ARDUINO >= 100)
# include <Arduino.h>
#else
# include <WProgram.h>
#endif
#include <SPI.h>
class SoftSPI : public SPIClass {
private:
void wait(uint_fast8_t del);
private:
uint8_t _cke;
uint8_t _ckp;
uint8_t _delay;
uint8_t _miso;
uint8_t _mosi;
uint8_t _sck;
uint8_t _order;
public:
SoftSPI(uint8_t mosi, uint8_t miso, uint8_t sck);
void begin();
void end();
void setBitOrder(uint8_t);
void setDataMode(uint8_t);
void setClockDivider(uint8_t);
uint8_t transfer(uint8_t);
uint16_t transfer16(uint16_t data);
// Added for RX5808 Software SPI
uint32_t transfer32(uint32_t data, uint8_t data_length);
};
#endif

82
rx5808.cpp

@ -0,0 +1,82 @@
#include "rx5808.h"
#include <SPI.h>
#include "SoftSPI.h"
#define SPI_ADDRESS_SYNTH_B 0x01
#define SPI_ADDRESS_POWER 0x0A
#define SPI_ADDRESS_STATE 0x0F
#define PIN_SPI_RX_A 18
#define PIN_SPI_RX_B 16
static inline void sendRegister(uint8_t address, uint32_t data);
// Create new SPI port for RX5808_SPI1
// D5: (CH1) MOSI
// D12: MISO (using an unused pin)
// D18: (CH2) CS
// D19: (CH3) SCK
SoftSPI RX5808_SPI1(5, 34, 19);
// D4: (CH1) MOSI
// D13: MISO (using an unused pin)
// D16: (CH2) CS
// D17: (CH3) SCK
SoftSPI RX5808_SPI2(4, 35, 17);
// TODO: COntinue to set address to power down the SPI
namespace RX5808 {
void begin() {
RX5808_SPI1.begin();
RX5808_SPI2.begin();
}
void setSynthRegisterB(uint16_t value) {
sendRegister(SPI_ADDRESS_SYNTH_B, value);
}
void setPowerDownRegister(uint32_t value) {
sendRegister(SPI_ADDRESS_POWER, value);
}
void setStateRegister(uint32_t value) {
sendRegister(SPI_ADDRESS_STATE, value);
}
void rxStandby(uint8_t receiver_id) {
sendRegister(SPI_ADDRESS_STATE, 0b00000000000000000010);
// sendCommand(0b00000000000000000010);
}
void rxPowerOn(uint8_t receiver_id) {
sendRegister(SPI_ADDRESS_STATE, 0b00000000000000000001);
// sendCommand(0b00000000000000000001);
}
void rxReset(uint8_t receiver_id) {
sendRegister(SPI_ADDRESS_STATE, 0b00000000000000000000);
// sendCommand(0b00000000000000000000);
}
}
static inline void sendRegister(uint8_t addressBits, uint32_t dataBits) {
uint32_t data = addressBits | (1 << 4) | (dataBits << 5);
RX5808_SPI1.setDataMode(SPI_MODE0);
RX5808_SPI1.setBitOrder(LSBFIRST);
RX5808_SPI1.setClockDivider(SPI_CLOCK_DIV8);
digitalWrite(PIN_SPI_RX_A, LOW);
RX5808_SPI1.transfer32(data, 25);
digitalWrite(PIN_SPI_RX_A, HIGH);
RX5808_SPI2.setDataMode(SPI_MODE0);
RX5808_SPI2.setBitOrder(LSBFIRST);
RX5808_SPI2.setClockDivider(SPI_CLOCK_DIV8);
digitalWrite(PIN_SPI_RX_B, LOW);
RX5808_SPI2.transfer32(data, 25);
digitalWrite(PIN_SPI_RX_B, HIGH);
// RX5808_SPI1.endTransaction();
// RX5808_SPI2.endTransaction();
}

25
rx5808.h

@ -0,0 +1,25 @@
/*
* Filename: rx5808.h
* Date: Mon 20 Sep 22:14:58 +08 2021
* Author: Englebert
* Description:
* - rx5808 protocols
*/
#ifndef RX5808_H
#define RX5808_H
#include "BertFPVDiversity.h"
namespace RX5808 {
void begin();
void setSynthRegisterB(uint16_t value);
void setPowerDownRegister(uint32_t value);
void setStateRegister(uint32_t value);
void rxStandby(uint8_t receiver_id);
void rxPowerOn(uint8_t receiver_id);
void rxReset(uint8_t receiver_id);
}
#endif
Loading…
Cancel
Save