Add mode AC handling, and clean up the parsers and serializers to avoid duplication.
This commit is contained in:
@@ -359,7 +359,7 @@ const ProtobufCMessageDescriptor adsb_packet__descriptor =
|
||||
(ProtobufCMessageInit) adsb_packet__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
static const ProtobufCFieldDescriptor adsb__field_descriptors[3] =
|
||||
static const ProtobufCFieldDescriptor adsb__field_descriptors[4] =
|
||||
{
|
||||
{
|
||||
"header",
|
||||
@@ -374,11 +374,23 @@ static const ProtobufCFieldDescriptor adsb__field_descriptors[3] =
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"mode_s_short",
|
||||
"mode_ac",
|
||||
2,
|
||||
PROTOBUF_C_LABEL_OPTIONAL,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(Adsb, mode_ac),
|
||||
&adsb_packet__descriptor,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"mode_s_short",
|
||||
3,
|
||||
PROTOBUF_C_LABEL_OPTIONAL,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(Adsb, mode_s_short),
|
||||
&adsb_packet__descriptor,
|
||||
NULL,
|
||||
@@ -387,7 +399,7 @@ static const ProtobufCFieldDescriptor adsb__field_descriptors[3] =
|
||||
},
|
||||
{
|
||||
"mode_s_long",
|
||||
3,
|
||||
4,
|
||||
PROTOBUF_C_LABEL_OPTIONAL,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
0, /* quantifier_offset */
|
||||
@@ -400,13 +412,14 @@ static const ProtobufCFieldDescriptor adsb__field_descriptors[3] =
|
||||
};
|
||||
static const unsigned adsb__field_indices_by_name[] = {
|
||||
0, /* field[0] = header */
|
||||
2, /* field[2] = mode_s_long */
|
||||
1, /* field[1] = mode_s_short */
|
||||
1, /* field[1] = mode_ac */
|
||||
3, /* field[3] = mode_s_long */
|
||||
2, /* field[2] = mode_s_short */
|
||||
};
|
||||
static const ProtobufCIntRange adsb__number_ranges[1 + 1] =
|
||||
{
|
||||
{ 1, 0 },
|
||||
{ 0, 3 }
|
||||
{ 0, 4 }
|
||||
};
|
||||
const ProtobufCMessageDescriptor adsb__descriptor =
|
||||
{
|
||||
@@ -416,7 +429,7 @@ const ProtobufCMessageDescriptor adsb__descriptor =
|
||||
"Adsb",
|
||||
"",
|
||||
sizeof(Adsb),
|
||||
3,
|
||||
4,
|
||||
adsb__field_descriptors,
|
||||
adsb__field_indices_by_name,
|
||||
1, adsb__number_ranges,
|
||||
|
||||
@@ -60,12 +60,13 @@ struct _Adsb
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
AdsbHeader *header;
|
||||
AdsbPacket *mode_ac;
|
||||
AdsbPacket *mode_s_short;
|
||||
AdsbPacket *mode_s_long;
|
||||
};
|
||||
#define ADSB__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&adsb__descriptor) \
|
||||
, NULL, NULL, NULL }
|
||||
, NULL, NULL, NULL, NULL }
|
||||
|
||||
|
||||
struct _AdsbStream
|
||||
|
||||
@@ -12,29 +12,14 @@
|
||||
|
||||
#define SEND_MHZ 20
|
||||
|
||||
struct __attribute__((packed)) airspy_adsb_common_overlay {
|
||||
uint8_t mlat_timestamp[8];
|
||||
struct __attribute__((packed)) airspy_adsb_overlay {
|
||||
char semicolon1;
|
||||
uint8_t mlat_precision[2];
|
||||
uint8_t mlat_timestamp[8];
|
||||
char semicolon2;
|
||||
uint8_t rssi[4];
|
||||
uint8_t mlat_precision[2];
|
||||
char semicolon3;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) airspy_adsb_mode_s_short_overlay {
|
||||
char asterisk;
|
||||
uint8_t payload[14];
|
||||
char semicolon;
|
||||
struct airspy_adsb_common_overlay common;
|
||||
char cr_lf;
|
||||
char lf;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) airspy_adsb_mode_s_long_overlay {
|
||||
char asterisk;
|
||||
uint8_t payload[28];
|
||||
char semicolon;
|
||||
struct airspy_adsb_common_overlay common;
|
||||
uint8_t rssi[4];
|
||||
char semicolon4;
|
||||
char cr_lf;
|
||||
char lf;
|
||||
};
|
||||
@@ -43,10 +28,19 @@ struct airspy_adsb_parser_state {
|
||||
struct packet_mlat_state mlat_state;
|
||||
};
|
||||
|
||||
static bool airspy_adsb_parse_common(const struct airspy_adsb_common_overlay *overlay, struct packet *packet, struct airspy_adsb_parser_state *state) {
|
||||
if (overlay->semicolon1 != ';' ||
|
||||
static bool airspy_adsb_parse_packet(struct buf *buf, struct packet *packet, struct airspy_adsb_parser_state *state, enum packet_type type) {
|
||||
size_t payload_bytes = packet_payload_len[type];
|
||||
size_t overlay_start = 1 + payload_bytes;
|
||||
struct airspy_adsb_overlay *overlay = (struct airspy_adsb_overlay *) buf_at(buf, overlay_start);
|
||||
size_t total_len = overlay_start + sizeof(*overlay);
|
||||
|
||||
if (((buf->length < total_len - 1 || overlay->cr_lf != '\n') &&
|
||||
(buf->length < total_len || overlay->cr_lf != '\r' || overlay->lf != '\n')) ||
|
||||
buf_chr(buf, 0) != '*' ||
|
||||
overlay->semicolon1 != ';' ||
|
||||
overlay->semicolon2 != ';' ||
|
||||
overlay->semicolon3 != ';') {
|
||||
overlay->semicolon3 != ';' ||
|
||||
overlay->semicolon4 != ';') {
|
||||
return false;
|
||||
}
|
||||
uint16_t mlat_mhz = 2 * (uint16_t) hex_to_int(overlay->mlat_precision, sizeof(overlay->mlat_precision) / 2);
|
||||
@@ -59,108 +53,41 @@ static bool airspy_adsb_parse_common(const struct airspy_adsb_common_overlay *ov
|
||||
}
|
||||
packet->mlat_timestamp = packet_mlat_timestamp_scale_in((uint64_t) mlat_timestamp_in, UINT32_MAX, mlat_mhz, &state->mlat_state);
|
||||
packet->rssi = packet_rssi_scale_in((uint32_t) hex_to_int(overlay->rssi, sizeof(overlay->rssi) / 2), UINT16_MAX);
|
||||
packet->type = type;
|
||||
if (!hex_to_bin(packet->payload, buf_at(buf, 1), payload_bytes)) {
|
||||
return false;
|
||||
}
|
||||
buf_consume(buf, overlay->cr_lf == '\r' ? total_len : total_len - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool airspy_adsb_parse_mode_s_short(struct buf *buf, struct packet *packet, struct airspy_adsb_parser_state *state) {
|
||||
struct airspy_adsb_mode_s_short_overlay *overlay = (struct airspy_adsb_mode_s_short_overlay *) buf_at(buf, 0);
|
||||
if (((buf->length < sizeof(*overlay) - 1 || overlay->cr_lf != '\n') &&
|
||||
(buf->length < sizeof(*overlay) || overlay->cr_lf != '\r' || overlay->lf != '\n')) ||
|
||||
overlay->asterisk != '*' ||
|
||||
overlay->semicolon != ';') {
|
||||
return false;
|
||||
}
|
||||
if (!airspy_adsb_parse_common(&overlay->common, packet, state)) {
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_MODE_S_SHORT;
|
||||
if (!hex_to_bin(packet->payload, overlay->payload, sizeof(overlay->payload) / 2)) {
|
||||
return false;
|
||||
}
|
||||
buf_consume(buf, overlay->cr_lf == '\r' ? sizeof(*overlay) : sizeof(*overlay) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool airspy_adsb_parse_mode_s_long(struct buf *buf, struct packet *packet, struct airspy_adsb_parser_state *state) {
|
||||
struct airspy_adsb_mode_s_long_overlay *overlay = (struct airspy_adsb_mode_s_long_overlay *) buf_at(buf, 0);
|
||||
if (((buf->length < sizeof(*overlay) - 1 || overlay->cr_lf != '\n') &&
|
||||
(buf->length < sizeof(*overlay) || overlay->cr_lf != '\r' || overlay->lf != '\n')) ||
|
||||
overlay->asterisk != '*' ||
|
||||
overlay->semicolon != ';') {
|
||||
return false;
|
||||
}
|
||||
if (!airspy_adsb_parse_common(&overlay->common, packet, state)) {
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_MODE_S_LONG;
|
||||
if (!hex_to_bin(packet->payload, overlay->payload, sizeof(overlay->payload) / 2)) {
|
||||
return false;
|
||||
}
|
||||
buf_consume(buf, overlay->cr_lf == '\r' ? sizeof(*overlay) : sizeof(*overlay) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void airspy_adsb_fill_common(struct packet *packet, struct airspy_adsb_common_overlay *overlay) {
|
||||
overlay->semicolon1 = overlay->semicolon2 = overlay->semicolon3 = ';';
|
||||
hex_from_int_upper(
|
||||
overlay->mlat_timestamp,
|
||||
packet_mlat_timestamp_scale_out(packet->mlat_timestamp, UINT32_MAX, SEND_MHZ),
|
||||
sizeof(overlay->mlat_timestamp) / 2);
|
||||
hex_from_int_upper(overlay->mlat_precision, SEND_MHZ / 2, sizeof(overlay->mlat_precision) / 2);
|
||||
hex_from_int_upper(overlay->rssi, packet_rssi_scale_out(packet->rssi, UINT16_MAX), sizeof(overlay->rssi) / 2);
|
||||
}
|
||||
|
||||
static void airspy_adsb_serialize_mode_s_short(struct packet *packet, struct buf *buf) {
|
||||
struct airspy_adsb_mode_s_short_overlay *overlay = (struct airspy_adsb_mode_s_short_overlay *) buf_at(buf, 0);
|
||||
overlay->asterisk = '*';
|
||||
overlay->semicolon = ';';
|
||||
overlay->cr_lf = '\r';
|
||||
overlay->lf = '\n';
|
||||
hex_from_bin_upper(overlay->payload, packet->payload, sizeof(overlay->payload) / 2);
|
||||
|
||||
airspy_adsb_fill_common(packet, &overlay->common);
|
||||
|
||||
buf->length = sizeof(*overlay);
|
||||
}
|
||||
|
||||
static void airspy_adsb_serialize_mode_s_long(struct packet *packet, struct buf *buf) {
|
||||
struct airspy_adsb_mode_s_long_overlay *overlay = (struct airspy_adsb_mode_s_long_overlay *) buf_at(buf, 0);
|
||||
overlay->asterisk = '*';
|
||||
overlay->semicolon = ';';
|
||||
overlay->cr_lf = '\r';
|
||||
overlay->lf = '\n';
|
||||
hex_from_bin_upper(overlay->payload, packet->payload, sizeof(overlay->payload) / 2);
|
||||
|
||||
airspy_adsb_fill_common(packet, &overlay->common);
|
||||
|
||||
buf->length = sizeof(*overlay);
|
||||
}
|
||||
|
||||
void airspy_adsb_init() {
|
||||
assert(sizeof(struct airspy_adsb_parser_state) <= PARSER_STATE_LEN);
|
||||
assert(sizeof(struct airspy_adsb_mode_s_short_overlay) < BUF_LEN_MAX);
|
||||
assert(sizeof(struct airspy_adsb_mode_s_long_overlay) < BUF_LEN_MAX);
|
||||
assert(1 + PACKET_PAYLOAD_LEN_MAX + sizeof(struct airspy_adsb_overlay) < BUF_LEN_MAX);
|
||||
}
|
||||
|
||||
bool airspy_adsb_parse(struct buf *buf, struct packet *packet, void *state_in) {
|
||||
struct airspy_adsb_parser_state *state = (struct airspy_adsb_parser_state *) state_in;
|
||||
|
||||
return (
|
||||
airspy_adsb_parse_mode_s_short(buf, packet, state) ||
|
||||
airspy_adsb_parse_mode_s_long(buf, packet, state));
|
||||
airspy_adsb_parse_packet(buf, packet, state, PACKET_TYPE_MODE_AC) ||
|
||||
airspy_adsb_parse_packet(buf, packet, state, PACKET_TYPE_MODE_S_SHORT) ||
|
||||
airspy_adsb_parse_packet(buf, packet, state, PACKET_TYPE_MODE_S_LONG));
|
||||
}
|
||||
|
||||
void airspy_adsb_serialize(struct packet *packet, struct buf *buf) {
|
||||
switch (packet->type) {
|
||||
case PACKET_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_S_SHORT:
|
||||
airspy_adsb_serialize_mode_s_short(packet, buf);
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_S_LONG:
|
||||
airspy_adsb_serialize_mode_s_long(packet, buf);
|
||||
break;
|
||||
}
|
||||
size_t payload_bytes = packet_payload_len[packet->type];
|
||||
struct airspy_adsb_overlay *overlay = (struct airspy_adsb_overlay *) buf_at(buf, 1 + payload_bytes);
|
||||
buf_chr(buf, 0) = '*';
|
||||
overlay->semicolon1 = overlay->semicolon2 = overlay->semicolon3 = overlay->semicolon4 =';';
|
||||
overlay->cr_lf = '\r';
|
||||
overlay->lf = '\n';
|
||||
hex_from_bin_upper(buf_at(buf, 1), packet->payload, payload_bytes);
|
||||
hex_from_int_upper(
|
||||
overlay->mlat_timestamp,
|
||||
packet_mlat_timestamp_scale_out(packet->mlat_timestamp, UINT32_MAX, SEND_MHZ),
|
||||
sizeof(overlay->mlat_timestamp) / 2);
|
||||
hex_from_int_upper(overlay->mlat_precision, SEND_MHZ / 2, sizeof(overlay->mlat_precision) / 2);
|
||||
hex_from_int_upper(overlay->rssi, packet_rssi_scale_out(packet->rssi, UINT16_MAX), sizeof(overlay->rssi) / 2);
|
||||
buf->length = 1 + payload_bytes + sizeof(*overlay);
|
||||
}
|
||||
|
||||
103
adsbus/beast.c
103
adsbus/beast.c
@@ -9,29 +9,19 @@
|
||||
|
||||
#include "beast.h"
|
||||
|
||||
struct __attribute__((packed)) beast_common_overlay {
|
||||
struct __attribute__((packed)) beast_overlay {
|
||||
uint8_t one_a;
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) beast_mode_s_short_overlay {
|
||||
struct beast_common_overlay common;
|
||||
uint8_t mlat_timestamp[6];
|
||||
uint8_t rssi;
|
||||
uint8_t payload[7];
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) beast_mode_s_long_overlay {
|
||||
struct beast_common_overlay common;
|
||||
uint8_t mlat_timestamp[6];
|
||||
uint8_t rssi;
|
||||
uint8_t payload[14];
|
||||
};
|
||||
|
||||
struct beast_parser_state {
|
||||
struct packet_mlat_state mlat_state;
|
||||
};
|
||||
|
||||
#define BEAST_MLAT_MHZ 12
|
||||
|
||||
static uint64_t beast_parse_mlat(uint8_t *mlat_timestamp) {
|
||||
return (
|
||||
((uint64_t) mlat_timestamp[0]) << 40 |
|
||||
@@ -78,46 +68,32 @@ static void beast_escape(struct buf *out, const struct buf *in) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool beast_parse_mode_s_short(struct buf *buf, struct packet *packet, struct beast_parser_state *state) {
|
||||
static bool beast_parse_packet(struct buf *buf, struct packet *packet, struct beast_parser_state *state, enum packet_type type) {
|
||||
struct buf buf2 = BUF_INIT;
|
||||
ssize_t in_bytes = beast_unescape(&buf2, buf, sizeof(struct beast_mode_s_short_overlay));
|
||||
size_t payload_bytes = packet_payload_len[type];
|
||||
ssize_t in_bytes = beast_unescape(&buf2, buf, sizeof(struct beast_overlay) + payload_bytes);
|
||||
if (in_bytes < 0) {
|
||||
return false;
|
||||
}
|
||||
struct beast_mode_s_short_overlay *overlay = (struct beast_mode_s_short_overlay *) buf_at(&buf2, 0);
|
||||
packet->type = PACKET_TYPE_MODE_S_SHORT;
|
||||
struct beast_overlay *overlay = (struct beast_overlay *) buf_at(&buf2, 0);
|
||||
packet->type = type;
|
||||
uint64_t source_mlat = beast_parse_mlat(overlay->mlat_timestamp);
|
||||
packet->mlat_timestamp = packet_mlat_timestamp_scale_in(source_mlat, UINT64_C(0xffffffffffff), 12, &state->mlat_state);
|
||||
packet->mlat_timestamp = packet_mlat_timestamp_scale_in(source_mlat, UINT64_C(0xffffffffffff), BEAST_MLAT_MHZ, &state->mlat_state);
|
||||
packet->rssi = packet_rssi_scale_in(overlay->rssi, UINT8_MAX);
|
||||
memcpy(packet->payload, overlay->payload, sizeof(overlay->payload));
|
||||
memcpy(packet->payload, buf_at(&buf2, sizeof(*overlay)), payload_bytes);
|
||||
buf_consume(buf, (size_t) in_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool beast_parse_mode_s_long(struct buf *buf, struct packet *packet, struct beast_parser_state *state) {
|
||||
static void beast_serialize_packet(struct packet *packet, struct buf *buf, uint8_t type) {
|
||||
struct buf buf2 = BUF_INIT;
|
||||
ssize_t in_bytes = beast_unescape(&buf2, buf, sizeof(struct beast_mode_s_long_overlay));
|
||||
if (in_bytes < 0) {
|
||||
return false;
|
||||
}
|
||||
struct beast_mode_s_long_overlay *overlay = (struct beast_mode_s_long_overlay *) buf_at(&buf2, 0);
|
||||
packet->type = PACKET_TYPE_MODE_S_LONG;
|
||||
uint64_t source_mlat = beast_parse_mlat(overlay->mlat_timestamp);
|
||||
packet->mlat_timestamp = packet_mlat_timestamp_scale_in(source_mlat, UINT64_C(0xffffffffffff), 12, &state->mlat_state);
|
||||
packet->rssi = packet_rssi_scale_in(overlay->rssi == UINT8_MAX ? 0 : overlay->rssi, UINT8_MAX);
|
||||
memcpy(packet->payload, overlay->payload, sizeof(overlay->payload));
|
||||
buf_consume(buf, (size_t) in_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void beast_serialize_mode_s_short(struct packet *packet, struct buf *buf) {
|
||||
struct buf buf2 = BUF_INIT;
|
||||
struct beast_mode_s_short_overlay *overlay = (struct beast_mode_s_short_overlay *) buf_at(&buf2, 0);
|
||||
overlay->common.one_a = 0x1a;
|
||||
overlay->common.type = 0x32;
|
||||
memcpy(overlay->payload, packet->payload, sizeof(overlay->payload));
|
||||
size_t payload_bytes = packet_payload_len[type];
|
||||
struct beast_overlay *overlay = (struct beast_overlay *) buf_at(&buf2, 0);
|
||||
overlay->one_a = 0x1a;
|
||||
overlay->type = type;
|
||||
memcpy(buf_at(&buf2, sizeof(*overlay)), packet->payload, payload_bytes);
|
||||
beast_write_mlat(
|
||||
packet_mlat_timestamp_scale_out(packet->mlat_timestamp, UINT64_C(0xffffffffffff), 12),
|
||||
packet_mlat_timestamp_scale_out(packet->mlat_timestamp, UINT64_C(0xffffffffffff), BEAST_MLAT_MHZ),
|
||||
overlay->mlat_timestamp);
|
||||
|
||||
if (packet->rssi) {
|
||||
@@ -126,54 +102,35 @@ static void beast_serialize_mode_s_short(struct packet *packet, struct buf *buf)
|
||||
overlay->rssi = UINT8_MAX;
|
||||
}
|
||||
|
||||
buf2.length = sizeof(*overlay);
|
||||
beast_escape(buf, &buf2);
|
||||
}
|
||||
|
||||
static void beast_serialize_mode_s_long(struct packet *packet, struct buf *buf) {
|
||||
struct buf buf2 = BUF_INIT;
|
||||
struct beast_mode_s_long_overlay *overlay = (struct beast_mode_s_long_overlay *) buf_at(&buf2, 0);
|
||||
overlay->common.one_a = 0x1a;
|
||||
overlay->common.type = 0x33;
|
||||
memcpy(overlay->payload, packet->payload, sizeof(overlay->payload));
|
||||
beast_write_mlat(
|
||||
packet_mlat_timestamp_scale_out(packet->mlat_timestamp, UINT64_C(0xffffffffffff), 12),
|
||||
overlay->mlat_timestamp);
|
||||
|
||||
if (packet->rssi) {
|
||||
overlay->rssi = (uint8_t) packet_rssi_scale_out(packet->rssi, UINT8_MAX);
|
||||
} else {
|
||||
overlay->rssi = UINT8_MAX;
|
||||
}
|
||||
|
||||
buf2.length = sizeof(*overlay);
|
||||
buf2.length = sizeof(*overlay) + payload_bytes;
|
||||
beast_escape(buf, &buf2);
|
||||
}
|
||||
|
||||
void beast_init() {
|
||||
assert(sizeof(struct beast_parser_state) <= PARSER_STATE_LEN);
|
||||
assert(sizeof(struct beast_mode_s_short_overlay) * 2 <= BUF_LEN_MAX);
|
||||
assert(sizeof(struct beast_mode_s_long_overlay) * 2 <= BUF_LEN_MAX);
|
||||
assert((sizeof(struct beast_overlay) + PACKET_PAYLOAD_LEN_MAX) * 2 <= BUF_LEN_MAX);
|
||||
}
|
||||
|
||||
bool beast_parse(struct buf *buf, struct packet *packet, void *state_in) {
|
||||
struct beast_parser_state *state = (struct beast_parser_state *) state_in;
|
||||
struct beast_overlay *overlay = (struct beast_overlay *) buf_at(buf, 0);
|
||||
|
||||
if (buf->length < sizeof(struct beast_common_overlay) ||
|
||||
if (buf->length < sizeof(*overlay) ||
|
||||
buf_chr(buf, 0) != 0x1a) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct beast_common_overlay *overlay = (struct beast_common_overlay *) buf_at(buf, 0);
|
||||
switch (overlay->type) {
|
||||
case 0x31:
|
||||
return beast_parse_packet(buf, packet, state, PACKET_TYPE_MODE_AC);
|
||||
|
||||
case 0x32:
|
||||
return beast_parse_mode_s_short(buf, packet, state);
|
||||
return beast_parse_packet(buf, packet, state, PACKET_TYPE_MODE_S_SHORT);
|
||||
|
||||
case 0x33:
|
||||
return beast_parse_mode_s_long(buf, packet, state);
|
||||
return beast_parse_packet(buf, packet, state, PACKET_TYPE_MODE_S_LONG);
|
||||
|
||||
default:
|
||||
fprintf(stderr, "R %s: Unknown beast type %x\n", packet->source_id, overlay->type);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@@ -184,12 +141,16 @@ void beast_serialize(struct packet *packet, struct buf *buf) {
|
||||
case PACKET_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_AC:
|
||||
beast_serialize_packet(packet, buf, 0x31);
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_S_SHORT:
|
||||
beast_serialize_mode_s_short(packet, buf);
|
||||
beast_serialize_packet(packet, buf, 0x32);
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_S_LONG:
|
||||
beast_serialize_mode_s_long(packet, buf);
|
||||
beast_serialize_packet(packet, buf, 0x33);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,18 +44,11 @@ static void json_add_common(struct packet *packet, json_t *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
static void json_serialize_mode_s_short(struct packet *packet, struct buf *buf) {
|
||||
uint8_t hexbuf[14];
|
||||
hex_from_bin_upper(hexbuf, packet->payload, 7);
|
||||
json_t *out = json_pack("{ss#}", "payload", hexbuf, 14);
|
||||
json_add_common(packet, out);
|
||||
json_serialize_to_buf(out, buf);
|
||||
}
|
||||
|
||||
static void json_serialize_mode_s_long(struct packet *packet, struct buf *buf) {
|
||||
uint8_t hexbuf[28];
|
||||
hex_from_bin_upper(hexbuf, packet->payload, 14);
|
||||
json_t *out = json_pack("{ss#}", "payload", hexbuf, 28);
|
||||
static void json_serialize_payload(struct packet *packet, struct buf *buf) {
|
||||
size_t bytes = packet_payload_len[packet->type];
|
||||
uint8_t hexbuf[PACKET_PAYLOAD_LEN_MAX * 2];
|
||||
hex_from_bin_upper(hexbuf, packet->payload, bytes);
|
||||
json_t *out = json_pack("{ss#}", "payload", hexbuf, bytes * 2);
|
||||
json_add_common(packet, out);
|
||||
json_serialize_to_buf(out, buf);
|
||||
}
|
||||
@@ -139,38 +132,34 @@ static bool json_parse_common(json_t *in, struct packet *packet, struct json_par
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool json_parse_mode_s_short(json_t *in, struct packet *packet, struct json_parser_state *state) {
|
||||
static bool json_parse_payload(json_t *in, struct packet *packet, struct json_parser_state *state, enum packet_type type) {
|
||||
size_t bytes = packet_payload_len[type];
|
||||
if (!json_parse_common(in, packet, state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
json_t *payload = json_object_get(in, "payload");
|
||||
if (!payload || !json_is_string(payload) || json_string_length(payload) != 14) {
|
||||
if (!payload || !json_is_string(payload) || json_string_length(payload) != bytes * 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hex_to_bin(packet->payload, (const uint8_t *) json_string_value(payload), 7)) {
|
||||
if (!hex_to_bin(packet->payload, (const uint8_t *) json_string_value(payload), bytes)) {
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_MODE_S_SHORT;
|
||||
packet->type = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool json_parse_mode_ac(json_t *in, struct packet *packet, struct json_parser_state *state) {
|
||||
return json_parse_payload(in, packet, state, PACKET_TYPE_MODE_AC);
|
||||
}
|
||||
|
||||
static bool json_parse_mode_s_short(json_t *in, struct packet *packet, struct json_parser_state *state) {
|
||||
return json_parse_payload(in, packet, state, PACKET_TYPE_MODE_S_SHORT);
|
||||
}
|
||||
|
||||
static bool json_parse_mode_s_long(json_t *in, struct packet *packet, struct json_parser_state *state) {
|
||||
if (!json_parse_common(in, packet, state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
json_t *payload = json_object_get(in, "payload");
|
||||
if (!payload || !json_is_string(payload) || json_string_length(payload) != 28) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hex_to_bin(packet->payload, (const uint8_t *) json_string_value(payload), 14)) {
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_MODE_S_LONG;
|
||||
return true;
|
||||
return json_parse_payload(in, packet, state, PACKET_TYPE_MODE_S_LONG);
|
||||
}
|
||||
|
||||
void json_init() {
|
||||
@@ -226,6 +215,8 @@ bool json_parse(struct buf *buf, struct packet *packet, void *state_in) {
|
||||
bool (*parser)(json_t *, struct packet *, struct json_parser_state *) = NULL;
|
||||
if (!strcmp(type_str, "header")) {
|
||||
parser = json_parse_header;
|
||||
} else if (!strcmp(type_str, "Mode-AC")) {
|
||||
parser = json_parse_mode_ac;
|
||||
} else if (!strcmp(type_str, "Mode-S short")) {
|
||||
parser = json_parse_mode_s_short;
|
||||
} else if (!strcmp(type_str, "Mode-S long")) {
|
||||
@@ -251,12 +242,10 @@ void json_serialize(struct packet *packet, struct buf *buf) {
|
||||
case PACKET_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_AC:
|
||||
case PACKET_TYPE_MODE_S_SHORT:
|
||||
json_serialize_mode_s_short(packet, buf);
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_S_LONG:
|
||||
json_serialize_mode_s_long(packet, buf);
|
||||
json_serialize_payload(packet, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -8,10 +10,18 @@
|
||||
|
||||
char *packet_type_names[] = {
|
||||
"INVALID",
|
||||
"Mode-AC",
|
||||
"Mode-S short",
|
||||
"Mode-S long",
|
||||
};
|
||||
|
||||
size_t packet_payload_len[] = {
|
||||
0,
|
||||
2,
|
||||
7,
|
||||
14,
|
||||
};
|
||||
|
||||
static uint64_t packet_mlat_timestamp_scale_mhz_in(uint64_t timestamp, uint32_t mhz) {
|
||||
assert(mhz > 0);
|
||||
return timestamp * (PACKET_MLAT_MHZ / mhz);
|
||||
|
||||
@@ -6,17 +6,21 @@
|
||||
#define PACKET_DATA_LEN_MAX 14
|
||||
struct packet {
|
||||
const uint8_t *source_id;
|
||||
enum {
|
||||
enum packet_type {
|
||||
PACKET_TYPE_NONE,
|
||||
PACKET_TYPE_MODE_AC,
|
||||
PACKET_TYPE_MODE_S_SHORT,
|
||||
PACKET_TYPE_MODE_S_LONG,
|
||||
} type;
|
||||
#define NUM_TYPES 3
|
||||
#define NUM_TYPES 4
|
||||
uint8_t payload[PACKET_DATA_LEN_MAX];
|
||||
uint64_t mlat_timestamp;
|
||||
uint32_t rssi;
|
||||
};
|
||||
extern char *packet_type_names[];
|
||||
extern size_t packet_payload_len[];
|
||||
|
||||
#define PACKET_PAYLOAD_LEN_MAX 14
|
||||
|
||||
#define PACKET_MLAT_MHZ 120
|
||||
// Use the signed max to avoid problems with some consumers; it's large enough to not matter.
|
||||
|
||||
@@ -55,6 +55,14 @@ static void proto_serialize_packet(struct packet *packet, AdsbPacket *out, size_
|
||||
out->payload.len = len;
|
||||
}
|
||||
|
||||
static void proto_serialize_mode_ac(struct packet *packet, struct buf *buf) {
|
||||
AdsbPacket packet_out = ADSB_PACKET__INIT;
|
||||
proto_serialize_packet(packet, &packet_out, 2);
|
||||
Adsb msg = ADSB__INIT;
|
||||
msg.mode_ac = &packet_out;
|
||||
proto_wrap_to_buf(&msg, buf);
|
||||
}
|
||||
|
||||
static void proto_serialize_mode_s_short(struct packet *packet, struct buf *buf) {
|
||||
AdsbPacket packet_out = ADSB_PACKET__INIT;
|
||||
proto_serialize_packet(packet, &packet_out, 7);
|
||||
@@ -216,6 +224,12 @@ bool proto_parse(struct buf *buf, struct packet *packet, void *state_in) {
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_NONE;
|
||||
} else if (msg->mode_ac) {
|
||||
if (!proto_parse_packet(msg->mode_ac, packet, state, 2)) {
|
||||
adsb__free_unpacked(msg, NULL);
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_MODE_AC;
|
||||
} else if (msg->mode_s_short) {
|
||||
if (!proto_parse_packet(msg->mode_s_short, packet, state, 7)) {
|
||||
adsb__free_unpacked(msg, NULL);
|
||||
@@ -244,6 +258,11 @@ void proto_serialize(struct packet *packet, struct buf *buf) {
|
||||
case PACKET_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_AC:
|
||||
proto_serialize_mode_ac(packet, buf);
|
||||
break;
|
||||
|
||||
|
||||
case PACKET_TYPE_MODE_S_SHORT:
|
||||
proto_serialize_mode_s_short(packet, buf);
|
||||
break;
|
||||
|
||||
87
adsbus/raw.c
87
adsbus/raw.c
@@ -9,94 +9,49 @@
|
||||
|
||||
#include "raw.h"
|
||||
|
||||
struct __attribute__((packed)) raw_mode_s_short_overlay {
|
||||
char asterisk;
|
||||
uint8_t payload[14];
|
||||
struct __attribute__((packed)) raw_overlay {
|
||||
char semicolon;
|
||||
char cr_lf;
|
||||
char lf;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) raw_mode_s_long_overlay {
|
||||
char asterisk;
|
||||
uint8_t payload[28];
|
||||
char semicolon;
|
||||
char cr_lf;
|
||||
char lf;
|
||||
};
|
||||
static bool raw_parse_packet(struct buf *buf, struct packet *packet, enum packet_type type) {
|
||||
size_t payload_bytes = packet_payload_len[type];
|
||||
size_t overlay_start = 1 + payload_bytes;
|
||||
struct raw_overlay *overlay = (struct raw_overlay *) buf_at(buf, overlay_start);
|
||||
size_t total_len = overlay_start + sizeof(*overlay);
|
||||
|
||||
static bool raw_parse_mode_s_short(struct buf *buf, struct packet *packet) {
|
||||
struct raw_mode_s_short_overlay *overlay = (struct raw_mode_s_short_overlay *) buf_at(buf, 0);
|
||||
if (((buf->length < sizeof(*overlay) - 1 || overlay->cr_lf != '\n') &&
|
||||
(buf->length < sizeof(*overlay) || overlay->cr_lf != '\r' || overlay->lf != '\n')) ||
|
||||
overlay->asterisk != '*' ||
|
||||
buf_chr(buf, 0) != '*' ||
|
||||
overlay->semicolon != ';') {
|
||||
return false;
|
||||
}
|
||||
if (!hex_to_bin(packet->payload, overlay->payload, sizeof(overlay->payload) / 2)) {
|
||||
if (!hex_to_bin(packet->payload, buf_at(buf, 1), payload_bytes)) {
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_MODE_S_SHORT;
|
||||
buf_consume(buf, overlay->cr_lf == '\r' ? sizeof(*overlay) : sizeof(*overlay) - 1);
|
||||
packet->type = type;
|
||||
buf_consume(buf, overlay->cr_lf == '\r' ? total_len : total_len - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool raw_parse_mode_s_long(struct buf *buf, struct packet *packet) {
|
||||
struct raw_mode_s_long_overlay *overlay = (struct raw_mode_s_long_overlay *) buf_at(buf, 0);
|
||||
if (((buf->length < sizeof(*overlay) - 1 || overlay->cr_lf != '\n') &&
|
||||
(buf->length < sizeof(*overlay) || overlay->cr_lf != '\r' || overlay->lf != '\n')) ||
|
||||
overlay->asterisk != '*' ||
|
||||
overlay->semicolon != ';') {
|
||||
return false;
|
||||
}
|
||||
if (!hex_to_bin(packet->payload, overlay->payload, sizeof(overlay->payload) / 2)) {
|
||||
return false;
|
||||
}
|
||||
packet->type = PACKET_TYPE_MODE_S_LONG;
|
||||
buf_consume(buf, overlay->cr_lf == '\r' ? sizeof(*overlay) : sizeof(*overlay) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void raw_serialize_mode_s_short(struct packet *packet, struct buf *buf) {
|
||||
struct raw_mode_s_short_overlay *overlay = (struct raw_mode_s_short_overlay *) buf_at(buf, 0);
|
||||
overlay->asterisk = '*';
|
||||
overlay->semicolon = ';';
|
||||
overlay->lf = '\n';
|
||||
hex_from_bin_upper(overlay->payload, packet->payload, sizeof(overlay->payload) / 2);
|
||||
buf->length = sizeof(*overlay);
|
||||
}
|
||||
|
||||
static void raw_serialize_mode_s_long(struct packet *packet, struct buf *buf) {
|
||||
struct raw_mode_s_long_overlay *overlay = (struct raw_mode_s_long_overlay *) buf_at(buf, 0);
|
||||
overlay->asterisk = '*';
|
||||
overlay->semicolon = ';';
|
||||
overlay->lf = '\n';
|
||||
hex_from_bin_upper(overlay->payload, packet->payload, sizeof(overlay->payload) / 2);
|
||||
buf->length = sizeof(*overlay);
|
||||
}
|
||||
|
||||
void raw_init() {
|
||||
assert(sizeof(struct raw_mode_s_short_overlay) < BUF_LEN_MAX);
|
||||
assert(sizeof(struct raw_mode_s_long_overlay) < BUF_LEN_MAX);
|
||||
assert(1 + PACKET_PAYLOAD_LEN_MAX + sizeof(struct raw_overlay) < BUF_LEN_MAX);
|
||||
}
|
||||
|
||||
bool raw_parse(struct buf *buf, struct packet *packet, void __attribute__((unused)) *state_in) {
|
||||
return (
|
||||
raw_parse_mode_s_short(buf, packet) ||
|
||||
raw_parse_mode_s_long(buf, packet));
|
||||
raw_parse_packet(buf, packet, PACKET_TYPE_MODE_AC) ||
|
||||
raw_parse_packet(buf, packet, PACKET_TYPE_MODE_S_SHORT) ||
|
||||
raw_parse_packet(buf, packet, PACKET_TYPE_MODE_S_LONG));
|
||||
}
|
||||
|
||||
void raw_serialize(struct packet *packet, struct buf *buf) {
|
||||
switch (packet->type) {
|
||||
case PACKET_TYPE_NONE:
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_S_SHORT:
|
||||
raw_serialize_mode_s_short(packet, buf);
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_MODE_S_LONG:
|
||||
raw_serialize_mode_s_long(packet, buf);
|
||||
break;
|
||||
}
|
||||
size_t payload_bytes = packet_payload_len[packet->type];
|
||||
struct raw_overlay *overlay = (struct raw_overlay *) buf_at(buf, 1 + payload_bytes);
|
||||
buf_chr(buf, 0) = '*';
|
||||
overlay->semicolon = ';';
|
||||
overlay->lf = '\n';
|
||||
hex_from_bin_upper(buf_at(buf, 1), packet->payload, payload_bytes);
|
||||
buf->length = 1 + payload_bytes + sizeof(*overlay);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@ message AdsbPacket {
|
||||
message Adsb {
|
||||
oneof record {
|
||||
AdsbHeader header = 1;
|
||||
AdsbPacket mode_s_short = 2;
|
||||
AdsbPacket mode_s_long = 3;
|
||||
AdsbPacket mode_ac = 2;
|
||||
AdsbPacket mode_s_short = 3;
|
||||
AdsbPacket mode_s_long = 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user