MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_l6.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_l6.c : QZSS L6 frame header parsing and service classification
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 *----------------------------------------------------------------------------*/
8#include "mrtklib/mrtk_l6.h"
9
10#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15/* nominal L6 PRN assignments (see l6_prn_info_t). MADOCA iono regions:
16 * PRN 200 Philippines/Indonesia/western Australia, PRN 201 Japan/eastern
17 * Australia. */
18static const l6_prn_info_t l6_prn_table[] = {
19 {193, "QZS1", 0, L6_SVC_CLAS, -1, 0}, {194, "QZS2", 0, L6_SVC_CLAS, -1, 204},
20 {195, "QZS4", 0, L6_SVC_CLAS, -1, 205}, {196, "QZS1R", 0, L6_SVC_CLAS, -1, 206},
21 {197, "QZS5", 0, L6_SVC_CLAS, -1, 207}, {199, "QZS3", 0, L6_SVC_CLAS, -1, 209},
22 {200, "QZS6", 0, L6_SVC_MADOCA_IONO, 0, 210}, {201, "QZS7", 0, L6_SVC_MADOCA_IONO, 1, 211},
23 {204, "QZS2", 1, L6_SVC_MADOCA, -1, 194}, {205, "QZS4", 1, L6_SVC_MADOCA, -1, 195},
24 {206, "QZS1R", 1, L6_SVC_MADOCA, -1, 196}, {207, "QZS5", 1, L6_SVC_MADOCA, -1, 197},
25 {209, "QZS3", 1, L6_SVC_MADOCA, -1, 199}, {210, "QZS6", 1, L6_SVC_MADOCA, -1, 200},
26 {211, "QZS7", 1, L6_SVC_MADOCA, -1, 201},
27};
28
29extern int l6_is_null(const uint8_t* frame) {
30 int i;
31
32 if (frame[5] != 0 || !(frame[6] & 0x80)) {
33 return 0;
34 }
35 /* byte 6 = alert bit + first 7 data bits "0101010"b = 0xAA */
36 for (i = 6; i < L6_FRAME_LEN; i++) {
37 if (frame[i] != 0xAA) {
38 return 0;
39 }
40 }
41 return 1;
42}
43
44extern int l6_parse_header(const uint8_t* frame, l6_header_t* h) {
45 h->preamble = ((uint32_t)frame[0] << 24) | ((uint32_t)frame[1] << 16) | ((uint32_t)frame[2] << 8) | frame[3];
46 h->prn = frame[4];
47 h->msgid = frame[5];
48 h->vid = (h->msgid >> 5) & 0x07;
49 h->fac = (h->msgid >> 3) & 0x03;
50 h->ptn = (h->msgid >> 1) & 0x03;
51 h->csid = (h->msgid >> 2) & 0x01;
52 h->anme = (h->msgid >> 1) & 0x01;
53 h->sf_ind = h->msgid & 0x01;
54 h->alert = (frame[6] >> 7) & 0x01;
55
56 if (h->preamble != L6_PREAMBLE) {
58 return 0;
59 }
60 if (l6_is_null(frame)) {
61 h->svc = L6_SVC_NULL;
62 } else if (h->vid == L6_VID_CLAS) {
63 h->svc = L6_SVC_CLAS;
64 } else if (h->vid == L6_VID_MADOCA) {
66 } else if (h->vid == L6_VID_QZNMA) {
67 h->svc = L6_SVC_QZNMA;
68 } else {
70 }
71 return 1;
72}
73
74extern const l6_prn_info_t* l6_prn_info(int prn) {
75 size_t i;
76
77 for (i = 0; i < sizeof(l6_prn_table) / sizeof(l6_prn_table[0]); i++) {
78 if (l6_prn_table[i].prn == prn) {
79 return l6_prn_table + i;
80 }
81 }
82 return NULL;
83}
84
85extern int l6_service_expected(const l6_header_t* h) {
86 const l6_prn_info_t* info = l6_prn_info(h->prn);
87
88 if (h->svc == L6_SVC_NULL) {
89 return 1;
90 }
91 if (!info) {
92 return 0;
93 }
94 if (info->l6e) {
95 return h->svc == L6_SVC_MADOCA || h->svc == L6_SVC_QZNMA;
96 }
97 return h->svc == info->svc;
98}
99
100extern l6_file_type_t l6_file_type(const char* file) {
101 static const char* const ext[] = {".l6", ".l6d", ".l6e"};
102 const char* p = strrchr(file, '.');
103 size_t i, k;
104
105 if (!p) {
106 return L6_FILE_NONE;
107 }
108 for (i = 0; i < sizeof(ext) / sizeof(ext[0]); i++) {
109 for (k = 0; p[k] && ext[i][k]; k++) {
110 char c = p[k] >= 'A' && p[k] <= 'Z' ? (char)(p[k] - 'A' + 'a') : p[k];
111 if (c != ext[i][k]) break;
112 }
113 if (!p[k] && !ext[i][k]) {
114 return (l6_file_type_t)(L6_FILE_L6 + i);
115 }
116 }
117 return L6_FILE_NONE;
118}
119
120extern l6_service_t l6_file_service(const char* file) {
122 l6_header_t hdr;
123 uint8_t* buf;
124 FILE* fp;
125 size_t n, i, keep;
126
127 if (!(fp = fopen(file, "rb"))) {
128 return L6_SVC_UNKNOWN;
129 }
130 if (!(buf = (uint8_t*)malloc(L6_FILE_SCAN_BYTES + L6_FRAME_LEN))) {
131 fclose(fp);
132 return L6_SVC_UNKNOWN;
133 }
134 /* read in chunks until the first classifiable frame or the end of the
135 * file: a long run of null messages must not hide the service. "keep"
136 * bytes of the previous chunk are carried over so a frame that straddles
137 * two chunks is still seen. */
138 keep = 0;
139 while (svc == L6_SVC_UNKNOWN && (n = fread(buf + keep, 1, L6_FILE_SCAN_BYTES, fp)) > 0) {
140 n += keep;
141 for (i = 0; i + L6_FRAME_LEN <= n; i++) {
142 if (!l6_parse_header(buf + i, &hdr)) {
143 continue;
144 }
145 if (hdr.svc != L6_SVC_NULL && hdr.svc != L6_SVC_UNKNOWN) {
146 svc = hdr.svc;
147 break;
148 }
149 i += L6_FRAME_LEN - 1; /* null / reserved frame: skip to the next one */
150 }
151 if (svc != L6_SVC_UNKNOWN) {
152 break;
153 }
154 keep = n - i < L6_FRAME_LEN ? n - i : 0; /* partial frame at the end */
155 memmove(buf, buf + n - keep, keep);
156 }
157 fclose(fp);
158 free(buf);
159 return svc;
160}
161
162extern const char* l6_service_name(l6_service_t svc) {
163 switch (svc) {
164 case L6_SVC_NULL:
165 return "NULL";
166 case L6_SVC_CLAS:
167 return "CLAS";
168 case L6_SVC_MADOCA:
169 return "MADOCA";
171 return "MADOCA-IONO";
172 case L6_SVC_QZNMA:
173 return "QZNMA";
174 default:
175 return "UNKNOWN";
176 }
177}
const l6_prn_info_t * l6_prn_info(int prn)
Look up the auxiliary information of an L6 PRN.
Definition mrtk_l6.c:74
static const l6_prn_info_t l6_prn_table[]
Definition mrtk_l6.c:18
int l6_service_expected(const l6_header_t *h)
Test whether a classified frame matches the nominal assignment of its PRN.
Definition mrtk_l6.c:85
l6_file_type_t l6_file_type(const char *file)
Classify a file name by its QZSS L6 extension (case-insensitive).
Definition mrtk_l6.c:100
int l6_parse_header(const uint8_t *frame, l6_header_t *h)
Parse the header of one L6 frame and classify its service.
Definition mrtk_l6.c:44
l6_service_t l6_file_service(const char *file)
Service of an L6 frame file, from the first non-null frame header.
Definition mrtk_l6.c:120
int l6_is_null(const uint8_t *frame)
Test whether an L6 frame is a null message.
Definition mrtk_l6.c:29
const char * l6_service_name(l6_service_t svc)
Short name of an L6 service, for logs.
Definition mrtk_l6.c:162
MRTKLIB L6 Module — QZSS L6 frame header parsing.
l6_service_t
Service carried by an L6 frame.
Definition mrtk_l6.h:58
@ L6_SVC_UNKNOWN
Definition mrtk_l6.h:59
@ L6_SVC_NULL
Definition mrtk_l6.h:60
@ L6_SVC_QZNMA
Definition mrtk_l6.h:64
@ L6_SVC_CLAS
Definition mrtk_l6.h:61
@ L6_SVC_MADOCA
Definition mrtk_l6.h:62
@ L6_SVC_MADOCA_IONO
Definition mrtk_l6.h:63
#define L6_FRAME_LEN
Definition mrtk_l6.h:43
#define L6_VID_CLAS
Definition mrtk_l6.h:51
#define L6_VID_QZNMA
Definition mrtk_l6.h:50
#define L6_PREAMBLE
Definition mrtk_l6.h:42
l6_file_type_t
QZSS L6 file type from the file name extension.
Definition mrtk_l6.h:142
@ L6_FILE_L6
Definition mrtk_l6.h:144
@ L6_FILE_NONE
Definition mrtk_l6.h:143
#define L6_FILE_SCAN_BYTES
Definition mrtk_l6.h:47
#define L6_VID_MADOCA
Definition mrtk_l6.h:49
Decoded L6 frame header. Raw bit fields; no service-specific remapping.
Definition mrtk_l6.h:68
uint8_t prn
Definition mrtk_l6.h:70
uint8_t anme
Definition mrtk_l6.h:76
uint8_t alert
Definition mrtk_l6.h:78
uint8_t csid
Definition mrtk_l6.h:75
uint8_t msgid
Definition mrtk_l6.h:71
l6_service_t svc
Definition mrtk_l6.h:79
uint8_t fac
Definition mrtk_l6.h:73
uint8_t vid
Definition mrtk_l6.h:72
uint8_t ptn
Definition mrtk_l6.h:74
uint32_t preamble
Definition mrtk_l6.h:69
uint8_t sf_ind
Definition mrtk_l6.h:77
Auxiliary per-PRN information for one L6 PRN.
Definition mrtk_l6.h:92
l6_service_t svc
Definition mrtk_l6.h:96
uint8_t l6e
Definition mrtk_l6.h:95
#define malloc(x)
Definition toml.c:52
#define free(x)
Definition toml.c:53