Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SigMF file format support #2632

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/fileformat.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ enum file_type {
F_FLOAT = 1 << 1,
F_1CH = 1 << 4,
F_2CH = 2 << 4,
F_W4 = 4 << 8,
F_W8 = 8 << 8,
F_W12 = 12 << 8,
F_W16 = 16 << 8,
Expand Down Expand Up @@ -56,6 +57,8 @@ enum file_type {
F_CS32 = F_2CH | F_SIGNED | F_INT | F_W32,
F_F32 = F_1CH | F_SIGNED | F_FLOAT | F_W32,
F_CF32 = F_2CH | F_SIGNED | F_FLOAT | F_W32,
F_F64 = F_1CH | F_SIGNED | F_FLOAT | F_W64,
F_CF64 = F_2CH | F_SIGNED | F_FLOAT | F_W64,
// compound types
CU8_IQ = F_CU8 | F_IQ,
CS8_IQ = F_CS8 | F_IQ,
Expand All @@ -72,14 +75,21 @@ enum file_type {
PULSE_OOK = F_OOK,
};

enum container_type {
FILEFMT_RAW = 0,
FILEFMT_SIGMF = 1,
};

typedef struct {
uint32_t format;
uint32_t raw_format;
uint32_t container;
uint32_t center_frequency;
uint32_t sample_rate;
char const *spec;
char const *path;
FILE *file;
void *file_aux;
} file_info_t;

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

/// Return a SigMF datset type string for the format.
char const *file_info_to_sigmf_type(file_info_t *info);

/// Parse a SigMF datset type string to a format.
uint32_t file_info_from_sigmf_type(char const *sigmf_datatype);

#endif /* INCLUDE_FILEFORMAT_H_ */
95 changes: 95 additions & 0 deletions include/microtar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2017 rxi
* modified 2023 by Christian Zuckschwerdt
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See `microtar.c` for details.
*/

#ifndef MICROTAR_H
#define MICROTAR_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>
#include <stdlib.h>

#define MTAR_VERSION "0.1.0"

enum {
MTAR_ESUCCESS = 0,
MTAR_EFAILURE = -1,
MTAR_EOPENFAIL = -2,
MTAR_EREADFAIL = -3,
MTAR_EWRITEFAIL = -4,
MTAR_ESEEKFAIL = -5,
MTAR_EBADCHKSUM = -6,
MTAR_ENULLRECORD = -7,
MTAR_ENOTFOUND = -8
};

enum {
MTAR_TREG = '0',
MTAR_TLNK = '1',
MTAR_TSYM = '2',
MTAR_TCHR = '3',
MTAR_TBLK = '4',
MTAR_TDIR = '5',
MTAR_TFIFO = '6',
MTAR_TCONT = '7', /* reserved */
MTAR_TXHD = 'x', /* Extended header referring to the next file in the archive */
MTAR_TXGL = 'g' /* Global extended header */
};

typedef struct {
unsigned mode;
unsigned owner;
unsigned group;
unsigned size;
unsigned mtime;
unsigned type;
unsigned devmajor; /* USTAR ext. */
unsigned devminor; /* USTAR ext. */
char name[101];
char linkname[101];
char uname[33]; /* USTAR ext. */
char gname[33]; /* USTAR ext. */
} mtar_header_t;


typedef struct mtar_t mtar_t;

struct mtar_t {
void *stream;
unsigned pos;
unsigned remaining_data;
unsigned last_header;
};


const char* mtar_strerror(int err);

int mtar_open(mtar_t *tar, const char *filename, const char *mode);
int mtar_close(mtar_t *tar);

int mtar_seek(mtar_t *tar, unsigned pos);
int mtar_rewind(mtar_t *tar);
int mtar_next(mtar_t *tar);
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
int mtar_read_header(mtar_t *tar, mtar_header_t *h);
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size);

int mtar_write_header(mtar_t *tar, const mtar_header_t *h);
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size);
int mtar_write_dir_header(mtar_t *tar, const char *name);
int mtar_write_data(mtar_t *tar, const void *data, unsigned size);
int mtar_finalize(mtar_t *tar);

#ifdef __cplusplus
}
#endif

#endif
4 changes: 3 additions & 1 deletion include/samp_grab.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <stdint.h>

typedef struct samp_grab {
int sg_fileformat; ///< Signal grabber format: 0=raw, 1=SigMF

uint32_t *frequency;
uint32_t *samp_rate;
int *sample_size;
Expand All @@ -26,7 +28,7 @@ typedef struct samp_grab {
unsigned sg_len;
} samp_grab_t;

samp_grab_t *samp_grab_create(unsigned size);
samp_grab_t *samp_grab_create(unsigned size, int sg_fileformat);

void samp_grab_free(samp_grab_t *g);

Expand Down
67 changes: 67 additions & 0 deletions include/sigmf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/** @file
SigMF file read and write support.

Copyright (C) 2023 Christian Zuckschwerdt

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/

#ifndef INCLUDE_SIGMF_H_
#define INCLUDE_SIGMF_H_

#include <stdint.h>
#include <stdio.h>

#include "microtar.h"

/** A data structure for SigMF reader/writer related fields.
*/
typedef struct sigmf {
char *datatype; ///< meta data
uint32_t sample_rate; ///< meta data
char *recorder; ///< meta data
char *description; ///< meta data
uint32_t first_sample_start; ///< meta data
uint32_t first_frequency; ///< meta data

//FILE *file; ///< data stream output
uint32_t data_len; ///< data size, if known beforehand
uint32_t data_offset; ///< data offset in the file
mtar_t mtar; ///< base tar file
} sigmf_t;

/** Check if the given path is a valid .sigmf file name.
*/
int sigmf_valid_filename(char const *p);

/** A simple SigMF reader.

Opens the file at @p path, reads the meta data and seeks to the data offset.

Collections are not supported and a warning will be reported if encountered.
Multiple streams per file are not supported and a warning will be reported if encountered.
*/
int sigmf_reader_open(sigmf_t *sigmf, char const *path);

/** Closes the SigMF reader.
*/
int sigmf_reader_close(sigmf_t *sigmf);

/** A simple SigMF writer.

Creates the file at @p path, writes the meta data and seeks to the data offset.
*/
int sigmf_writer_open(sigmf_t *sigmf, char const *path, int overwrite);

/** Finalizes writing and closes the SigMF writer.
*/
int sigmf_writer_close(sigmf_t *sigmf);

/** Frees SigMF data items, but not the struct itself.
*/
int sigmf_free_items(sigmf_t *sigmf);

#endif /* INCLUDE_SIGMF_H_ */
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_library(r_433 STATIC
jsmn.c
list.c
logger.c
microtar.c
mongoose.c
optparse.c
output_file.c
Expand All @@ -40,6 +41,7 @@ add_library(r_433 STATIC
rfraw.c
samp_grab.c
sdr.c
sigmf.c
term_ctl.c
util.c
write_sigrok.c
Expand Down
57 changes: 54 additions & 3 deletions src/fileformat.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,51 @@ char const *file_info_string(file_info_t *info)
}
}

char const *file_info_to_sigmf_type(file_info_t *info)
{
switch (info->format) {
case CU8_IQ: return "cu8";
case CS8_IQ: return "ci8";
//case CU16_IQ: return "cu16_le";
case CS16_IQ: return "ci16_le";
//case CU32_IQ: return "cu32_le";
//case CS32_IQ: return "ci32_le";
case CF32_IQ: return "cf32_le";
//case CF64_IQ: return "cf64_le";
//case U8_IQ: return "ru8";
//case S8_IQ: return "ri8";
//case U16_IQ: return "ru16_le";
//case S16_IQ: return "ri16_le";
//case U32_IQ: return "ru32_le";
//case S32_IQ: return "ri32_le";
//case F32_IQ: return "rf32_le";
//case F64_IQ: return "rf64_le";
default: return "Unknown";
}
}

uint32_t file_info_from_sigmf_type(char const *sigmf_datatype)
{
if (!sigmf_datatype) return 0;
else if (!strcmp("cu8", sigmf_datatype)) return F_CU8;
else if (!strcmp("ci8", sigmf_datatype)) return F_CS8;
else if (!strcmp("cu16_le", sigmf_datatype)) return F_CU16;
else if (!strcmp("ci16_le", sigmf_datatype)) return F_CS16;
else if (!strcmp("cu32_le", sigmf_datatype)) return F_CU32;
else if (!strcmp("ci32_le", sigmf_datatype)) return F_CS32;
else if (!strcmp("cf32_le", sigmf_datatype)) return F_CF32;
else if (!strcmp("cf64_le", sigmf_datatype)) return F_CF64;
else if (!strcmp("ru8", sigmf_datatype)) return F_U8;
else if (!strcmp("ri8", sigmf_datatype)) return F_S8;
else if (!strcmp("ru16_le", sigmf_datatype)) return F_U16;
else if (!strcmp("ri16_le", sigmf_datatype)) return F_S16;
else if (!strcmp("ru32_le", sigmf_datatype)) return F_U32;
else if (!strcmp("ri32_le", sigmf_datatype)) return F_S32;
else if (!strcmp("rf32_le", sigmf_datatype)) return F_F32;
else if (!strcmp("rf64_le", sigmf_datatype)) return F_F64;
else return 0;
}

static void file_type_set_format(uint32_t *type, uint32_t val)
{
*type = (*type & 0xffff0000) | val;
Expand Down Expand Up @@ -203,9 +248,10 @@ static void file_type(char const *filename, file_info_t *info)
else if (len == 4 && !strncasecmp("cf32", t, 4)) file_type_set_format(&info->format, F_CF32);
else if (len == 5 && !strncasecmp("cfile", t, 5)) file_type_set_format(&info->format, F_CF32); // compat
else if (len == 5 && !strncasecmp("logic", t, 5)) file_type_set_content(&info->format, F_LOGIC);
else if (len == 3 && !strncasecmp("complex16u", t, 10)) file_type_set_format(&info->format, F_CU8); // compat
else if (len == 3 && !strncasecmp("complex16s", t, 10)) file_type_set_format(&info->format, F_CS8); // compat
else if (len == 4 && !strncasecmp("complex", t, 7)) file_type_set_format(&info->format, F_CF32); // compat
else if (len == 10 && !strncasecmp("complex16u", t, 10)) file_type_set_format(&info->format, F_CU8); // compat
else if (len == 10 && !strncasecmp("complex16s", t, 10)) file_type_set_format(&info->format, F_CS8); // compat
else if (len == 7 && !strncasecmp("complex", t, 7)) file_type_set_format(&info->format, F_CF32); // compat
else if (len == 5 && !strncasecmp("sigmf", t, 5)) info->container = FILEFMT_SIGMF;
//else fprintf(stderr, "Skipping type (len %ld) %s\n", len, t);
} else {
p++; // skip non-alphanum char otherwise
Expand Down Expand Up @@ -255,6 +301,11 @@ int file_info_parse_filename(file_info_t *info, char const *filename)
return 0;
}

//if (sigmf_valid_filename(filename)) {
// // just set the container type
// // other info needs to be read later
//}

info->spec = filename;

char const *p = last_plain_colon(filename);
Expand Down
Loading