Porównaj commity

...

4 Commity

Autor SHA1 Wiadomość Data
Michal Fratczak 7e0108c49b Remove habhub interface from webClient 2023-02-28 20:09:16 +01:00
Michal Fratczak d60b46d1b8 Remove habhub interface. 2023-02-28 20:00:43 +01:00
Michal Fratczak fbb2ac35a5 Simplified build steps for Raspberry PI
It is now possible to use system installed Boost and FFTW3
2023-02-28 19:44:13 +01:00
Michal Fratczak 82930e34dc Add missing <limits> header to CompressedVector.h 2023-02-28 19:10:19 +01:00
16 zmienionych plików z 88 dodań i 866 usunięć

Wyświetl plik

@ -1,15 +1,33 @@
# Building HABDEC from source
To build habdec from source code, you need to build it's dependecies first:
- FFTW
Habdec relies on following dependencies:
- FFTW3
- boost (any version with boost-beast 1.66+)
- CMake version 3.8.2 (make sure CMake version supports your boost version, otherwise CMake could fail finding stuff)
- optionally: FLTK
- CMake version 3.8.2+ (make sure CMake version supports your boost version, otherwise CMake could fail finding stuff)
If you target RaspberryPi, consider starting with PiSDR image https://github.com/luigifcruz/pisdr-image
It has preinstalled all dependencies except FFTW.
## Simplified Raspberry Pi Build
If you target RaspberryPi, consider starting with PiSDR image (https://github.com/luigifcruz/pisdr-image) or DragonOS image (https://cemaxecuter.com/).
These systems have all required libraries preinstalled.
Below are instructions how to obtain and compile each package. Keep in mind, these are WIP and some adjustment to your build env may be needed.
You can also try starting with fresh/vanilla Raspberry Pi OS and download dependencies:
sudo apt install build-essential cmake libfftw3-single3 libboost-dev
sudo apt install rtl-sdr soapysdr-tools soapysdr-module-rtlsdr
If all depencencies are preinstalled, use these commands to build habdec:
git clone --recurse-submodules https://github.com/ogre/habdec.git
cd habdec
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=Off ../code
make
make install
## Full Build With Dependencies
Below are instructions how to obtain and compile each library. Keep in mind, these are WIP and some adjustment to your build env may be needed.
For windows, you need to start 64bit build env, ie: `C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat`

Wyświetl plik

@ -2,7 +2,7 @@
![alt text](./webClientScreenshot.png)
Habdec is a C++17 software to decode RTTY telemetry from High Altitude Balloons and upload it to [UKHAS Habitat](http://habitat.habhub.org/) and [sondehub.org](https://amateur.sondehub.org)
Habdec is a C++17 software to decode RTTY telemetry from High Altitude Balloons and upload it to ~~UKHAS Habitat~~ [sondehub.org](https://amateur.sondehub.org)
Some facts:
- builds and runs on Windows/Linux and x64/RaspberryPI/OdroixXU4 platforms
@ -73,8 +73,6 @@ CLI opts:
--lowpass arg lowpass bandwidth in Hertz
--lp_trans arg lowpass transition width. (0-1)
--sentence_cmd arg Call external command with sentence as parameter
--flights [=arg(=0)] List Habitat flights
--payload arg Configure for Payload ID
--sondehub arg (=https://api.v2.sondehub.org) sondehub API url
```
@ -157,32 +155,13 @@ habdecWebsocketServer.exe --device 0 --sampling_rate 2.5e6
--freq 434.5 --gain 20 --biast 1 --afc 1
```
Load configuration for specific Habitat Payload
```
./habdecWebsocketServer --flights
Habitat Flights:
Flight: Belice-3 6d8281c7b6e54c0c9f2488c77d043f8a
lat/lon: 49.7665 14.4731
Payload: DNA-3 289b03bf7a92e06cff8ab4fec1f789bd
RS41-1 Belice 10/11/2018 St. Martin's day
Flight ID: 6d8281c7b6e54c0c9f2488c77d043f8a
freq 434,250,000
baud/ascii/stops 50 7 2
./habdecWebsocketServer --payload 289b03bf7a92e06cff8ab4fec1f789bd
Loading parameters for payload 289b03bf7a92e06cff8ab4fec1f789bd
baud: 50
ascii_bits: 7
ascii_stops: 2
frequency: 434,250,000
```
### Web Client
To control habdec parameters from your browser:
- start browser
- open `habitat/code/webClient/index.html` file from disk
- open `habdec/code/webClient/index.html` file from disk
- set server field ip:port and Connect
Do not try connecting directly to `http://ip:port ` - habdec is not an HTTP server and you will see this error:
@ -193,19 +172,14 @@ Do not try connecting directly to `http://ip:port ` - habdec is not an HTTP serv
## Known Limitations
- RTTY Modes **NOT** supported: 5bit baudot, 1.5 bit stop
- Decoding will stop if decimation setting is too low or too high. It was tested to work with stream around 40kHz bandwidth.
- SSDV images are not uploaded to http://ssdv.habhub.org
- Automatic Frequency Correction needs more work. Use consciously. dc_remove=on can help if AFC is confused by center spike.
- Connecting from browser is not very reliable yet, sometimes you need to refresh and wait.
- habdec was developed and tested with [AirSpy](https://airspy.com/) and [OdroidXU4](http://hardkernel.com/),[RaspberryPI](http://raspberrypi.org). Support for windows and RtlSdr is less tested.
## Reporting Problems
Use bugtracker, please.
## Contributions
Gladly accepted :)
Use bugtracker.
## Authors

16
code/Decoder/CMakeLists.txt 100755 → 100644
Wyświetl plik

@ -3,11 +3,17 @@
include_directories( ${PROJECT_SOURCE_DIR} )
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
set ( FFTW3f_DIR ../CMake )
find_package( FFTW3f REQUIRED )
include_directories( ${FFTW3f_INCLUDE_DIRS} )
message( "FFTW Include:" ${FFTW3f_INCLUDE_DIRS} )
message( "FFTW Lib:" ${FFTW3f_LIBRARIES} )
if(DEFINED FFTW_ROOT) # custom FFTW build
set ( FFTW3f_DIR ../CMake )
find_package( FFTW3f REQUIRED )
include_directories( ${FFTW3f_INCLUDE_DIRS} )
message( "FFTW Include:" ${FFTW3f_INCLUDE_DIRS} )
message( "FFTW Lib:" ${FFTW3f_LIBRARIES} )
else()
find_package(PkgConfig REQUIRED)
pkg_search_module(FFTW REQUIRED fftw3f IMPORTED_TARGET)
link_libraries (PkgConfig::FFTW)
endif()
# RTTY DECODER

Wyświetl plik

@ -1,65 +0,0 @@
#pragma once
#include <string>
#include <map>
namespace habdec
{
namespace habitat
{
std::string HabitatUploadSentence(
const std::string& i_sentence,
const std::string& i_listener_callsign
);
struct HabitatPayload
{
std::string name_ {""};
std::string id_ {""};
std::string flight_id_ {""};
std::string desc_ {""};
int frequency_ = 0;
int baud_ = 0;
int ascii_bits_ = 0;
int ascii_stops_ = 0;
std::string coord_format_lat_ {""}; // dd.dddd or dd.mm.mmmm
std::string coord_format_lon_ {""}; // dd.dddd or dd.mm.mmmm
};
std::ostream&
operator<<(std::ostream& os, const HabitatPayload& p);
struct HabitatFlight
{
std::string id_ {""};
std::string name_ {""};
float lat_ = 0;
float lon_ = 0;
std::map<std::string, HabitatPayload> payloads_;
};
std::ostream&
operator<<(std::ostream& os, const HabitatFlight& f);
std::map<std::string, HabitatFlight>
ListFlights(int hour_offset);
int UploadStationInfo(
const std::string& i_callsign,
const std::string& i_radio
);
int UploadStationTelemetry(
const std::string& i_callsign,
const float i_lat, const float i_lon,
const float i_alt, const float i_speed,
bool i_chase
);
} // namespace habitat
} // namespace habdec

Wyświetl plik

@ -1,177 +0,0 @@
#include "habitat_interface.h"
#include "common/http_request.h"
#include <string>
#include <iostream>
#include <map>
#include <chrono>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "common/console_colors.h"
namespace
{
std::string FlightsListUrl(int hour_offset = 0)
{
using namespace std;
auto now = chrono::system_clock::now() + chrono::hours(hour_offset);
long int secs_since_ep = chrono::duration_cast<chrono::seconds>(
now.time_since_epoch() ).count();
return string("/habitat/_design/flight/_view/end_start_including_payloads?startkey=["
+ to_string(secs_since_ep) + "]"
+ "&include_docs=True");
}
std::map<std::string, habdec::habitat::HabitatFlight> ParseFlightsJson(const std::string& i_json_str)
{
using namespace std;
namespace pt = boost::property_tree;
using namespace habdec::habitat;
pt::ptree root;
stringstream ss; ss << i_json_str;
pt::read_json(ss, root);
std::map<string, HabitatFlight> flights_map;
// flights
//
for( pt::ptree::value_type& row : root.get_child("rows") )
{
auto& doc = row.second.get_child("doc");
if( doc.get<string>("type") != "flight" )
continue;
/*if( !doc.get<bool>("approved") )
continue;*/
HabitatFlight _f;
_f.name_ = doc.get<string>("name");
_f.id_ = doc.get<string>("_id");
_f.lat_ = doc.get_child("launch").get_child("location").get<float>("latitude");
_f.lon_ = doc.get_child("launch").get_child("location").get<float>("longitude");
flights_map[_f.id_] = _f;
}
// payloads
//
for( pt::ptree::value_type& row : root.get_child("rows") )
{
auto& doc = row.second.get_child("doc");
if( doc.get<string>("type") != "payload_configuration" )
continue;
HabitatPayload _p;
_p.flight_id_ = row.second.get<string>("id");
_p.name_ = doc.get<string>("name");
_p.id_ = doc.get<string>("_id");
if( doc.count("metadata") )
_p.desc_ = doc.get_child("metadata").get<string>("description", "no description");
auto& transmissions = doc.get_child("transmissions");
for(auto& t : transmissions )
{
if( t.second.get<string>("modulation") != "RTTY" )
continue;
string ascii_bits = t.second.get<string>("encoding");
if( ascii_bits == "ASCII-7" )
_p.ascii_bits_ = 7;
else if( ascii_bits == "ASCII-8" )
_p.ascii_bits_ = 8;
else
continue;
_p.baud_ = t.second.get<float>("baud");
_p.ascii_stops_ = t.second.get<float>("stop");
_p.frequency_ = t.second.get<float>("frequency");
break; // use first of RTTY transmissions
}
auto& sentences = doc.get_child("sentences");
for(auto& sentence : sentences)
{
auto& fields = sentence.second.get_child("fields");
for(auto& field : fields)
{
if( field.second.get<string>("name") == "latitude" )
_p.coord_format_lat_ = field.second.get<string>("format");
if( field.second.get<string>("name") == "longitude" )
_p.coord_format_lon_ = field.second.get<string>("format");
}
}
if(_p.baud_ && _p.ascii_bits_ && _p.ascii_stops_)
flights_map[_p.flight_id_].payloads_[_p.id_] = _p;
}
return flights_map;
}
} // namespace
namespace habdec
{
namespace habitat
{
std::ostream& operator<<(std::ostream& os, const habdec::habitat::HabitatPayload& p)
{
os << "Payload: " << p.name_ << " "
<< C_RED << p.id_ << C_OFF << "\n"
<< "\t" << p.desc_ << "\n"
<< "\tFlight ID: " << p.flight_id_<< "\n"
<< "\tfreq " << p.frequency_ << "\n"
<< "\tbaud/ascii/stops "
<< p.baud_ << " "
<< p.ascii_bits_ << " "
<< p.ascii_stops_;
return os;
}
std::ostream& operator<<(std::ostream& os, const habdec::habitat::HabitatFlight& f)
{
os << "Flight: " << f.name_ << " " << f.id_ << "\n"
<< "\tlat/lon: " << f.lat_ << " " << f.lon_ << "\n";
for(const auto& p : f.payloads_)
os << p.second << "\n";
return os;
}
std::map<std::string, habdec::habitat::HabitatFlight> ListFlights(int hour_offset)
{
using namespace std;
using namespace habdec::habitat;
string docs_json;
int result = HttpRequest(
"habitat.habhub.org", FlightsListUrl(hour_offset), 80,
habdec::HTTP_VERB::kGet, "application/json", "", docs_json );
std::map<std::string, HabitatFlight> flights;
if( result )
flights = ParseFlightsJson( docs_json );
else
cout<<"Habitat Flights List error: "<<result<<endl;
return flights;
}
} // namespace habitat
} // namespace habdec

Wyświetl plik

@ -1,260 +0,0 @@
#include "habitat_interface.h"
#include "common/http_request.h"
#include <string>
#include <vector>
#include <iostream>
#include <map>
#include <sstream>
#include <chrono>
#include <thread>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/c_local_time_adjustor.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "common/picosha2.h"
namespace
{
std::string sha256(const std::string& i_str)
{
using namespace std;
vector<unsigned char> hash(picosha2::k_digest_size);
picosha2::hash256(i_str.cbegin(), i_str.cend(), hash.begin(), hash.end());
return picosha2::bytes_to_hex_string(hash.begin(), hash.end());
}
const char encodeLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char padCharacter = '=';
std::string base64Encode(std::string inputBuffer)
{
using namespace std;
string encodedString;
encodedString.reserve(((inputBuffer.size()/3) + (inputBuffer.size() % 3 > 0)) * 4);
long temp;
auto cursor = inputBuffer.begin();
for(size_t idx = 0; idx < inputBuffer.size()/3; idx++)
{
temp = (*cursor++) << 16; //Convert to big endian
temp += (*cursor++) << 8;
temp += (*cursor++);
encodedString.append(1,encodeLookup[(temp & 0x00FC0000) >> 18]);
encodedString.append(1,encodeLookup[(temp & 0x0003F000) >> 12]);
encodedString.append(1,encodeLookup[(temp & 0x00000FC0) >> 6 ]);
encodedString.append(1,encodeLookup[(temp & 0x0000003F) ]);
}
switch(inputBuffer.size() % 3)
{
case 1:
temp = (*cursor++) << 16; //Convert to big endian
encodedString.append(1,encodeLookup[(temp & 0x00FC0000) >> 18]);
encodedString.append(1,encodeLookup[(temp & 0x0003F000) >> 12]);
encodedString.append(2,padCharacter);
break;
case 2:
temp = (*cursor++) << 16; //Convert to big endian
temp += (*cursor++) << 8;
encodedString.append(1,encodeLookup[(temp & 0x00FC0000) >> 18]);
encodedString.append(1,encodeLookup[(temp & 0x0003F000) >> 12]);
encodedString.append(1,encodeLookup[(temp & 0x00000FC0) >> 6 ]);
encodedString.append(1,padCharacter);
break;
}
return encodedString;
}
std::string UtcNow()
{
using namespace boost::posix_time;
ptime now = second_clock::universal_time();
return to_iso_extended_string(now) + "Z"; // habitat needs Z at the end
}
std::string SentenceToHabJson(
const std::string& i_sentence,
const std::string& i_listener_callsign
)
{
using namespace std;
using namespace boost::posix_time;
ptime now = second_clock::universal_time();
string utc_now_str = to_iso_extended_string(now) + "Z"; // habitat needs Z at the end
boost::property_tree::ptree root;
root.put( "type", "payload_telemetry" );
root.put( "data._raw", i_sentence );
root.put( "receivers." + i_listener_callsign + ".time_created", utc_now_str );
root.put( "receivers." + i_listener_callsign + ".time_uploaded", utc_now_str );
stringstream ss;
boost::property_tree::json_parser::write_json(ss, root);
return ss.str();
}
} // namespace
namespace habdec
{
namespace habitat
{
std::string HabitatUploadSentence(
const std::string& i_sentence,
const std::string& i_listener_callsign
)
{
using namespace std;
string sentence = i_sentence;
if( sentence.compare(0, 2, "$$") )
sentence = "$$" + sentence;
if( sentence.compare(sentence.size()-1, 1, "\n") )
sentence += "\n";
string sentence_b64 = base64Encode(sentence);
string sentence_sha256 = sha256(sentence_b64);
string sentence_json = SentenceToHabJson(sentence_b64, i_listener_callsign);
string result;
// return result;
int retries_left = 5;
while( retries_left-- )
{
int http_result = HttpRequest(
"habitat.habhub.org",
"/habitat/_design/payload_telemetry/_update/add_listener/" + sentence_sha256,
80,
habdec::HTTP_VERB::kPost,
"application/json",
sentence_json,
result
);
switch( http_result )
{
case 201: // Success
case 403: // Success, sentence has already seen by others
retries_left = 0;
break;
case 409: // Upload conflict (server busy). Sleep for a moment, then retry
default:
this_thread::sleep_for( ( chrono::duration<double, milli>(300) ) );
break;
}
}
return result;
}
int UploadStationInfo(
const std::string& i_callsign,
const std::string& i_radio
)
{
using namespace std;
using namespace boost::posix_time;
using namespace habdec;
ptime now = second_clock::universal_time();
string utc_now_str = to_iso_extended_string(now) + "Z"; // habitat needs Z at the end
const string info_template = R"_(
{
"type": "listener_information",
"data": {"callsign": "$callsign", "radio": "$radio" },
"time_created": "$time",
"time_uploaded": "$time"
}
)_";
string info_data_str = info_template;
info_data_str.replace( info_data_str.find("$callsign"), 9, i_callsign );
info_data_str.replace( info_data_str.find("$time"), 5, utc_now_str );
info_data_str.replace( info_data_str.find("$time"), 5, utc_now_str );
info_data_str.replace( info_data_str.find("$radio"), 6, i_radio );
string http_req_result;
int res = HttpRequest(
"habitat.habhub.org",
"/habitat",
80,
habdec::HTTP_VERB::kPost,
"application/json",
info_data_str,
http_req_result
);
return res;
}
int UploadStationTelemetry(
const std::string& i_callsign,
const float i_lat, const float i_lon,
const float i_alt, const float i_speed,
bool i_chase
)
{
using namespace std;
using namespace boost::posix_time;
using namespace habdec;
ptime now = second_clock::universal_time();
string utc_now_str = to_iso_extended_string(now) + "Z"; // habitat needs Z at the end
const string telemetry_template = R"_(
{
"type": "listener_telemetry",
"time_created": "$time",
"time_uploaded": "$time",
"data": {
"callsign": "$callsign",
"latitude": $lat,
"longitude": $lon,
"altitude": $alt,
"speed": $speed,
"chase": $chase
}
}
)_";
string telemetry_data_str = telemetry_template;
telemetry_data_str.replace( telemetry_data_str.find("$callsign"), 9, i_callsign );
telemetry_data_str.replace( telemetry_data_str.find("$time"), 5, utc_now_str );
telemetry_data_str.replace( telemetry_data_str.find("$time"), 5, utc_now_str );
telemetry_data_str.replace( telemetry_data_str.find("$lat"), 4, to_string(i_lat) );
telemetry_data_str.replace( telemetry_data_str.find("$lon"), 4, to_string(i_lon) );
telemetry_data_str.replace( telemetry_data_str.find("$alt"), 4, to_string(i_alt) );
telemetry_data_str.replace( telemetry_data_str.find("$speed"), 6, to_string(i_speed) );
telemetry_data_str.replace( telemetry_data_str.find("$chase"), 6, i_chase ? "true" : "false" );
string http_req_result;
int res = HttpRequest(
"habitat.habhub.org",
"/habitat",
80,
habdec::HTTP_VERB::kPost,
"application/json",
telemetry_data_str,
http_req_result
);
return res;
}
} // namespace habitat
} // namespace habdec

1
code/pyClient/habdecClient.py 100755 → 100644
Wyświetl plik

@ -137,7 +137,6 @@ def SendCommand(i_cmd):
set:decimation=2 get:decimation
set:afc=1 get:afc
set:dc_remove=1 get:dc_remove
set:payload=9f25cc048d401ebed112479a2ecef4f8
power:res=512,zoom=0.5
demod:res=256
liveprint

Wyświetl plik

@ -131,7 +131,6 @@ input[type=checkbox]
z-index: 1;
}
/* Payload Button */
.MenuDropMenu button {
display: block;
/* color: black; */

Wyświetl plik

@ -208,132 +208,6 @@ function toggleFullscreen(elem)
}
////////////////////////////////////////
///////////// Flights Menu /////////////
////////////////////////////////////////
function LoadFlightsData()
{
var d = new Date();
var now = d.getTime() / 1000;
var _url = 'http://habitat.habhub.org/habitat/_design/flight/_view/end_start_including_payloads?startkey=[' + now + ']&include_docs=True'
console.debug(_url);
let xhr = new XMLHttpRequest();
xhr.open('GET', _url);
xhr.onload = function () {
if (xhr.status != 200) {
console.debug("LoadFlightsData failed. Status: ", xhr.status);
} else {
LoadFlightsData_CB( JSON.parse(xhr.responseText) )
}
};
xhr.onerror = function () { alert("LoadFlightsData: Request to HTTP server failed."); };
xhr.send();
}
function LoadFlightsData_CB(i_data)
{
var FLIGHTS = {};
var flights = i_data["rows"];
for(i in flights)
{
var _id = flights[i]["id"];
var doc = flights[i]["doc"];
if(doc["type"] == "flight")
{
var payloads = doc["payloads"];
if(payloads && payloads.length)
{
FLIGHTS[_id] = {};
FLIGHTS[_id]["payloads"] = {};
for(p in payloads)
{
var payload_id = doc["payloads"][p];
FLIGHTS[_id]["payloads"][payload_id] = {};
}
}
}
}
for(i in flights)
{
var _id = flights[i]["id"];
var doc = flights[i]["doc"];
if(doc["type"] == "payload_configuration")
{
var payload_id = doc["_id"];
var transmissions = doc["transmissions"];
for(t_id in transmissions)
{
if(transmissions[t_id]["modulation"] == "RTTY")
{
FLIGHTS[_id]["payloads"][payload_id]["name"] = doc["name"];
FLIGHTS[_id]["payloads"][payload_id]["name"] = doc["name"];
FLIGHTS[_id]["payloads"][payload_id]["frequency"] = transmissions[t_id]["frequency"];
FLIGHTS[_id]["payloads"][payload_id]["baud"] = transmissions[t_id]["baud"];
FLIGHTS[_id]["payloads"][payload_id]["encoding"] = transmissions[t_id]["encoding"];
FLIGHTS[_id]["payloads"][payload_id]["stop"] = transmissions[t_id]["stop"];
}
}
}
}
UpdatePayloadsButton( FLIGHTS );
}
function CreatePayloadsButton()
{
var PayloadsWrapperDiv = document.getElementById("PayloadsWrapperDiv");
PayloadsWrapperDiv.classList.add("MenuDropdownWrapper");
var PayloadsButton = document.createElement("button");
PayloadsButton.classList.add("MenuDropButton");
PayloadsButton.id = "HabDec_PayloadsButton";
PayloadsButton.onclick = function() { document.getElementById("PayloadsDropMenuDiv").classList.toggle("show") };
PayloadsButton.innerHTML = "HabHub Flights";
PayloadsWrapperDiv.appendChild(PayloadsButton);
var DropMenuDiv = document.createElement("div");
DropMenuDiv.id = "PayloadsDropMenuDiv";
DropMenuDiv.classList.add("MenuDropMenu");
PayloadsWrapperDiv.appendChild(DropMenuDiv);
LoadFlightsData();
}
function UpdatePayloadsButton(i_Flights)
{
var DropMenuDiv = document.getElementById("PayloadsDropMenuDiv");
for(f_id in i_Flights)
{
for(p_id in i_Flights[f_id]["payloads"])
(
function(p_id)
{
var payload = i_Flights[f_id]["payloads"][p_id];
var label = payload["name"] + ": " + payload["baud"] + "Bd " + payload["encoding"] + "/" + payload["stop"] + " " + (parseInt(payload["frequency"])/1000000) + "MHz";
var pl_button = document.createElement("button");
pl_button.innerHTML = label;
pl_button.onclick = function(){
SetPayload(p_id);
document.getElementById('HabDec_PayloadsButton').click();
};
DropMenuDiv.appendChild(pl_button);
}
)(p_id)
}
}
////////////////////////////////////////
///////////// Color Schemes ////////////
////////////////////////////////////////
@ -685,10 +559,6 @@ function HABDEC_BUILD_UI(parent_div)
var div_server = HABDEC_BUILD_UI_Server();
//<!-- <div id="PayloadsWrapperDiv"></div> -->
// flights list
var div_payloads_wrapper = document.createElement("div");
div_payloads_wrapper.id = "PayloadsWrapperDiv";
// color schemes list
var div_colors_wrapper = document.createElement("div");
div_colors_wrapper.id = "ColorSchemesWrapperDiv";
@ -700,10 +570,9 @@ function HABDEC_BUILD_UI(parent_div)
btnFullscreen.onclick = () => { toggleFullscreen() };
div_but_fs.appendChild(btnFullscreen);
// div for [flights, colors, fillscreen] - in row
// div for [colors, fillscreen] - in row
var extra_options = document.createElement("div");
extra_options.style.display = 'flex';
extra_options.appendChild(div_payloads_wrapper);
extra_options.appendChild(div_colors_wrapper);
extra_options.appendChild(div_but_fs);
@ -717,7 +586,6 @@ function HABDEC_BUILD_UI(parent_div)
parent_div.appendChild(extra_options);
CreateControls();
CreatePayloadsButton();
CreateColorSchemesButton();
window.addEventListener('message', HB_WinMsgHandler);

Wyświetl plik

@ -442,8 +442,3 @@ function SetDCRemove()
button.style.color = "#000";
}
}
function SetPayload(i_payload_id)
{
SendCommand("set:payload=" + i_payload_id);
}

Wyświetl plik

@ -6,13 +6,23 @@ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
include_directories( ${PROJECT_SOURCE_DIR} )
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
set ( FFTW3f_DIR ../CMake )
find_package( FFTW3f REQUIRED )
include_directories( ${FFTW3f_INCLUDE_DIRS} )
if(DEFINED FFTW_ROOT) # custom FFTW build
set ( FFTW3f_DIR ../CMake )
find_package( FFTW3f REQUIRED )
include_directories( ${FFTW3f_INCLUDE_DIRS} )
message( "FFTW Include:" ${FFTW3f_INCLUDE_DIRS} )
message( "FFTW Lib:" ${FFTW3f_LIBRARIES} )
else()
find_package(PkgConfig REQUIRED)
pkg_search_module(FFTW REQUIRED fftw3f IMPORTED_TARGET)
link_libraries (PkgConfig::FFTW)
endif()
# boost
set ( Boost_NO_BOOST_CMAKE ON )
set ( Boost_NO_SYSTEM_PATHS ON ) #remove line to use system installed boost
if(DEFINED BOOST_ROOT) # custom boost build
set ( Boost_NO_SYSTEM_PATHS ON ) # don't use system installed boost
endif()
set ( Boost_USE_STATIC_LIBS ON )
add_definitions ( -DBOOST_ALL_NO_LIB )
find_package(Boost REQUIRED COMPONENTS program_options system date_time )
@ -57,8 +67,6 @@ set ( websocketServer_src
websocket_session.h websocket_session.cpp
ws_server.h ws_server.cpp
CompressedVector.h CompressedVector.cpp
${CMAKE_SOURCE_DIR}/habitat/habitat_upload.cpp
${CMAKE_SOURCE_DIR}/habitat/habitat_list_flights.cpp
${CMAKE_SOURCE_DIR}/sondehub/sondehub_uploader.cpp
${CMAKE_SOURCE_DIR}/common/http_request.cpp
${CMAKE_SOURCE_DIR}/common/GpsDistance.cpp

Wyświetl plik

@ -23,6 +23,7 @@
#include <vector>
#include <algorithm>
#include <iostream>
#include <limits>
namespace habdec
{
@ -83,7 +84,7 @@ public:
max_ = *std::max_element(values_.begin(), values_.end());
return max_;
}
private:
template<typename U>

Wyświetl plik

@ -79,7 +79,7 @@ public:
int device_ = 0; // index to SoapySDR::Device::enumerate()
std::string command_host_ = "0.0.0.0";
int command_port_ = 5555;
std::string station_callsign_ = ""; // habitat upload
std::string station_callsign_ = "";
float station_lat_ = 0;
float station_lon_ = 0;
float station_alt_ = 0;
@ -100,7 +100,6 @@ public:
float lowpass_tr_ = 0.025;
bool no_exit_ = false;
std::string sentence_cmd_ = "";
std::string habitat_payload_ = "";
std::string coord_format_lat_ = "dd.dddd"; // encoding of lat/lon coords: dd.dddd or ddmm.mmmm
std::string coord_format_lon_ = "dd.dddd"; // encoding of lat/lon coords: dd.dddd or ddmm.mmmm
std::string ssdv_dir_ = ".";
@ -138,7 +137,6 @@ public:
&& station_alt_ == rhs.station_alt_
&& sampling_rate_ == rhs.sampling_rate_
&& sentence_cmd_ == rhs.sentence_cmd_
&& habitat_payload_ == rhs.habitat_payload_
&& no_exit_ == rhs.no_exit_
&& coord_format_lat_ == rhs.coord_format_lat_
&& coord_format_lon_ == rhs.coord_format_lon_
@ -177,7 +175,6 @@ public:
oFile<<"lowpass = "<<GLOBALS::get().par_.lowpass_bw_Hz_<<endl;
oFile<<"lp_trans = "<<GLOBALS::get().par_.lowpass_tr_<<endl;
oFile<<"sentence_cmd = "<<GLOBALS::get().par_.sentence_cmd_<<endl;
oFile<<"payload = "<<GLOBALS::get().par_.habitat_payload_<<endl;
oFile<<"no_exit = "<<GLOBALS::get().par_.no_exit_<<endl;
oFile<<"sondehub = "<<GLOBALS::get().par_.sondehub_<<endl;
@ -199,7 +196,6 @@ public:
cout<<"\tcommand_host: "<<GLOBALS::get().par_.command_host_<<endl;
cout<<"\tcommand_port: "<<GLOBALS::get().par_.command_port_<<endl;
cout<<"\tsentence_cmd: "<<GLOBALS::get().par_.sentence_cmd_<<endl;
cout<<"\tpayload: "<<GLOBALS::get().par_.habitat_payload_<<endl;
cout<<"\tstation: "<<GLOBALS::get().par_.station_callsign_<<endl;
cout<<"\tlatlon: "<<GLOBALS::get().par_.station_lat_<<" "<<GLOBALS::get().par_.station_lon_<<endl;
cout<<"\talt: "<<GLOBALS::get().par_.station_alt_<<endl;

Wyświetl plik

@ -41,7 +41,6 @@ namespace websocket = boost::beast::websocket;
#include "common/console_colors.h"
#include "GLOBALS.h"
#include "NetTransport.h"
#include "habitat/habitat_interface.h"
// i_param == "" --> sends all parameters
@ -326,60 +325,6 @@ std::vector< std::shared_ptr<HabdecMessage> > HandleCommand(const std::string i
GLOBALS::get().par_.dc_remove_ = value;
result = EchoParameter("dc_remove");
}
else if( regex_match(i_command, match, regex(R"_(set\:payload=(\w+))_")) && match.size() > 1 )
{
using namespace habdec::habitat;
string payload_id = match[1];
std::map<std::string, HabitatFlight> flights;
try {
flights = ListFlights(0);
}
catch(const exception& e) {
cout<<"Failed loading flights list: "<<e.what()<<endl;
return result;
}
auto& DEC = GLOBALS::get().decoder_;
for(auto& flight : flights)
{
for(auto& payload : flight.second.payloads_)
{
if( !payload_id.compare(payload.second.id_) )
{
GLOBALS::get().par_.baud_ = payload.second.baud_;
GLOBALS::get().par_.rtty_ascii_bits_ = payload.second.ascii_bits_;
GLOBALS::get().par_.rtty_ascii_stops_ = payload.second.ascii_stops_;
GLOBALS::get().par_.frequency_ = payload.second.frequency_;
GLOBALS::get().par_.coord_format_lat_ = payload.second.coord_format_lat_;
GLOBALS::get().par_.coord_format_lon_ = payload.second.coord_format_lon_;
DEC.baud( GLOBALS::get().par_.baud_ );
DEC.rtty_bits( GLOBALS::get().par_.rtty_ascii_bits_ );
DEC.rtty_stops( GLOBALS::get().par_.rtty_ascii_stops_ );
GLOBALS::get().p_iq_source_->setOption("frequency_double", &GLOBALS::get().par_.frequency_);
cout<<C_MAGENTA<<"Loading parameters for payload "<<payload_id<<C_OFF<<endl;
cout<<"\tbaud: "<<GLOBALS::get().par_.baud_<<endl;
cout<<"\tascii_bits: "<<GLOBALS::get().par_.rtty_ascii_bits_<<endl;
cout<<"\tascii_stops: "<<GLOBALS::get().par_.rtty_ascii_stops_<<endl;
cout<<"\tfrequency: "<<GLOBALS::get().par_.frequency_<<endl;
break;
}
}
}
auto res_fr = EchoParameter("frequency");
auto res_bd = EchoParameter("baud");
auto res_rb = EchoParameter("rtty_bits");
auto res_rs = EchoParameter("rtty_stops");
result.insert( result.end(), res_fr.begin(), res_fr.end() );
result.insert( result.end(), res_bd.begin(), res_bd.end() );
result.insert( result.end(), res_rb.begin(), res_rb.end() );
result.insert( result.end(), res_rs.begin(), res_rs.end() );
}
else
{
cout<<C_RED<<"Unknown command: "<<i_command<<C_OFF<<endl;

86
code/websocketServer/main.cpp 100755 → 100644
Wyświetl plik

@ -39,7 +39,6 @@
#include "IQSource/IQSource_SoapySDR.h"
#include "Decoder/Decoder.h"
#include "common/console_colors.h"
#include "habitat/habitat_interface.h"
#include "GLOBALS.h"
#include "ws_server.h"
#include "common/git_repo_sha1.h"
@ -355,20 +354,6 @@ void SentenceCallback( std::string callsign, std::string data, std::string crc,
}
// habitat upload
if(GLOBALS::get().par_.station_callsign_ != "")
{
try {
string res = habdec::habitat::HabitatUploadSentence( sentence, GLOBALS::get().par_.station_callsign_ );
if( res != "OK" )
cout<<C_CLEAR<<C_RED<<"HAB Upload result: "<<res<<endl;
}
catch(const exception& e) {
cout<<"Failed upload to habitat: "<<e.what()<<endl;
}
}
// print distance and elevation
if( GLOBALS::get().par_.station_lat_ )
{
@ -515,53 +500,42 @@ int main(int argc, char** argv)
}
// station info
if( G.par_.station_callsign_ != "" )
if( G.par_.station_callsign_ != ""
&& G.par_.station_lat_
&& G.par_.station_lon_ )
{
habdec::habitat::UploadStationInfo( G.par_.station_callsign_,
device["driver"] + " - habdec" );
if( G.par_.station_lat_
&& G.par_.station_lon_ ) {
// habitat
cout<<"Uploading station info to HabHub."<<endl;
habdec::habitat::UploadStationTelemetry(
G.par_.station_callsign_,
G.par_.station_lat_, G.par_.station_lon_,
G.par_.station_alt_, 0, false
);
// sondehub
using json = nlohmann::json;
json sh_json;
sh_json["software_name"] = "habdec";
sh_json["software_version"] = string(g_GIT_SHA1).substr(0,7);
sh_json["uploader_callsign"] = G.par_.station_callsign_;
sh_json["uploader_position"] = vector<float>{
G.par_.station_lat_, G.par_.station_lon_, G.par_.station_alt_};
sh_json["uploader_radio"] = device["driver"];
sh_json["mobile"] = false;
// sondehub
using json = nlohmann::json;
json sh_json;
sh_json["software_name"] = "habdec";
sh_json["software_version"] = string(g_GIT_SHA1).substr(0,7);
sh_json["uploader_callsign"] = G.par_.station_callsign_;
sh_json["uploader_position"] = vector<float>{
G.par_.station_lat_, G.par_.station_lon_, G.par_.station_alt_};
sh_json["uploader_radio"] = device["driver"];
sh_json["mobile"] = false;
cout<<"Uploading station info to SondeHub."<<endl;
// cout<<sh_json<<endl;
stringstream s;
s<<sh_json;
cout<<"Uploading station info to SondeHub."<<endl;
// cout<<sh_json<<endl;
stringstream s;
s<<sh_json;
cpr::Response r = cpr::Put(
cpr::Url{G.par_.sondehub_ + "/amateur/listeners"},
cpr::Body{s.str()},
cpr::Header{
{"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0"},
{"Content-Type", "application/json"}
}
);
if(r.status_code != 200) {
cout<<"sondehub station info upload error:\n";
cout<<r.status_code<<endl; // 200
cout<<r.header["content-type"]<<endl; // application/json; charset=utf-8
cout<<r.text<<endl;
cpr::Response r = cpr::Put(
cpr::Url{G.par_.sondehub_ + "/amateur/listeners"},
cpr::Body{s.str()},
cpr::Header{
{"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0"},
{"Content-Type", "application/json"}
}
);
if(r.status_code != 200) {
cout<<"sondehub station info upload error:\n";
cout<<r.status_code<<endl; // 200
cout<<r.header["content-type"]<<endl; // application/json; charset=utf-8
cout<<r.text<<endl;
}
}

Wyświetl plik

@ -28,46 +28,6 @@
#include "GLOBALS.h"
#include "common/console_colors.h"
#include "habitat/habitat_interface.h"
namespace
{
int LoadPayloadParameters(std::string i_payload_id)
{
using namespace std;
using namespace habdec::habitat;
std::map<std::string, HabitatFlight> flights = ListFlights(0);
for(auto& flight : flights)
{
for(auto& payload : flight.second.payloads_)
{
if( !i_payload_id.compare(payload.second.id_) )
{
GLOBALS::get().par_.baud_ = payload.second.baud_;
GLOBALS::get().par_.rtty_ascii_bits_ = payload.second.ascii_bits_;
GLOBALS::get().par_.rtty_ascii_stops_ = payload.second.ascii_stops_;
GLOBALS::get().par_.frequency_ = payload.second.frequency_;
GLOBALS::get().par_.coord_format_lat_ = payload.second.coord_format_lat_;
GLOBALS::get().par_.coord_format_lon_ = payload.second.coord_format_lon_;
cout<<C_MAGENTA<<"Loading parameters for payload "<<i_payload_id<<C_OFF<<endl;
cout<<"\tbaud: "<<payload.second.baud_<<endl;
cout<<"\tascii_bits: "<<payload.second.ascii_bits_<<endl;
cout<<"\tascii_stops: "<<payload.second.ascii_stops_<<endl;
cout<<"\tfrequency: "<<payload.second.frequency_<<endl;
return 1;
}
}
}
return 0;
}
} // namespace
void prog_opts(int ac, char* av[])
{
@ -106,9 +66,6 @@ void prog_opts(int ac, char* av[])
("sentence_cmd", po::value<string>(), "Call external command with sentence as parameter")
("flights", po::value<int>()->implicit_value(0), "List Habitat flights")
("payload", po::value<string>(), "Configure for Payload ID")
("ssdv_dir", po::value<string>()->default_value(GLOBALS::get().par_.ssdv_dir_), "SSDV directory.")
("sondehub", po::value<string>()->default_value("https://api.v2.sondehub.org"), "sondehub API url")
@ -182,12 +139,6 @@ void prog_opts(int ac, char* av[])
{
GLOBALS::get().par_.station_callsign_ = vm["station"].as<string>();
}
if (vm.count("payload"))
{
GLOBALS::get().par_.habitat_payload_ = vm["payload"].as<string>();
if( !LoadPayloadParameters( GLOBALS::get().par_.habitat_payload_ ) )
cout<<C_RED<<"Failed loading payload "<<GLOBALS::get().par_.habitat_payload_ <<endl;
}
if (vm.count("sentence_cmd"))
{
GLOBALS::get().par_.sentence_cmd_ = vm["sentence_cmd"].as<string>();
@ -268,16 +219,6 @@ void prog_opts(int ac, char* av[])
GLOBALS::get().par_.rtty_ascii_bits_ = rtty_tokens[1];
GLOBALS::get().par_.rtty_ascii_stops_ = rtty_tokens[2];
}
if (vm.count("flights"))
{
using namespace habdec::habitat;
int hours_offset = vm["flights"].as<int>();
cout<<"Habitat Flights: "<<endl;
std::map<std::string, HabitatFlight> payloads = ListFlights(hours_offset);
for(auto& flight : payloads)
cout<<flight.second<<endl;
exit(0);
}
if (vm.count("latlon"))
{
vector<float> latlon_vec = vm["latlon"].as< vector<float> >();