Skip to content

Commit 803c805

Browse files
authored
Add SigMF file format support (#2632)
1 parent 81978f1 commit 803c805

11 files changed

Lines changed: 1318 additions & 28 deletions

File tree

include/fileformat.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ enum file_type {
2727
F_FLOAT = 1 << 1,
2828
F_1CH = 1 << 4,
2929
F_2CH = 2 << 4,
30+
F_W4 = 4 << 8,
3031
F_W8 = 8 << 8,
3132
F_W12 = 12 << 8,
3233
F_W16 = 16 << 8,
@@ -56,6 +57,8 @@ enum file_type {
5657
F_CS32 = F_2CH | F_SIGNED | F_INT | F_W32,
5758
F_F32 = F_1CH | F_SIGNED | F_FLOAT | F_W32,
5859
F_CF32 = F_2CH | F_SIGNED | F_FLOAT | F_W32,
60+
F_F64 = F_1CH | F_SIGNED | F_FLOAT | F_W64,
61+
F_CF64 = F_2CH | F_SIGNED | F_FLOAT | F_W64,
5962
// compound types
6063
CU8_IQ = F_CU8 | F_IQ,
6164
CS8_IQ = F_CS8 | F_IQ,
@@ -72,14 +75,21 @@ enum file_type {
7275
PULSE_OOK = F_OOK,
7376
};
7477

78+
enum container_type {
79+
FILEFMT_RAW = 0,
80+
FILEFMT_SIGMF = 1,
81+
};
82+
7583
typedef struct {
7684
uint32_t format;
7785
uint32_t raw_format;
86+
uint32_t container;
7887
uint32_t center_frequency;
7988
uint32_t sample_rate;
8089
char const *spec;
8190
char const *path;
8291
FILE *file;
92+
void *file_aux;
8393
} file_info_t;
8494

8595
/// Clear all file info.
@@ -135,4 +145,10 @@ void file_info_check_write(file_info_t *info);
135145
/// @return a string describing the format
136146
char const *file_info_string(file_info_t *info);
137147

148+
/// Return a SigMF dataset type string for the format.
149+
char const *file_info_to_sigmf_type(file_info_t *info);
150+
151+
/// Parse a SigMF dataset type string to a format.
152+
uint32_t file_info_from_sigmf_type(char const *sigmf_datatype);
153+
138154
#endif /* INCLUDE_FILEFORMAT_H_ */

include/microtar.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* Copyright (c) 2017 rxi
3+
* modified 2023 by Christian Zuckschwerdt
4+
*
5+
* This library is free software; you can redistribute it and/or modify it
6+
* under the terms of the MIT license. See `microtar.c` for details.
7+
*/
8+
9+
#ifndef MICROTAR_H
10+
#define MICROTAR_H
11+
12+
#ifdef __cplusplus
13+
extern "C"
14+
{
15+
#endif
16+
17+
#include <stdio.h>
18+
#include <stdlib.h>
19+
20+
#define MTAR_VERSION "0.1.0"
21+
22+
enum {
23+
MTAR_ESUCCESS = 0,
24+
MTAR_EFAILURE = -1,
25+
MTAR_EOPENFAIL = -2,
26+
MTAR_EREADFAIL = -3,
27+
MTAR_EWRITEFAIL = -4,
28+
MTAR_ESEEKFAIL = -5,
29+
MTAR_EBADCHKSUM = -6,
30+
MTAR_ENULLRECORD = -7,
31+
MTAR_ENOTFOUND = -8
32+
};
33+
34+
enum {
35+
MTAR_TREG = '0',
36+
MTAR_TLNK = '1',
37+
MTAR_TSYM = '2',
38+
MTAR_TCHR = '3',
39+
MTAR_TBLK = '4',
40+
MTAR_TDIR = '5',
41+
MTAR_TFIFO = '6',
42+
MTAR_TCONT = '7', /* reserved */
43+
MTAR_TXHD = 'x', /* Extended header referring to the next file in the archive */
44+
MTAR_TXGL = 'g' /* Global extended header */
45+
};
46+
47+
typedef struct {
48+
unsigned mode;
49+
unsigned owner;
50+
unsigned group;
51+
unsigned size;
52+
unsigned mtime;
53+
unsigned type;
54+
unsigned devmajor; /* USTAR ext. */
55+
unsigned devminor; /* USTAR ext. */
56+
char name[101];
57+
char linkname[101];
58+
char uname[33]; /* USTAR ext. */
59+
char gname[33]; /* USTAR ext. */
60+
} mtar_header_t;
61+
62+
63+
typedef struct mtar_t mtar_t;
64+
65+
struct mtar_t {
66+
void *stream;
67+
unsigned pos;
68+
unsigned remaining_data;
69+
unsigned last_header;
70+
};
71+
72+
73+
const char* mtar_strerror(int err);
74+
75+
int mtar_open(mtar_t *tar, const char *filename, const char *mode);
76+
int mtar_close(mtar_t *tar);
77+
78+
int mtar_seek(mtar_t *tar, unsigned pos);
79+
int mtar_rewind(mtar_t *tar);
80+
int mtar_next(mtar_t *tar);
81+
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
82+
int mtar_read_header(mtar_t *tar, mtar_header_t *h);
83+
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size);
84+
85+
int mtar_write_header(mtar_t *tar, const mtar_header_t *h);
86+
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size);
87+
int mtar_write_dir_header(mtar_t *tar, const char *name);
88+
int mtar_write_data(mtar_t *tar, const void *data, unsigned size);
89+
int mtar_finalize(mtar_t *tar);
90+
91+
#ifdef __cplusplus
92+
}
93+
#endif
94+
95+
#endif

include/samp_grab.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <stdint.h>
1616

1717
typedef struct samp_grab {
18+
int sg_fileformat; ///< Signal grabber format: 0=raw, 1=SigMF
19+
1820
uint32_t *frequency;
1921
uint32_t *samp_rate;
2022
int *sample_size;
@@ -26,7 +28,7 @@ typedef struct samp_grab {
2628
unsigned sg_len;
2729
} samp_grab_t;
2830

29-
samp_grab_t *samp_grab_create(unsigned size);
31+
samp_grab_t *samp_grab_create(unsigned size, int sg_fileformat);
3032

3133
void samp_grab_free(samp_grab_t *g);
3234

include/sigmf.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/** @file
2+
SigMF file read and write support.
3+
4+
Copyright (C) 2023 Christian Zuckschwerdt
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation; either version 2 of the License, or
9+
(at your option) any later version.
10+
*/
11+
12+
#ifndef INCLUDE_SIGMF_H_
13+
#define INCLUDE_SIGMF_H_
14+
15+
#include <stdint.h>
16+
#include <stdio.h>
17+
18+
#include "microtar.h"
19+
20+
/** A data structure for SigMF reader/writer related fields.
21+
*/
22+
typedef struct sigmf {
23+
char *datatype; ///< meta data
24+
uint32_t sample_rate; ///< meta data
25+
char *recorder; ///< meta data
26+
char *description; ///< meta data
27+
uint32_t first_sample_start; ///< meta data
28+
uint32_t first_frequency; ///< meta data
29+
30+
//FILE *file; ///< data stream output
31+
uint32_t data_len; ///< data size, if known beforehand
32+
uint32_t data_offset; ///< data offset in the file
33+
mtar_t mtar; ///< base tar file
34+
} sigmf_t;
35+
36+
/** Check if the given path is a valid .sigmf file name.
37+
*/
38+
int sigmf_valid_filename(char const *p);
39+
40+
/** A simple SigMF reader.
41+
42+
Opens the file at @p path, reads the meta data and seeks to the data offset.
43+
44+
Collections are not supported and a warning will be reported if encountered.
45+
Multiple streams per file are not supported and a warning will be reported if encountered.
46+
*/
47+
int sigmf_reader_open(sigmf_t *sigmf, char const *path);
48+
49+
/** Closes the SigMF reader.
50+
*/
51+
int sigmf_reader_close(sigmf_t *sigmf);
52+
53+
/** A simple SigMF writer.
54+
55+
Creates the file at @p path, writes the meta data and seeks to the data offset.
56+
*/
57+
int sigmf_writer_open(sigmf_t *sigmf, char const *path, int overwrite);
58+
59+
/** Finalizes writing and closes the SigMF writer.
60+
*/
61+
int sigmf_writer_close(sigmf_t *sigmf);
62+
63+
/** Frees SigMF data items, but not the struct itself.
64+
*/
65+
int sigmf_free_items(sigmf_t *sigmf);
66+
67+
#endif /* INCLUDE_SIGMF_H_ */

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_library(r_433 STATIC
2121
jsmn.c
2222
list.c
2323
logger.c
24+
microtar.c
2425
mongoose.c
2526
optparse.c
2627
output_file.c
@@ -41,6 +42,7 @@ add_library(r_433 STATIC
4142
rfraw.c
4243
samp_grab.c
4344
sdr.c
45+
sigmf.c
4446
term_ctl.c
4547
write_sigrok.c
4648
devices/abmt.c

src/fileformat.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,51 @@ char const *file_info_string(file_info_t *info)
9494
}
9595
}
9696

97+
char const *file_info_to_sigmf_type(file_info_t *info)
98+
{
99+
switch (info->format) {
100+
case CU8_IQ: return "cu8";
101+
case CS8_IQ: return "ci8";
102+
//case CU16_IQ: return "cu16_le";
103+
case CS16_IQ: return "ci16_le";
104+
//case CU32_IQ: return "cu32_le";
105+
//case CS32_IQ: return "ci32_le";
106+
case CF32_IQ: return "cf32_le";
107+
//case CF64_IQ: return "cf64_le";
108+
//case U8_IQ: return "ru8";
109+
//case S8_IQ: return "ri8";
110+
//case U16_IQ: return "ru16_le";
111+
//case S16_IQ: return "ri16_le";
112+
//case U32_IQ: return "ru32_le";
113+
//case S32_IQ: return "ri32_le";
114+
//case F32_IQ: return "rf32_le";
115+
//case F64_IQ: return "rf64_le";
116+
default: return "Unknown";
117+
}
118+
}
119+
120+
uint32_t file_info_from_sigmf_type(char const *sigmf_datatype)
121+
{
122+
if (!sigmf_datatype) return 0;
123+
else if (!strcmp("cu8", sigmf_datatype)) return F_CU8;
124+
else if (!strcmp("ci8", sigmf_datatype)) return F_CS8;
125+
else if (!strcmp("cu16_le", sigmf_datatype)) return F_CU16;
126+
else if (!strcmp("ci16_le", sigmf_datatype)) return F_CS16;
127+
else if (!strcmp("cu32_le", sigmf_datatype)) return F_CU32;
128+
else if (!strcmp("ci32_le", sigmf_datatype)) return F_CS32;
129+
else if (!strcmp("cf32_le", sigmf_datatype)) return F_CF32;
130+
else if (!strcmp("cf64_le", sigmf_datatype)) return F_CF64;
131+
else if (!strcmp("ru8", sigmf_datatype)) return F_U8;
132+
else if (!strcmp("ri8", sigmf_datatype)) return F_S8;
133+
else if (!strcmp("ru16_le", sigmf_datatype)) return F_U16;
134+
else if (!strcmp("ri16_le", sigmf_datatype)) return F_S16;
135+
else if (!strcmp("ru32_le", sigmf_datatype)) return F_U32;
136+
else if (!strcmp("ri32_le", sigmf_datatype)) return F_S32;
137+
else if (!strcmp("rf32_le", sigmf_datatype)) return F_F32;
138+
else if (!strcmp("rf64_le", sigmf_datatype)) return F_F64;
139+
else return 0;
140+
}
141+
97142
static void file_type_set_format(uint32_t *type, uint32_t val)
98143
{
99144
*type = (*type & 0xffff0000) | val;
@@ -206,6 +251,7 @@ static void file_type(char const *filename, file_info_t *info)
206251
else if (len == 10 && !strncasecmp("complex16u", t, 10)) file_type_set_format(&info->format, F_CU8); // compat
207252
else if (len == 10 && !strncasecmp("complex16s", t, 10)) file_type_set_format(&info->format, F_CS8); // compat
208253
else if (len == 7 && !strncasecmp("complex", t, 7)) file_type_set_format(&info->format, F_CF32); // compat
254+
else if (len == 5 && !strncasecmp("sigmf", t, 5)) info->container = FILEFMT_SIGMF;
209255
//else fprintf(stderr, "Skipping type (len %lu) %s\n", (unsigned long)len, t);
210256
} else {
211257
p++; // skip non-alphanum char otherwise
@@ -255,6 +301,11 @@ int file_info_parse_filename(file_info_t *info, char const *filename)
255301
return 0;
256302
}
257303

304+
//if (sigmf_valid_filename(filename)) {
305+
// // just set the container type
306+
// // other info needs to be read later
307+
//}
308+
258309
info->spec = filename;
259310

260311
char const *p = last_plain_colon(filename);

0 commit comments

Comments
 (0)