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. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <algorithm>
#include <exception> #include <exception>
#include <cstdio> #include <cstdio>
#include <cctype> #include <cctype>
@ -53,6 +54,8 @@ bool CQnetITAP::Initialize(const std::string &cfgfile)
if (ReadConfig(cfgfile)) if (ReadConfig(cfgfile))
return true; return true;
serialLog.open("serial.log", std::ios::out | std::ios::trunc | std::ios::binary);
std::string name("Gate2Modem"); std::string name("Gate2Modem");
name.append(1, RPTR_MOD); name.append(1, RPTR_MOD);
printf("Opening %s\n", name.c_str()); printf("Opening %s\n", name.c_str());
@ -115,41 +118,44 @@ int CQnetITAP::OpenITAP()
return fd; 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); printf("%s: ", title);
if (buf[0] > 41) //if (buf[0] > 41)
{ //{
printf("UNKNOWN: length=%u", (unsigned)buf[0]); // printf("UNKNOWN: length=%u\n", (unsigned)buf[0]);
return; // return;
} //}
SITAP itap; SITAP itap;
memcpy(&itap, buf, buf[0]); memcpy(&itap, buf, std::min((size_t)buf[0], sizeof(SITAP)));
switch (itap.type) switch (itap.type)
{ {
case 0x03U: //pong case 0x03U: //pong
printf("Pong\n"); printf("Pong");
break; break;
case 0x10U: // header case 0x10U: // header
case 0x20U: 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); 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; break;
case 0x13U: // bt data??
case 0x12U: // data case 0x12U: // data
case 0x22U: 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; break;
case 0x11U: // header acknowledgement case 0x11U: // header acknowledgement
case 0x21U: case 0x21U:
printf("Header acknowledgement code=%02u", itap.header.flag[0]); printf("Header acknowledgement code=%02u", itap.header.flag[0]);
break; break;
case 0x13U: // data acknowledgment
case 0x23U: case 0x23U:
printf("Data acknowledgement seq=%02u code=%02u", itap.header.flag[0], itap.header.flag[1]); printf("Data acknowledgement seq=%02u code=%02u", itap.header.flag[0], itap.header.flag[1]);
break; break;
default: default:
printf("UNKNOWN packet buf[0] = 0x%02u\n", buf[0]); printf("UNKNOWN packet buf[0] = 0x%02u", buf[0]);
break; break;
} }
printf("\n");
} }
REPLY_TYPE CQnetITAP::GetITAPData(unsigned char *buf) REPLY_TYPE CQnetITAP::GetITAPData(unsigned char *buf)
@ -203,6 +209,8 @@ REPLY_TYPE CQnetITAP::GetITAPData(unsigned char *buf)
return RT_HEADER; return RT_HEADER;
case 0x12U: case 0x12U:
return RT_DATA; return RT_DATA;
case 0x13U:
return RT_DATA_BT;
case 0x21U: case 0x21U:
return RT_HEADER_ACK; return RT_HEADER_ACK;
case 0x23U: case 0x23U:
@ -275,7 +283,10 @@ void CQnetITAP::Run()
if (keep_running && FD_ISSET(serfd, &readfds)) // there is something to read from the Icom! 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: case RT_ERROR:
alive = false; alive = false;
@ -299,6 +310,13 @@ void CQnetITAP::Run()
keep_running = false; keep_running = false;
lastdataTimer.start(); lastdataTimer.start();
break; 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: case RT_PONG:
if (! initialized) if (! initialized)
{ {
@ -341,8 +359,6 @@ void CQnetITAP::Run()
case RT_TIMEOUT: // nothing or 0xff case RT_TIMEOUT: // nothing or 0xff
break; break;
default: default:
if (buf[0] != 255)
DumpSerialPacket("GetITAPData returned", buf);
break; break;
} }
FD_CLR(serfd, &readfds); FD_CLR(serfd, &readfds);
@ -380,7 +396,10 @@ void CQnetITAP::Run()
if (alive) { if (alive) {
SendToIcom(frame.data()); SendToIcom(frame.data());
ackTimer.start(); 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) if (! alive)
{ {
close(serfd); close(serfd);
serialLog.close();
poll_counter = 0; poll_counter = 0;
pingtime = 0.001; pingtime = 0.001;
initialized = false; initialized = false;
@ -425,10 +445,13 @@ void CQnetITAP::Close()
void CQnetITAP::SendToIcom(const unsigned char *buf) void CQnetITAP::SendToIcom(const unsigned char *buf)
{ {
serialLog << 'O';
ssize_t n; ssize_t n;
unsigned int ptr = 0; unsigned int ptr = 0;
unsigned int length = (0xffu == buf[0]) ? 2 : buf[0]; unsigned int length = (0xffu == buf[0]) ? 2 : buf[0];
serialLog.write((char*)buf, length);
while (ptr < length) while (ptr < length)
{ {
n = write(serfd, buf + ptr, length - ptr); 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 else // write an AMBE packet
{ {
itap.length = 16U; 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.counter = counter++;
itap.voice.sequence = dsvt.ctrl; itap.voice.frame.sequence = dsvt.ctrl;
if (LOG_QSO && (dsvt.ctrl & 0x40)) if (LOG_QSO && (dsvt.ctrl & 0x40))
printf("Queued ITAP end of stream\n"); printf("Queued ITAP end of stream\n");
if ((dsvt.ctrl & ~0x40U) > 20) if ((dsvt.ctrl & ~0x40U) > 20)
printf("DEBUG: ProcessGateway: unexpected voice sequence number %d\n", itap.voice.sequence); printf("DEBUG: ProcessGateway: unexpected voice sequence number %d\n", itap.voice.frame.sequence);
memcpy(itap.voice.ambe, dsvt.vasd.voice, 12); memcpy(itap.voice.frame.ambe, dsvt.vasd.voice, 12);
} }
queue.push(CFrame(&itap.length)); queue.push(CFrame(&itap.length));
@ -514,6 +538,8 @@ bool CQnetITAP::ProcessITAP(const unsigned char *buf)
static short stream_id = 0U; static short stream_id = 0U;
SITAP itap; SITAP itap;
unsigned int len = (0x10U == buf[1]) ? 41 : 16; 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 memcpy(&itap.length, buf, len); // transfer raw data to SITAP struct
// create a stream id if this is a header // create a stream id if this is a header
@ -580,16 +606,35 @@ bool CQnetITAP::ProcessITAP(const unsigned char *buf)
} }
else if (16 == len) // ambe else if (16 == len) // ambe
{ {
dsvt.ctrl = itap.voice.sequence; dsvt.ctrl = itap.voice.frame.sequence;
memcpy(dsvt.vasd.voice, itap.voice.ambe, 12); memcpy(dsvt.vasd.voice, itap.voice.frame.ambe, 12);
if (ToGate.Write(dsvt.title, 27)) if (ToGate.Write(dsvt.title, 27))
{ {
printf("ERROR: ProcessMMDVM: Could not write gateway voice packet\n"); printf("ERROR: ProcessMMDVM: Could not write gateway voice packet\n");
return true; 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)); 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; return false;

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

Loading…
Cancel
Save

Powered by TurnKey Linux.