test: ICOM ID-52 PLUS terminal mode over Bluetooth

pull/22/head
Citlali del Rey 5 months ago
parent 4d8cc8bd9d
commit 0aa7488ba3
No known key found for this signature in database
GPG Key ID: 342661C4F68CD06D

@ -19,6 +19,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <algorithm>
#include <exception>
#include <cstdio>
#include <cctype>
@ -53,6 +54,8 @@ bool CQnetITAP::Initialize(const std::string &cfgfile)
if (ReadConfig(cfgfile))
return true;
serialLog.open("serial.log", std::ios::out | std::ios::trunc | std::ios::binary);
std::string name("Gate2Modem");
name.append(1, RPTR_MOD);
printf("Opening %s\n", name.c_str());
@ -115,41 +118,44 @@ int CQnetITAP::OpenITAP()
return fd;
}
void CQnetITAP::DumpSerialPacket(const char *title, const unsigned char *buf)
void CQnetITAP::DumpSerialPacket(const char *title, const unsigned char *buf, const char dir)
{
serialLog.write(&dir, 1);
serialLog.write((char*)buf, buf[0]);
printf("%s: ", title);
if (buf[0] > 41)
{
printf("UNKNOWN: length=%u", (unsigned)buf[0]);
return;
}
//if (buf[0] > 41)
//{
// printf("UNKNOWN: length=%u\n", (unsigned)buf[0]);
// return;
//}
SITAP itap;
memcpy(&itap, buf, buf[0]);
memcpy(&itap, buf, std::min((size_t)buf[0], sizeof(SITAP)));
switch (itap.type)
{
case 0x03U: //pong
printf("Pong\n");
printf("Pong");
break;
case 0x10U: // header
case 0x20U:
printf("Header ur=%8.8s r1=%8.8s r2=%8.8s my=%8.8s/%4.4s", itap.header.ur, itap.header.r1, itap.header.r2, itap.header.my, itap.header.nm);
break;
case 0x13U: // bt data??
case 0x12U: // data
case 0x22U:
printf("Data count=%u seq=%u f=%02u%02u%02u a=%02u%02u%02u%02u%02u%02u%02u%02u%02u t=%02u%02u%02u\n", itap.voice.counter, itap.voice.sequence, itap.header.flag[0], itap.header.flag[1], itap.header.flag[2], itap.voice.ambe[0], itap.voice.ambe[1], itap.voice.ambe[2], itap.voice.ambe[3], itap.voice.ambe[4], itap.voice.ambe[5], itap.voice.ambe[6], itap.voice.ambe[7], itap.voice.ambe[8], itap.voice.text[0], itap.voice.text[1], itap.voice.text[2]);
printf("Data count=%u seq=%u f=%02u%02u%02u a=%02u%02u%02u%02u%02u%02u%02u%02u%02u t=%02u%02u%02u", itap.voice.counter, itap.voice.frame.sequence, itap.header.flag[0], itap.header.flag[1], itap.header.flag[2], itap.voice.frame.ambe[0], itap.voice.frame.ambe[1], itap.voice.frame.ambe[2], itap.voice.frame.ambe[3], itap.voice.frame.ambe[4], itap.voice.frame.ambe[5], itap.voice.frame.ambe[6], itap.voice.frame.ambe[7], itap.voice.frame.ambe[8], itap.voice.frame.text[0], itap.voice.frame.text[1], itap.voice.frame.text[2]);
break;
case 0x11U: // header acknowledgement
case 0x21U:
printf("Header acknowledgement code=%02u", itap.header.flag[0]);
break;
case 0x13U: // data acknowledgment
case 0x23U:
printf("Data acknowledgement seq=%02u code=%02u", itap.header.flag[0], itap.header.flag[1]);
break;
default:
printf("UNKNOWN packet buf[0] = 0x%02u\n", buf[0]);
printf("UNKNOWN packet buf[0] = 0x%02u", buf[0]);
break;
}
printf("\n");
}
REPLY_TYPE CQnetITAP::GetITAPData(unsigned char *buf)
@ -203,6 +209,8 @@ REPLY_TYPE CQnetITAP::GetITAPData(unsigned char *buf)
return RT_HEADER;
case 0x12U:
return RT_DATA;
case 0x13U:
return RT_DATA_BT;
case 0x21U:
return RT_HEADER_ACK;
case 0x23U:
@ -275,7 +283,10 @@ void CQnetITAP::Run()
if (keep_running && FD_ISSET(serfd, &readfds)) // there is something to read from the Icom!
{
switch (GetITAPData(buf))
auto res = GetITAPData(buf);
if (res != RT_TIMEOUT)
DumpSerialPacket("I", buf, 'I');
switch (res)
{
case RT_ERROR:
alive = false;
@ -299,6 +310,13 @@ void CQnetITAP::Run()
keep_running = false;
lastdataTimer.start();
break;
case RT_DATA_BT:
// TODO: how to ACK bluetooth packet? is it even
// needed/desired?
if (ProcessITAP(buf))
keep_running = false;
lastdataTimer.start();
break;
case RT_PONG:
if (! initialized)
{
@ -341,8 +359,6 @@ void CQnetITAP::Run()
case RT_TIMEOUT: // nothing or 0xff
break;
default:
if (buf[0] != 255)
DumpSerialPacket("GetITAPData returned", buf);
break;
}
FD_CLR(serfd, &readfds);
@ -380,7 +396,10 @@ void CQnetITAP::Run()
if (alive) {
SendToIcom(frame.data());
ackTimer.start();
acknowledged = false;
// TODO: radio does not ACK over BT, perhaps
// because we are sending one-by-one instead
// of by-fours.
acknowledged = true; // = false;
}
}
}
@ -397,6 +416,7 @@ void CQnetITAP::Run()
if (! alive)
{
close(serfd);
serialLog.close();
poll_counter = 0;
pingtime = 0.001;
initialized = false;
@ -425,10 +445,13 @@ void CQnetITAP::Close()
void CQnetITAP::SendToIcom(const unsigned char *buf)
{
serialLog << 'O';
ssize_t n;
unsigned int ptr = 0;
unsigned int length = (0xffu == buf[0]) ? 2 : buf[0];
serialLog.write((char*)buf, length);
while (ptr < length)
{
n = write(serfd, buf + ptr, length - ptr);
@ -492,14 +515,15 @@ bool CQnetITAP::ProcessGateway(const int len, const unsigned char *raw)
else // write an AMBE packet
{
itap.length = 16U;
itap.type = 0x22U;
itap.type = 0x22U; // TODO: what is used to write BT groups
// of 4?
itap.voice.counter = counter++;
itap.voice.sequence = dsvt.ctrl;
itap.voice.frame.sequence = dsvt.ctrl;
if (LOG_QSO && (dsvt.ctrl & 0x40))
printf("Queued ITAP end of stream\n");
if ((dsvt.ctrl & ~0x40U) > 20)
printf("DEBUG: ProcessGateway: unexpected voice sequence number %d\n", itap.voice.sequence);
memcpy(itap.voice.ambe, dsvt.vasd.voice, 12);
printf("DEBUG: ProcessGateway: unexpected voice sequence number %d\n", itap.voice.frame.sequence);
memcpy(itap.voice.frame.ambe, dsvt.vasd.voice, 12);
}
queue.push(CFrame(&itap.length));
@ -514,6 +538,8 @@ bool CQnetITAP::ProcessITAP(const unsigned char *buf)
static short stream_id = 0U;
SITAP itap;
unsigned int len = (0x10U == buf[1]) ? 41 : 16;
if (buf[1] == 0x13U) len = 56;
memcpy(&itap.length, buf, len); // transfer raw data to SITAP struct
// create a stream id if this is a header
@ -580,17 +606,36 @@ bool CQnetITAP::ProcessITAP(const unsigned char *buf)
}
else if (16 == len) // ambe
{
dsvt.ctrl = itap.voice.sequence;
memcpy(dsvt.vasd.voice, itap.voice.ambe, 12);
dsvt.ctrl = itap.voice.frame.sequence;
memcpy(dsvt.vasd.voice, itap.voice.frame.ambe, 12);
if (ToGate.Write(dsvt.title, 27))
{
printf("ERROR: ProcessMMDVM: Could not write gateway voice packet\n");
return true;
}
if (LOG_QSO && (dsvt.ctrl & 0x40))
if (LOG_QSO && (dsvt.ctrl & 0x40)) {
printf("Sent dsvt end of streamid=%04x\n", ntohs(dsvt.streamid));
}
}
else if (56 == len) // ambe-BT
{
for (int i = 0; i < itap.voice_bt.count; i++) {
dsvt.ctrl = itap.voice_bt.frame[i].sequence;
memcpy(dsvt.vasd.voice, itap.voice_bt.frame[i].ambe, 12);
if (ToGate.Write(dsvt.title, 27))
{
printf("ERROR: ProcessMMDVM: Could not write gateway voice packet\n");
return true;
}
if (LOG_QSO && ((dsvt.ctrl & 0x40))) {
printf("Sent dsvt end of streamid=%04x\n", ntohs(dsvt.streamid));
}
}
}
return false;
}

@ -20,6 +20,7 @@
#include <atomic>
#include <cstring>
#include <fstream>
#include <string>
#include <queue>
@ -40,9 +41,14 @@ enum REPLY_TYPE
RT_DATA,
RT_HEADER_ACK,
RT_DATA_ACK,
RT_PONG
RT_PONG,
RT_DATA_BT
};
struct ambe_frame {
unsigned char sequence;
unsigned char ambe[9];
unsigned char text[3];
};
// Icom Terminal and Access Point Mode data structure
#pragma pack(push, 1)
using SITAP = struct itap_tag
@ -74,10 +80,14 @@ using SITAP = struct itap_tag
struct
{
unsigned char counter; // ordinal counter is reset with each header
unsigned char sequence; // is modulo 21
unsigned char ambe[9];
unsigned char text[3];
ambe_frame frame;
} voice;
struct
{
unsigned char counter;
unsigned char count;
ambe_frame frame[4];
} voice_bt;
};
};
#pragma pack(pop)
@ -125,7 +135,7 @@ private:
void SendToIcom(const unsigned char *buf);
REPLY_TYPE GetITAPData(unsigned char *buf);
void calcPFCS(const unsigned char *packet, unsigned char *pfcs);
void DumpSerialPacket(const char *title, const unsigned char *);
void DumpSerialPacket(const char *title, const unsigned char *, const char dir);
// read configuration file
bool ReadConfig(const std::string &path);
@ -149,4 +159,6 @@ private:
// Queue
std::queue<CFrame> queue;
bool acknowledged;
std::ofstream serialLog;
};

Loading…
Cancel
Save

Powered by TurnKey Linux.