Ir:USER: Difference between revisions
Socram8888 (talk | contribs) Redirected page to IR Services#IR Service "ir:USER" |
Socram8888 (talk | contribs) No edit summary |
||
Line 1: | Line 1: | ||
This service was added with [[2.0.0-2]]. It employs a custom packet format with obfuscation and error detection. | |||
= Command set = | |||
When sending data, SendIrnop is used when the size is <=0xFC, otherwise SendIrnopLarge is used. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Command Header | |||
! Available since system version | |||
! Description | |||
|- | |||
| 0x00010182 | |||
| [[2.0.0-2]] | |||
| InitializeIrnop | |||
|- | |||
| 0x00020000 | |||
| [[2.0.0-2]] | |||
| FinalizeIrnop | |||
|- | |||
| 0x00030000 | |||
| [[2.0.0-2]] | |||
| ClearReceiveBuffer | |||
|- | |||
| 0x00040000 | |||
| [[2.0.0-2]] | |||
| ClearSendBuffer | |||
|- | |||
| 0x0005.... | |||
| [[2.0.0-2]] | |||
| WaitConnection | |||
|- | |||
| 0x00060040 | |||
| [[2.0.0-2]] | |||
| RequireConnection (u8 input) | |||
|- | |||
| 0x0007.... | |||
| [[2.0.0-2]] | |||
| AutoConnection | |||
|- | |||
| 0x0008.... | |||
| [[2.0.0-2]] | |||
| AnyConnection | |||
|- | |||
| 0x00090000 | |||
| [[2.0.0-2]] | |||
| Disconnect | |||
|- | |||
| 0x000A0000 | |||
| [[2.0.0-2]] | |||
| GetReceiveEvent (writes event handle to cmdreply[3]) | |||
|- | |||
| 0x000B0000 | |||
| [[2.0.0-2]] | |||
| GetSendEvent (writes event handle to cmdreply[3]) | |||
|- | |||
| 0x000C0000 | |||
| [[2.0.0-2]] | |||
| GetConnectionStatusEvent (writes event handle to cmdreply[3]) | |||
|- | |||
| 0x000D0042 | |||
| [[2.0.0-2]] | |||
| SendIrnop (u32 size, ((Size<<14) <nowiki>|</nowiki> 2), inbufptr) | |||
|- | |||
| 0x000E0042 | |||
| [[2.0.0-2]] | |||
| SendIrnopLarge (u32 size, ((Size<<8) <nowiki>|</nowiki> 10), inbufptr) | |||
|- | |||
| 0x000F.... | |||
| [[2.0.0-2]] | |||
| ReceiveIrnop | |||
|- | |||
| 0x0010.... | |||
| [[2.0.0-2]] | |||
| ReceiveIrnopLarge | |||
|- | |||
| 0x0011.... | |||
| [[2.0.0-2]] | |||
| GetLatestReceiveErrorResult | |||
|- | |||
| 0x0012.... | |||
| [[2.0.0-2]] | |||
| GetLatestSendErrorResult | |||
|- | |||
| 0x0013.... | |||
| [[2.0.0-2]] | |||
| GetConnectionStatus | |||
|- | |||
| 0x0014.... | |||
| [[2.0.0-2]] | |||
| GetTryingToConnectStatus | |||
|- | |||
| 0x0015.... | |||
| [[2.0.0-2]] | |||
| GetReceiveSizeFreeAndUsed | |||
|- | |||
| 0x0016.... | |||
| [[2.0.0-2]] | |||
| GetSendSizeFreeAndUsed | |||
|- | |||
| 0x0017.... | |||
| [[2.2.0-X]] | |||
| GetConnectionRole | |||
|- | |||
| 0x00180182 | |||
| [[2.2.0-X]] | |||
| InitializeIrnopShared (u32, u32, u32, u32, u32, u8, 0, handle) | |||
|- | |||
| 0x00190040 | |||
| [[2.2.0-X]] | |||
| ReleaseReceivedData (32bit_value input) | |||
|- | |||
| 0x001A0040 | |||
| [[2.2.0-X]] | |||
| SetOwnMachineId (u8 input) | |||
|} | |||
= Protocol description = | |||
Packets are sent using IrDA-SIR, with a 8N1 encoding (eight data bits, one stop bit, without parity). Each one is formed by a 2-byte header, a varint with the payload size, an obfuscated payload, and trailing error detection byte. | |||
== Packet header == | |||
The packet header is fixed and consists in a synchronization byte (0xA5), followed by a unused (possibly RFU) zero byte. After these two hardcoded bytes, there's a varint representing the payload size, which may use one byte or two, depending on the how big the payload is. | |||
* For payloads with less than 64 bytes, the third byte represents the payload size. | |||
* For packets with up to 16383 bytes, the size is split in two bytes, with the third byte being the upper 6 bits of the payload size, OR'd with 0x40, and the fourth being the lower eight bits of the payload size | |||
For packets with less than 64 bytes: | |||
{| class="wikitable" border="1" | |||
! Sync | |||
! RFU | |||
! Size | |||
|- | |||
| 0xA5 | |||
| 0x00 | |||
| size | |||
|} | |||
For packets with up to 16383 bytes: | |||
{| class="wikitable" border="1" | |||
! Sync | |||
! RFU | |||
! Size (1) | |||
! Size (2) | |||
|- | |||
| 0xA5 | |||
| 0x00 | |||
| (size >> 8) <nowiki>|</nowiki> 0x40 | |||
| size & 0xFF | |||
|} | |||
In C: | |||
<nowiki>uint8_t * setPacketHeader(uint8_t * buffer, size_t payloadSize) { | |||
assert(payloadSize < 16384); | |||
buffer[0] = 0xA5; | |||
buffer[1] = 0x00; | |||
if (payloadSize < 64) { | |||
buffer[2] = payloadSize; | |||
buffer += 3; | |||
} else { | |||
buffer[2] = 0x40 | (payloadSize >> 8); | |||
buffer[3] = payloadSize; | |||
buffer += 4; | |||
} | |||
return buffer; | |||
}</nowiki> | |||
== Payload == | |||
The payload is obfuscated using a XOR-based encryption. In C: | |||
<nowiki>void payloadObfuscate(const void * voidplain, void * voidcipher, size_t size) { | |||
uint16_t * plain = (uint16_t *) voidplain; | |||
uint16_t * cipher = (uint16_t *) voidcipher; | |||
size_t halfCount = size / sizeof(uint16_t); | |||
uint16_t xorval = htobe16(0xE963); | |||
size_t i; | |||
for (i = 0; i < halfCount; i++) { | |||
xorval ^= plain[i]; | |||
cipher[i] = xorval; | |||
} | |||
} | |||
void payloadDeobfuscate(const void * voidcipher, void * voidplain, size_t size) { | |||
uint16_t * cipher = (uint16_t *) voidcipher; | |||
uint16_t * plain = (uint16_t *) voidplain; | |||
size_t halfCount = size / sizeof(uint16_t); | |||
if (halfCount) { | |||
size_t i; | |||
for (i = halfCount - 1; i > 0; i--) { | |||
plain[i] = cipher[i] ^ cipher[i - 1]; | |||
} | |||
plain[0] = cipher[0] ^ htobe16(0xE963); | |||
} | |||
}</nowiki> | |||
== Error detection == | |||
The trailing error detection byte is calculated using [[CRC-8-CCITT]] <b>over the whole packet</b> (both the header and the payload) |