QnetGateway icon indicating copy to clipboard operation
QnetGateway copied to clipboard

draft: ICOM ID-52 PLUS terminal mode over Bluetooth

Open nullobsi opened this issue 6 months ago • 2 comments

The code is messy, I'm putting this out there to show that it's possible.

The ID-52 PLUS supports Terminal/Access Point mode over Bluetooth. For me, the mobile apps designed for this purpose (RS-MS3A/I) do not function properly.

I thought QnetGateway was a more featureful option, but it only worked over USB serial. I adapted some of the code to work with the Bluetooth serial connection.

I have tested this patch with my ID-52A PLUS to connect to a couple reflectors with success making a few QSOs.

Important differences:

  • When the HT sends voice data packets, it sends them in groups of four with the following format:
struct AMBEFrameBt {
    u8 seq;
    u8 ambe[9];
    u8 slowdata[3];
};

struct VoiceInBt {
    u8 counter; // Counts by 1, each one representing a packet of 4
    u8 count;
    AMBEFrameBt frames[count];
};
  • The HT sends this packet with type = 0x13, the same type QnetITAP uses to ACK single-frame voice packets over USB.
  • The HT does not 0x23 ACK received single-frame type 0x22 voice packets as it does over USB, although it will play them back.
  • Header format is the same, and the HT ACKs headers it receives properly.

TODO:

  • [ ] Can we send packets in groups of 4 to the HT? (type = 0x23?)
  • [ ] How do we ACK these megapackets from the HT?

(I wrote a shitty "serial log" feature to help me figure out the data format. Included is an imHex "pattern file" to highlight the binary dump.)

ImHex pattern ``` import type.base; import std.mem; u64 currPacketStart;

enum Type : u8 { IHeader = 0x10, OHeader = 0x20, VoiceOut = 0x22, VoiceIn = 0x12, VoiceInBt = 0x13, };

struct PollPacket { u8 p; }; struct HeaderPacket<auto Append> { u8 flag[3]; char RPT2[8]; char RPT1[8]; char UR[8]; char MY[8]; char NM[4]; char append[Append]; }; struct VoiceDataOut { u8 counter; u8 sequence; u8 ambe[9] [[color("FF0000")]]; char slowdata[3] [[color("00FF00")]]; };

struct AMBEFrameBt { u8 seq [[color("5601b1")]]; u8 ambe[9] [[color("FF0000")]]; u8 slowdata[3] [[color("00FF00")]]; };

struct VoiceInBt { u8 counter; // Counts by 1, each one representing a packet of 4 u8 count; AMBEFrameBt frames[count]; };

struct Packet { currPacketStart = addressof(this); char dir [[color(this == 'O' ? "FFFF00" : "00FFFF")]]; u8 length; u8 type; if (!(dir == 'O' && length == 0xFF && type == 0xFF)){ match (dir, length, type) { (, , Type::IHeader): HeaderPacket<3> packet; (, , Type::OHeader): HeaderPacket<0> packet; (, , Type::VoiceOut): VoiceDataOut vd; (,, Type::VoiceIn): VoiceDataOut vd; ('I', , Type::VoiceInBt): VoiceInBt vd; (,,): type::Hex data2[0]; } if ($-currPacketStart-1 < length) { type::Hex data[length-($-currPacketStart)+1] [[color("0000FF")]]; } }

};

Packet p[while(!std::mem::eof())] @ 0x00;

</details>

nullobsi avatar Jul 08 '25 03:07 nullobsi

This is really cool, but the correct way to do this in the QnetGateway universe is to create a new modem type (QnetBT?) rather than hacking up QnetITAP. After all, it's using a completely different character device. It will also be much easier for users to config it and use it.

n7tae avatar Jul 08 '25 19:07 n7tae

sure, thanks for the tip; I at least wanted to put this out here, but I'll definitely clean it up and try making a new modem type based on QnetITAP.

nullobsi avatar Jul 08 '25 20:07 nullobsi