Add ASL Web Transceiver support
This commit is contained in:
parent
b30527395f
commit
4c83f05ed2
|
|
@ -430,6 +430,7 @@ contentItem: Text {
|
|||
droidstar.set_essid(settingsTab.comboEssid.currentText);
|
||||
droidstar.set_bm_password(settingsTab.bmpwEdit.text);
|
||||
droidstar.set_tgif_password(settingsTab.tgifpwEdit.text);
|
||||
droidstar.set_asl_password(settingsTab.aslpwEdit.text);
|
||||
droidstar.set_latitude(settingsTab.latEdit.text);
|
||||
droidstar.set_longitude(settingsTab.lonEdit.text);
|
||||
droidstar.set_location(settingsTab.locEdit.text);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ I am excited to announce the release of several new features and improvements:
|
|||
|
||||
- **Recent TG-ID Dropdown**: The dropdown records all the recently dialed Talk Group ids and lets you choose from the list. You no longer have to memorize the TG ID.
|
||||
|
||||
- **ASL Web Transceiver**: Allows you to connect to any ASL node with your ASL password.
|
||||
|
||||
## Downloads
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ Item {
|
|||
property alias comboEssid: comboessid
|
||||
property alias bmpwEdit: bmpwedit
|
||||
property alias tgifpwEdit: tgifpwedit
|
||||
property alias aslpwEdit: aslpwedit
|
||||
property alias latEdit: latedit
|
||||
property alias lonEdit: lonedit
|
||||
property alias locEdit: locedit
|
||||
|
|
@ -259,11 +260,30 @@ Item {
|
|||
echoMode: TextInput.Password
|
||||
}
|
||||
Text {
|
||||
id: latLabel
|
||||
id: aslpwLabel
|
||||
x: 10
|
||||
y: 270
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("ASL Pass")
|
||||
color: "white"
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
TextField {
|
||||
id: aslpwedit
|
||||
x: 100
|
||||
y: aslpwLabel.y
|
||||
width: parent.width - 110
|
||||
height: 25
|
||||
selectByMouse: true
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
Text {
|
||||
id: latLabel
|
||||
x: 10
|
||||
y: 300
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("Latitude")
|
||||
color: "white"
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
|
@ -279,7 +299,7 @@ Item {
|
|||
Text {
|
||||
id: lonLabel
|
||||
x: 10
|
||||
y: 300
|
||||
y: 330
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("Longitude")
|
||||
|
|
@ -297,7 +317,7 @@ Item {
|
|||
Text {
|
||||
id: locLabel
|
||||
x: 10
|
||||
y: 330
|
||||
y: 360
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("Location")
|
||||
|
|
@ -315,7 +335,7 @@ Item {
|
|||
Text {
|
||||
id: descLabel
|
||||
x: 10
|
||||
y: 360
|
||||
y: 390
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("Description")
|
||||
|
|
@ -333,7 +353,7 @@ Item {
|
|||
Text {
|
||||
id: urlLabel
|
||||
x: 10
|
||||
y: 390
|
||||
y: 420
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("URL")
|
||||
|
|
@ -351,7 +371,7 @@ Item {
|
|||
Text {
|
||||
id: swidLabel
|
||||
x: 10
|
||||
y: 420
|
||||
y: 450
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("SoftwareID")
|
||||
|
|
@ -369,7 +389,7 @@ Item {
|
|||
Text {
|
||||
id: pkgidLabel
|
||||
x: 10
|
||||
y: 450
|
||||
y: 480
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("PackageID")
|
||||
|
|
@ -387,7 +407,7 @@ Item {
|
|||
Text {
|
||||
id: dmroptslabel
|
||||
x: 10
|
||||
y: 480
|
||||
y: 510
|
||||
width: 80
|
||||
height: 25
|
||||
text: qsTr("DMR+ Opts")
|
||||
|
|
|
|||
|
|
@ -358,6 +358,56 @@ void DroidStar::tts_text_changed(QString ttstxt)
|
|||
emit input_source_changed(m_tts, m_ttstxt);
|
||||
}
|
||||
|
||||
|
||||
void DroidStar::obtain_asl_wt_creds()
|
||||
{
|
||||
if (!m_wt_callingname.isEmpty() && (m_asl_password == m_wt_callingname_pass)) {
|
||||
return;
|
||||
}
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||
QUrl url("https://www.allstarlink.org/portal/login.php");
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QByteArray postData;
|
||||
postData.append("user=" + QUrl::toPercentEncoding(m_callsign.toUtf8()));
|
||||
postData.append("&pass=" + QUrl::toPercentEncoding(m_asl_password.toUtf8()));
|
||||
|
||||
connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QUrl url("https://www.allstarlink.org/portal/webtransceiver.php?node=12345");
|
||||
QNetworkRequest request(url);
|
||||
|
||||
connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QString html = reply->readAll();
|
||||
QStringList l = html.split('\n');
|
||||
for (int i = 0; i < l.size(); i++) {
|
||||
if (l.at(i).contains("callingName")) {
|
||||
QStringList ll = l.at(i).split('"');
|
||||
m_wt_callingname = ll.at(3);
|
||||
m_wt_callingname_pass = m_asl_password;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle error
|
||||
qDebug() << "Error: " << reply->errorString();
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
|
||||
manager->get(request);
|
||||
} else {
|
||||
// Handle error
|
||||
qDebug() << "Error: " << reply->errorString();
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
|
||||
manager->post(request, postData);
|
||||
}
|
||||
|
||||
void DroidStar::process_connect()
|
||||
{
|
||||
if(connect_status != Mode::DISCONNECTED){
|
||||
|
|
@ -465,7 +515,7 @@ void DroidStar::process_connect()
|
|||
if(m_protocol == "IAX"){
|
||||
QString iaxuser = sl.at(2).simplified();
|
||||
QString iaxpass = sl.at(3).simplified();
|
||||
m_mode->set_iax_params(iaxuser, iaxpass, m_refname, m_host, m_port);
|
||||
m_mode->set_iax_params(iaxuser, iaxpass, m_wt_callingname, m_refname, m_host, m_port);
|
||||
connect(this, SIGNAL(send_dtmf(QByteArray)), m_mode, SLOT(send_dtmf(QByteArray)));
|
||||
}
|
||||
|
||||
|
|
@ -652,6 +702,9 @@ void DroidStar::process_mode_change(const QString &m)
|
|||
}
|
||||
if(m == "IAX"){
|
||||
process_iax_hosts();
|
||||
if (!m_asl_password.isEmpty()) {
|
||||
obtain_asl_wt_creds();
|
||||
}
|
||||
m_label1 = "";
|
||||
m_label2 = "";
|
||||
m_label3 = "";
|
||||
|
|
@ -684,6 +737,7 @@ void DroidStar::save_settings()
|
|||
m_settings->setValue("ESSID", m_essid);
|
||||
m_settings->setValue("BMPASSWORD", m_bm_password);
|
||||
m_settings->setValue("TGIFPASSWORD", m_tgif_password);
|
||||
m_settings->setValue("ASLPASSWORD", m_asl_password);
|
||||
m_settings->setValue("DMRTGID", m_dmr_destid);
|
||||
m_settings->setValue("DMRLAT", m_latitude);
|
||||
m_settings->setValue("DMRLONG", m_longitude);
|
||||
|
|
@ -746,6 +800,7 @@ void DroidStar::process_settings()
|
|||
m_essid = m_settings->value("ESSID").toString().simplified().toUInt();
|
||||
m_bm_password = m_settings->value("BMPASSWORD").toString().simplified();
|
||||
m_tgif_password = m_settings->value("TGIFPASSWORD").toString().simplified();
|
||||
m_asl_password = m_settings->value("ASLPASSWORD").toString().simplified();
|
||||
m_latitude = m_settings->value("DMRLAT", "0").toString().simplified();
|
||||
m_longitude = m_settings->value("DMRLONG", "0").toString().simplified();
|
||||
m_location = m_settings->value("DMRLOC").toString().simplified();
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ public slots:
|
|||
}
|
||||
void set_bm_password(const QString &bmpwd) { m_bm_password = bmpwd; save_settings(); }
|
||||
void set_tgif_password(const QString &tgifpwd) { m_tgif_password = tgifpwd; save_settings(); }
|
||||
void set_asl_password(const QString &aslpwd) { m_asl_password = aslpwd; save_settings(); }
|
||||
void set_latitude(const QString &lat){ m_latitude = lat; save_settings(); }
|
||||
void set_longitude(const QString &lon){ m_longitude = lon; save_settings(); }
|
||||
void set_location(const QString &loc){ m_location = loc; save_settings(); }
|
||||
|
|
@ -206,6 +207,7 @@ public slots:
|
|||
QString get_essid() { return m_essid ? QString("%1").arg(m_essid - 1, 2, 10, QChar('0')) : "None"; }
|
||||
QString get_bm_password() { return m_bm_password; }
|
||||
QString get_tgif_password() { return m_tgif_password; }
|
||||
QString get_asl_password() { return m_asl_password; }
|
||||
QString get_latitude() { return m_latitude; }
|
||||
QString get_longitude() { return m_longitude; }
|
||||
QString get_location() { return m_location; }
|
||||
|
|
@ -283,6 +285,7 @@ public slots:
|
|||
void set_output_level(unsigned short l){ m_outlevel = l; }
|
||||
void tts_changed(QString);
|
||||
void tts_text_changed(QString);
|
||||
void obtain_asl_wt_creds();
|
||||
private:
|
||||
int connect_status;
|
||||
bool m_update_host_files;
|
||||
|
|
@ -298,6 +301,7 @@ private:
|
|||
QString m_protocol;
|
||||
QString m_bm_password;
|
||||
QString m_tgif_password;
|
||||
QString m_asl_password;
|
||||
QString m_latitude;
|
||||
QString m_longitude;
|
||||
QString m_location;
|
||||
|
|
@ -372,6 +376,8 @@ private:
|
|||
QStringList m_playbacks;
|
||||
QStringList m_captures;
|
||||
bool m_mdirect;
|
||||
QString m_wt_callingname;
|
||||
QString m_wt_callingname_pass;
|
||||
|
||||
int m_tts;
|
||||
QString m_ttstxt;
|
||||
|
|
|
|||
95
iax.cpp
95
iax.cpp
|
|
@ -48,7 +48,8 @@ IAX::IAX() :
|
|||
m_rxdropped(0),
|
||||
m_rxooo(0),
|
||||
m_ttsid(0),
|
||||
m_cnt(0)
|
||||
m_cnt(0),
|
||||
m_wt(false)
|
||||
{
|
||||
#ifdef USE_FLITE
|
||||
flite_init();
|
||||
|
|
@ -62,13 +63,14 @@ IAX::~IAX()
|
|||
{
|
||||
}
|
||||
|
||||
void IAX::set_iax_params(QString username, QString password, QString node, QString host, int port)
|
||||
void IAX::set_iax_params(QString username, QString password, QString callingname, QString node, QString host, int port)
|
||||
{
|
||||
m_username = username;
|
||||
m_password = password;
|
||||
m_node = node;
|
||||
m_host = host;
|
||||
m_port = port;
|
||||
m_callingname = callingname;
|
||||
|
||||
QStringList l = m_node.split('@');
|
||||
if(l.size() == 2){
|
||||
|
|
@ -78,6 +80,10 @@ void IAX::set_iax_params(QString username, QString password, QString node, QStri
|
|||
else{
|
||||
m_context = "iax-client";
|
||||
}
|
||||
|
||||
if (m_username == "allstar-public" && m_password == "allstar") {
|
||||
m_wt = true;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t ulaw_decode(int8_t number)
|
||||
|
|
@ -123,6 +129,9 @@ int8_t ulaw_encode(int16_t number)
|
|||
|
||||
void IAX::send_call()
|
||||
{
|
||||
if (m_wt) {
|
||||
//send_disconnect();
|
||||
}
|
||||
uint16_t scall = htons(++m_scallno | 0x8000);
|
||||
m_oseq = m_iseq = 0;
|
||||
QByteArray out;
|
||||
|
|
@ -142,13 +151,28 @@ void IAX::send_call()
|
|||
out.append('\x00');
|
||||
out.append(IAX_PROTO_VERSION);
|
||||
out.append(IAX_IE_CALLED_NUMBER);
|
||||
out.append(m_node.size());
|
||||
out.append(m_node.toUtf8(), m_node.size());
|
||||
if (m_wt) {
|
||||
out.append('\x01');
|
||||
out.append('s');
|
||||
} else {
|
||||
out.append(m_node.size());
|
||||
out.append(m_node.toUtf8(), m_node.size());
|
||||
}
|
||||
out.append(IAX_IE_CALLING_NUMBER);
|
||||
out.append('\x00');
|
||||
if (m_wt) {
|
||||
out.append(m_node.size());
|
||||
out.append(m_node.toUtf8(), m_node.size());
|
||||
} else {
|
||||
out.append('\x00');
|
||||
}
|
||||
out.append(IAX_IE_CALLING_NAME);
|
||||
out.append(m_callsign.size());
|
||||
out.append(m_callsign.toUtf8(), m_callsign.size());
|
||||
if (m_wt) {
|
||||
out.append(m_callingname.size());
|
||||
out.append(m_callingname.toUtf8(), m_callingname.size());
|
||||
} else {
|
||||
out.append(m_callsign.size());
|
||||
out.append(m_callsign.toUtf8(), m_callsign.size());
|
||||
}
|
||||
out.append(IAX_IE_USERNAME);
|
||||
out.append(m_username.size());
|
||||
out.append(m_username.toUtf8(), m_username.size());
|
||||
|
|
@ -499,10 +523,16 @@ void IAX::hostname_lookup(QHostInfo i)
|
|||
m_udp = new QUdpSocket(this);
|
||||
m_regtimer = new QTimer();
|
||||
connect(m_udp, SIGNAL(readyRead()), this, SLOT(process_udp()));
|
||||
connect(m_regtimer, SIGNAL(timeout()), this, SLOT(send_registration()));
|
||||
if (m_wt) {
|
||||
connect(m_regtimer, SIGNAL(timeout()), this, SLOT(send_call()));
|
||||
send_call();
|
||||
//m_regtimer->start(240000);
|
||||
} else {
|
||||
connect(m_regtimer, SIGNAL(timeout()), this, SLOT(send_registration()));
|
||||
send_registration(0);
|
||||
m_regtimer->start(60000);
|
||||
}
|
||||
m_timestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
send_registration(0);
|
||||
m_regtimer->start(60000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -608,6 +638,9 @@ void IAX::process_udp()
|
|||
{
|
||||
//int16_t zeropcm[160];
|
||||
//memset(zeropcm, 0, 160 * sizeof(int16_t));
|
||||
if (m_wt && m_modeinfo.status == CONNECTING) {
|
||||
connected();
|
||||
}
|
||||
++m_rxframes;
|
||||
m_dcallno = (((buf.data()[0] & 0x7f) << 8) | ((uint8_t)buf.data()[1]));
|
||||
m_iseq = buf.data()[8] + 1;
|
||||
|
|
@ -620,22 +653,7 @@ void IAX::process_udp()
|
|||
(buf.data()[11] == AST_CONTROL_ANSWER) )
|
||||
{
|
||||
if(m_modeinfo.status == CONNECTING){
|
||||
m_modeinfo.status = CONNECTED_RW;
|
||||
m_txtimer = new QTimer();
|
||||
connect(m_txtimer, SIGNAL(timeout()), this, SLOT(transmit()));
|
||||
m_rxtimer = new QTimer();
|
||||
connect(m_rxtimer, SIGNAL(timeout()), this, SLOT(process_rx_data()));
|
||||
m_rxtimer->start(19);
|
||||
m_pingtimer = new QTimer();
|
||||
connect(m_pingtimer, SIGNAL(timeout()), this, SLOT(send_ping()));
|
||||
m_pingtimer->start(2000);
|
||||
m_audio = new AudioEngine(m_audioin, m_audioout);
|
||||
m_audio->init();
|
||||
m_audio->start_playback();
|
||||
m_audio->set_input_buffer_size(640);
|
||||
m_audio->start_capture();
|
||||
//m_txtimer->start(19);
|
||||
m_modeinfo.sw_vocoder_loaded = true;
|
||||
connected();
|
||||
}
|
||||
++m_rxframes;
|
||||
m_dcallno = (((buf.data()[0] & 0x7f) << 8) | ((uint8_t)buf.data()[1]));
|
||||
|
|
@ -735,6 +753,25 @@ void IAX::process_udp()
|
|||
emit update(m_modeinfo);
|
||||
}
|
||||
|
||||
void IAX::connected() {
|
||||
m_modeinfo.status = CONNECTED_RW;
|
||||
m_txtimer = new QTimer();
|
||||
connect(m_txtimer, SIGNAL(timeout()), this, SLOT(transmit()));
|
||||
m_rxtimer = new QTimer();
|
||||
connect(m_rxtimer, SIGNAL(timeout()), this, SLOT(process_rx_data()));
|
||||
m_rxtimer->start(19);
|
||||
m_pingtimer = new QTimer();
|
||||
connect(m_pingtimer, SIGNAL(timeout()), this, SLOT(send_ping()));
|
||||
m_pingtimer->start(2000);
|
||||
m_audio = new AudioEngine(m_audioin, m_audioout);
|
||||
m_audio->init();
|
||||
m_audio->start_playback();
|
||||
m_audio->set_input_buffer_size(640);
|
||||
m_audio->start_capture();
|
||||
//m_txtimer->start(19);
|
||||
m_modeinfo.sw_vocoder_loaded = true;
|
||||
}
|
||||
|
||||
void IAX::process_rx_data()
|
||||
{
|
||||
int16_t pcm[160];
|
||||
|
|
@ -757,12 +794,14 @@ void IAX::toggle_tx(bool tx)
|
|||
|
||||
void IAX::start_tx()
|
||||
{
|
||||
int16_t pcm[160];
|
||||
//std::cerr << "Pressed TX buffersize == " << audioin->bufferSize() << std::endl;
|
||||
//QByteArray tx("*99", 3);
|
||||
//send_dtmf(tx);
|
||||
send_radio_key(true);
|
||||
m_ttscnt = 0;
|
||||
qDebug() << "start_tx() " << m_ttsid << " " << m_ttstext;
|
||||
while(m_audio->read(pcm));
|
||||
m_tx = true;
|
||||
#ifdef USE_FLITE
|
||||
if(m_ttsid == 1){
|
||||
|
|
@ -820,7 +859,9 @@ void IAX::transmit()
|
|||
for(int i = 0; i < s; ++i){
|
||||
out.append(ulaw_encode(pcm[i]));
|
||||
}
|
||||
m_udp->writeDatagram(out, m_address, m_port);
|
||||
if (!m_wt || m_tx) {
|
||||
m_udp->writeDatagram(out, m_address, m_port);
|
||||
}
|
||||
#ifdef DEBUGG
|
||||
fprintf(stderr, "SEND: ");
|
||||
for(int i = 0; i < out.size(); ++i){
|
||||
|
|
|
|||
5
iax.h
5
iax.h
|
|
@ -26,7 +26,7 @@ class IAX : public Mode
|
|||
public:
|
||||
IAX();//QString callsign, QString username, QString password, QString node, QString host, int port, QString audioin, QString audioout);
|
||||
~IAX();
|
||||
void set_iax_params(QString username, QString password, QString node, QString host, int port);
|
||||
void set_iax_params(QString username, QString password, QString callingname, QString node, QString host, int port);
|
||||
//uint8_t get_status(){ return m_status; }
|
||||
QString get_host() { return m_host; }
|
||||
int get_port() { return m_port; }
|
||||
|
|
@ -54,12 +54,14 @@ private slots:
|
|||
void send_radio_key(bool);
|
||||
void in_audio_vol_changed(qreal v){ m_audio->set_input_volume(v); }
|
||||
void out_audio_vol_changed(qreal v){ m_audio->set_output_volume(v); }
|
||||
void connected();
|
||||
private:
|
||||
QUdpSocket *m_udp = nullptr;
|
||||
QHostAddress m_address;
|
||||
QString m_callsign;
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
QString m_callingname;
|
||||
QString m_node;
|
||||
QString m_context;
|
||||
QString m_host;
|
||||
|
|
@ -93,6 +95,7 @@ private:
|
|||
QString m_ttstext;
|
||||
uint16_t m_ttscnt;
|
||||
int m_cnt;
|
||||
bool m_wt;
|
||||
//qreal m_rxgain;
|
||||
#ifdef USE_FLITE
|
||||
cst_voice *voice_slt;
|
||||
|
|
|
|||
1
main.qml
1
main.qml
|
|
@ -530,6 +530,7 @@ ApplicationWindow {
|
|||
settingsTab.comboEssid.currentIndex = settingsTab.comboEssid.find(droidstar.get_essid());
|
||||
settingsTab.bmpwEdit.text = droidstar.get_bm_password();
|
||||
settingsTab.tgifpwEdit.text = droidstar.get_tgif_password();
|
||||
settingsTab.aslpwEdit.text = droidstar.get_asl_password();
|
||||
settingsTab.latEdit.text = droidstar.get_latitude();
|
||||
settingsTab.lonEdit.text = droidstar.get_longitude();
|
||||
settingsTab.locEdit.text = droidstar.get_location();
|
||||
|
|
|
|||
2
mode.h
2
mode.h
|
|
@ -70,7 +70,7 @@ public:
|
|||
m_m17TXLevel = m17TXLevel;
|
||||
}
|
||||
virtual void set_dmr_params(uint8_t, QString, QString, QString, QString, QString, QString, QString, QString, QString, QString) {}
|
||||
virtual void set_iax_params(QString, QString, QString, QString, int) {}
|
||||
virtual void set_iax_params(QString, QString, QString, QString, QString, int) {}
|
||||
bool get_hwrx() { return m_hwrx; }
|
||||
bool get_hwtx() { return m_hwtx; }
|
||||
void set_hostname(std::string);
|
||||
|
|
|
|||
Loading…
Reference in New Issue