save failed integration state
This commit is contained in:
parent
473aa805c0
commit
6bd55e7c22
@ -5,7 +5,15 @@ CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/rtable/csp_rtable_cidr.c)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/crypto/*.c)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/arch/posix/*.c)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/transport/*.c)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/p60-dock_client/src/*.c)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/*.c)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/rparam/*.c)
|
||||
|
||||
INCLUDES += $(CURRENTPATH)/libcsp/include
|
||||
INCLUDES += $(CURRENTPATH)/libcsp/include/csp/crypto
|
||||
INCLUDES += $(CURRENTPATH)/libcsp
|
||||
INCLUDES += $(CURRENTPATH)/p60-dock_client/include/gs/p60-dock/param
|
||||
INCLUDES += $(CURRENTPATH)/libparam_client/include
|
||||
INCLUDES += $(CURRENTPATH)/libparam_client/include/deprecated
|
||||
INCLUDES += $(CURRENTPATH)/libp60_client/include
|
||||
INCLUDES += $(CURRENTPATH)/libutil/include
|
48
gomspace/libp60_client/include/p60.h
Normal file
48
gomspace/libp60_client/include/p60.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef _P60_H_
|
||||
#define _P60_H_
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define P60_PORT_RPARAM 7
|
||||
#define P60_PORT_GNDWDT_RESET 9
|
||||
#define P60_PORT_CMDCONTROL 10
|
||||
#define P60_PORT_GSSB_SERVICE 15
|
||||
#define P60_PORT_GSCRIPT 22
|
||||
|
||||
/** FRAM MEMORY MAP */
|
||||
#define P60_FRAM_BOARD 0x0000
|
||||
|
||||
/** FRAM FILENAMES */
|
||||
#define P60_FNO_BOARD 0
|
||||
#define P60_FNO_BOARD_DFL 4
|
||||
|
||||
#define P60_FRAM_WP_BEGIN (0x1000)
|
||||
#define P60_FRAM_WP_END (0x1C00 - 1)
|
||||
|
||||
/** GND WD FRAM ADDR **/
|
||||
#define P60_FRAM_GNDWDT 0x1F00
|
||||
|
||||
/** PARAM INDEX MAP */
|
||||
#define P60_BOARD_PARAM 0
|
||||
|
||||
#define DEVICE_FM24CL64B 0
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN_RST = 0,
|
||||
GND_WDT_RST,
|
||||
I2C_WDT_RST,
|
||||
CAN_WDT_RST,
|
||||
EXT_HARD_RST,
|
||||
EXT_SOFT_RST,
|
||||
} p60_reset_cause_t;
|
||||
|
||||
extern const uint8_t board_fallback_type;
|
||||
extern const uint8_t csp_fallback_addr;
|
||||
extern const uint8_t board_rs422_mode;
|
||||
|
||||
extern void module_init_early(void);
|
||||
extern void module_init(void);
|
||||
extern void wdt_gnd_clear(void);
|
||||
extern uint16_t command_control(uint8_t *packet, uint16_t length);
|
||||
extern void module_task(void * pvParameters);
|
||||
|
||||
#endif /* _P60_H_ */
|
35
gomspace/libp60_client/include/p60_board.h
Normal file
35
gomspace/libp60_client/include/p60_board.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* NanoCom firmware
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef P60_PARAM_H_
|
||||
#define P60_PARAM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <param/param_types.h>
|
||||
|
||||
/**
|
||||
* Define memory space
|
||||
*/
|
||||
#define P60_BOARD_UID 0x00
|
||||
#define P60_BOARD_TYPE 0x10
|
||||
#define P60_BOARD_REV 0x11
|
||||
#define P60_BOARD_CSP_ADDR 0x12
|
||||
#define P60_BOARD_I2C_ADDR 0x13
|
||||
#define P60_BOARD_I2C_SPEED_KHZ 0x14
|
||||
#define P60_BOARD_CAN_SPEED_KHZ 0x16
|
||||
#define P60_BOARD_KISS_ENABLE 0x18
|
||||
#define P60_BOARD_RS422_MODE 0x19
|
||||
#define P60_BOARD_RS422_SPEED_KHZ 0x1C
|
||||
#define P60_BOARD_RTABLE_STR 0x20 //! This one is 0x60 = 96 bytes
|
||||
#define P60_BOARD_RTABLE_STR_SIZE 0x60
|
||||
|
||||
/** Define the memory size */
|
||||
#define P60_BOARD_PARAM_SIZE 0x80
|
||||
|
||||
extern const param_table_t p60_config[];
|
||||
extern const int p60_config_count;
|
||||
|
||||
#endif /* P60_PARAM_H_ */
|
62
gomspace/libp60_client/include/power_if.h
Normal file
62
gomspace/libp60_client/include/power_if.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* NanoPower firmware
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POWER_IF_H_
|
||||
#define POWER_IF_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define POWER_IF_SET 1
|
||||
#define POWER_IF_GET 2
|
||||
#define POWER_IF_LIST 3
|
||||
|
||||
#define POWER_IF_STATUS_OK 0
|
||||
#define POWER_IF_STATUS_ERROR 1
|
||||
|
||||
#define POWER_IF_NAME_LEN 8
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t ch_idx;
|
||||
uint8_t mode;
|
||||
uint16_t on_cnt;
|
||||
uint16_t off_cnt;
|
||||
uint16_t cur_lu_lim;
|
||||
uint16_t cur_lim;
|
||||
uint16_t voltage;
|
||||
int16_t current;
|
||||
uint16_t latchup;
|
||||
char name[POWER_IF_NAME_LEN];
|
||||
} power_if_ch_status_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t ch_idx;
|
||||
uint8_t mode;
|
||||
char name[8];
|
||||
} power_if_list_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
power_if_ch_status_t ch_status;
|
||||
} power_if_cmd_request_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
power_if_ch_status_t ch_status;
|
||||
} power_if_cmd_response_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t count;
|
||||
power_if_list_t list[16];
|
||||
} power_if_cmd_list_response_t;
|
||||
|
||||
int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p);
|
||||
uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max);
|
||||
|
||||
#endif /* POWER_IF_H_ */
|
147
gomspace/libp60_client/src/cmd/power_if_cmd.c
Normal file
147
gomspace/libp60_client/src/cmd/power_if_cmd.c
Normal file
@ -0,0 +1,147 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <csp/csp.h>
|
||||
#include <util/console.h>
|
||||
|
||||
#include <power_if.h>
|
||||
|
||||
static uint8_t power_if_port = 10;
|
||||
static uint32_t power_if_timeout = 5000;
|
||||
|
||||
static int cmd_power_if_port(struct command_context * ctx) {
|
||||
if (ctx->argc < 2) {
|
||||
printf("Current port is %d\n", power_if_port);
|
||||
return CMD_ERROR_NONE;
|
||||
}
|
||||
power_if_port = atoi(ctx->argv[1]);
|
||||
return CMD_ERROR_NONE;
|
||||
}
|
||||
|
||||
static int cmd_power_if_timeout(struct command_context *ctx) {
|
||||
if (ctx->argc < 2) {
|
||||
printf("Current timeout is %"PRIu32"\n", power_if_timeout);
|
||||
return CMD_ERROR_NONE;
|
||||
}
|
||||
if (sscanf(command_args(ctx), "%"SCNu32, &power_if_timeout) != 1)
|
||||
return CMD_ERROR_SYNTAX;
|
||||
if (power_if_timeout > 30000) {
|
||||
printf("Timeout set to high, limited to 30000 ms\n");
|
||||
power_if_timeout = 30000;
|
||||
}
|
||||
printf("Timeout set to %"PRIu32"\n", power_if_timeout);
|
||||
return CMD_ERROR_NONE;
|
||||
}
|
||||
|
||||
static int cmd_power_if_set_get(struct command_context * ctx) {
|
||||
power_if_ch_status_t ch_status;
|
||||
|
||||
if (ctx->argc < 3) {
|
||||
return CMD_ERROR_SYNTAX;
|
||||
}
|
||||
uint8_t node = atoi(ctx->argv[1]);
|
||||
memset(&ch_status, 0, sizeof(ch_status));
|
||||
strncpy(ch_status.name, ctx->argv[2], 7);
|
||||
ch_status.name[7] = 0;
|
||||
char * cmd = ctx->argv[0];
|
||||
if (!strcmp(cmd, "status") && (ctx->argc == 3)) {
|
||||
if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_GET, &ch_status)) {
|
||||
return CMD_ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
if (!strcmp(cmd, "on")) {
|
||||
ch_status.mode = 1;
|
||||
} else if (!strcmp(cmd, "off")) {
|
||||
ch_status.mode = 0;
|
||||
}
|
||||
ch_status.on_cnt = (ctx->argc > 3) ? atoi(ctx->argv[3]) : 0;
|
||||
ch_status.off_cnt = (ctx->argc > 4) ? atoi(ctx->argv[4]) : 0;
|
||||
if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_SET, &ch_status)) {
|
||||
return CMD_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
printf("Node %u, Output channel '%s' (%u) is %s\r\n", node, ch_status.name, ch_status.ch_idx, (ch_status.mode ? "ON": "OFF"));
|
||||
printf(" ch_idx: %u\r\n", ch_status.ch_idx);
|
||||
printf(" mode: %u\r\n", ch_status.mode);
|
||||
printf(" on_cnt: %u\r\n", ch_status.on_cnt);
|
||||
printf(" off_cnt: %u\r\n", ch_status.off_cnt);
|
||||
printf(" cur_lu_lim: %u\r\n", ch_status.cur_lu_lim);
|
||||
printf(" cur_lim: %u\r\n", ch_status.cur_lim);
|
||||
printf(" voltage: %u\r\n", ch_status.voltage);
|
||||
printf(" current: %d\r\n", ch_status.current);
|
||||
printf(" latchup: %u\r\n", ch_status.latchup);
|
||||
|
||||
return CMD_ERROR_NONE;
|
||||
}
|
||||
|
||||
static int cmd_power_if_list(struct command_context * ctx) {
|
||||
if (ctx->argc < 2) {
|
||||
return CMD_ERROR_SYNTAX;
|
||||
}
|
||||
uint8_t node = atoi(ctx->argv[1]);
|
||||
power_if_cmd_list_response_t ch_list;
|
||||
if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_LIST, &ch_list)) {
|
||||
return CMD_ERROR_FAIL;
|
||||
}
|
||||
printf("ch name status\r\n");
|
||||
for (uint8_t ch = 0; ch < ch_list.count; ch++) {
|
||||
printf("%2u %-8s %s\r\n", ch_list.list[ch].ch_idx, ch_list.list[ch].name, ch_list.list[ch].mode ? "ON": "OFF");
|
||||
}
|
||||
return CMD_ERROR_NONE;
|
||||
}
|
||||
|
||||
command_t power_if_commands[] = {
|
||||
{
|
||||
.name = "port",
|
||||
.help = "Set power interface port (default is 10)",
|
||||
.usage = "<port>",
|
||||
.handler = cmd_power_if_port,
|
||||
},
|
||||
{
|
||||
.name = "timeout",
|
||||
.help = "Set power interface timeout in milliseconds",
|
||||
.usage = "<timeout>",
|
||||
.handler = cmd_power_if_timeout,
|
||||
},
|
||||
{
|
||||
.name = "status",
|
||||
.help = "Get power channel status",
|
||||
.usage = "<node> <channel>",
|
||||
.handler = cmd_power_if_set_get,
|
||||
},
|
||||
{
|
||||
.name = "on",
|
||||
.help = "Turn power channel on",
|
||||
.usage = "<node> <channel> [<on_cnt> <off_cnt>]",
|
||||
.handler = cmd_power_if_set_get,
|
||||
},
|
||||
{
|
||||
.name = "off",
|
||||
.help = "Turn power channel off",
|
||||
.usage = "<node> <channel> off [<on_cnt> <off_cnt>]",
|
||||
.handler = cmd_power_if_set_get,
|
||||
},
|
||||
{
|
||||
.name = "list",
|
||||
.help = "Get list power channels",
|
||||
.usage = "<node>",
|
||||
.handler = cmd_power_if_list,
|
||||
},
|
||||
};
|
||||
|
||||
command_t __root_command power_if_root_command[] = {
|
||||
{
|
||||
.name = "power",
|
||||
.help = "client: NanoPower P60",
|
||||
.chain = INIT_CHAIN(power_if_commands),
|
||||
}
|
||||
};
|
||||
|
||||
void cmd_power_if_setup(void) {
|
||||
command_register(power_if_root_command);
|
||||
}
|
33
gomspace/libp60_client/src/p60_client.c
Normal file
33
gomspace/libp60_client/src/p60_client.c
Normal file
@ -0,0 +1,33 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* NanoCom firmware
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <csp/csp.h>
|
||||
#include <csp/csp_endian.h>
|
||||
|
||||
#include <p60.h>
|
||||
#include <p60_board.h>
|
||||
|
||||
/**
|
||||
* Setup info about board configuration parameters
|
||||
*/
|
||||
const param_table_t p60_config[] = {
|
||||
{.name = "uid", .addr = P60_BOARD_UID, .type = PARAM_STRING, .size = 16},
|
||||
{.name = "type", .addr = P60_BOARD_TYPE, .type = PARAM_UINT8, .size = sizeof(uint8_t)},
|
||||
{.name = "rev", .addr = P60_BOARD_REV, .type = PARAM_UINT8, .size = sizeof(uint8_t)},
|
||||
{.name = "csp_addr", .addr = P60_BOARD_CSP_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)},
|
||||
{.name = "i2c_addr", .addr = P60_BOARD_I2C_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)},
|
||||
{.name = "i2c_speed", .addr = P60_BOARD_I2C_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)},
|
||||
{.name = "can_speed", .addr = P60_BOARD_CAN_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)},
|
||||
{.name = "kiss_en", .addr = P60_BOARD_KISS_ENABLE, .type = PARAM_UINT8, .size = sizeof(uint8_t)},
|
||||
{.name = "rs422_mode", .addr = P60_BOARD_RS422_MODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)},
|
||||
{.name = "rs422_speed", .addr = P60_BOARD_RS422_SPEED_KHZ, .type = PARAM_UINT32, .size = sizeof(uint32_t)},
|
||||
{.name = "csp_rtable", .addr = P60_BOARD_RTABLE_STR, .type = PARAM_STRING, .size = P60_BOARD_RTABLE_STR_SIZE},
|
||||
|
||||
};
|
||||
|
||||
const int p60_config_count = sizeof(p60_config) / sizeof(p60_config[0]);
|
91
gomspace/libp60_client/src/power_if.c
Normal file
91
gomspace/libp60_client/src/power_if.c
Normal file
@ -0,0 +1,91 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* NanoPower firmware
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <csp/csp.h>
|
||||
#include <csp/csp_endian.h>
|
||||
|
||||
#include <power_if.h>
|
||||
|
||||
uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max) {
|
||||
|
||||
uint8_t result = 1;
|
||||
uint8_t len = strlen(ch_name);
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!isdigit(ch_name[i])) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result) {
|
||||
*ch_no = atoi(ch_name);
|
||||
if (*ch_no >= ch_no_max) {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p) {
|
||||
|
||||
power_if_cmd_request_t req;
|
||||
|
||||
if ((cmd == POWER_IF_SET) || (cmd == POWER_IF_GET)) {
|
||||
power_if_cmd_response_t resp;
|
||||
power_if_ch_status_t * ch_status = (power_if_ch_status_t *)ch_status_p;
|
||||
if (cmd == POWER_IF_SET) {
|
||||
req.cmd = POWER_IF_SET;
|
||||
req.ch_status.mode = ch_status->mode;
|
||||
req.ch_status.on_cnt = csp_hton16(ch_status->on_cnt);
|
||||
req.ch_status.off_cnt = csp_hton16(ch_status->off_cnt);
|
||||
} else {
|
||||
req.cmd = POWER_IF_GET;
|
||||
req.ch_status.mode = 0;
|
||||
req.ch_status.on_cnt = 0;
|
||||
req.ch_status.off_cnt = 0;
|
||||
}
|
||||
ch_status->name[POWER_IF_NAME_LEN - 1] = 0;
|
||||
strcpy(req.ch_status.name, ch_status->name);
|
||||
if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), &resp, sizeof(power_if_cmd_response_t))) {
|
||||
if ((resp.cmd == POWER_IF_SET) || (resp.cmd == POWER_IF_GET)) {
|
||||
if (resp.status == POWER_IF_STATUS_OK) {
|
||||
ch_status->ch_idx = resp.ch_status.ch_idx;
|
||||
ch_status->mode = resp.ch_status.mode;
|
||||
ch_status->on_cnt = csp_ntoh16(resp.ch_status.on_cnt);
|
||||
ch_status->off_cnt = csp_ntoh16(resp.ch_status.off_cnt);
|
||||
ch_status->cur_lu_lim = csp_ntoh16(resp.ch_status.cur_lu_lim);
|
||||
ch_status->cur_lim = csp_ntoh16(resp.ch_status.cur_lim);
|
||||
ch_status->voltage = csp_ntoh16(resp.ch_status.voltage);
|
||||
ch_status->current = csp_ntoh16(resp.ch_status.current);
|
||||
ch_status->latchup = csp_ntoh16(resp.ch_status.latchup);
|
||||
strncpy(ch_status->name, resp.ch_status.name, POWER_IF_NAME_LEN - 1);
|
||||
/* Ensure zero termination*/
|
||||
ch_status->name[POWER_IF_NAME_LEN - 1] = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (cmd == POWER_IF_LIST) {
|
||||
power_if_cmd_list_response_t * ch_list = (power_if_cmd_list_response_t *)ch_status_p;
|
||||
req.cmd = POWER_IF_LIST;
|
||||
req.ch_status.mode = 0;
|
||||
req.ch_status.on_cnt = 0;
|
||||
req.ch_status.off_cnt = 0;
|
||||
req.ch_status.name[0] = 0;
|
||||
if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), ch_list, sizeof(power_if_cmd_list_response_t))) {
|
||||
if ((ch_list->cmd == POWER_IF_LIST) && (ch_list->status == POWER_IF_STATUS_OK)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
28
gomspace/libp60_client/wscript
Normal file
28
gomspace/libp60_client/wscript
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved.
|
||||
|
||||
APPNAME = 'p60_client'
|
||||
|
||||
|
||||
def options(ctx):
|
||||
gr = ctx.add_option_group('NanoPower-P60 library client options')
|
||||
gr.add_option('--disable-libp60-cmd', action='store_true', help='Disable client cmd code for NanoPower-P60 library')
|
||||
|
||||
|
||||
def configure(ctx):
|
||||
ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/*.c'])
|
||||
if not ctx.options.disable_libp60_cmd:
|
||||
ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/cmd/*.c'])
|
||||
|
||||
|
||||
def build(ctx):
|
||||
public_include = APPNAME + '_h'
|
||||
ctx(export_includes=['include'], name=public_include)
|
||||
ctx.objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBP60_CLIENT),
|
||||
target=APPNAME,
|
||||
use=['csp', 'gosh', 'param', 'param_client', 'util', public_include])
|
||||
|
||||
|
||||
def gs_dist(ctx):
|
||||
ctx.add_default_files(source_module=True)
|
@ -0,0 +1,15 @@
|
||||
#ifndef PARAM_PARAM_CLIENT_H
|
||||
#define PARAM_PARAM_CLIENT_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Legacy/deprecated include of header files for libparam client.
|
||||
*/
|
||||
|
||||
#include <param/param_serializer.h>
|
||||
#include <param/param_string.h>
|
||||
#include <param/param_lock.h>
|
||||
#include <param/rparam_client.h>
|
||||
|
||||
#endif
|
@ -0,0 +1,27 @@
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* GomSpace Parameter System.
|
||||
*/
|
||||
#ifndef PARAM_PARAM_LOCK_H_
|
||||
#define PARAM_PARAM_LOCK_H_
|
||||
|
||||
#include <gs/param/table.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline void param_lock(param_index_t * mem)
|
||||
{
|
||||
gs_param_table_lock((gs_param_table_instance_t *) mem);
|
||||
}
|
||||
|
||||
static inline void param_unlock(param_index_t * mem)
|
||||
{
|
||||
gs_param_table_unlock((gs_param_table_instance_t *) mem);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,55 @@
|
||||
#ifndef PARAM_PARAM_SERIALIZER_H
|
||||
#define PARAM_PARAM_SERIALIZER_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* GomSpace Parameter System
|
||||
*/
|
||||
|
||||
#include <param/param_types.h>
|
||||
#include <gs/param/serialize.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef gs_param_serialize_flags_t param_serializer_flags;
|
||||
|
||||
static inline int param_betoh(param_type_t type, void * item)
|
||||
{
|
||||
return gs_param_betoh(type, item);
|
||||
}
|
||||
|
||||
static inline int param_htobe(param_type_t type, void * item)
|
||||
{
|
||||
return gs_param_htobe(type, item);
|
||||
}
|
||||
|
||||
static inline int param_serialize_full_table(param_index_t * mem, unsigned int *start, uint8_t * buf, unsigned int maxbuflen, param_serializer_flags flags)
|
||||
{
|
||||
unsigned int buf_pos = 0;
|
||||
gs_error_t error = gs_param_serialize_full_table((gs_param_table_instance_t *) mem, start, flags, buf, maxbuflen, &buf_pos);
|
||||
return (error == GS_OK) ? (int) buf_pos : -1;
|
||||
}
|
||||
|
||||
static inline gs_error_t param_serialize_item(const param_table_t * param, uint16_t addr, uint8_t * buf, uint16_t * pos, unsigned int maxlen, void * item, param_serializer_flags flags)
|
||||
{
|
||||
unsigned int tmp_pos = *pos;
|
||||
gs_error_t error = gs_param_serialize_item((const gs_param_table_row_t*) param, addr, item, flags, buf, maxlen, &tmp_pos);
|
||||
*pos = tmp_pos;
|
||||
return (error == GS_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline gs_error_t param_deserialize(param_index_t * mem, uint8_t * buf, int len, param_serializer_flags flags)
|
||||
{
|
||||
return (gs_param_deserialize((gs_param_table_instance_t *) mem, buf, len, flags) == GS_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline gs_error_t param_deserialize_item(const param_table_t * param, uint16_t addr, param_index_t * mem, void * item, param_serializer_flags flags)
|
||||
{
|
||||
return (gs_param_deserialize_item((gs_param_table_instance_t *) mem, (const gs_param_table_row_t*)param, addr, item, flags) == GS_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,74 @@
|
||||
#ifndef PARAM_PARAM_STRING_H
|
||||
#define PARAM_PARAM_STRING_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* GomSpace Parameter System
|
||||
*/
|
||||
|
||||
#include <param/param_types.h>
|
||||
#include <gs/param/table.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
const param_table_t * row3;
|
||||
const gs_param_table_row_t * row4;
|
||||
} gs_param_row_align_t;
|
||||
|
||||
static inline const param_table_t * param_find_name(const param_table_t rows[], size_t row_count, const char * name)
|
||||
{
|
||||
gs_param_row_align_t row_in = {.row3 = rows};
|
||||
gs_param_row_align_t row_out = {.row4 = gs_param_row_by_name(name, row_in.row4, row_count)};
|
||||
return row_out.row3;
|
||||
}
|
||||
|
||||
static inline const param_table_t * param_find_addr(const param_table_t rows[], size_t row_count, uint16_t addr)
|
||||
{
|
||||
gs_param_row_align_t row_in = {.row3 = rows};
|
||||
gs_param_row_align_t row_out = {.row4 = gs_param_row_by_address(addr, row_in.row4, row_count)};
|
||||
return row_out.row3;
|
||||
}
|
||||
|
||||
static inline void param_list_single(param_table_t * param, param_index_t * mem, int do_read)
|
||||
{
|
||||
gs_param_list_single((gs_param_table_instance_t *) mem, (const gs_param_table_row_t *) param, (do_read != 0));
|
||||
}
|
||||
|
||||
static inline void param_list(param_index_t * mem, int do_read)
|
||||
{
|
||||
gs_param_list((gs_param_table_instance_t *) mem, (do_read != 0));
|
||||
}
|
||||
|
||||
static inline gs_error_t param_from_string(const param_table_t * param , const char * string, void * value)
|
||||
{
|
||||
return gs_param_from_string((const gs_param_table_row_t *)param , string, value);
|
||||
}
|
||||
|
||||
static inline int param_to_string(const param_table_t * param, char * buf, int pos, const void * value, int with_type, int max_size)
|
||||
{
|
||||
unsigned int written = 0;
|
||||
gs_param_to_string((const gs_param_table_row_t *)param, value, with_type, buf, max_size, pos, &written);
|
||||
return (int) written;
|
||||
}
|
||||
|
||||
static inline const char * param_type_to_string(param_type_t type)
|
||||
{
|
||||
return gs_param_type_to_string(type);
|
||||
}
|
||||
|
||||
static inline uint16_t param_index_chksum(param_index_t * mem)
|
||||
{
|
||||
return gs_param_table_checksum((gs_param_table_instance_t*)mem);
|
||||
}
|
||||
|
||||
static inline uint16_t param_index_chksum2(param_index_t * mem)
|
||||
{
|
||||
return gs_param_table_checksum2((gs_param_table_instance_t*)mem);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,92 @@
|
||||
#ifndef PARAM_PARAM_TYPES_H
|
||||
#define PARAM_PARAM_TYPES_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Legacy/deprecated parameter types and definitions - use <gs/param/types.h>.
|
||||
*/
|
||||
|
||||
#include <gs/param/table.h>
|
||||
#include <gs/param/rparam.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_PARAM_NAME_LEN GS_PARAM_MAX_NAME
|
||||
|
||||
/*
|
||||
Legacy parameter type definition - matches gs_param_type_t exactly.
|
||||
*/
|
||||
typedef gs_param_type_t param_type_t;
|
||||
|
||||
/*
|
||||
Legacy table row definition - matches gs_param_table_row_t exactly.
|
||||
*/
|
||||
typedef struct param_table_s {
|
||||
uint16_t addr;
|
||||
param_type_t type;
|
||||
uint8_t size;
|
||||
uint8_t count; // -> array_size
|
||||
uint8_t flags;
|
||||
char name[MAX_PARAM_NAME_LEN];
|
||||
} param_table_t;
|
||||
|
||||
#define PARAM_COUNT gs_max(GS_PGM_UINT8((param)->count), 1)
|
||||
#define PARAM_SIZE GS_PARAM_SIZE(param)
|
||||
#define PARAM_TYPE GS_PARAM_TYPE(param)
|
||||
#define PARAM_ADDR GS_PARAM_ADDR(param)
|
||||
#define PARAM_FLAGS GS_PARAM_FLAGS(param)
|
||||
|
||||
#define RPARAM_QUERY_MAX_LEN GS_RPARAM_MAX_QUERY
|
||||
|
||||
#define PARAM_MAX_FILESIZE 0x400
|
||||
|
||||
struct param_index_s;
|
||||
|
||||
/*
|
||||
Legacy callback - matches gs_param_callback_func_t exactly.
|
||||
*/
|
||||
typedef void (*param_callback_func)(uint16_t addr, struct param_index_s * index);
|
||||
|
||||
typedef gs_param_table_id_t param_mem;
|
||||
|
||||
/*
|
||||
Legacy table instance definition - matches gs_param_table_instance_t exactly.
|
||||
*/
|
||||
typedef struct param_index_s {
|
||||
const char * name;
|
||||
param_mem mem_id;
|
||||
const param_table_t * table;
|
||||
unsigned int count;
|
||||
void * physaddr;
|
||||
unsigned int size;
|
||||
const gs_param_function_interface_t function_interface;
|
||||
const uint16_t table_chksum;
|
||||
const uint16_t chksum2;
|
||||
const uint16_t checksum_le;
|
||||
const gs_mutex_t lock;
|
||||
param_callback_func callback;
|
||||
const char * const var1;
|
||||
const char * const var2;
|
||||
const void * const var3;
|
||||
const void * const var4;
|
||||
const void * const var5;
|
||||
const void * const var6;
|
||||
const void * const var7;
|
||||
const uint32_t var8;
|
||||
} param_index_t;
|
||||
|
||||
/**
|
||||
Return base size of a parameter type.
|
||||
*/
|
||||
static inline uint8_t param_type_size(param_type_t type)
|
||||
{
|
||||
return gs_param_type_size(type);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,208 @@
|
||||
#ifndef PARAM_RPARAM_CLIENT_H
|
||||
#define PARAM_RPARAM_CLIENT_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
* GomSpace Parameter System
|
||||
*/
|
||||
|
||||
#include <param/param_types.h>
|
||||
#include <gs/param/rparam.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Legacy magic checksum.
|
||||
@deprecated use #GS_RPARAM_MAGIC_CHECKSUM (if remote products supports it).
|
||||
*/
|
||||
#define GS_RPARAM_LEGACY_MAGIC_CHECKSUM 0xb00b
|
||||
|
||||
static inline int rparam_get_full_table(param_index_t* idx, int node, int port, int index_id, uint32_t timeout_ms)
|
||||
{
|
||||
return (gs_rparam_get_full_table((gs_param_table_instance_t *) idx,
|
||||
node,
|
||||
index_id,
|
||||
GS_RPARAM_LEGACY_MAGIC_CHECKSUM,
|
||||
timeout_ms) == GS_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int rparam_download_table_spec_from_remote_and_save_to_file2(const char* fname, uint8_t node, uint8_t port, param_index_t* idx, uint16_t* return_checksum, uint32_t timeout_ms)
|
||||
{
|
||||
return (gs_rparam_download_table_spec((gs_param_table_instance_t *) idx,
|
||||
fname,
|
||||
node,
|
||||
idx->mem_id,
|
||||
timeout_ms,
|
||||
return_checksum) == GS_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int rparam_download_table_spec_from_remote_and_save_to_file(const char* fname, uint8_t node, uint8_t port, param_index_t* idx, uint16_t* checksum)
|
||||
{
|
||||
return rparam_download_table_spec_from_remote_and_save_to_file2(fname, node, port, idx, checksum, 10000);
|
||||
}
|
||||
|
||||
static inline int rparam_load_table_spec_from_file(const char* fname, param_index_t* idx, uint16_t* return_checksum)
|
||||
{
|
||||
return (gs_rparam_load_table_spec((gs_param_table_instance_t *) idx, fname, return_checksum) == GS_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int rparam_get_single(void * out, uint16_t addr, param_type_t type, int size, int mem_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return (gs_rparam_get(node, mem_id, addr, type, GS_RPARAM_LEGACY_MAGIC_CHECKSUM, timeout_ms, out, size) == GS_OK) ? size : -1;
|
||||
}
|
||||
|
||||
static inline int rparam_set_single(const void * in, uint16_t addr, param_type_t type, int size, int mem_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return (gs_rparam_set(node, mem_id, addr, type, GS_RPARAM_LEGACY_MAGIC_CHECKSUM, timeout_ms, in, size) == GS_OK) ? size : -1;
|
||||
}
|
||||
|
||||
static inline int rparam_copy(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to)
|
||||
{
|
||||
return (gs_rparam_copy(node, timeout_ms, from, to) == GS_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline int rparam_save(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to)
|
||||
{
|
||||
return (gs_rparam_save(node, timeout_ms, from, to) == GS_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline int rparam_load(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to)
|
||||
{
|
||||
return (gs_rparam_load(node, timeout_ms, from, to) == GS_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote getters for parameters.
|
||||
* @param out pointer to the output buffer/parameter
|
||||
* @param outlen length of the supplied out-buffer, only applies to rparam_get_string()
|
||||
* @param addr local address of the parameter
|
||||
* @param node CSP address of the node to query
|
||||
* @param port CSP port of the parameter server
|
||||
* @param timeout timeout on remote CSP calls
|
||||
* @returns <0 on error in which case the contents of out is invalid, >0 on success
|
||||
*/
|
||||
static inline int rparam_get_string(char *out, int outlen, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_STRING, outlen, index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote setters for parameters.
|
||||
* @param in pointer to the buffer/parameter value to set
|
||||
* @param inlen length of the supplied in-buffer, only applies to rparam_set_string()
|
||||
* @param addr local address of the parameter
|
||||
* @param node CSP address of the node to query
|
||||
* @param port CSP port of the parameter server
|
||||
* @param timeout timeout on remote CSP calls
|
||||
* @returns <0 on error in which case the contents of out is invalid, >0 on success
|
||||
*/
|
||||
static inline int rparam_set_string(const char *in, int inlen, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_STRING, inlen, index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_uint8(uint8_t * out, uint16_t addr, int tinst_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_UINT8, sizeof(uint8_t), tinst_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_uint8(const uint8_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_UINT8, sizeof(uint8_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_uint16(uint16_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_UINT16, sizeof(uint16_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_uint16(const uint16_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_UINT16, sizeof(uint16_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_uint32(uint32_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_UINT32, sizeof(uint32_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_uint32(const uint32_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_UINT32, sizeof(uint32_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_uint64(uint64_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_UINT64, sizeof(uint64_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_uint64(const uint64_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_UINT64, sizeof(uint64_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_int8(int8_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_INT8, sizeof(int8_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_int8(const int8_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_INT8, sizeof(int8_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_int16(int16_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_INT16, sizeof(int16_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_int16(const int16_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_INT16, sizeof(int16_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_int32(int32_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_INT32, sizeof(int32_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_int32(const int32_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_INT32, sizeof(int32_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_int64(int64_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_INT64, sizeof(int64_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_int64(const int64_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_INT64, sizeof(int64_t), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_float(float * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_FLOAT, sizeof(float), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_float(const float * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_FLOAT, sizeof(float), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_get_double(double * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_get_single(out, addr, PARAM_DOUBLE, sizeof(double), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
static inline int rparam_set_double(const double * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms)
|
||||
{
|
||||
return rparam_set_single(in, addr, PARAM_DOUBLE, sizeof(double), index_id, node, port, timeout_ms);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,42 @@
|
||||
#ifndef GS_PARAM_INTERNAL_PP_I2C_I2C_H
|
||||
#define GS_PARAM_INTERNAL_PP_I2C_I2C_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/param/pp/i2c/i2c.h>
|
||||
#include <gs/param/internal/pp/i2c/slave_dispatch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GS_PARAM_I2C_LENGTH_TABLE(length, table) ((length << 3) | (table & 0x07))
|
||||
#define GS_PARAM_I2C_LENGTH_TABLE_TO_LENGTH(lt) ((lt >> 3) & 0x1f)
|
||||
#define GS_PARAM_I2C_LENGTH_TABLE_TO_TABLE(lt) (lt & 0x07)
|
||||
|
||||
/**
|
||||
Data structure for setting parameter.
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) gs_param_i2c_set_request {
|
||||
gs_i2c_slave_dispatch_header_t header;
|
||||
uint8_t length_table;
|
||||
uint8_t addr;
|
||||
uint8_t data[]; // data (+ checksum)
|
||||
} gs_param_i2c_set_request_t;
|
||||
|
||||
/**
|
||||
Data structure for getting parameter.
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) gs_param_i2c_get_request {
|
||||
gs_i2c_slave_dispatch_header_t header;
|
||||
uint8_t length_table;
|
||||
uint8_t addr;
|
||||
uint8_t checksum; // optional
|
||||
} gs_param_i2c_get_request_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,71 @@
|
||||
#ifndef GS_PARAM_INTERNAL_PP_I2C_SLAVE_DISPATCH_H
|
||||
#define GS_PARAM_INTERNAL_PP_I2C_SLAVE_DISPATCH_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/util/drivers/i2c/slave.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Header for I2C slave dispatch protocol - must be first in all protocols.
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) gs_i2c_slave_dispatch_header {
|
||||
uint8_t domain_command;
|
||||
} gs_i2c_slave_dispatch_header_t;
|
||||
|
||||
/**
|
||||
Make header from domain and command.
|
||||
*/
|
||||
#define GS_I2C_SLAVE_DISPATCH_HEADER(domain, command) ((domain << 5) | (command & 0x1f))
|
||||
|
||||
/**
|
||||
Extract domain from header.
|
||||
*/
|
||||
#define GS_I2C_SLAVE_DISPATCH_HEADER_TO_DOMAIN(header) ((header >> 5) & 0x7)
|
||||
|
||||
/**
|
||||
Extract comman from header.
|
||||
*/
|
||||
#define GS_I2C_SLAVE_DISPATCH_HEADER_TO_COMMAND(header) (header & 0x1f)
|
||||
|
||||
/**
|
||||
Domain handler.
|
||||
|
||||
Basically same features as normal I2C slave rx callback. The generic I2C dispatch interface will parse the header (first byte)
|
||||
and call the associated handler, based on the domain.
|
||||
|
||||
@param[in] channel I2C channel (handle).
|
||||
@param[in] cmd domain specific command.
|
||||
@param[in] rx_buffer Pointer to start of rx buffer.
|
||||
@param[in] rx number of bytes received so far.
|
||||
@param[in] cswitch If called from within an ISR (embedded platform), this will none NULL.
|
||||
@return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current I2C transaction.
|
||||
*/
|
||||
typedef void (* gs_i2c_slave_dispatch_handler_t)(uint8_t channel, uint8_t cmd, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch);
|
||||
|
||||
/**
|
||||
Dispatch domains.
|
||||
|
||||
Standard domains should be assigned from the lowest value.
|
||||
Application/board/product should be assigned from highest value.
|
||||
*/
|
||||
typedef enum {
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_RESERVED = 0, //! Avoid use - reserved for GSSB, GSSB broadcasts UID request on domain=0, cmd=13
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_USER1, //! Avoid use - overlap with GSSB commands
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_USER2, //! Avoid use - may overlap with GSSB commands
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_USER3, //! Avoid use - may overlap with GSSB commands
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, //! Reserved for libparam.
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_USER5,
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_USER6,
|
||||
GS_I2C_SLAVE_DISPATCH_DOMAIN_USER7,
|
||||
} gs_i2c_slave_dispatch_domain_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,80 @@
|
||||
#ifndef GS_PARAM_INTERNAL_PP_SPI_SLAVE_DISPATCH_H
|
||||
#define GS_PARAM_INTERNAL_PP_SPI_SLAVE_DISPATCH_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/util/drivers/spi/slave.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Header for SPI slave dispatch protocol - must be first in all protocols.
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) gs_spi_slave_dispatch_header {
|
||||
uint8_t domain_command;
|
||||
} gs_spi_slave_dispatch_header_t;
|
||||
|
||||
/**
|
||||
Make header from domain and command.
|
||||
*/
|
||||
#define GS_SPI_SLAVE_DISPATCH_HEADER(domain, command) ((domain << 5) | (command & 0x1f))
|
||||
|
||||
/**
|
||||
Extract domain from header.
|
||||
*/
|
||||
#define GS_SPI_SLAVE_DISPATCH_HEADER_TO_DOMAIN(header) ((header >> 5) & 0x7)
|
||||
|
||||
/**
|
||||
Extract comman from header.
|
||||
*/
|
||||
#define GS_SPI_SLAVE_DISPATCH_HEADER_TO_COMMAND(header) (header & 0x1f)
|
||||
|
||||
/**
|
||||
Domain handler.
|
||||
|
||||
Basically same features as normal SPI slave rx callback. The generic SPI dispatch interface will parse the header (first byte)
|
||||
and call the associated handler, based on the domain.
|
||||
|
||||
@param[in] channel SPI channel (handle).
|
||||
@param[in] cmd domain specific command.
|
||||
@param[in] rx_buffer Pointer to start of rx buffer.
|
||||
@param[in] rx number of bytes received so far.
|
||||
@param[in] cswitch If called from within an ISR (embedded platform), this will none NULL.
|
||||
@return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction.
|
||||
*/
|
||||
typedef uint8_t (* gs_spi_slave_dispatch_handler_t)(uint8_t channel, uint8_t cmd, const uint8_t * rx_buffer, size_t rx, gs_context_switch_t * cswitch);
|
||||
|
||||
/**
|
||||
Dispatch domains.
|
||||
|
||||
Standard domains should be assigned form the lowest value.
|
||||
Application/board/product should be assigned from highest value.
|
||||
*/
|
||||
typedef enum {
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_RESERVED = 0, //! Avoid using 0,
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_USER1,
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_USER2,
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_USER3,
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM,
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_USER5,
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_USER6,
|
||||
GS_SPI_SLAVE_DISPATCH_DOMAIN_USER7,
|
||||
} gs_spi_slave_dispatch_domain_t;
|
||||
|
||||
/**
|
||||
Slave dispatch SPI receiver.
|
||||
|
||||
Must be added on the channel as receiver function, using gs_spi_slave_set_rx().
|
||||
|
||||
@param[in] cswitch If called from within an ISR (embedded platform), this will be set and allow for triggering context switch.
|
||||
*/
|
||||
uint8_t gs_spi_slave_dispatch_rx(uint8_t channel, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,65 @@
|
||||
#ifndef GS_PARAM_INTERNAL_PP_SPI_SPI_H
|
||||
#define GS_PARAM_INTERNAL_PP_SPI_SPI_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/param/pp/spi/spi.h>
|
||||
#include <gs/param/internal/pp/spi/slave_dispatch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Domain commands.
|
||||
*/
|
||||
typedef enum {
|
||||
GS_PARAM_SPI_COMMAND_SET = 1,
|
||||
GS_PARAM_SPI_COMMAND_GET = 2,
|
||||
GS_PARAM_SPI_COMMAND_SET_WITH_CHECKSUM = 10,
|
||||
GS_PARAM_SPI_COMMAND_GET_WITH_CHECKSUM = 11,
|
||||
} gs_param_spi_command_t;
|
||||
|
||||
#define GS_PARAM_SPI_LENGTH_TABLE(length, table) ((length << 3) | (table & 0x07))
|
||||
#define GS_PARAM_SPI_LENGTH_TABLE_TO_LENGTH(lt) ((lt >> 3) & 0x1f)
|
||||
#define GS_PARAM_SPI_LENGTH_TABLE_TO_TABLE(lt) (lt & 0x07)
|
||||
|
||||
/**
|
||||
Data structure for setting parameter.
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) gs_param_spi_set {
|
||||
gs_spi_slave_dispatch_header_t header;
|
||||
uint8_t length_table;
|
||||
uint8_t addr;
|
||||
uint8_t data[]; // data (+ checksum)
|
||||
} gs_param_spi_set_t;
|
||||
|
||||
/**
|
||||
Data structure for getting parameter.
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) gs_param_spi_get {
|
||||
gs_spi_slave_dispatch_header_t header;
|
||||
uint8_t length_table;
|
||||
uint8_t addr;
|
||||
uint8_t filler; // filler/delay - allow slave to find and prepare data/response
|
||||
uint8_t data[]; // data
|
||||
} gs_param_spi_get_t;
|
||||
|
||||
/**
|
||||
Data structure for getting parameter with checksum
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) gs_param_spi_get_with_checksum {
|
||||
gs_spi_slave_dispatch_header_t header;
|
||||
uint8_t length_table;
|
||||
uint8_t addr;
|
||||
uint8_t checksum;
|
||||
uint8_t filler; // filler/delay - allow slave to find and prepare data/response
|
||||
uint8_t data[]; // data + checksum
|
||||
} gs_param_spi_get_with_checksum_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
146
gomspace/libparam_client/include/gs/param/internal/rparam.h
Normal file
146
gomspace/libparam_client/include/gs/param/internal/rparam.h
Normal file
@ -0,0 +1,146 @@
|
||||
#ifndef GS_PARAM_INTERNAL_RPARAM_H
|
||||
#define GS_PARAM_INTERNAL_RPARAM_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/param/rparam.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Max query payload in a single message (bytes).
|
||||
*/
|
||||
#define GS_RPARAM_QUERY_MAX_PAYLOAD 180
|
||||
|
||||
/**
|
||||
Macro for calculating total query message size, header + payload.
|
||||
*/
|
||||
#define RPARAM_QUERY_LENGTH(query, payload_size) (sizeof(*query) - sizeof(query->payload) + payload_size)
|
||||
|
||||
/**
|
||||
R(emote) parameter request codes.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Get one or more parameters.
|
||||
*/
|
||||
RPARAM_GET = 0x00,
|
||||
/**
|
||||
Reply to a request.
|
||||
*/
|
||||
RPARAM_REPLY = 0x55,
|
||||
/**
|
||||
Set one or more parameters.
|
||||
*/
|
||||
RPARAM_SET = 0xFF,
|
||||
// RPARAM_SET_TO_FILE = 0xEE,
|
||||
/**
|
||||
Download table specification.
|
||||
*/
|
||||
RPARAM_TABLE = 0x44,
|
||||
/**
|
||||
Copy memory slot to memory slot.
|
||||
@version 4.x: Not supported.
|
||||
*/
|
||||
RPARAM_COPY = 0x77,
|
||||
/**
|
||||
Load from file (slot) to memory (slot).
|
||||
@version 4.x: Only load from primary store - file (slot) is ignored.
|
||||
*/
|
||||
RPARAM_LOAD = 0x88,
|
||||
/**
|
||||
Load from file (slot) to memory (slot).
|
||||
@version 4.x: load by name(s).
|
||||
*/
|
||||
RPARAM_LOAD_FROM_STORE = 0x89,
|
||||
/**
|
||||
Save from memory (slot) to file (slot).
|
||||
@version 4.x: Only save to primary store - file (slot) is ignored.
|
||||
*/
|
||||
RPARAM_SAVE = 0x99,
|
||||
/**
|
||||
Save from memory (slot) to file (slot).
|
||||
@version 4.x: save by name(s).
|
||||
*/
|
||||
RPARAM_SAVE_TO_STORE = 0x9a,
|
||||
// RPARAM_CLEAR = 0xAA, - completely removed
|
||||
} gs_rparam_action_t;
|
||||
|
||||
/**
|
||||
R(emote) parameter reply/completion codes.
|
||||
*/
|
||||
typedef enum {
|
||||
RPARAM_SET_OK = 1,
|
||||
RPARAM_LOAD_OK = 2,
|
||||
RPARAM_SAVE_OK = 3,
|
||||
RPARAM_COPY_OK = 4,
|
||||
// RPARAM_CLEAR_OK = 5,
|
||||
RPARAM_ERROR = 0xFF,
|
||||
} gs_rparam_reply_t;
|
||||
|
||||
/**
|
||||
Payload - save/load to/from stores
|
||||
@version 4
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
char table[25 + 1];
|
||||
char store[25 + 1];
|
||||
char slot[25 + 1];
|
||||
} gs_rparam_query_payload_store_t;
|
||||
|
||||
/**
|
||||
Payload.
|
||||
*/
|
||||
typedef union __attribute__ ((packed)) {
|
||||
uint16_t addr[0]; //! action = RPARAM_GET
|
||||
uint8_t packed[0]; //! action = RPARAM_REPLY | RPARAM_SET
|
||||
struct { //! action = RPARAM_COPY | RPARAM_LOAD | RPARM_SAVE
|
||||
uint8_t from;
|
||||
uint8_t to;
|
||||
} copy;
|
||||
} gs_rparam_query_payload_t;
|
||||
|
||||
/**
|
||||
Protocol between client and server.
|
||||
@version 4.x: layout (size) has not changed - only naming of certain fields.
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
/**
|
||||
Request (gs_rparam_action_t) or Reply (gs_rparam_reply_t).
|
||||
*/
|
||||
uint8_t action;
|
||||
/**
|
||||
Table id.
|
||||
Name changed in 4.0 from \a mem.
|
||||
*/
|
||||
uint8_t table_id;
|
||||
/**
|
||||
Length/size of \a payload in bytes.
|
||||
*/
|
||||
uint16_t length;
|
||||
/**
|
||||
Fletcher's checksum.
|
||||
*/
|
||||
uint16_t checksum;
|
||||
/**
|
||||
Sequence number when split over multiple frames (messages).
|
||||
*/
|
||||
uint16_t seq;
|
||||
/**
|
||||
Total number of frames.
|
||||
*/
|
||||
uint16_t total;
|
||||
/**
|
||||
Payload.
|
||||
*/
|
||||
gs_rparam_query_payload_t payload;
|
||||
} gs_rparam_query_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,29 @@
|
||||
#ifndef GS_PARAM_INTERNAL_SERIALIZE_H
|
||||
#define GS_PARAM_INTERNAL_SERIALIZE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/param/serialize.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Serialize data
|
||||
* @param mem Pointer to indexed parameter table
|
||||
* @param addr Array of addresses to serialize
|
||||
* @param addr_count number of items in addr array
|
||||
* @param[in|out] param_offset table parameter offset
|
||||
* @param flags Set options using combination of flags
|
||||
* @param buf Pointer to output
|
||||
* @param buf_size Size of \a buf.
|
||||
*/
|
||||
gs_error_t gs_param_serialize_list(gs_param_table_instance_t * tinst, const uint16_t addr[], unsigned int addr_count, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
19
gomspace/libparam_client/include/gs/param/internal/table.h
Normal file
19
gomspace/libparam_client/include/gs/param/internal/table.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef GS_PARAM_INTERNAL_TABLE_H
|
||||
#define GS_PARAM_INTERNAL_TABLE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/param/table.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
gs_error_t gs_param_parse_name_and_array_index(const char * inp, char * name, size_t size_name, uint8_t * array_index, bool * return_is_array);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
129
gomspace/libparam_client/include/gs/param/internal/types.h
Normal file
129
gomspace/libparam_client/include/gs/param/internal/types.h
Normal file
@ -0,0 +1,129 @@
|
||||
#ifndef GS_PARAM_INTERNAL_TYPES_H
|
||||
#define GS_PARAM_INTERNAL_TYPES_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#if (GS_PARAM_INTERNAL_USE)
|
||||
|
||||
#include <gs/param/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Table instance.
|
||||
*/
|
||||
struct gs_param_table_instance {
|
||||
/**
|
||||
Name of table.
|
||||
*/
|
||||
const char * name;
|
||||
|
||||
/**
|
||||
Table id.
|
||||
*/
|
||||
gs_param_table_id_t id;
|
||||
|
||||
/**
|
||||
Table elements/rows.
|
||||
*/
|
||||
const gs_param_table_row_t * rows;
|
||||
/**
|
||||
Table element/row count.
|
||||
*/
|
||||
unsigned int row_count;
|
||||
|
||||
/**
|
||||
Table memory - volatile parameter store.
|
||||
The allocated size must be at least \a memory_size bytes.
|
||||
*/
|
||||
void * memory;
|
||||
|
||||
/**
|
||||
Size of table data memory in bytes, normally size of memory allocated \a memory.
|
||||
Size must always be specified, even when using function interface and no memory is allocated.
|
||||
*/
|
||||
unsigned int memory_size;
|
||||
|
||||
/**
|
||||
Function interface, e.g. get/set.
|
||||
*/
|
||||
gs_param_function_interface_t function_interface;
|
||||
|
||||
/**
|
||||
Checksum - based on host order (e.g. le or be).
|
||||
@see gs_param_table_checksum()
|
||||
*/
|
||||
uint16_t checksum;
|
||||
|
||||
/**
|
||||
Checksum - based on big-endian (address converted to big-endian).
|
||||
@see gs_param_table_checksum_be()
|
||||
*/
|
||||
uint16_t checksum_be;
|
||||
|
||||
/**
|
||||
Checksum - based on little-endian (address converted to little-endian).
|
||||
@see gs_param_table_checksum_le()
|
||||
*/
|
||||
uint16_t checksum_le;
|
||||
|
||||
/**
|
||||
Lock.
|
||||
Internal access/use only, use gs_param_lock() and gs_param_unlock() to lock and un-lock table.
|
||||
*/
|
||||
gs_mutex_t lock;
|
||||
|
||||
/**
|
||||
Callback for table (data) change.
|
||||
*/
|
||||
void (*callback)(uint16_t addr, gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Store location(s).
|
||||
CSV format, e.g. \"persistent,protected\".
|
||||
*/
|
||||
const char * stores;
|
||||
|
||||
/**
|
||||
Auto-persist.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
Store.
|
||||
*/
|
||||
const char * store;
|
||||
|
||||
/**
|
||||
User context(s) for the \a set function.
|
||||
*/
|
||||
void * context1;
|
||||
void * context2;
|
||||
|
||||
/**
|
||||
Set/write parameter.
|
||||
*/
|
||||
gs_error_t (*set)(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * item, size_t size, uint32_t flags);
|
||||
} auto_persist;
|
||||
|
||||
/**
|
||||
Function for initializing table.
|
||||
*/
|
||||
gs_error_t (*initializer_function)(gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Default values for initializing table.
|
||||
*/
|
||||
const void * default_values;
|
||||
|
||||
/**
|
||||
Future flags.
|
||||
*/
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
60
gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h
Normal file
60
gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef GS_PARAM_PP_I2C_I2C_H
|
||||
#define GS_PARAM_PP_I2C_I2C_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
I2C param protocol client interface.
|
||||
*/
|
||||
|
||||
#include <gs/param/pp/pp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Commands.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Set parameter.
|
||||
*/
|
||||
GS_PARAM_I2C_COMMAND_SET = 1,
|
||||
/**
|
||||
Get parameter.
|
||||
*/
|
||||
GS_PARAM_I2C_COMMAND_GET = 2,
|
||||
/**
|
||||
Lock table.
|
||||
*/
|
||||
GS_PARAM_I2C_COMMAND_SET_LOCK_WITH_CHECKSUM = 3,
|
||||
/**
|
||||
Get table lock state.
|
||||
*/
|
||||
GS_PARAM_I2C_COMMAND_GET_LOCK_WITH_CHECKSUM = 4,
|
||||
/**
|
||||
Set parameter with checksum.
|
||||
*/
|
||||
GS_PARAM_I2C_COMMAND_SET_WITH_CHECKSUM = 10,
|
||||
/**
|
||||
Get parameter with checksum.
|
||||
*/
|
||||
GS_PARAM_I2C_COMMAND_GET_WITH_CHECKSUM = 11,
|
||||
} gs_param_i2c_command_t;
|
||||
|
||||
/**
|
||||
Initialize the param protocol handle for I2C.
|
||||
|
||||
@param[in] pp handle.
|
||||
@param[in] bus bus to communicate on.
|
||||
@param[in] addr address of node.
|
||||
@param[in] big_endian \a true if slave is big endian. Used to convert to host endian.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_pp_i2c_init(gs_pp_t * pp, uint8_t bus, uint8_t addr, bool big_endian);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
214
gomspace/libparam_client/include/gs/param/pp/pp.h
Normal file
214
gomspace/libparam_client/include/gs/param/pp/pp.h
Normal file
@ -0,0 +1,214 @@
|
||||
#ifndef GS_PARAM_PP_PP_H
|
||||
#define GS_PARAM_PP_PP_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Param Protocol (PP) API - generic interface for getting/setting parameters over SPI, I2C, etc.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Flags used in gs_pp_xxx() functions.
|
||||
@{
|
||||
*/
|
||||
/**
|
||||
Use checksum in transfer.
|
||||
@see gs_pp_checksum8()
|
||||
*/
|
||||
#define GS_PP_FLAG_CHECKSUM 0x0001
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
Handle for a protocol connection.
|
||||
*/
|
||||
typedef struct gs_pp gs_pp_t;
|
||||
|
||||
/**
|
||||
Callback for getting a parameter.
|
||||
*/
|
||||
typedef gs_error_t (*gs_pp_get_t)(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Callback for setting a parameter.
|
||||
*/
|
||||
typedef gs_error_t (*gs_pp_set_t)(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Callback for setting table lock.
|
||||
*/
|
||||
typedef gs_error_t (*gs_pp_get_table_lock_t)(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags);
|
||||
|
||||
/**
|
||||
Callback for setting table lock.
|
||||
*/
|
||||
typedef gs_error_t (*gs_pp_set_table_lock_t)(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags);
|
||||
|
||||
/**
|
||||
Handle for a protocol connection.
|
||||
*/
|
||||
struct gs_pp {
|
||||
/**
|
||||
Endian type of slave.
|
||||
*/
|
||||
bool big_endian;
|
||||
/**
|
||||
Callback function for \a get.
|
||||
*/
|
||||
gs_pp_get_t get;
|
||||
/**
|
||||
Callback function for \a set.
|
||||
*/
|
||||
gs_pp_set_t set;
|
||||
/**
|
||||
Callback function for \a get_table_lock.
|
||||
*/
|
||||
gs_pp_get_table_lock_t get_table_lock;
|
||||
/**
|
||||
Callback function for \a set_table_lock.
|
||||
*/
|
||||
gs_pp_set_table_lock_t set_table_lock;
|
||||
/**
|
||||
Protocol specifics.
|
||||
*/
|
||||
union {
|
||||
/**
|
||||
SPI connection.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
SPI slave id.
|
||||
*/
|
||||
uint8_t slave;
|
||||
} spi;
|
||||
/**
|
||||
I2C connection.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
I2C bus.
|
||||
*/
|
||||
uint8_t bus;
|
||||
/**
|
||||
I2C address.
|
||||
*/
|
||||
uint8_t addr;
|
||||
} i2c;
|
||||
} pp;
|
||||
};
|
||||
|
||||
/**
|
||||
Calculate very simple 8 bit checksum.
|
||||
The checksum is calculated by adding all bytes. If the checksum is 0 (zero), the checksum is set to 1 (one).
|
||||
@param[in] data data to calculate checksum for.
|
||||
@param[in] length data length.
|
||||
@return checksum
|
||||
*/
|
||||
uint8_t gs_pp_checksum8(const void * data, size_t length);
|
||||
|
||||
/**
|
||||
Get lock value
|
||||
|
||||
@param[in] pp Handle for connection
|
||||
@param[in] table_id Table ID
|
||||
@param[out] value Lock state (0 = unlocked, 1 = locked)
|
||||
@param[in] flags
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set lock value
|
||||
|
||||
@param[in] pp Handle for connection
|
||||
@param[in] table_id Table ID
|
||||
@param[in] value Lock state (0 = unlocked, 1 = locked)
|
||||
@param[in] flags
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get int8.
|
||||
*/
|
||||
gs_error_t gs_pp_get_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int8_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set int8.
|
||||
*/
|
||||
gs_error_t gs_pp_set_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int8_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get uint8.
|
||||
*/
|
||||
gs_error_t gs_pp_get_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint8_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set uint8.
|
||||
*/
|
||||
gs_error_t gs_pp_set_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint8_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get int16.
|
||||
*/
|
||||
gs_error_t gs_pp_get_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int16_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set int16.
|
||||
*/
|
||||
gs_error_t gs_pp_set_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int16_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get uint16.
|
||||
*/
|
||||
gs_error_t gs_pp_get_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint16_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set uint16.
|
||||
*/
|
||||
gs_error_t gs_pp_set_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint16_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get int32.
|
||||
*/
|
||||
gs_error_t gs_pp_get_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int32_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set int32.
|
||||
*/
|
||||
gs_error_t gs_pp_set_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int32_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get uint32.
|
||||
*/
|
||||
gs_error_t gs_pp_get_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint32_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set uint32.
|
||||
*/
|
||||
gs_error_t gs_pp_set_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint32_t * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get float.
|
||||
*/
|
||||
gs_error_t gs_pp_get_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, float * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set float.
|
||||
*/
|
||||
gs_error_t gs_pp_set_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const float * value, size_t count, uint32_t flags);
|
||||
|
||||
/**
|
||||
Register commands.
|
||||
*/
|
||||
gs_error_t gs_pp_register_commands(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
29
gomspace/libparam_client/include/gs/param/pp/spi/spi.h
Normal file
29
gomspace/libparam_client/include/gs/param/pp/spi/spi.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef GS_PARAM_PP_SPI_SPI_H
|
||||
#define GS_PARAM_PP_SPI_SPI_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
SPI Param Protocol (pp) client interface.
|
||||
*/
|
||||
|
||||
#include <gs/param/pp/pp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Initialize the param protocol handle for SPI.
|
||||
|
||||
@param[in] pp handle.
|
||||
@param[in] slave slave to communicate with.
|
||||
@param[in] big_endian \a true if slave is big endian. Used to convert to host endian.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_pp_spi_init(gs_pp_t * pp, uint8_t slave, bool big_endian);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
395
gomspace/libparam_client/include/gs/param/rparam.h
Normal file
395
gomspace/libparam_client/include/gs/param/rparam.h
Normal file
@ -0,0 +1,395 @@
|
||||
#ifndef GS_PARAM_REMOTE_H
|
||||
#define GS_PARAM_REMOTE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Remote parameter API - pending refactoring.
|
||||
*/
|
||||
|
||||
#include <gs/param/types.h>
|
||||
#include <gs/util/string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Magic checksum.
|
||||
If specifying a magic checksum, the rparam server will ignore/skip checksum validation.
|
||||
*/
|
||||
#define GS_RPARAM_MAGIC_CHECKSUM 0x0bb0
|
||||
|
||||
/**
|
||||
Register rparam commands.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_register_commands(void);
|
||||
|
||||
/**
|
||||
Download all (data) values from a remote table to a local instance.
|
||||
|
||||
@param[in] tinst local table instance.
|
||||
@param[in] node CSP address.
|
||||
@param[in] table_id remote table id to download.
|
||||
@param[in] checksum table checksum.
|
||||
@param[in] timeout_ms timeout.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_get_full_table(gs_param_table_instance_t * tinst,
|
||||
uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint16_t checksum,
|
||||
uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
Download a table specification from a remote node, store it in memory and save it to local file system.
|
||||
|
||||
@note Will free existing rows - do not use this on table instances with static assigned rows.
|
||||
|
||||
Table memory will be (re)allocated to match specification.
|
||||
|
||||
@param[in] tinst local table instance.
|
||||
@param[in] fname name of the file to store the table specification in. If NULL, no file will be stored.
|
||||
@param[in] node CSP address
|
||||
@param[in] table_id remote table id to download.
|
||||
@param[in] timeout_ms timeout.
|
||||
@param[out] return_checksum fletcher16 checksum of downloaded specification "as is" - before network/host swapping.
|
||||
@return_gs_error_t
|
||||
@see gs_param_table_free()
|
||||
*/
|
||||
gs_error_t gs_rparam_download_table_spec(gs_param_table_instance_t * tinst,
|
||||
const char * fname,
|
||||
uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint32_t timeout_ms,
|
||||
uint16_t * return_checksum);
|
||||
|
||||
/**
|
||||
Load a table specification from a local file and store it in memory.
|
||||
|
||||
@note Will free existing rows - do not use this on table instances with static assigned rows.
|
||||
|
||||
Table memory will be (re)allocated to match specification.
|
||||
|
||||
@param[in] tinst local table instance.
|
||||
@param[in] fname name of the file to load the table specification from.
|
||||
@param[out] return_checksum fletcher16 checksum stored in file.
|
||||
@return_gs_error_t
|
||||
@see gs_param_table_free()
|
||||
*/
|
||||
gs_error_t gs_rparam_load_table_spec(gs_param_table_instance_t * tinst, const char* fname, uint16_t * return_checksum);
|
||||
|
||||
/**
|
||||
Copy from one table to another table.
|
||||
|
||||
@deprecated Not supported by a param 4 backend and future versions.
|
||||
|
||||
@param[in] node CSP address
|
||||
@param[in] timeout_ms timeout on remote CSP calls
|
||||
@param[in] from from table-id.
|
||||
@param[in] to to table-id.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_copy(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to);
|
||||
|
||||
/**
|
||||
Save table.
|
||||
|
||||
@note On a param 4 backend, the table will always be saved to it's primary store.
|
||||
|
||||
@param[in] node CSP address
|
||||
@param[in] timeout_ms timeout on remote CSP calls
|
||||
@param[in] id table to save.
|
||||
@param[in] to to file slot - ignored on param 4 backends.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, gs_param_table_id_t id, uint8_t to);
|
||||
|
||||
/**
|
||||
Save table.
|
||||
|
||||
@version 4
|
||||
@param[in] node CSP address
|
||||
@param[in] timeout_ms timeout on remote CSP calls
|
||||
@param[in] table_id remote table id.
|
||||
@param[in] store store name.
|
||||
@param[in] slot slot within store.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id,
|
||||
const char * store, const char * slot);
|
||||
|
||||
/**
|
||||
Load table from store.
|
||||
|
||||
@note On a param 4 backend, the specified table will be loadded from it's primary store.
|
||||
|
||||
@param[in] node CSP address
|
||||
@param[in] timeout_ms timeout on remote CSP calls
|
||||
@param[in] from from file slot - ignored on param 4 backends.
|
||||
@param[in] id table to load.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, gs_param_table_id_t id);
|
||||
|
||||
/**
|
||||
Load table from store.
|
||||
|
||||
@version 4
|
||||
@param[in] node CSP address
|
||||
@param[in] timeout_ms timeout on remote CSP calls
|
||||
@param[in] table_id remote table id.
|
||||
@param[in] store store name.
|
||||
@param[in] slot slot within store.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id,
|
||||
const char * store, const char * slot);
|
||||
|
||||
/**
|
||||
Get parameter.
|
||||
|
||||
@param[in] node CSP address
|
||||
@param[in] table_id remote table id.
|
||||
@param[in] addr parameter address (remote table).
|
||||
@param[in] type parameter type.
|
||||
@param[in] checksum checksum
|
||||
@param[in] timeout_ms timeout
|
||||
@param[out] value returned value (user allocated)
|
||||
@param[in] value_size size of \a value buffer.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_get(uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint16_t addr,
|
||||
gs_param_type_t type,
|
||||
uint16_t checksum,
|
||||
uint32_t timeout_ms,
|
||||
void * value,
|
||||
size_t value_size);
|
||||
|
||||
/**
|
||||
Set parameter.
|
||||
|
||||
@param[in] node CSP address
|
||||
@param[in] table_id remote table id.
|
||||
@param[in] addr parameter address (remote table).
|
||||
@param[in] type parameter type.
|
||||
@param[in] checksum checksum
|
||||
@param[in] timeout_ms timeout
|
||||
@param[in] value value to set
|
||||
@param[in] value_size size of \a value.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_set(uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint16_t addr,
|
||||
gs_param_type_t type,
|
||||
uint16_t checksum,
|
||||
uint32_t timeout_ms,
|
||||
const void * value,
|
||||
size_t value_size);
|
||||
|
||||
/**
|
||||
Get string.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_string(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, char * value, size_t value_size)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_STRING, checksum, timeout_ms, value, value_size);
|
||||
}
|
||||
|
||||
/**
|
||||
Set string.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_string(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, const char * value, size_t value_size)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_STRING, checksum, timeout_ms, value, (value_size == 0) ? (strlen(value) + 1) : value_size);
|
||||
}
|
||||
|
||||
/**
|
||||
Get int8.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_int8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int8_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_INT8, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set int8.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_int8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int8_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_INT8, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get uint8.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_uint8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint8_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT8, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set uint8.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_uint8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint8_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT8, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get int16.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_int16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int16_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_INT16, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set int16.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_int16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int16_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_INT16, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get uint16.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_uint16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint16_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT16, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set uint16.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_uint16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint16_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT16, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get int32.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_int32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int32_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_INT32, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set int32.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_int32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int32_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_INT32, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get uint32.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_uint32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint32_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT32, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set uint32.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_uint32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint32_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT32, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get int64.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_int64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int64_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_INT64, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set int64.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_int64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, int64_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_INT64, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get uint64.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_uint64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint64_t * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT64, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set uint64.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_uint64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, uint64_t value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT64, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get float.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_float(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, float * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_FLOAT, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set float.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_float(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, float value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_FLOAT, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
Get double.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_get_double(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, double * value)
|
||||
{
|
||||
return gs_rparam_get(node, table_id, addr, GS_PARAM_DOUBLE, checksum, timeout_ms, value, sizeof(*value));
|
||||
}
|
||||
|
||||
/**
|
||||
Set double.
|
||||
*/
|
||||
static inline gs_error_t gs_rparam_set_double(uint8_t node, gs_param_table_id_t table_id, uint16_t addr,
|
||||
uint16_t checksum, uint32_t timeout_ms, double value)
|
||||
{
|
||||
return gs_rparam_set(node, table_id, addr, GS_PARAM_DOUBLE, checksum, timeout_ms, &value, sizeof(value));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
101
gomspace/libparam_client/include/gs/param/serialize.h
Normal file
101
gomspace/libparam_client/include/gs/param/serialize.h
Normal file
@ -0,0 +1,101 @@
|
||||
#ifndef GS_PARAM_CLIENT_SERIALIZE_H
|
||||
#define GS_PARAM_CLIENT_SERIALIZE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Serialize API - pending refactoring.
|
||||
*/
|
||||
|
||||
#include <gs/param/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Serialize/deserialize flags
|
||||
Flags must be in range: bit 8 - 15, to avoid clash with other parts of the parameter system.
|
||||
*/
|
||||
typedef enum {
|
||||
GS_PARAM_SF_DRY_RUN = (1 << 8), //!< F_DRY_RUN do not write to memory
|
||||
GS_PARAM_SF_TO_BIG_ENDIAN = (1 << 9), //!< F_TO_BIG_ENDIAN Convert from host to big endian
|
||||
GS_PARAM_SF_FROM_BIG_ENDIAN = (1 << 10), //!< F_FROM_BIG_ENDIAN Confert from big endian to host order
|
||||
GS_PARAM_SF_PACKED = (1 << 11), //!< F_PACKED Do not pack addresses
|
||||
|
||||
F_DRY_RUN = GS_PARAM_SF_DRY_RUN,
|
||||
F_TO_BIG_ENDIAN = GS_PARAM_SF_TO_BIG_ENDIAN,
|
||||
F_FROM_BIG_ENDIAN = GS_PARAM_SF_FROM_BIG_ENDIAN,
|
||||
F_PACKED = GS_PARAM_SF_PACKED,
|
||||
} gs_param_serialize_flags_t;
|
||||
|
||||
/**
|
||||
* In-place conversion of a single parameter from big endian to host byte order
|
||||
* @param type param type
|
||||
* @param item pointer to parameter memory
|
||||
* @return 1 if memory has been swapped, 0 if not
|
||||
*/
|
||||
bool gs_param_betoh(gs_param_type_t type, void * item);
|
||||
|
||||
/**
|
||||
* In-place conversion of a single parameter from host byte order to big endian
|
||||
* @param type param type
|
||||
* @param item porinter to parameter memory
|
||||
* @return 1 if memory has been swapped, 0 if not
|
||||
*/
|
||||
bool gs_param_htobe(gs_param_type_t type, void * item);
|
||||
|
||||
/**
|
||||
Serialize data
|
||||
|
||||
@param[in] tinst table.
|
||||
@param[in,out] param_pos parameter iterator.
|
||||
@param[in] flags flags.
|
||||
@param[out] buf user supplied buffer of \a buf_size.
|
||||
@param[in] buf_size of size of \a buf
|
||||
@param[in,out] buf_pos index into \a buf
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_serialize_full_table(gs_param_table_instance_t * tinst, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos);
|
||||
|
||||
/**
|
||||
Serialize single item
|
||||
|
||||
@param[in] param parameter to serialize
|
||||
@param[in] addr Address of item
|
||||
@param[in] item item to serialize.
|
||||
@param[in] flags flags.
|
||||
@param[out] buf user supplied buffer of \a buf_size.
|
||||
@param[in] buf_size of size of \a buf
|
||||
@param[in,out] buf_pos index into \a buf
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_serialize_item(const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos);
|
||||
|
||||
/**
|
||||
Deserialize packed parameters into memory
|
||||
|
||||
@param[in] tinst table.
|
||||
@param[in] buf serialized data.
|
||||
@param[in] buf_size size \a buf containing serialized data
|
||||
@param[in] flags flags.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_deserialize(gs_param_table_instance_t * tinst, const uint8_t * buf, unsigned int buf_size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Deserialize a sginle item from a string into memory
|
||||
|
||||
@param[in] tinst table.
|
||||
@param param Pointer to specific parameter to deserialize
|
||||
@param addr Address of parameter
|
||||
@param item Pointer to memory area where item should be written
|
||||
@param flags Set options using combination of flags
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_deserialize_item(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
428
gomspace/libparam_client/include/gs/param/table.h
Normal file
428
gomspace/libparam_client/include/gs/param/table.h
Normal file
@ -0,0 +1,428 @@
|
||||
#ifndef GS_PARAM_TABLE_H
|
||||
#define GS_PARAM_TABLE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Client table API.
|
||||
*/
|
||||
|
||||
#include <gs/param/types.h>
|
||||
#include <gs/util/stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate table memory when creating a table.
|
||||
|
||||
Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system.
|
||||
*/
|
||||
#define GS_PARAM_TABLE_F_ALLOC_MEMORY 0x0100
|
||||
/**
|
||||
Allocate table rows.
|
||||
|
||||
Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system.
|
||||
*/
|
||||
#define GS_PARAM_TABLE_F_ALLOC_ROWS 0x0200
|
||||
/**
|
||||
Disable table locking.
|
||||
|
||||
Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system.
|
||||
*/
|
||||
#define GS_PARAM_TABLE_F_NO_LOCK 0x0400
|
||||
|
||||
/**
|
||||
Calculate memory size based on table rows.
|
||||
|
||||
@param[in] rows rows
|
||||
@param[in] row_count row count.
|
||||
@return size of table or 0 in case of invalid arguments.
|
||||
*/
|
||||
size_t gs_param_calc_table_size(const gs_param_table_row_t * rows, size_t row_count);
|
||||
|
||||
/**
|
||||
Return size of table instance.
|
||||
*/
|
||||
size_t gs_param_table_instance_size(void);
|
||||
|
||||
/**
|
||||
Clear (and check size) of memory for table instance.
|
||||
|
||||
@param[in] var user allocated space of at least gs_param_table_instance_size() bytes.
|
||||
@param[in] var_size of \a var.
|
||||
@return table instance
|
||||
@see gs_param_table_instance_size()
|
||||
@see #GS_PARAM_TINST_VAR
|
||||
*/
|
||||
gs_param_table_instance_t * gs_param_table_instance_clear(void * var, size_t var_size);
|
||||
|
||||
/**
|
||||
Allocates aligned space on the stack for a table instance structure.
|
||||
@param[in] var name of table instsance variable.
|
||||
*/
|
||||
#define GS_PARAM_TINST_VAR(var) uint8_t var##__data [gs_param_table_instance_size()] __attribute__ ((aligned(4))); gs_param_table_instance_t * var = gs_param_table_instance_clear(var##__data, sizeof(var##__data))
|
||||
|
||||
/**
|
||||
Allocate memory for table instance.
|
||||
|
||||
Use gs_param_table_free() to free any internal resources.
|
||||
|
||||
Use standard free() to free allocated memory.
|
||||
|
||||
@return table instance on success, otherwise NULL.
|
||||
*/
|
||||
gs_param_table_instance_t * gs_param_table_instance_alloc(void);
|
||||
|
||||
/**
|
||||
Find row by name.
|
||||
|
||||
@param[in] name parameter name.
|
||||
@param[in] rows rows
|
||||
@param[in] row_count row count.
|
||||
@return row or NULL if not found.
|
||||
*/
|
||||
const gs_param_table_row_t * gs_param_row_by_name(const char * name, const gs_param_table_row_t * rows, size_t row_count);
|
||||
|
||||
/**
|
||||
Find row by address.
|
||||
|
||||
@param[in] addr parameter address.
|
||||
@param[in] rows rows
|
||||
@param[in] row_count row count.
|
||||
@return row or NULL if not found.
|
||||
*/
|
||||
const gs_param_table_row_t * gs_param_row_by_address(uint16_t addr, const gs_param_table_row_t * rows, size_t row_count);
|
||||
|
||||
/**
|
||||
Return table memory.
|
||||
|
||||
@note handle with care - any read/write should be atomic to prevent inconsistent data.
|
||||
|
||||
@param[in] tinst table instance
|
||||
@param[out] return_size if not NULL, the memory size is returned.
|
||||
@return pointer to the table's data memory.
|
||||
*/
|
||||
void * gs_param_table_get_memory(gs_param_table_instance_t * tinst, size_t * return_size);
|
||||
|
||||
/**
|
||||
Return table rows.
|
||||
|
||||
@param[in] tinst table instance
|
||||
@param[out] return_count if not NULL, the row count is returned.
|
||||
@return pointer to the table rows.
|
||||
*/
|
||||
const gs_param_table_row_t * gs_param_table_get_rows(gs_param_table_instance_t * tinst, size_t * return_count);
|
||||
|
||||
/**
|
||||
Lock table (recursive).
|
||||
|
||||
@param[in] tinst table instance
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_table_lock(gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Unlock table.
|
||||
|
||||
Unlock must be called once for every time gs_param_table_lock() has been called.
|
||||
|
||||
@param[in] tinst table instance
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_table_unlock(gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Free internal resources and clears instance.
|
||||
|
||||
@param[in] tinst table instance
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_table_free(gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Print a single parameter on stream.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] row row to print.
|
||||
@param[in] list_data \a true includes parameter value.
|
||||
@param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX.
|
||||
@param[in] out output stream.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_list_single_to_stream(gs_param_table_instance_t * tinst, const gs_param_table_row_t * row, bool list_data, uint32_t flags, FILE * out);
|
||||
|
||||
/**
|
||||
Print a single parameter on stdout.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] row row to print.
|
||||
@param[in] list_data \a true includes parameter value.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
static inline gs_error_t gs_param_list_single(gs_param_table_instance_t * tinst, const gs_param_table_row_t * row, bool list_data)
|
||||
{
|
||||
return gs_param_list_single_to_stream(tinst, row, list_data, 0, stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
Print entire table on stream.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] list_data \a true includes parameter value.
|
||||
@param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX.
|
||||
@param[in] out output stream.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_list_to_stream(gs_param_table_instance_t * tinst, bool list_data, uint32_t flags, FILE * out);
|
||||
|
||||
/**
|
||||
Print entire table on stdout.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] list_data \a true includes parameter value.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
static inline gs_error_t gs_param_list(gs_param_table_instance_t * tinst, bool list_data)
|
||||
{
|
||||
return gs_param_list_to_stream(tinst, list_data, 0, stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
Convert string to parameter.
|
||||
|
||||
@param[in] row row defining the parameter to convert.
|
||||
@param[in] string string to convert.
|
||||
@param[out] return_value user supplied buffer for returning the value - must be at least the size specified in \a row
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_from_string(const gs_param_table_row_t * row, const char * string, void * return_value);
|
||||
|
||||
/**
|
||||
Convert parameter to string.
|
||||
|
||||
@param[in] row row defining the parameter to convert.
|
||||
@param[in] value parameter value to convert.
|
||||
@param[in] with_type \a true includes data type.
|
||||
@param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX.
|
||||
@param[out] buf user supplied buffer of \a buf_size bytes.
|
||||
@param[in] buf_size size of \a buf in bytes.
|
||||
@param[in] buf_pos buffer position to insert string.
|
||||
@param[out] return_buf_written number of bytes written to \a buf.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_to_string2(const gs_param_table_row_t * row, const void * value, bool with_type, uint32_t flags, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * return_buf_written);
|
||||
|
||||
/**
|
||||
Convert parameter to string.
|
||||
|
||||
@param[in] row row defining the parameter to convert.
|
||||
@param[in] value parameter value to convert.
|
||||
@param[in] with_type \a true includes data type.
|
||||
@param[out] buf user supplied buffer of \a buf_size bytes.
|
||||
@param[in] buf_size size of \a buf in bytes.
|
||||
@param[in] buf_pos buffer position to insert string.
|
||||
@param[out] return_buf_written number of bytes written to \a buf.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
static inline gs_error_t gs_param_to_string(const gs_param_table_row_t * row, const void * value, bool with_type, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * return_buf_written)
|
||||
{
|
||||
return gs_param_to_string2(row, value, with_type, 0, buf, buf_size, buf_pos, return_buf_written);
|
||||
}
|
||||
|
||||
/**
|
||||
Convert parameter type to string.
|
||||
|
||||
@param[in] type parameter type.
|
||||
@return pointer to a static string.
|
||||
*/
|
||||
const char * gs_param_type_to_string(gs_param_type_t type);
|
||||
|
||||
/**
|
||||
Return size of parameter type.
|
||||
|
||||
@param[in] type parameter type.
|
||||
@return size of parameter type in bytes.
|
||||
*/
|
||||
uint8_t gs_param_type_size(gs_param_type_t type);
|
||||
|
||||
/**
|
||||
Get table checksum - little-endian.
|
||||
@note Use/exchange gs_param_table_checksum_be(), as this is calculated the same on all platforms.
|
||||
@param[in] tinst table instance.
|
||||
@returns 16-bit fletcher checksum
|
||||
*/
|
||||
uint16_t gs_param_table_checksum_le(gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Get table checksum - big-endian/network-order (prefered).
|
||||
@param[in] tinst table instance.
|
||||
@returns 16-bit fletcher checksum
|
||||
*/
|
||||
uint16_t gs_param_table_checksum_be(gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Get table checksum - host-order (not cross-platform).
|
||||
@deprecated use gs_param_table_checksum_be()
|
||||
@param[in] tinst table instance.
|
||||
@returns 16-bit fletcher checksum
|
||||
*/
|
||||
uint16_t gs_param_table_checksum(gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Get table checksum - big-endian.
|
||||
@deprecated use gs_param_table_checksum_be()
|
||||
@param[in] tinst table instance.
|
||||
@returns 16-bit fletcher checksum
|
||||
*/
|
||||
static inline uint16_t gs_param_table_checksum2(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
return gs_param_table_checksum_be(tinst);
|
||||
}
|
||||
|
||||
/**
|
||||
Get/read parameter from table.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] addr parameter address (offset in table).
|
||||
@param[in] type parameter type.
|
||||
@param[out] return_value value of parameter - user supplied memory of at least \a size size.
|
||||
@param[in] size number of bytes to get/read - must match \a type, e.g. 4 bytes for an uint32_t.
|
||||
@param[in] flags flags.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_get(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * return_value, size_t size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set/write parameter in table.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] addr parameter address (offset in table).
|
||||
@param[in] type parameter type.
|
||||
@param[in] value value of parameter.
|
||||
@param[in] size number of bytes to set/write - must match \a type, e.g. 4 bytes for an uint32_t.
|
||||
@param[in] flags flags.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_set(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * value, size_t size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get string parameter.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] addr parameter address (offset in table).
|
||||
@param[out] buf value of parameter - user supplied memory of at least parameter size + 1 to hold NUL termination.
|
||||
@param[in] buf_size size of \a buf - ensure room for NUL termination.
|
||||
@param[in] flags flags.
|
||||
@return GS_ERROR_OVERFLOW if string + NUL termination exceeds \a buf_size.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_get_string(gs_param_table_instance_t * tinst, uint16_t addr, char * buf, size_t buf_size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set string parameter.
|
||||
|
||||
@param[in] tinst table.
|
||||
@param[in] addr parameter address (offset in table).
|
||||
@param[in] value string to save - parameter must be able to hold string + NUL termination.
|
||||
@param[in] flags flags.
|
||||
@return GS_ERROR_OVERFLOW if string + NUL termination exceeds parameter size.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_set_string(gs_param_table_instance_t * tinst, uint16_t addr, const char * value, uint32_t flags);
|
||||
|
||||
/**
|
||||
Get data parameter.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] addr parameter address (offset in table).
|
||||
@param[out] buf value of parameter - user supplied memory of at least parameter size.
|
||||
@param[in] buf_size size of \a buf.
|
||||
@param[in] flags flags.
|
||||
@return GS_ERROR_OVERFLOW if parameter size is greater than \a buf_size.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_get_data(gs_param_table_instance_t * tinst, uint16_t addr, void * buf, size_t buf_size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Set data parameter.
|
||||
|
||||
@param[in] tinst table instanc.
|
||||
@param[in] addr parameter address (offset in table).
|
||||
@param[in] value value of parameter.
|
||||
@param[in] value_size size of \a value.
|
||||
@param[in] flags flags.
|
||||
@return GS_ERROR_OVERFLOW if parameter size is greater than \a buf_size.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_param_set_data(gs_param_table_instance_t * tinst, uint16_t addr, const void * value, size_t value_size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Macro for expanding get/set functions.
|
||||
@param[in] name function suffix name.
|
||||
@param[in] native_type native type
|
||||
@param[in] param_type parameter type
|
||||
*/
|
||||
#define GS_PARAM_PASTE(name, native_type, param_type) \
|
||||
static inline gs_error_t gs_param_get_##name(gs_param_table_instance_t * tinst, uint16_t addr, native_type * buf, uint32_t flags) { \
|
||||
return gs_param_get(tinst, addr, param_type, buf, sizeof(*buf), flags); \
|
||||
} \
|
||||
static inline native_type gs_param_get_##name##_nc(gs_param_table_instance_t * tinst, uint16_t addr, uint32_t flags) { \
|
||||
native_type value = 0; \
|
||||
gs_param_get(tinst, addr, param_type, &value, sizeof(value), flags); \
|
||||
return value; \
|
||||
} \
|
||||
static inline gs_error_t gs_param_set_##name(gs_param_table_instance_t * tinst, uint16_t addr, native_type value, uint32_t flags) { \
|
||||
return gs_param_set(tinst, addr, param_type, &value, sizeof(value), flags); \
|
||||
}
|
||||
|
||||
/**
|
||||
Get/set boolean.
|
||||
*/
|
||||
GS_PARAM_PASTE(bool, bool, GS_PARAM_BOOL)
|
||||
/**
|
||||
Get/set uint8.
|
||||
*/
|
||||
GS_PARAM_PASTE(uint8, uint8_t, GS_PARAM_UINT8)
|
||||
/**
|
||||
Get/set uint16.
|
||||
*/
|
||||
GS_PARAM_PASTE(uint16, uint16_t, GS_PARAM_UINT16)
|
||||
/**
|
||||
Get/set uint32.
|
||||
*/
|
||||
GS_PARAM_PASTE(uint32, uint32_t, GS_PARAM_UINT32)
|
||||
/**
|
||||
Get/set uint64.
|
||||
*/
|
||||
GS_PARAM_PASTE(uint64, uint64_t, GS_PARAM_UINT64)
|
||||
/**
|
||||
Get/set int8.
|
||||
*/
|
||||
GS_PARAM_PASTE(int8, int8_t, GS_PARAM_INT8)
|
||||
/**
|
||||
Get/set int16.
|
||||
*/
|
||||
GS_PARAM_PASTE(int16, int16_t, GS_PARAM_INT16)
|
||||
/**
|
||||
Get/set int32.
|
||||
*/
|
||||
GS_PARAM_PASTE(int32, int32_t, GS_PARAM_INT32)
|
||||
/**
|
||||
Get/set int64.
|
||||
*/
|
||||
GS_PARAM_PASTE(int64, int64_t, GS_PARAM_INT64)
|
||||
/**
|
||||
Get/set double.
|
||||
*/
|
||||
GS_PARAM_PASTE(double, double, GS_PARAM_DOUBLE)
|
||||
/**
|
||||
Get/set float.
|
||||
*/
|
||||
GS_PARAM_PASTE(float, float, GS_PARAM_FLOAT)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
272
gomspace/libparam_client/include/gs/param/types.h
Normal file
272
gomspace/libparam_client/include/gs/param/types.h
Normal file
@ -0,0 +1,272 @@
|
||||
#ifndef GS_PARAM_TYPES_H
|
||||
#define GS_PARAM_TYPES_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Parameter types.
|
||||
*/
|
||||
|
||||
#include <gs/util/mutex.h>
|
||||
#include <gs/util/pgm.h>
|
||||
#include <gs/util/minmax.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Macros for accessing table row members.
|
||||
These macros can be used to access members in a cross-platform way, compensating for the AVR8's memory model.
|
||||
@{
|
||||
*/
|
||||
#define GS_PARAM_ARRAY_SIZE(p) gs_max(GS_PGM_UINT8((p)->array_size), 1)
|
||||
#define GS_PARAM_SIZE(p) GS_PGM_UINT8((p)->size)
|
||||
#define GS_PARAM_TYPE(p) GS_PGM_UINT8((p)->type)
|
||||
#define GS_PARAM_ADDR(p) GS_PGM_UINT16((p)->addr)
|
||||
#define GS_PARAM_FLAGS(p) GS_PGM_UINT8((p)->flags)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
Max parameter name - including 0 termination.
|
||||
@note In some rare/old table definitions, the name may not be NULL terminated.
|
||||
*/
|
||||
#define GS_PARAM_MAX_NAME 14
|
||||
|
||||
/**
|
||||
Parameter flags.
|
||||
Flags must be in range: bit 0 - 7, to avoid clash with other parts of the parameter system.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Parameter will be stored in configured auto-persist store when set.
|
||||
@note Flag must be specified when setting the parameter.
|
||||
*/
|
||||
GS_PARAM_F_AUTO_PERSIST = (1 << 0),
|
||||
/**
|
||||
@deprecated Not supported in version 4.0
|
||||
*/
|
||||
PARAM_F_READONLY = (1 << 1),
|
||||
/**
|
||||
Skip callback, when parameter is set.
|
||||
@note Flag must be specified when setting the parameter.
|
||||
*/
|
||||
GS_PARAM_F_NO_CALLBACK = (1 << 2),
|
||||
/**
|
||||
Show/display parameter in hex.
|
||||
*/
|
||||
GS_PARAM_F_SHOW_HEX = (1 << 3),
|
||||
/**
|
||||
Show double/float using scientific notation.
|
||||
*/
|
||||
GS_PARAM_F_SHOW_SCIENTIFIC = (1 << 4),
|
||||
|
||||
PARAM_F_NOCALLBACK = GS_PARAM_F_NO_CALLBACK,
|
||||
PARAM_F_PERSIST = GS_PARAM_F_AUTO_PERSIST,
|
||||
} gs_param_flags_t;
|
||||
|
||||
/**
|
||||
* Parameter types.
|
||||
*/
|
||||
typedef enum __attribute__((__packed__)) {
|
||||
/**
|
||||
Unsigned 8 bit (uint8_t).
|
||||
*/
|
||||
GS_PARAM_UINT8 = 0,
|
||||
/**
|
||||
Unsigned 16 bit (uint16_t).
|
||||
*/
|
||||
GS_PARAM_UINT16 = 1,
|
||||
/**
|
||||
Unsigned 32 bit (uint32_t).
|
||||
*/
|
||||
GS_PARAM_UINT32 = 2,
|
||||
/**
|
||||
Unsigned 64 bit (uint64_t).
|
||||
*/
|
||||
GS_PARAM_UINT64 = 3,
|
||||
/**
|
||||
Signed 8 bit (int8_t).
|
||||
*/
|
||||
GS_PARAM_INT8 = 4,
|
||||
/**
|
||||
Signed 16 bit (int16_t).
|
||||
*/
|
||||
GS_PARAM_INT16 = 5,
|
||||
/**
|
||||
Signed 32 bit (int32_t).
|
||||
*/
|
||||
GS_PARAM_INT32 = 6,
|
||||
/**
|
||||
Signed 64 bit (int64_t).
|
||||
*/
|
||||
GS_PARAM_INT64 = 7,
|
||||
/**
|
||||
@deprecated - use #GS_PARAM_UINT8 and #GS_PARAM_F_SHOW_HEX.
|
||||
*/
|
||||
PARAM_X8 = 8,
|
||||
/**
|
||||
@deprecated - use #GS_PARAM_UINT16 and #GS_PARAM_F_SHOW_HEX.
|
||||
*/
|
||||
PARAM_X16 = 9,
|
||||
/**
|
||||
@deprecated - use #GS_PARAM_UINT32 and #GS_PARAM_F_SHOW_HEX.
|
||||
*/
|
||||
PARAM_X32 = 10,
|
||||
/**
|
||||
@deprecated - use #GS_PARAM_UINT64 and #GS_PARAM_F_SHOW_HEX.
|
||||
*/
|
||||
PARAM_X64 = 11,
|
||||
/**
|
||||
Double.
|
||||
*/
|
||||
GS_PARAM_DOUBLE = 12,
|
||||
/**
|
||||
Float.
|
||||
*/
|
||||
GS_PARAM_FLOAT = 13,
|
||||
/**
|
||||
C or null-terminated string.
|
||||
@note The specified \a size must include space for the NUL character.
|
||||
*/
|
||||
GS_PARAM_STRING = 14,
|
||||
/**
|
||||
Data (binary blob).
|
||||
Binary blob: [0, 0x40, 0x4f] -> '00404f'
|
||||
*/
|
||||
GS_PARAM_DATA = 15,
|
||||
/**
|
||||
Boolean.
|
||||
Expected same size as uint8_t.
|
||||
*/
|
||||
GS_PARAM_BOOL = 16,
|
||||
|
||||
PARAM_UINT8 = GS_PARAM_UINT8,
|
||||
PARAM_UINT16 = GS_PARAM_UINT16,
|
||||
PARAM_UINT32 = GS_PARAM_UINT32,
|
||||
PARAM_UINT64 = GS_PARAM_UINT64,
|
||||
PARAM_INT8 = GS_PARAM_INT8,
|
||||
PARAM_INT16 = GS_PARAM_INT16,
|
||||
PARAM_INT32 = GS_PARAM_INT32,
|
||||
PARAM_INT64 = GS_PARAM_INT64,
|
||||
PARAM_DOUBLE = GS_PARAM_DOUBLE,
|
||||
PARAM_FLOAT = GS_PARAM_FLOAT,
|
||||
PARAM_STRING = GS_PARAM_STRING,
|
||||
PARAM_DATA = GS_PARAM_DATA,
|
||||
PARAM_BOOL = GS_PARAM_BOOL,
|
||||
} gs_param_type_t;
|
||||
|
||||
/**
|
||||
Table row.
|
||||
|
||||
A table row defines one parameter, and a table is defined by one or more rows.
|
||||
|
||||
@note Make sure to update gs_param_table_checksum2(), if adding fields > 1 byte.
|
||||
|
||||
@note AVR8: Table definitions must be located in \a program memory, i.e. must be const.
|
||||
*/
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
/**
|
||||
Address (or offset) in table.
|
||||
*/
|
||||
uint16_t addr;
|
||||
/**
|
||||
Type.
|
||||
*/
|
||||
gs_param_type_t type;
|
||||
/**
|
||||
Size of element.
|
||||
uint32_t = 4, string[5] = 5 (4 characters + 1 for NUL), etc.
|
||||
*/
|
||||
uint8_t size;
|
||||
/**
|
||||
Array size.
|
||||
Size greater than 1, will make the parameter an array - if the value is 0 or 1, the parameter is not an array.
|
||||
*/
|
||||
uint8_t array_size;
|
||||
/**
|
||||
Flags.
|
||||
@see gs_param_flags_t
|
||||
*/
|
||||
uint8_t flags;
|
||||
/**
|
||||
Name (C string).
|
||||
@note In some rare/old table definitions, the name may not be NUL terminated.
|
||||
*/
|
||||
char name[GS_PARAM_MAX_NAME];
|
||||
} gs_param_table_row_t;
|
||||
|
||||
/**
|
||||
Table instance.
|
||||
*/
|
||||
typedef struct gs_param_table_instance gs_param_table_instance_t;
|
||||
|
||||
/**
|
||||
Table id.
|
||||
|
||||
Tables can be associated with a number/id, which normally is unique on a specific node.
|
||||
*/
|
||||
typedef uint8_t gs_param_table_id_t;
|
||||
|
||||
/**
|
||||
Undefined table id.
|
||||
*/
|
||||
#define GS_PARAM_UNDEFINED_TABLE_ID 255
|
||||
|
||||
/**
|
||||
Function for setting a parameter.
|
||||
|
||||
@param[in] context user context/reference.
|
||||
@param[in] tinst table instance.
|
||||
@param[in] addr parameter address.
|
||||
@param[in] type parameter type.
|
||||
@param[in] item parameter value.
|
||||
@param[in] size parameter size (e.g. how many bytes to copy from \a item).
|
||||
@param[in] flags flags related to the operation - these may vary depending on the context.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_param_table_function_set_t)(void * context, gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * item, size_t size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Function for getting a parameter.
|
||||
|
||||
@param[in] context user context/reference.
|
||||
@param[in] tinst table instance.
|
||||
@param[in] addr parameter address.
|
||||
@param[in] type parameter type.
|
||||
@param[out] item parameter buffer (provided by the caller).
|
||||
@param[in] size parameter size (e.g. how many bytes to copy to \a item).
|
||||
@param[in] flags flags related to the operation - these may vary depending on the context.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_param_table_function_get_t)(void * context, gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * item, size_t size, uint32_t flags);
|
||||
|
||||
/**
|
||||
Function interface for setting and getting parameters.
|
||||
Functions will be invoked, when set/get is called on the table instance.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
User context, provided in the callback functions.
|
||||
*/
|
||||
void * context;
|
||||
/**
|
||||
Called when setting a parameter.
|
||||
*/
|
||||
gs_param_table_function_set_t set;
|
||||
/**
|
||||
Called when getting a parameter.
|
||||
*/
|
||||
gs_param_table_function_get_t get;
|
||||
} gs_param_function_interface_t;
|
||||
|
||||
/**
|
||||
Callback function for changed parameter.
|
||||
See gs_param_table_create() for details.
|
||||
*/
|
||||
typedef void (*gs_param_callback_func_t)(uint16_t addr, gs_param_table_instance_t * tinst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
1084
gomspace/libparam_client/src/bindings/python/pyparam.c
Normal file
1084
gomspace/libparam_client/src/bindings/python/pyparam.c
Normal file
File diff suppressed because it is too large
Load Diff
418
gomspace/libparam_client/src/pp/cmd/master_cmd.c
Normal file
418
gomspace/libparam_client/src/pp/cmd/master_cmd.c
Normal file
@ -0,0 +1,418 @@
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#include <gs/param/pp/spi/spi.h>
|
||||
#include <gs/param/pp/i2c/i2c.h>
|
||||
#include <gs/util/gosh/command.h>
|
||||
#include <gs/util/stdio.h>
|
||||
#include <gs/util/string.h>
|
||||
#include <gs/util/log.h>
|
||||
|
||||
static bool use_checksum;
|
||||
|
||||
static gs_pp_t gs_pp;
|
||||
|
||||
static int cmd_spi_init(gs_command_context_t *ctx)
|
||||
{
|
||||
uint8_t slave;
|
||||
gs_error_t error = gs_string_to_uint8(ctx->argv[1], &slave);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
bool big_endian = false;
|
||||
if (ctx->argc > 2) {
|
||||
error = gs_string_to_bool(ctx->argv[2], &big_endian);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
error = gs_pp_spi_init(&gs_pp, slave, big_endian);
|
||||
if (error) {
|
||||
memset(&gs_pp, 0, sizeof(gs_pp));
|
||||
return error;
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static int cmd_i2c_init(gs_command_context_t *ctx)
|
||||
{
|
||||
uint8_t bus;
|
||||
gs_error_t error = gs_string_to_uint8(ctx->argv[1], &bus);
|
||||
if (error) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
uint8_t addr;
|
||||
error = gs_string_to_uint8(ctx->argv[2], &addr);
|
||||
if (error) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
bool big_endian = false;
|
||||
if (ctx->argc > 3) {
|
||||
error = gs_string_to_bool(ctx->argv[3], &big_endian);
|
||||
if (error) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
error = gs_pp_i2c_init(&gs_pp, bus, addr, big_endian);
|
||||
if (error) {
|
||||
memset(&gs_pp, 0, sizeof(gs_pp));
|
||||
return error;
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static int cmd_checksum(gs_command_context_t *ctx)
|
||||
{
|
||||
if (ctx->argc > 1) {
|
||||
if (gs_string_to_bool(ctx->argv[1], &use_checksum)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
printf("Use CHECKSUM: %d\r\n", use_checksum);
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
// get_xxxx <table> <addr>
|
||||
static int cmd_parse(gs_command_context_t *ctx,
|
||||
uint32_t * table, uint32_t * addr)
|
||||
{
|
||||
if (ctx->argc < 3) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
gs_error_t error = gs_string_to_uint32(ctx->argv[1], table);
|
||||
if (error || (*table > 7)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
error = gs_string_to_uint32(ctx->argv[2], addr);
|
||||
if (error || (*addr > 255)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static int cmd_get_parse(gs_command_context_t * ctx,
|
||||
uint32_t * table, uint32_t * addr, uint32_t * count)
|
||||
{
|
||||
int res = cmd_parse(ctx, table, addr);
|
||||
if (res == GS_OK) {
|
||||
*count = 1;
|
||||
if (ctx->argc > 3) {
|
||||
gs_error_t error = gs_string_to_uint32(ctx->argv[3], count);
|
||||
if (error || (*count > 100)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define CMD_GET(_ctx, _type, _func, _format) \
|
||||
{ \
|
||||
uint32_t table; \
|
||||
uint32_t addr; \
|
||||
uint32_t count; \
|
||||
int res = cmd_get_parse(_ctx, &table, &addr, &count); \
|
||||
if (res == GS_OK) { \
|
||||
_type value[count]; \
|
||||
gs_error_t error = _func(&gs_pp, table, addr, value, count, use_checksum ? GS_PP_FLAG_CHECKSUM : 0); \
|
||||
if (error) { \
|
||||
return error; \
|
||||
} \
|
||||
printf("value(s): "); \
|
||||
for (unsigned int i = 0; i < count; ++i) { \
|
||||
printf("%" _format " ", value[i]); \
|
||||
} \
|
||||
printf("\r\n"); \
|
||||
} \
|
||||
return res; \
|
||||
}
|
||||
|
||||
static int cmd_get_int8(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_GET(ctx, int8_t, gs_pp_get_int8, PRId8);
|
||||
}
|
||||
|
||||
static int cmd_get_int16(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_GET(ctx, int16_t, gs_pp_get_int16, PRId16);
|
||||
}
|
||||
|
||||
static int cmd_get_int32(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_GET(ctx, int32_t, gs_pp_get_int32, PRId32);
|
||||
}
|
||||
|
||||
static int cmd_get_uint8(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_GET(ctx, uint8_t, gs_pp_get_uint8, PRIu8);
|
||||
}
|
||||
|
||||
static int cmd_get_uint16(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_GET(ctx, uint16_t, gs_pp_get_uint16, PRIu16);
|
||||
}
|
||||
|
||||
static int cmd_get_uint32(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_GET(ctx, uint32_t, gs_pp_get_uint32, PRIu32);
|
||||
}
|
||||
|
||||
static int cmd_get_float(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_GET(ctx, float, gs_pp_get_float, "f");
|
||||
}
|
||||
|
||||
#define CMD_SET(_ctx, _type, _func, _convert) \
|
||||
{ \
|
||||
const unsigned int MAX_VALUES = 20; \
|
||||
uint32_t table; \
|
||||
uint32_t addr; \
|
||||
int res = cmd_parse(_ctx, &table, &addr); \
|
||||
if (res == GS_OK) { \
|
||||
_type value[MAX_VALUES]; \
|
||||
unsigned int count = 0; \
|
||||
for (int i = 3; (i < _ctx->argc) && (count < MAX_VALUES); ++i, ++count) { \
|
||||
res = _convert(_ctx->argv[i], &value[count]); \
|
||||
if (res) { \
|
||||
return GS_ERROR_DATA; \
|
||||
} \
|
||||
} \
|
||||
res = _func(&gs_pp, table, addr, value, count, use_checksum ? GS_PP_FLAG_CHECKSUM : 0); \
|
||||
} \
|
||||
return res; \
|
||||
}
|
||||
|
||||
static int cmd_set_int8(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_SET(ctx, int8_t, gs_pp_set_int8, gs_string_to_int8);
|
||||
}
|
||||
|
||||
static int cmd_set_int16(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_SET(ctx, int16_t, gs_pp_set_int16, gs_string_to_int16);
|
||||
}
|
||||
|
||||
static int cmd_set_int32(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_SET(ctx, int32_t, gs_pp_set_int32, gs_string_to_int32);
|
||||
}
|
||||
|
||||
static int cmd_set_uint8(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_SET(ctx, uint8_t, gs_pp_set_uint8, gs_string_to_uint8);
|
||||
}
|
||||
|
||||
static int cmd_set_uint16(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_SET(ctx, uint16_t, gs_pp_set_uint16, gs_string_to_uint16);
|
||||
}
|
||||
|
||||
static int cmd_set_uint32(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_SET(ctx, uint32_t, gs_pp_set_uint32, gs_string_to_uint32);
|
||||
}
|
||||
|
||||
static int cmd_set_float(gs_command_context_t * ctx)
|
||||
{
|
||||
CMD_SET(ctx, float, gs_pp_set_float, gs_string_to_float);
|
||||
}
|
||||
|
||||
static int cmd_get_table_lock(gs_command_context_t * ctx)
|
||||
{
|
||||
uint32_t table;
|
||||
gs_error_t res = gs_string_to_uint32(ctx->argv[1], &table);
|
||||
if (res == GS_OK) {
|
||||
if (table <= 7) {
|
||||
bool lock;
|
||||
res = gs_pp_get_table_lock(&gs_pp, table, &lock, GS_PP_FLAG_CHECKSUM);
|
||||
if (res == GS_OK) {
|
||||
const char locked[] = "locked\n";
|
||||
const char unlocked[] = "unlocked\n";
|
||||
const char * lock_state = (lock) ? locked : unlocked;
|
||||
printf("Table %s", lock_state);
|
||||
}
|
||||
} else {
|
||||
res = GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int cmd_set_table_lock(gs_command_context_t * ctx)
|
||||
{
|
||||
uint32_t table;
|
||||
gs_error_t res = gs_string_to_uint32(ctx->argv[1], &table);
|
||||
if (res == GS_OK) {
|
||||
if (table <= 7) {
|
||||
uint32_t lock;
|
||||
res = gs_string_to_uint32(ctx->argv[2], &lock);
|
||||
if (res == GS_OK) {
|
||||
if(lock <= 1) {
|
||||
res = gs_pp_set_table_lock(&gs_pp, table, (bool *)&lock, GS_PP_FLAG_CHECKSUM);
|
||||
} else {
|
||||
res = GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const gs_command_t gs_param_cmd_master_pp_sub[] = {
|
||||
{
|
||||
.name = "spi_init",
|
||||
.help = "Initialize/setup SPI device",
|
||||
.usage = "<slave> [big_endian]",
|
||||
.handler = cmd_spi_init,
|
||||
.mandatory_args = 1,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "i2c_init",
|
||||
.help = "Initialize/setup I2C device",
|
||||
.usage = "<device> <addr> [big_endian]",
|
||||
.handler = cmd_i2c_init,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "checksum",
|
||||
.help = "Enable/disable checksum",
|
||||
.usage = "[0|1]",
|
||||
.handler = cmd_checksum,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "get_table_lock",
|
||||
.help = "Get table lock (0 = unlocked, 1 = locked)",
|
||||
.usage = "<table>",
|
||||
.mandatory_args = 1,
|
||||
.handler = cmd_get_table_lock,
|
||||
},{
|
||||
.name = "set_table_lock",
|
||||
.help = "Set table lock (0 = unlocked, 1 = locked)",
|
||||
.usage = "<table> <lock/unlock>",
|
||||
.mandatory_args = 2,
|
||||
.handler = cmd_set_table_lock,
|
||||
},{
|
||||
.name = "get_int8",
|
||||
.help = "Get int8",
|
||||
.usage = "<table> <addr> [count]",
|
||||
.handler = cmd_get_int8,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "get_int16",
|
||||
.help = "Get int16",
|
||||
.usage = "<table> <addr> [count]",
|
||||
.handler = cmd_get_int16,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "get_int32",
|
||||
.help = "Get int32",
|
||||
.usage = "<table> <addr> [count]",
|
||||
.handler = cmd_get_int32,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "get_uint8",
|
||||
.help = "Get uint8",
|
||||
.usage = "<table> <addr> [count]",
|
||||
.handler = cmd_get_uint8,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "get_uint16",
|
||||
.help = "Get uint16",
|
||||
.usage = "<table> <addr> [count]",
|
||||
.handler = cmd_get_uint16,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "get_uint32",
|
||||
.help = "Get uint32",
|
||||
.usage = "<table> <addr> [count]",
|
||||
.handler = cmd_get_uint32,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "get_float",
|
||||
.help = "Get float",
|
||||
.usage = "<table> <addr> [count]",
|
||||
.handler = cmd_get_float,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "set_int8",
|
||||
.help = "Set int8",
|
||||
.usage = "<table> <addr> <data> [data] ...",
|
||||
.handler = cmd_set_int8,
|
||||
.mandatory_args = 3,
|
||||
.optional_args = 20,
|
||||
},{
|
||||
.name = "set_int16",
|
||||
.help = "Set int16",
|
||||
.usage = "<table> <addr> <data> [data] ...",
|
||||
.handler = cmd_set_int16,
|
||||
.mandatory_args = 3,
|
||||
.optional_args = 20,
|
||||
},{
|
||||
.name = "set_int32",
|
||||
.help = "Set int32",
|
||||
.usage = "<table> <addr> <data> [data] ...",
|
||||
.handler = cmd_set_int32,
|
||||
.mandatory_args = 3,
|
||||
.optional_args = 20,
|
||||
},{
|
||||
.name = "set_uint8",
|
||||
.help = "Set uint8",
|
||||
.usage = "<table> <addr> <data> [data] ...",
|
||||
.handler = cmd_set_uint8,
|
||||
.mandatory_args = 3,
|
||||
.optional_args = 20,
|
||||
},{
|
||||
.name = "set_uint16",
|
||||
.help = "Set uint16",
|
||||
.usage = "<table> <addr> <data> [data] ...",
|
||||
.handler = cmd_set_uint16,
|
||||
.mandatory_args = 3,
|
||||
.optional_args = 20,
|
||||
},{
|
||||
.name = "set_uint32",
|
||||
.help = "Set uint32",
|
||||
.usage = "<table> <addr> <data> [data] ...",
|
||||
.handler = cmd_set_uint32,
|
||||
.mandatory_args = 3,
|
||||
.optional_args = 20,
|
||||
},{
|
||||
.name = "set_float",
|
||||
.help = "Set float",
|
||||
.usage = "<table> <addr> <data> [data] ...",
|
||||
.handler = cmd_set_float,
|
||||
.mandatory_args = 3,
|
||||
.optional_args = 20,
|
||||
}
|
||||
};
|
||||
|
||||
static const gs_command_t GS_COMMAND_ROOT gs_param_cmd_master_pp[] = {
|
||||
{
|
||||
.name = "pp",
|
||||
.help = "Param Protocol interface",
|
||||
.chain = GS_COMMAND_INIT_CHAIN(gs_param_cmd_master_pp_sub),
|
||||
}
|
||||
};
|
||||
|
||||
gs_error_t gs_pp_register_commands(void)
|
||||
{
|
||||
return GS_COMMAND_REGISTER(gs_param_cmd_master_pp);
|
||||
}
|
129
gomspace/libparam_client/src/pp/i2c/i2c.c
Normal file
129
gomspace/libparam_client/src/pp/i2c/i2c.c
Normal file
@ -0,0 +1,129 @@
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include <gs/param/internal/pp/i2c/i2c.h>
|
||||
#include <gs/util/drivers/i2c/master.h>
|
||||
#include <gs/util/string.h>
|
||||
#include <gs/util/check.h>
|
||||
#include <alloca.h>
|
||||
|
||||
static gs_error_t gs_pp_i2c_write(gs_param_i2c_command_t cmd, gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, bool checksum)
|
||||
{
|
||||
GS_CHECK_RANGE(table_id <= 7);
|
||||
GS_CHECK_RANGE(addr <= 255);
|
||||
GS_CHECK_RANGE((value_size > 0) && (value_size <= 31));
|
||||
|
||||
gs_param_i2c_set_request_t * request;
|
||||
const size_t size = (sizeof(*request) + value_size + (checksum ? 1 : 0));
|
||||
request = alloca(size);
|
||||
|
||||
request->header.domain_command = GS_I2C_SLAVE_DISPATCH_HEADER(GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, cmd);
|
||||
request->length_table = GS_PARAM_I2C_LENGTH_TABLE(value_size, table_id);
|
||||
request->addr = addr;
|
||||
memcpy(request->data, value, value_size);
|
||||
|
||||
if (checksum) {
|
||||
request->data[value_size] = gs_pp_checksum8(request, size - 1);
|
||||
}
|
||||
return gs_i2c_master_transaction(pp->pp.i2c.bus, pp->pp.i2c.addr, request, size, NULL, 0, 1000);
|
||||
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_i2c_read(gs_param_i2c_command_t cmd, gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, bool checksum)
|
||||
{
|
||||
GS_CHECK_RANGE(table_id <= 7);
|
||||
GS_CHECK_RANGE(addr <= 255);
|
||||
GS_CHECK_RANGE((value_size > 0) && (value_size <= 31));
|
||||
|
||||
gs_param_i2c_get_request_t request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.length_table = GS_PARAM_I2C_LENGTH_TABLE(value_size, table_id);
|
||||
request.addr = addr;
|
||||
size_t request_size;
|
||||
|
||||
uint8_t reply[value_size + sizeof(request.checksum)]; // + for checksum
|
||||
memset(reply, 0, sizeof(reply));
|
||||
size_t reply_size;
|
||||
|
||||
request.header.domain_command = GS_I2C_SLAVE_DISPATCH_HEADER(GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, cmd);
|
||||
|
||||
if (checksum) {
|
||||
request.checksum = gs_pp_checksum8(&request, (sizeof(request) - sizeof(request.checksum)));
|
||||
request_size = sizeof(request);
|
||||
reply_size = sizeof(reply);
|
||||
} else {
|
||||
request_size = sizeof(request) - sizeof(request.checksum);
|
||||
reply_size = sizeof(reply) - sizeof(request.checksum);
|
||||
}
|
||||
|
||||
gs_error_t error = gs_i2c_master_transaction(pp->pp.i2c.bus, pp->pp.i2c.addr, &request, request_size, reply, reply_size, 1000);
|
||||
if (error == GS_OK) {
|
||||
if (checksum) {
|
||||
if (gs_pp_checksum8(reply, value_size) != reply[value_size]) {
|
||||
return GS_ERROR_DATA;
|
||||
}
|
||||
}
|
||||
memcpy(value, reply, value_size);
|
||||
}
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_i2c_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
gs_param_i2c_command_t cmd;
|
||||
bool checksum = false;
|
||||
if (flags & GS_PP_FLAG_CHECKSUM) {
|
||||
checksum = true;
|
||||
cmd = GS_PARAM_I2C_COMMAND_GET_WITH_CHECKSUM;
|
||||
} else {
|
||||
cmd = GS_PARAM_I2C_COMMAND_GET;
|
||||
}
|
||||
return gs_pp_i2c_read(cmd, pp, table_id, addr, value, value_size, checksum);
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_i2c_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
gs_param_i2c_command_t cmd;
|
||||
bool checksum = false;
|
||||
if (flags & GS_PP_FLAG_CHECKSUM) {
|
||||
checksum = true;
|
||||
cmd = GS_PARAM_I2C_COMMAND_SET_WITH_CHECKSUM;
|
||||
} else {
|
||||
cmd = GS_PARAM_I2C_COMMAND_SET;
|
||||
}
|
||||
return gs_pp_i2c_write(cmd, pp, table_id, addr, (void *)value, value_size, checksum);
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_i2c_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags)
|
||||
{
|
||||
gs_param_i2c_command_t cmd = GS_PARAM_I2C_COMMAND_SET_LOCK_WITH_CHECKSUM;
|
||||
bool checksum = true;
|
||||
return gs_pp_i2c_write(cmd, pp, table_id, 0, (void *)value, 1, checksum);
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_i2c_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags)
|
||||
{
|
||||
gs_param_i2c_command_t cmd = GS_PARAM_I2C_COMMAND_GET_LOCK_WITH_CHECKSUM;
|
||||
bool checksum = true;
|
||||
return gs_pp_i2c_read(cmd, pp, table_id, 0, value, 1, checksum);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_i2c_init(gs_pp_t * pp, uint8_t bus, uint8_t addr, bool big_endian)
|
||||
{
|
||||
GS_CHECK_HANDLE(pp != NULL);
|
||||
|
||||
memset(pp, 0, sizeof(*pp));
|
||||
|
||||
pp->get = gs_pp_i2c_get;
|
||||
pp->set = gs_pp_i2c_set;
|
||||
pp->set_table_lock = gs_pp_i2c_set_table_lock;
|
||||
pp->get_table_lock = gs_pp_i2c_get_table_lock;
|
||||
pp->big_endian = big_endian;
|
||||
|
||||
pp->pp.i2c.bus = bus;
|
||||
pp->pp.i2c.addr = addr;
|
||||
|
||||
return GS_OK;
|
||||
}
|
189
gomspace/libparam_client/src/pp/pp.c
Normal file
189
gomspace/libparam_client/src/pp/pp.c
Normal file
@ -0,0 +1,189 @@
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#include <gs/param/pp/pp.h>
|
||||
#include <gs/util/string.h>
|
||||
#include <gs/util/check.h>
|
||||
#include <gs/util/byteorder.h>
|
||||
#include <gs/util/endian.h>
|
||||
|
||||
static inline bool gs_pp_endian_convert(gs_pp_t * pp)
|
||||
{
|
||||
return (pp && (pp->big_endian != gs_endian_big()));
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
if (pp == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
if (pp->get == NULL) {
|
||||
return GS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return pp->get(pp, table_id, addr, value, value_size, flags);
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
if (pp == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
if (pp->set == NULL) {
|
||||
return GS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return pp->set(pp, table_id, addr, value, value_size, flags);
|
||||
}
|
||||
|
||||
uint8_t gs_pp_checksum8(const void * data_in, size_t length)
|
||||
{
|
||||
const uint8_t * data = data_in;
|
||||
unsigned int checksum = 0;
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
checksum += *data++;
|
||||
}
|
||||
checksum &= 0xff;
|
||||
return checksum ? checksum : 1;
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_HANDLE(pp != NULL);
|
||||
if (pp->get_table_lock == NULL) {
|
||||
return GS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return pp->get_table_lock(pp, table_id, value, flags);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_HANDLE(pp != NULL);
|
||||
if (pp->set_table_lock == NULL) {
|
||||
return GS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return pp->set_table_lock(pp, table_id, value, flags);
|
||||
}
|
||||
|
||||
// int8_t
|
||||
gs_error_t gs_pp_get_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int8_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
return gs_pp_get_uint8(pp, table_id, addr, (uint8_t *) value, count, flags);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int8_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
return gs_pp_set_uint8(pp, table_id, addr, (const uint8_t *) value, count, flags);
|
||||
}
|
||||
|
||||
// uint8_t
|
||||
|
||||
gs_error_t gs_pp_get_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint8_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
return gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint8_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
}
|
||||
|
||||
// int16_t
|
||||
|
||||
gs_error_t gs_pp_get_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int16_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
return gs_pp_get_uint16(pp, table_id, addr, (uint16_t *) value, count, flags);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int16_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
return gs_pp_set_uint16(pp, table_id, addr, (const uint16_t *) value, count, flags);
|
||||
}
|
||||
|
||||
// uint16_t
|
||||
|
||||
gs_error_t gs_pp_get_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint16_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
if (gs_pp_endian_convert(pp)) {
|
||||
gs_bswap_16_array(value, value, count);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint16_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
uint16_t _converted[count];
|
||||
if (gs_pp_endian_convert(pp)) {
|
||||
gs_bswap_16_array(value, _converted, count);
|
||||
value = _converted;
|
||||
}
|
||||
return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
}
|
||||
|
||||
// int32_t
|
||||
|
||||
gs_error_t gs_pp_get_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int32_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
return gs_pp_get_uint32(pp, table_id, addr, (uint32_t *) value, count, flags);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int32_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
return gs_pp_set_uint32(pp, table_id, addr, (const uint32_t *) value, count, flags);
|
||||
}
|
||||
|
||||
// uint32_t
|
||||
|
||||
gs_error_t gs_pp_get_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint32_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
if (gs_pp_endian_convert(pp)) {
|
||||
gs_bswap_32_array(value, value, count);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint32_t * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
uint32_t _converted[count];
|
||||
if (gs_pp_endian_convert(pp)) {
|
||||
gs_bswap_32_array(value, _converted, count);
|
||||
value = _converted;
|
||||
}
|
||||
return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_get_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, float * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
if (gs_pp_endian_convert(pp)) {
|
||||
gs_bswap_float_array(value, value, count);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_set_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const float * value, size_t count, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_ARG(value != NULL);
|
||||
GS_CHECK_ARG(count > 0);
|
||||
float _converted[count];
|
||||
if (gs_pp_endian_convert(pp)) {
|
||||
gs_bswap_float_array(value, _converted, count);
|
||||
value = _converted;
|
||||
}
|
||||
return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags);
|
||||
}
|
91
gomspace/libparam_client/src/pp/spi/spi.c
Normal file
91
gomspace/libparam_client/src/pp/spi/spi.c
Normal file
@ -0,0 +1,91 @@
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include <gs/param/internal/pp/spi/spi.h>
|
||||
#include <gs/util/drivers/spi/master.h>
|
||||
#include <gs/util/string.h>
|
||||
#include <gs/util/check.h>
|
||||
#include <alloca.h>
|
||||
|
||||
static gs_error_t gs_pp_spi_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_RANGE(table_id <= 7);
|
||||
GS_CHECK_RANGE(addr <= 255);
|
||||
|
||||
if (flags & GS_PP_FLAG_CHECKSUM) {
|
||||
gs_param_spi_get_with_checksum_t * request;
|
||||
const size_t size = (sizeof(*request) + value_size + 1); // +1 for CHECKSUM in returned data
|
||||
request = alloca(size);
|
||||
memset(request, 0, size);
|
||||
request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_GET_WITH_CHECKSUM);
|
||||
request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id);
|
||||
request->addr = addr;
|
||||
request->checksum = gs_pp_checksum8(request, (sizeof(*request) - sizeof(request->filler)));
|
||||
|
||||
gs_error_t error = gs_spi_master_transaction(pp->pp.spi.slave, request, request, size, 1000);
|
||||
if (error == GS_OK) {
|
||||
if (gs_pp_checksum8(request->data, value_size) != request->data[value_size]) {
|
||||
return GS_ERROR_DATA;
|
||||
}
|
||||
memcpy(value, request->data, value_size);
|
||||
}
|
||||
return error;
|
||||
|
||||
} else {
|
||||
gs_param_spi_get_t * request;
|
||||
const size_t size = (sizeof(*request) + value_size);
|
||||
request = alloca(size);
|
||||
memset(request, 0, size);
|
||||
request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_GET);
|
||||
request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id);
|
||||
request->addr = addr;
|
||||
|
||||
gs_error_t error = gs_spi_master_transaction(pp->pp.spi.slave, request, request, size, 1000);
|
||||
if (error == GS_OK) {
|
||||
memcpy(value, request->data, value_size);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static gs_error_t gs_pp_spi_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
GS_CHECK_RANGE(table_id <= 7);
|
||||
GS_CHECK_RANGE(addr <= 255);
|
||||
|
||||
gs_param_spi_set_t * request;
|
||||
const size_t size = (sizeof(*request) + value_size + ((flags & GS_PP_FLAG_CHECKSUM) ? 1 : 0));
|
||||
request = alloca(size);
|
||||
if (flags & GS_PP_FLAG_CHECKSUM) {
|
||||
request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_SET_WITH_CHECKSUM);
|
||||
} else {
|
||||
request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_SET);
|
||||
}
|
||||
request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id);
|
||||
request->addr = addr;
|
||||
memcpy(request->data, value, value_size);
|
||||
|
||||
if (flags & GS_PP_FLAG_CHECKSUM) {
|
||||
request->data[value_size] = gs_pp_checksum8(request, size - 1);
|
||||
}
|
||||
|
||||
return gs_spi_master_transaction(pp->pp.spi.slave, request, NULL, size, 1000);
|
||||
}
|
||||
|
||||
gs_error_t gs_pp_spi_init(gs_pp_t * pp, uint8_t slave, bool big_endian)
|
||||
{
|
||||
GS_CHECK_HANDLE(pp != NULL);
|
||||
|
||||
memset(pp, 0, sizeof(*pp));
|
||||
|
||||
pp->get = gs_pp_spi_get;
|
||||
pp->set = gs_pp_spi_set;
|
||||
pp->set_table_lock = NULL; // Not implemented
|
||||
pp->get_table_lock = NULL; // Not implemented
|
||||
pp->big_endian = big_endian;
|
||||
|
||||
pp->pp.spi.slave = slave;
|
||||
|
||||
return GS_OK;
|
||||
}
|
354
gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c
Normal file
354
gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c
Normal file
@ -0,0 +1,354 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include <gs/param/internal/rparam.h>
|
||||
#include <gs/param/internal/table.h>
|
||||
#include <gs/param/internal/serialize.h>
|
||||
#include <gs/param/internal/types.h>
|
||||
#include "../query.h"
|
||||
#include <gs/util/log.h>
|
||||
#include <gs/util/gosh/command.h>
|
||||
#include <gs/util/stdio.h>
|
||||
#include <gs/util/unistd.h>
|
||||
#include <gs/csp/csp.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_FILENAME 100
|
||||
|
||||
/** Remote param system setup */
|
||||
static gs_param_table_instance_t rparam_tinst;
|
||||
static gs_rparam_query_handle_t rquery = {.timeout_ms = 10000};
|
||||
static char * rparam_wd;
|
||||
|
||||
#define CHECK_TABLE() \
|
||||
if (rparam_tinst.rows == NULL) { \
|
||||
fprintf(ctx->out, "Run download or init to setup table\n"); \
|
||||
return GS_ERROR_NOT_FOUND; \
|
||||
}
|
||||
|
||||
static int cmd_rparam_list(gs_command_context_t *ctx)
|
||||
{
|
||||
CHECK_TABLE();
|
||||
return gs_param_list_to_stream(&rparam_tinst, true, 0, ctx->out);
|
||||
}
|
||||
|
||||
static void make_filename(char * fname, size_t fname_size)
|
||||
{
|
||||
char cwd[MAX_FILENAME + 1];
|
||||
const char * wd;
|
||||
if (gs_string_empty(rparam_wd) == false) {
|
||||
wd = rparam_wd;
|
||||
} else if (gs_getcwd(cwd, sizeof(cwd)) == GS_OK) {
|
||||
wd = cwd;
|
||||
} else {
|
||||
wd = NULL;
|
||||
}
|
||||
if (gs_string_empty(wd) == false) {
|
||||
snprintf(fname, fname_size, "%s/param-%d-%u.bin", wd, rquery.node, rquery.table_id);
|
||||
} else {
|
||||
fname[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_rparam_init_from_local_file(gs_command_context_t *ctx)
|
||||
{
|
||||
if (gs_string_to_uint8(ctx->argv[1], &rquery.node)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
if (ctx->argc > 2) {
|
||||
if (gs_string_to_uint8(ctx->argv[2], &rquery.table_id)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
char fname[100];
|
||||
make_filename(fname, sizeof(fname));
|
||||
return gs_rparam_load_table_spec(&rparam_tinst, fname, &rquery.checksum);
|
||||
}
|
||||
|
||||
static int cmd_rparam_init_from_remote_node(gs_command_context_t *ctx)
|
||||
{
|
||||
if (gs_string_to_uint8(ctx->argv[1], &rquery.node)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
if (ctx->argc > 2) {
|
||||
if (gs_string_to_uint8(ctx->argv[2], &rquery.table_id)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
char fname[100];
|
||||
make_filename(fname, sizeof(fname));
|
||||
return gs_rparam_download_table_spec(&rparam_tinst, fname, rquery.node, rquery.table_id, rquery.timeout_ms, &rquery.checksum);
|
||||
}
|
||||
|
||||
static int cmd_rparam_send(gs_command_context_t *ctx)
|
||||
{
|
||||
CHECK_TABLE();
|
||||
|
||||
gs_error_t error = gs_rparam_query_send(&rquery, &rparam_tinst);
|
||||
if (error == GS_OK) {
|
||||
if (rquery.action == RPARAM_GET) {
|
||||
const gs_param_table_row_t * last_print = NULL;
|
||||
for (unsigned int i = 0; i < rquery.length / 2; ++i) {
|
||||
const gs_param_table_row_t * row = gs_param_row_by_address(rquery.payload.addr[i], rparam_tinst.rows, rparam_tinst.row_count);
|
||||
if (row != last_print) { // work-around to avoid duplicate lines for elements within same array
|
||||
gs_param_list_single_to_stream(&rparam_tinst, row, true, 0, ctx->out);
|
||||
last_print = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
gs_rparam_query_reset(&rquery);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int cmd_rparam_get(gs_command_context_t *ctx)
|
||||
{
|
||||
CHECK_TABLE();
|
||||
|
||||
gs_rparam_query_set_quiet(&rquery, false);
|
||||
gs_error_t error = gs_rparam_query_get(&rquery, &rparam_tinst, ctx->argv[1]);
|
||||
if ((error == GS_OK) && rquery.auto_send) {
|
||||
error = cmd_rparam_send(ctx);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int cmd_rparam_getall(gs_command_context_t *ctx)
|
||||
{
|
||||
CHECK_TABLE();
|
||||
|
||||
fprintf(ctx->out, "Downloading table content for table %i from server %u\n", rquery.table_id, rquery.node);
|
||||
gs_error_t error = gs_rparam_get_full_table(&rparam_tinst, rquery.node, rquery.table_id, rquery.checksum, rquery.timeout_ms);
|
||||
if (error == GS_OK) {
|
||||
gs_param_list_to_stream(&rparam_tinst, true, 0, ctx->out);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int cmd_rparam_set(gs_command_context_t *ctx)
|
||||
{
|
||||
CHECK_TABLE();
|
||||
|
||||
gs_error_t error = gs_rparam_query_set(&rquery, &rparam_tinst, ctx->argv[1], &ctx->argv[2], ctx->argc - 2);
|
||||
if ((error == GS_OK) && rquery.auto_send) {
|
||||
error = cmd_rparam_send(ctx);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int cmd_rparam_copy(gs_command_context_t *ctx)
|
||||
{
|
||||
uint8_t from;
|
||||
if (gs_string_to_uint8(ctx->argv[1], &from)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
uint8_t to;
|
||||
if (gs_string_to_uint8(ctx->argv[2], &to)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
return gs_rparam_copy(rquery.node, rquery.timeout_ms, from, to);
|
||||
}
|
||||
|
||||
static int cmd_rparam_load(gs_command_context_t *ctx)
|
||||
{
|
||||
uint8_t table_id;
|
||||
if (gs_string_to_uint8(ctx->argv[2], &table_id)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
uint8_t file_id;
|
||||
if (gs_string_to_uint8(ctx->argv[1], &file_id)) {
|
||||
// This may be a store - no way of validating
|
||||
return gs_rparam_load_from_store(rquery.node, rquery.timeout_ms, table_id, ctx->argv[1], NULL);
|
||||
}
|
||||
|
||||
return gs_rparam_load(rquery.node, rquery.timeout_ms, file_id, table_id);
|
||||
}
|
||||
|
||||
static int cmd_rparam_save(gs_command_context_t *ctx)
|
||||
{
|
||||
uint8_t table_id;
|
||||
if (gs_string_to_uint8(ctx->argv[1], &table_id)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
uint8_t file_id;
|
||||
if (gs_string_to_uint8(ctx->argv[2], &file_id)) {
|
||||
// This may be a store - no way of validating
|
||||
return gs_rparam_save_to_store(rquery.node, rquery.timeout_ms, table_id, ctx->argv[2], NULL);
|
||||
}
|
||||
|
||||
return gs_rparam_save(rquery.node, rquery.timeout_ms, table_id, file_id);
|
||||
}
|
||||
|
||||
static int cmd_rparam_reset(gs_command_context_t *ctx)
|
||||
{
|
||||
gs_rparam_query_reset(&rquery);
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static int cmd_rparam_set_autosend(gs_command_context_t *ctx)
|
||||
{
|
||||
if (ctx->argc > 1) {
|
||||
if (gs_string_to_bool(ctx->argv[1], &rquery.auto_send)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
fprintf(ctx->out, "auto send: %d\r\n", rquery.auto_send);
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static int cmd_set_wd(gs_command_context_t *ctx)
|
||||
{
|
||||
if (ctx->argc > 1) {
|
||||
if (rparam_wd == NULL) {
|
||||
rparam_wd = malloc(MAX_FILENAME + 1);
|
||||
if (rparam_wd == NULL) {
|
||||
return GS_ERROR_ALLOC;
|
||||
}
|
||||
}
|
||||
strcpy(rparam_wd, ctx->argv[1]);
|
||||
}
|
||||
fprintf(ctx->out, "working directory: %s\r\n", rparam_wd ? rparam_wd : "not set");
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static int cmd_rparam_set_timeout(gs_command_context_t *ctx)
|
||||
{
|
||||
if (ctx->argc > 1) {
|
||||
if (gs_string_to_uint32(ctx->argv[1], &rquery.timeout_ms)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
fprintf(ctx->out, "timeout: %"PRIu32" mS\r\n", rquery.timeout_ms);
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static int cmd_rparam_set_checksum(gs_command_context_t *ctx)
|
||||
{
|
||||
if (ctx->argc > 1) {
|
||||
if (strcasecmp(ctx->argv[1], "magic") == 0) {
|
||||
rquery.checksum = GS_RPARAM_MAGIC_CHECKSUM;
|
||||
} else if (gs_string_to_uint16(ctx->argv[1], &rquery.checksum)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
fprintf(ctx->out, "checksum: 0x%04x (magic: 0x%04x)\r\n", rquery.checksum, GS_RPARAM_MAGIC_CHECKSUM);
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static const gs_command_t rparam_commands[] = {
|
||||
{
|
||||
.name = "init",
|
||||
.help = "Set server and load table spec. from file",
|
||||
.usage = "<server> [table-id]",
|
||||
.handler = cmd_rparam_init_from_local_file,
|
||||
.mandatory_args = 1,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "download",
|
||||
.help = "Set server and download table spec.",
|
||||
.usage = "<server> [table-id]",
|
||||
.handler = cmd_rparam_init_from_remote_node,
|
||||
.mandatory_args = 1,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "getall",
|
||||
.help = "Download full table contents from server",
|
||||
.handler = cmd_rparam_getall,
|
||||
.mandatory_args = GS_COMMAND_NO_ARGS,
|
||||
},{
|
||||
.name = "list",
|
||||
.help = "Lists the table specification",
|
||||
.handler = cmd_rparam_list,
|
||||
.mandatory_args = GS_COMMAND_NO_ARGS,
|
||||
},{
|
||||
.name = "get",
|
||||
.help = "Add a 'get' to the current query transaction",
|
||||
.usage = "<name>",
|
||||
.handler = cmd_rparam_get,
|
||||
.mandatory_args = 1,
|
||||
},{
|
||||
.name = "set",
|
||||
.help = "Add a 'set' to the current query transaction",
|
||||
.usage = "<parameter> <value> [value] ...",
|
||||
.handler = cmd_rparam_set,
|
||||
.mandatory_args = 2,
|
||||
.optional_args = 100,
|
||||
},{
|
||||
.name = "copy",
|
||||
.usage = "<from table-id> <to table-id>",
|
||||
.help = "Copy table to table (version <= 3 only)",
|
||||
.handler = cmd_rparam_copy,
|
||||
.mandatory_args = 2,
|
||||
},{
|
||||
.name = "load",
|
||||
.usage = "<file-id|store> <table-id>",
|
||||
.help = "Load table",
|
||||
.handler = cmd_rparam_load,
|
||||
.mandatory_args = 2,
|
||||
},{
|
||||
.name = "save",
|
||||
.usage = "<table-id> <file-id|store>",
|
||||
.help = "Save table",
|
||||
.handler = cmd_rparam_save,
|
||||
.mandatory_args = 2,
|
||||
/* },{ */
|
||||
/* .name = "print", */
|
||||
/* .help = "Print the current query", */
|
||||
/* .handler = cmd_rparam_print, */
|
||||
/* .mandatory_args = GS_COMMAND_NO_ARGS, */
|
||||
},{
|
||||
.name = "reset",
|
||||
.help = "Reset the current query",
|
||||
.handler = cmd_rparam_reset,
|
||||
.mandatory_args = GS_COMMAND_NO_ARGS,
|
||||
},{
|
||||
.name = "send",
|
||||
.help = "Send the current query",
|
||||
.handler = cmd_rparam_send,
|
||||
.mandatory_args = GS_COMMAND_NO_ARGS,
|
||||
},{
|
||||
.name = "wd",
|
||||
.help = "Set working directory for init/download",
|
||||
.usage = "[path]",
|
||||
.handler = cmd_set_wd,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "timeout",
|
||||
.help = "Set timeout",
|
||||
.usage = "[timeout mS]",
|
||||
.handler = cmd_rparam_set_timeout,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "checksum",
|
||||
.help = "Set checksum",
|
||||
.usage = "[magic|<checksum>]",
|
||||
.handler = cmd_rparam_set_checksum,
|
||||
.optional_args = 1,
|
||||
},{
|
||||
.name = "autosend",
|
||||
.usage = "[bool]",
|
||||
.help = "Enable/disable autosend for set and get queries",
|
||||
.handler = cmd_rparam_set_autosend,
|
||||
.optional_args = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static const gs_command_t GS_COMMAND_ROOT rparam_root_command[] = {
|
||||
{
|
||||
.name = "rparam",
|
||||
.help = "Remote access to Parameter System",
|
||||
.chain = GS_COMMAND_INIT_CHAIN(rparam_commands),
|
||||
},
|
||||
};
|
||||
|
||||
gs_error_t gs_rparam_register_commands(void)
|
||||
{
|
||||
return GS_COMMAND_REGISTER(rparam_root_command);
|
||||
}
|
6
gomspace/libparam_client/src/rparam/deprecated_rparam.c
Normal file
6
gomspace/libparam_client/src/rparam/deprecated_rparam.c
Normal file
@ -0,0 +1,6 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#include <deprecated/param/rparam_client.h>
|
||||
|
||||
// Old deprecated API uses common data - making it not thread-safe.
|
||||
//gs_rparam_handle_t rparam_handle;
|
212
gomspace/libparam_client/src/rparam/query.c
Normal file
212
gomspace/libparam_client/src/rparam/query.c
Normal file
@ -0,0 +1,212 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include "query.h"
|
||||
#include <gs/param/internal/rparam.h>
|
||||
#include <gs/param/internal/types.h>
|
||||
#include <gs/param/internal/table.h>
|
||||
#include "../serialize_local.h"
|
||||
#include <gs/csp/csp.h>
|
||||
#include <csp/csp_endian.h>
|
||||
|
||||
bool gs_rparam_query_is_set(gs_rparam_query_handle_t * handle)
|
||||
{
|
||||
return (handle->length > 0);
|
||||
}
|
||||
|
||||
void gs_rparam_query_reset(gs_rparam_query_handle_t * handle)
|
||||
{
|
||||
handle->action = RPARAM_GET;
|
||||
handle->length = 0;
|
||||
handle->get_size = 0;
|
||||
}
|
||||
|
||||
void gs_rparam_query_set_quiet(gs_rparam_query_handle_t * handle, bool quiet)
|
||||
{
|
||||
handle->quiet = quiet;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_query_get(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name)
|
||||
{
|
||||
if (tinst->rows == NULL)
|
||||
return GS_ERROR_NOT_FOUND;
|
||||
|
||||
/* Ensure correct header */
|
||||
if (handle->action != RPARAM_GET) {
|
||||
gs_rparam_query_reset(handle);
|
||||
handle->action = RPARAM_GET;
|
||||
}
|
||||
|
||||
char shortname[GS_PARAM_MAX_NAME + 20];
|
||||
uint8_t array_index = 0;
|
||||
bool is_array;
|
||||
if (gs_param_parse_name_and_array_index(param_name, shortname, sizeof(shortname), &array_index, &is_array)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * param = gs_param_row_by_name(shortname, tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (array_index >= GS_PARAM_ARRAY_SIZE(param)) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
if (is_array) {
|
||||
start = array_index;
|
||||
end = start + 1;
|
||||
} else {
|
||||
start = 0;
|
||||
end = GS_PARAM_ARRAY_SIZE(param);
|
||||
}
|
||||
for (unsigned int i = start; i < end; ++i) {
|
||||
|
||||
/* Size check */
|
||||
if (handle->get_size + param->size + sizeof(uint16_t) > GS_RPARAM_QUERY_MAX_PAYLOAD) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
|
||||
/* Add to query */
|
||||
handle->payload.addr[handle->length/2] = param->addr + (param->size * i);
|
||||
handle->length += sizeof(uint16_t);
|
||||
handle->get_size += param->size + sizeof(uint16_t);
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_query_set(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name, char * values[], uint8_t value_count)
|
||||
{
|
||||
/* Ensure correct header */
|
||||
if (handle->action != RPARAM_SET) {
|
||||
gs_rparam_query_reset(handle);
|
||||
handle->action = RPARAM_SET;
|
||||
}
|
||||
|
||||
char shortname[GS_PARAM_MAX_NAME + 20];
|
||||
uint8_t array_index = 0;
|
||||
if (gs_param_parse_name_and_array_index(param_name, shortname, sizeof(shortname), &array_index, NULL)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * param = gs_param_row_by_name(shortname, tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (array_index >= GS_PARAM_ARRAY_SIZE(param)) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < value_count; i++) {
|
||||
|
||||
/* Parse input */
|
||||
uint8_t value[param->size];
|
||||
gs_error_t error = gs_param_from_string(param, values[i], value);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
unsigned int bytes = 0;
|
||||
error = gs_param_serialize_item(param, param->addr + (param->size * (array_index + i)), value, F_TO_BIG_ENDIAN,
|
||||
&handle->payload.packed[handle->length], GS_RPARAM_QUERY_MAX_PAYLOAD - handle->length, &bytes);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
handle->length += bytes;
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_query_send(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (tinst->rows == NULL) {
|
||||
return GS_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (handle->length == 0) {
|
||||
return GS_ERROR_NO_DATA;
|
||||
}
|
||||
|
||||
gs_rparam_query_t * query;
|
||||
|
||||
/* Allocate outgoing buffer */
|
||||
csp_packet_t * packet = csp_buffer_get(RPARAM_QUERY_LENGTH(query, GS_RPARAM_QUERY_MAX_PAYLOAD));
|
||||
if (packet == NULL) {
|
||||
return GS_ERROR_NO_BUFFERS;
|
||||
}
|
||||
|
||||
csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, handle->node, GS_CSP_PORT_RPARAM, handle->timeout_ms, CSP_O_CRC32);
|
||||
if (conn == NULL) {
|
||||
csp_buffer_free(packet);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
query = (gs_rparam_query_t *) packet->data;
|
||||
|
||||
query->action = handle->action;
|
||||
query->table_id = handle->table_id;
|
||||
query->seq = 0;
|
||||
query->total = 0;
|
||||
query->length = csp_hton16(handle->length);
|
||||
query->checksum = csp_hton16(handle->checksum);
|
||||
|
||||
/* Copy payload to message */
|
||||
packet->length = RPARAM_QUERY_LENGTH(query, handle->length);
|
||||
memcpy(&query->payload, &handle->payload, handle->length);
|
||||
|
||||
/* Deal with endianness */
|
||||
if (handle->action == RPARAM_GET) {
|
||||
for (unsigned int i = 0; i < (handle->length/2); i++) {
|
||||
query->payload.addr[i] = csp_hton16(query->payload.addr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send packet */
|
||||
if (!csp_send(conn, packet, 0)) {
|
||||
csp_buffer_free(packet);
|
||||
csp_close(conn);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
/* Read reply */
|
||||
packet = csp_read(conn, handle->timeout_ms);
|
||||
if (packet == NULL) {
|
||||
csp_close(conn);
|
||||
return GS_ERROR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (packet->length <= 1) {
|
||||
gs_error_t error = GS_OK;
|
||||
if (packet->length == 1) {
|
||||
if (packet->data[0] == RPARAM_ERROR) {
|
||||
error = GS_ERROR_DATA;
|
||||
}
|
||||
} else {
|
||||
error = GS_ERROR_NO_DATA;
|
||||
}
|
||||
csp_buffer_free(packet);
|
||||
csp_close(conn);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* We have a reply */
|
||||
gs_rparam_query_t * reply = (gs_rparam_query_t *) packet->data;
|
||||
reply->length = csp_ntoh16(reply->length);
|
||||
|
||||
gs_error_t error;
|
||||
if (reply->action == RPARAM_REPLY) {
|
||||
error = gs_param_deserialize(tinst, reply->payload.packed, reply->length, F_FROM_BIG_ENDIAN);
|
||||
} else {
|
||||
error = GS_ERROR_TYPE;
|
||||
}
|
||||
|
||||
csp_buffer_free(packet);
|
||||
csp_close(conn);
|
||||
return error;
|
||||
}
|
110
gomspace/libparam_client/src/rparam/query.h
Normal file
110
gomspace/libparam_client/src/rparam/query.h
Normal file
@ -0,0 +1,110 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
|
||||
#include <gs/param/internal/rparam.h>
|
||||
|
||||
/**
|
||||
Rparam query handle.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
CSP node.
|
||||
*/
|
||||
uint8_t node;
|
||||
/**
|
||||
Remote table id.
|
||||
*/
|
||||
gs_param_table_id_t table_id;
|
||||
/**
|
||||
Remote table (definition) checksum.
|
||||
*/
|
||||
uint16_t checksum;
|
||||
/**
|
||||
Timeout (mS).
|
||||
*/
|
||||
uint32_t timeout_ms;
|
||||
/**
|
||||
If quite - no output to stdout.
|
||||
*/
|
||||
bool quiet;
|
||||
/**
|
||||
Auto send.
|
||||
*/
|
||||
bool auto_send;
|
||||
/**
|
||||
Type/action.
|
||||
*/
|
||||
int action;
|
||||
/**
|
||||
Size of current query.
|
||||
*/
|
||||
unsigned int length;
|
||||
/**
|
||||
Estimated total 'get' size.
|
||||
*/
|
||||
unsigned int get_size;
|
||||
/**
|
||||
Space for payload data.
|
||||
@note must be last in struct.
|
||||
*/
|
||||
union {
|
||||
uint16_t addr[0];
|
||||
uint8_t packed[GS_RPARAM_QUERY_MAX_PAYLOAD];
|
||||
} payload;
|
||||
} gs_rparam_query_handle_t;
|
||||
|
||||
/**
|
||||
Set whether rparam API should print to stdout or not.
|
||||
|
||||
@param[in] handle handle
|
||||
@param[in] quiet \a true print to stdout.
|
||||
*/
|
||||
void gs_rparam_query_set_quiet(gs_rparam_query_handle_t * handle, bool quiet);
|
||||
|
||||
/**
|
||||
Return true if any query has been set.
|
||||
|
||||
@param[in] handle handle
|
||||
@return \a true if any query has been set.
|
||||
*/
|
||||
bool gs_rparam_query_is_set(gs_rparam_query_handle_t * handle);
|
||||
|
||||
/**
|
||||
Add a 'get' query to the current query, after a succesfull rparam_query_send()
|
||||
the parameter value can be read using rparam_queury_get_value()
|
||||
|
||||
@param[in] handle handle
|
||||
@param[in] tinst table.
|
||||
@param[in] param_name name of the parameter.
|
||||
@return_gs_error_t
|
||||
@see rparam_query_send()
|
||||
*/
|
||||
gs_error_t gs_rparam_query_get(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name);
|
||||
|
||||
/**
|
||||
Add a 'set' query to the current query. Use rparam_query_send() to execute the set query.
|
||||
|
||||
@param[in] handle handle
|
||||
@param[in] tinst table.
|
||||
@param[in] param_name name of the parameter to set
|
||||
@param[in] values array of values to set, multiple values can be set for array type parameters
|
||||
@param[in] value_count number of elements in \a values
|
||||
@return_gs_error_t
|
||||
@see rparam_query_send()
|
||||
*/
|
||||
gs_error_t gs_rparam_query_set(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name, char * values[], uint8_t value_count);
|
||||
|
||||
/**
|
||||
Send the current query
|
||||
|
||||
@param[in] handle handle
|
||||
@param[in] tinst table.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rparam_query_send(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst);
|
||||
|
||||
/**
|
||||
Reset/clear the current query
|
||||
@param[in] handle handle
|
||||
*/
|
||||
void gs_rparam_query_reset(gs_rparam_query_handle_t * handle);
|
474
gomspace/libparam_client/src/rparam/rparam.c
Normal file
474
gomspace/libparam_client/src/rparam/rparam.c
Normal file
@ -0,0 +1,474 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include <gs/param/internal/rparam.h>
|
||||
#include <gs/param/internal/types.h>
|
||||
#include <gs/param/internal/table.h>
|
||||
#include "../serialize_local.h"
|
||||
#include <stdio.h>
|
||||
#include <alloca.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <gs/csp/csp.h>
|
||||
#include <csp/csp_endian.h>
|
||||
#include <gs/util/log.h>
|
||||
#include <gs/util/fletcher.h>
|
||||
#include <gs/util/check.h>
|
||||
|
||||
static gs_error_t gs_rparam_command(uint8_t node, uint32_t timeout_ms, uint8_t action, uint8_t table_id,
|
||||
const void * payload, size_t payload_size, char reply_ok)
|
||||
{
|
||||
gs_rparam_query_t * query = alloca(RPARAM_QUERY_LENGTH(query, payload_size));
|
||||
query->action = action;
|
||||
query->table_id = table_id;
|
||||
query->length = csp_hton16(payload_size);
|
||||
query->checksum = csp_hton16(GS_RPARAM_MAGIC_CHECKSUM); // Ignore checksum
|
||||
query->seq = 0;
|
||||
query->total = 0;
|
||||
memcpy(&query->payload, payload, payload_size);
|
||||
|
||||
/* Run single packet transaction */
|
||||
char reply = 0;
|
||||
if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, RPARAM_QUERY_LENGTH(query, payload_size),
|
||||
&reply, 1, CSP_O_CRC32) <= 0) {
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
return (reply == reply_ok) ? GS_OK : GS_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_copy(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to)
|
||||
{
|
||||
gs_rparam_query_payload_t payload;
|
||||
payload.copy.from = from;
|
||||
payload.copy.to = to;
|
||||
return gs_rparam_command(node, timeout_ms, RPARAM_COPY, from, &payload, sizeof(payload.copy), RPARAM_COPY_OK);
|
||||
}
|
||||
|
||||
static gs_error_t gs_rparam_store(uint8_t node, uint32_t timeout_ms, uint8_t action, char reply_ok, uint8_t table_id,
|
||||
const char * table, const char * store, const char * slot)
|
||||
{
|
||||
gs_rparam_query_payload_store_t payload;
|
||||
memset(&payload, 0, sizeof(payload));
|
||||
if (table && (gs_string_empty(table) == false)) {
|
||||
GS_STRNCPY(payload.table, table);
|
||||
}
|
||||
if (store && (gs_string_empty(store) == false)) {
|
||||
GS_STRNCPY(payload.store, store);
|
||||
}
|
||||
if (slot && (gs_string_empty(slot) == false)) {
|
||||
GS_STRNCPY(payload.slot, slot);
|
||||
}
|
||||
return gs_rparam_command(node, timeout_ms, action, table_id, &payload, sizeof(payload), reply_ok);
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id,
|
||||
const char * store, const char * slot)
|
||||
{
|
||||
return gs_rparam_store(node, timeout_ms, RPARAM_SAVE_TO_STORE, RPARAM_SAVE_OK, table_id, NULL, store, slot);
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id,
|
||||
const char * store, const char * slot)
|
||||
{
|
||||
return gs_rparam_store(node, timeout_ms, RPARAM_LOAD_FROM_STORE, RPARAM_LOAD_OK, table_id, NULL, store, slot);
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to)
|
||||
{
|
||||
gs_rparam_query_payload_t payload;
|
||||
payload.copy.from = from;
|
||||
payload.copy.to = to;
|
||||
return gs_rparam_command(node, timeout_ms, RPARAM_SAVE, from, &payload, sizeof(payload.copy), RPARAM_SAVE_OK);
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to)
|
||||
{
|
||||
gs_rparam_query_payload_t payload;
|
||||
payload.copy.from = from;
|
||||
payload.copy.to = to;
|
||||
return gs_rparam_command(node, timeout_ms, RPARAM_LOAD, to, &payload, sizeof(payload.copy), RPARAM_LOAD_OK);
|
||||
}
|
||||
|
||||
static gs_error_t update_table(const char * func,
|
||||
gs_param_table_instance_t * tinst,
|
||||
gs_param_table_row_t * rows, unsigned int row_count,
|
||||
uint16_t checksum)
|
||||
{
|
||||
size_t memory_size = gs_param_calc_table_size(rows, row_count);
|
||||
if ((tinst->memory == NULL) || (tinst->memory_size < memory_size)) {
|
||||
// (re)allocate memory
|
||||
if (memory_size == 0) {
|
||||
return GS_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
memory_size = gs_max(1000U, memory_size);
|
||||
void * memory = calloc(1, memory_size);
|
||||
if (memory == NULL) {
|
||||
return GS_ERROR_ALLOC;
|
||||
}
|
||||
|
||||
free(tinst->memory);
|
||||
tinst->memory = memory;
|
||||
tinst->memory_size = memory_size;
|
||||
tinst->flags |= GS_PARAM_TABLE_F_ALLOC_MEMORY;
|
||||
}
|
||||
|
||||
free((void*)tinst->rows);
|
||||
tinst->rows = rows;
|
||||
tinst->row_count = row_count;
|
||||
tinst->checksum_be = tinst->checksum_le = 0;
|
||||
tinst->flags |= GS_PARAM_TABLE_F_ALLOC_ROWS;
|
||||
|
||||
if ((checksum != gs_param_table_checksum_le(tinst)) && (checksum != gs_param_table_checksum_be(tinst))) {
|
||||
log_error("%s: table specification has invalid checksum: %u - different from LE: %u and BE: %u",
|
||||
func, checksum, gs_param_table_checksum_le(tinst), gs_param_table_checksum_be(tinst));
|
||||
return GS_ERROR_DATA;
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_load_table_spec(gs_param_table_instance_t * tinst, const char* fname, uint16_t * return_checksum)
|
||||
{
|
||||
GS_CHECK_HANDLE(tinst != NULL);
|
||||
GS_CHECK_ARG(fname != NULL);
|
||||
|
||||
FILE * fd = fopen(fname, "r");
|
||||
if (fd == NULL) {
|
||||
return GS_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
struct stat file_stat;
|
||||
if (fstat(fileno(fd), &file_stat) != 0) {
|
||||
log_error("%s: failed to stat file [%s]", __FUNCTION__, fname);
|
||||
fclose(fd);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
void * rows = calloc(file_stat.st_size, 1);
|
||||
if (rows == NULL) {
|
||||
fclose(fd);
|
||||
return GS_ERROR_ALLOC;
|
||||
}
|
||||
|
||||
uint16_t checksum = 0;
|
||||
size_t rs1 = fread(&checksum, 1, sizeof(checksum), fd);
|
||||
size_t rs2 = fread(rows, 1, file_stat.st_size, fd);
|
||||
fclose(fd);
|
||||
|
||||
const unsigned int single_row_size = sizeof(*tinst->rows);
|
||||
const unsigned int all_row_size = (file_stat.st_size - sizeof(checksum));
|
||||
const unsigned int row_count = (all_row_size) / single_row_size;
|
||||
if ((rs1 != sizeof(checksum)) || (rs2 != all_row_size) || (rs2 != (single_row_size * row_count))) {
|
||||
log_error("%s: incomplete/invalid read, expected %u + %u - read %u + %u, single row size: %u", __FUNCTION__,
|
||||
(unsigned int) sizeof(checksum), row_count,
|
||||
(unsigned int) rs1, (unsigned int) rs2, single_row_size);
|
||||
free(rows);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
gs_error_t error = update_table(__FUNCTION__, tinst, rows, row_count, checksum);
|
||||
|
||||
if (error == GS_OK) {
|
||||
if (return_checksum) {
|
||||
*return_checksum = checksum;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_download_table_spec(gs_param_table_instance_t * tinst,
|
||||
const char * fname,
|
||||
uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint32_t timeout_ms,
|
||||
uint16_t * return_checksum)
|
||||
{
|
||||
csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32);
|
||||
if (conn == NULL) {
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
/* Allocate outgoing buffer */
|
||||
gs_rparam_query_t * query;
|
||||
csp_packet_t * packet = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0));
|
||||
if (packet == NULL) {
|
||||
csp_close(conn);
|
||||
return GS_ERROR_NO_BUFFERS;
|
||||
}
|
||||
|
||||
// setup request
|
||||
query = (gs_rparam_query_t *) packet->data;
|
||||
query->action = RPARAM_TABLE;
|
||||
query->table_id = table_id;
|
||||
query->length = 0;
|
||||
query->checksum = csp_hton16(GS_RPARAM_MAGIC_CHECKSUM); // Ignore checksum
|
||||
query->seq = 0;
|
||||
query->total = 0;
|
||||
|
||||
packet->length = RPARAM_QUERY_LENGTH(query, 0);
|
||||
if (!csp_send(conn, packet, 0)) {
|
||||
csp_buffer_free(packet);
|
||||
csp_close(conn);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
/* Receive remote parameter table, in host byte order
|
||||
* Note: This is necessary, because the SFP functions does not know the dataformat
|
||||
* and hence cannot be converted server-side. */
|
||||
void * dataout = NULL;
|
||||
int totalsize = 0;
|
||||
int result = csp_sfp_recv(conn, &dataout, &totalsize, timeout_ms);
|
||||
csp_close(conn);
|
||||
|
||||
if (result < 0) {
|
||||
free(dataout);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
gs_param_table_row_t * rows = dataout;
|
||||
const uint8_t row_count = totalsize / sizeof(*rows);
|
||||
|
||||
/* Calculate checksum on table (before converting endians!) */
|
||||
const uint16_t checksum = gs_fletcher16(rows, totalsize);
|
||||
|
||||
/* Autodetect Endians */
|
||||
int sum_first = 0;
|
||||
int sum_last = 0;
|
||||
for (unsigned int i = 0; i < row_count; i++) {
|
||||
sum_first += (rows[i].addr & 0xFF00) >> 8;
|
||||
sum_last += rows[i].addr & 0xFF;
|
||||
}
|
||||
|
||||
/* Correct endians */
|
||||
if (sum_first > sum_last) {
|
||||
for (unsigned int i = 0; i < row_count; i++) {
|
||||
rows[i].addr = (((rows[i].addr & 0xff00) >> 8) | ((rows[i].addr & 0x00ff) << 8));
|
||||
}
|
||||
}
|
||||
|
||||
gs_error_t error = update_table(__FUNCTION__, tinst, rows, row_count, checksum);
|
||||
if (error == GS_OK) {
|
||||
|
||||
if (return_checksum) {
|
||||
*return_checksum = checksum;
|
||||
}
|
||||
|
||||
// If filename provided, store table specification to file.
|
||||
if (gs_string_empty(fname) == false) {
|
||||
FILE * fd = fopen(fname, "w");
|
||||
if (fd == NULL) {
|
||||
log_error("%s: failed to open/create file: [%s]", __FUNCTION__, fname);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
const size_t ws1_size = sizeof(checksum);
|
||||
const size_t ws1 = fwrite(&checksum, 1, ws1_size, fd);
|
||||
const size_t ws2 = fwrite(rows, 1, totalsize, fd);
|
||||
fclose(fd);
|
||||
if ((ws1 != ws1_size) || (ws2 != (size_t) totalsize)) {
|
||||
log_error("%s: failed to write %u + %d - wrote %u + %u", __FUNCTION__,
|
||||
(unsigned int) sizeof(checksum), totalsize, (unsigned int) ws1, (unsigned int) ws2);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_get_full_table(gs_param_table_instance_t * tinst,
|
||||
uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint16_t checksum,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
GS_CHECK_HANDLE(tinst != NULL);
|
||||
GS_CHECK_HANDLE(tinst->rows != NULL);
|
||||
GS_CHECK_HANDLE(tinst->memory != NULL);
|
||||
|
||||
unsigned int expected_bytes = 0;
|
||||
{
|
||||
unsigned int param_pos = 0;
|
||||
gs_error_t error = gs_param_serialize_full_table(tinst, ¶m_pos, GS_PARAM_SF_DRY_RUN, NULL, 10000, &expected_bytes);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
gs_rparam_query_t * query;
|
||||
csp_packet_t * request = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0));
|
||||
if (request == NULL) {
|
||||
return GS_ERROR_NO_BUFFERS;
|
||||
}
|
||||
|
||||
csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32);
|
||||
if (!conn) {
|
||||
csp_buffer_free(request);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
query = (gs_rparam_query_t *) request->data;
|
||||
query->action = RPARAM_GET;
|
||||
query->table_id = table_id;
|
||||
query->length = 0; // == get full table
|
||||
query->checksum = csp_hton16(checksum);
|
||||
query->seq = 0;
|
||||
query->total = 0;
|
||||
|
||||
request->length = RPARAM_QUERY_LENGTH(query, 0);
|
||||
if (!csp_send(conn, request, timeout_ms)) {
|
||||
csp_buffer_free(request);
|
||||
csp_close(conn);
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
csp_packet_t * reply;
|
||||
gs_error_t error = GS_OK;
|
||||
unsigned int total_bytes = 0;
|
||||
while ((reply = csp_read(conn, timeout_ms)) != NULL) {
|
||||
|
||||
/* We have a reply */
|
||||
query = (void *) reply->data;
|
||||
const uint16_t qlength = csp_ntoh16(query->length);
|
||||
total_bytes += qlength;
|
||||
const uint16_t seq = csp_ntoh16(query->seq);
|
||||
const uint16_t total = csp_ntoh16(query->total);
|
||||
|
||||
if (query->action == RPARAM_REPLY) {
|
||||
error = gs_param_deserialize(tinst, query->payload.packed, qlength, F_FROM_BIG_ENDIAN);
|
||||
}
|
||||
csp_buffer_free(reply);
|
||||
|
||||
if (error || (seq >= total)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reply == NULL) {
|
||||
error = GS_ERROR_TIMEOUT;
|
||||
}
|
||||
|
||||
if ((error == GS_OK) && (expected_bytes != total_bytes)) {
|
||||
log_warning("%s: expected %u != received %u bytes", __FUNCTION__, expected_bytes, total_bytes);
|
||||
error = GS_ERROR_DATA;
|
||||
}
|
||||
|
||||
csp_close(conn);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_get(uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint16_t addr,
|
||||
gs_param_type_t type,
|
||||
uint16_t checksum,
|
||||
uint32_t timeout_ms,
|
||||
void * value,
|
||||
size_t value_size)
|
||||
{
|
||||
/* Calculate length */
|
||||
gs_rparam_query_t * query;
|
||||
const size_t query_size = RPARAM_QUERY_LENGTH(query, sizeof(query->payload.addr[0]));
|
||||
const size_t reply_payload_size = (value_size + sizeof(query->payload.addr[0]));
|
||||
const size_t reply_size = RPARAM_QUERY_LENGTH(query, reply_payload_size);
|
||||
|
||||
query = alloca(reply_size);
|
||||
query->action = RPARAM_GET;
|
||||
query->table_id = table_id;
|
||||
query->checksum = csp_hton16(checksum);
|
||||
query->seq = 0;
|
||||
query->total = 0;
|
||||
query->payload.addr[0] = csp_hton16(addr);
|
||||
query->length = csp_hton16(sizeof(query->payload.addr[0]));
|
||||
|
||||
/* Run single packet transaction */
|
||||
if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, query_size, query, reply_size, CSP_O_CRC32) <= 0) {
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
/* We have a reply */
|
||||
query->length = csp_ntoh16(query->length);
|
||||
|
||||
if (query->length != reply_payload_size) {
|
||||
log_warning("%s: Invalid reply size %u - expected %u", __FUNCTION__, query->length, (unsigned int) reply_payload_size);
|
||||
return GS_ERROR_DATA;
|
||||
}
|
||||
|
||||
/* Read address */
|
||||
query->payload.addr[0] = csp_betoh16(query->payload.addr[0]);
|
||||
if (query->payload.addr[0] != addr) {
|
||||
log_warning("%s: Invalid address in reply %u", __FUNCTION__, query->payload.addr[0]);
|
||||
return GS_ERROR_DATA;
|
||||
}
|
||||
|
||||
/* Read value */
|
||||
memcpy(value, &query->payload.packed[2], value_size);
|
||||
gs_param_betoh(type, value);
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_set(uint8_t node,
|
||||
gs_param_table_id_t table_id,
|
||||
uint16_t addr,
|
||||
gs_param_type_t type,
|
||||
uint16_t checksum,
|
||||
uint32_t timeout_ms,
|
||||
const void * value,
|
||||
size_t value_size)
|
||||
{
|
||||
/* Calculate length */
|
||||
gs_rparam_query_t * query;
|
||||
const size_t payload_size = (value_size + sizeof(query->payload.addr[0]));
|
||||
const size_t query_size = RPARAM_QUERY_LENGTH(query, payload_size);
|
||||
|
||||
query = alloca(query_size);
|
||||
query->action = RPARAM_SET;
|
||||
query->table_id = table_id;
|
||||
query->seq = 0;
|
||||
query->total = 0;
|
||||
query->checksum = csp_hton16(checksum);
|
||||
|
||||
/* Actual set query */
|
||||
unsigned int bytes = 0;
|
||||
gs_error_t error = gs_param_serialize_item_direct(type, value_size, addr, value, F_TO_BIG_ENDIAN, query->payload.packed, payload_size, &bytes);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Add to query */
|
||||
query->length = csp_hton16(bytes);
|
||||
|
||||
/* Run single packet transaction */
|
||||
if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, query_size, query, 1, CSP_O_CRC32) <= 0) {
|
||||
return GS_ERROR_IO;
|
||||
}
|
||||
|
||||
/* We have a reply */
|
||||
query->length = csp_ntoh16(query->length);
|
||||
|
||||
if ((query->action != RPARAM_SET_OK) || (query->length != bytes)) {
|
||||
log_warning("%s: Invalid reply: size %u - expected %u, action %u - expected %u",
|
||||
__FUNCTION__, query->length, bytes, query->action, RPARAM_SET_OK);
|
||||
return GS_ERROR_DATA;
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_rparam_query_get_value(gs_param_table_instance_t * tinst, const char* param_name, uint16_t param_no, void* val_p, size_t val_size)
|
||||
{
|
||||
const gs_param_table_row_t * t = gs_param_row_by_name(param_name, tinst->rows, tinst->row_count);
|
||||
if (t == NULL) {
|
||||
return GS_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (val_size < t->size) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
|
||||
return gs_param_get(tinst, t->addr + (param_no * t->size), t->type, val_p, t->size, 0);
|
||||
}
|
353
gomspace/libparam_client/src/serialize.c
Normal file
353
gomspace/libparam_client/src/serialize.c
Normal file
@ -0,0 +1,353 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include "serialize_local.h"
|
||||
#include <gs/param/table.h>
|
||||
#include <gs/param/internal/types.h>
|
||||
#include <gs/util/byteorder.h>
|
||||
#include <gs/util/endian.h>
|
||||
#include <alloca.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <param/param_types.h> // need PARM_X??? definitions
|
||||
|
||||
bool gs_param_betoh(gs_param_type_t type, void * item)
|
||||
{
|
||||
if (item) {
|
||||
switch (type) {
|
||||
case GS_PARAM_UINT16:
|
||||
case GS_PARAM_INT16:
|
||||
case PARAM_X16:
|
||||
{
|
||||
*(uint16_t *) item = util_betoh16(*(uint16_t *) item);
|
||||
return true;
|
||||
}
|
||||
case GS_PARAM_UINT32:
|
||||
case GS_PARAM_INT32:
|
||||
case PARAM_X32:
|
||||
{
|
||||
*(uint32_t *) item = util_betoh32(*(uint32_t *) item);
|
||||
return true;
|
||||
}
|
||||
case GS_PARAM_UINT64:
|
||||
case GS_PARAM_INT64:
|
||||
case PARAM_X64:
|
||||
{
|
||||
*(uint64_t *) item = util_betoh64(*(uint64_t *) item);
|
||||
return true;
|
||||
}
|
||||
case GS_PARAM_FLOAT:
|
||||
{
|
||||
*(float *) item = util_ntohflt(*(float *) item);
|
||||
return true;
|
||||
}
|
||||
case GS_PARAM_DOUBLE:
|
||||
{
|
||||
*(double *) item = util_ntohdbl(*(double *) item);
|
||||
return true;
|
||||
}
|
||||
|
||||
case GS_PARAM_UINT8:
|
||||
case GS_PARAM_INT8:
|
||||
case PARAM_X8:
|
||||
case GS_PARAM_STRING:
|
||||
case GS_PARAM_DATA:
|
||||
case GS_PARAM_BOOL:
|
||||
// no swap
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gs_param_htobe(gs_param_type_t type, void * item)
|
||||
{
|
||||
if (item) {
|
||||
switch (type) {
|
||||
case PARAM_UINT16:
|
||||
case PARAM_INT16:
|
||||
case PARAM_X16:
|
||||
{
|
||||
*(uint16_t *) item = util_htobe16(*(uint16_t *) item);
|
||||
return true;
|
||||
}
|
||||
case PARAM_UINT32:
|
||||
case PARAM_INT32:
|
||||
case PARAM_X32:
|
||||
{
|
||||
*(uint32_t *) item = util_htobe32(*(uint32_t *) item);
|
||||
return true;
|
||||
}
|
||||
case PARAM_UINT64:
|
||||
case PARAM_INT64:
|
||||
case PARAM_X64:
|
||||
{
|
||||
*(uint64_t *) item = util_htobe64(*(uint64_t *) item);
|
||||
return true;
|
||||
}
|
||||
case PARAM_FLOAT:
|
||||
{
|
||||
*(float *) item = util_htonflt(*(float *) item);
|
||||
return true;
|
||||
}
|
||||
case PARAM_DOUBLE:
|
||||
{
|
||||
*(double *) item = util_htondbl(*(double *) item);
|
||||
return true;
|
||||
}
|
||||
|
||||
case PARAM_UINT8:
|
||||
case PARAM_INT8:
|
||||
case PARAM_X8:
|
||||
case PARAM_STRING:
|
||||
case PARAM_DATA:
|
||||
case PARAM_BOOL:
|
||||
// no swap
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool gs_param_require_endian_swap(gs_param_type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case PARAM_UINT16:
|
||||
case PARAM_INT16:
|
||||
case PARAM_X16:
|
||||
case PARAM_UINT32:
|
||||
case PARAM_INT32:
|
||||
case PARAM_X32:
|
||||
case PARAM_UINT64:
|
||||
case PARAM_INT64:
|
||||
case PARAM_X64:
|
||||
case PARAM_FLOAT:
|
||||
case PARAM_DOUBLE:
|
||||
// swap
|
||||
break;
|
||||
|
||||
case PARAM_UINT8:
|
||||
case PARAM_INT8:
|
||||
case PARAM_X8:
|
||||
case PARAM_STRING:
|
||||
case PARAM_DATA:
|
||||
case PARAM_BOOL:
|
||||
// no swap
|
||||
return false;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static gs_error_t gs_param_serialize_array(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos)
|
||||
{
|
||||
const unsigned int param_size = GS_PARAM_SIZE(param);
|
||||
const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param);
|
||||
const gs_param_type_t param_type = GS_PARAM_TYPE(param);
|
||||
|
||||
/* Calculate total parameter size (full array) */
|
||||
{
|
||||
unsigned int size = param_size * param_array_size;
|
||||
if ((flags & F_PACKED) == 0) {
|
||||
size += param_array_size * sizeof(uint16_t); // address
|
||||
}
|
||||
|
||||
/* Return if parameter array would exceed maxbuf */
|
||||
if (*buf_pos + size > buf_size) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t value[param_size];
|
||||
gs_error_t error = GS_OK;
|
||||
for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) {
|
||||
const uint16_t addr = GS_PARAM_ADDR(param) + (param_size * j);
|
||||
error = gs_param_get(tinst, addr, param_type, value, param_size, 0);
|
||||
if (error == GS_OK) {
|
||||
error = gs_param_serialize_item(param, addr, value, flags, buf, buf_size, buf_pos);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_serialize_item_direct(gs_param_type_t param_type, unsigned int param_size, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos)
|
||||
{
|
||||
/* Check length */
|
||||
if ((((flags & F_PACKED) ? 0 : sizeof(addr)) + param_size + *buf_pos) > buf_size) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
|
||||
/* Include address if not packed */
|
||||
if ((flags & F_PACKED) == 0) {
|
||||
|
||||
if (flags & F_TO_BIG_ENDIAN) {
|
||||
addr = util_htobe16(addr);
|
||||
}
|
||||
|
||||
if ((flags & F_DRY_RUN) == 0) {
|
||||
memcpy(&buf[*buf_pos], &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
*buf_pos += sizeof(addr);
|
||||
}
|
||||
|
||||
if ((flags & F_DRY_RUN) == 0) {
|
||||
if (flags & F_TO_BIG_ENDIAN) {
|
||||
void * tmp = alloca(param_size); // this must be aligned
|
||||
memcpy(tmp, item, param_size);
|
||||
gs_param_htobe(param_type, tmp);
|
||||
item = tmp;
|
||||
}
|
||||
memcpy(&buf[*buf_pos], item, param_size);
|
||||
}
|
||||
|
||||
*buf_pos += param_size;
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_serialize_item(const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos)
|
||||
{
|
||||
const gs_param_type_t param_type = GS_PARAM_TYPE(param);
|
||||
const unsigned int param_size = GS_PARAM_SIZE(param);
|
||||
return gs_param_serialize_item_direct(param_type, param_size, addr, item, flags, buf, buf_size, buf_pos);
|
||||
}
|
||||
|
||||
gs_error_t gs_param_serialize_full_table(gs_param_table_instance_t * tinst, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos)
|
||||
{
|
||||
if (flags & GS_PARAM_SF_DRY_RUN) {
|
||||
buf = NULL;
|
||||
buf_size = -1; // Max size
|
||||
}
|
||||
gs_error_t error = GS_OK;
|
||||
unsigned int i = *param_pos;
|
||||
for (; i < tinst->row_count; i++) {
|
||||
const gs_param_table_row_t * param = &tinst->rows[i];
|
||||
error = gs_param_serialize_array(tinst, param, flags, buf, buf_size, buf_pos);
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*param_pos = i;
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_serialize_list(gs_param_table_instance_t * tinst,
|
||||
const uint16_t addr[], unsigned int addr_count,
|
||||
unsigned int * param_pos, uint32_t flags,
|
||||
uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos)
|
||||
{
|
||||
if (tinst == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
|
||||
gs_error_t error = GS_OK;
|
||||
unsigned int i = *param_pos;
|
||||
for (; i < addr_count; ++i) {
|
||||
const gs_param_table_row_t * param = gs_param_row_by_address(addr[i], tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const gs_param_type_t param_type = GS_PARAM_TYPE(param);
|
||||
const unsigned int param_size = GS_PARAM_SIZE(param);
|
||||
uint8_t value[param_size];
|
||||
error = gs_param_get(tinst, addr[i], param_type, value, param_size, 0);
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
error = gs_param_serialize_item(param, addr[i], value, flags, buf, buf_size, buf_pos);
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*param_pos = i;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_deserialize_item(gs_param_table_instance_t * tinst,
|
||||
const gs_param_table_row_t * param,
|
||||
uint16_t addr,
|
||||
const void * item,
|
||||
uint32_t flags)
|
||||
{
|
||||
const gs_param_type_t param_type = GS_PARAM_TYPE(param);
|
||||
const unsigned int param_size = GS_PARAM_SIZE(param);
|
||||
|
||||
if (flags & F_FROM_BIG_ENDIAN) {
|
||||
if (gs_param_require_endian_swap(param_type)) {
|
||||
|
||||
// Copy to temporary storage, so we don't mess with input memory
|
||||
void * tmp = alloca(param_size);
|
||||
memcpy(tmp, item, param_size);
|
||||
|
||||
gs_param_betoh(param_type, tmp);
|
||||
|
||||
// Replace input pointer
|
||||
item = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
gs_error_t error = GS_OK;
|
||||
if ((flags & F_DRY_RUN) == 0) {
|
||||
error = gs_param_set(tinst, addr, param_type, item, param_size, GS_PARAM_FLAGS(param));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_deserialize(gs_param_table_instance_t * tinst, const uint8_t * buf, unsigned int buf_size, uint32_t flags)
|
||||
{
|
||||
unsigned int pos = 0;
|
||||
unsigned int count = 0;
|
||||
gs_error_t error = GS_OK;
|
||||
while ((pos < buf_size) && (error == GS_OK)) {
|
||||
|
||||
if (flags & F_PACKED) {
|
||||
/** PACKED */
|
||||
|
||||
/* Find in table */
|
||||
const gs_param_table_row_t * param = &tinst->rows[count];
|
||||
const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param);
|
||||
const unsigned int param_size = GS_PARAM_SIZE(param);
|
||||
|
||||
/* For each item in array */
|
||||
for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) {
|
||||
uint16_t addr = GS_PARAM_ADDR(param) + (param_size * j);
|
||||
error = gs_param_deserialize_item(tinst, param, addr, &buf[pos], flags);
|
||||
pos += param_size;
|
||||
}
|
||||
|
||||
} else {
|
||||
/** NOT PACKED */
|
||||
|
||||
/* Read address from data */
|
||||
uint16_t addr;
|
||||
memcpy(&addr, &buf[pos], sizeof(addr));
|
||||
if (flags & F_FROM_BIG_ENDIAN) {
|
||||
addr = util_betoh16(addr);
|
||||
}
|
||||
pos += sizeof(addr);
|
||||
|
||||
/* Find in table */
|
||||
const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Copy value */
|
||||
error = gs_param_deserialize_item(tinst, param, addr, &buf[pos], flags);
|
||||
pos += GS_PARAM_SIZE(param);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
9
gomspace/libparam_client/src/serialize_local.h
Normal file
9
gomspace/libparam_client/src/serialize_local.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef SRC_SERIALIZE_LOCAL_H
|
||||
#define SRC_SERIALIZE_LOCAL_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#include <gs/param/internal/serialize.h>
|
||||
|
||||
gs_error_t gs_param_serialize_item_direct(gs_param_type_t param_type, unsigned int param_size, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos);
|
||||
|
||||
#endif
|
589
gomspace/libparam_client/src/string.c
Normal file
589
gomspace/libparam_client/src/string.c
Normal file
@ -0,0 +1,589 @@
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include <gs/param/internal/types.h>
|
||||
#include <gs/param/internal/table.h>
|
||||
#include <gs/util/string.h>
|
||||
#include <gs/util/log.h>
|
||||
#include <gs/util/check.h>
|
||||
#include <gs/util/bytebuffer.h>
|
||||
#include <ctype.h>
|
||||
|
||||
size_t gs_param_calc_table_size(const gs_param_table_row_t * rows, size_t row_count)
|
||||
{
|
||||
if (rows && row_count) {
|
||||
const gs_param_table_row_t * last_row = rows;
|
||||
// table rows may not be in assending address- so we have to run through the entire table.
|
||||
for (size_t i = 0; i < row_count; ++i, ++rows) {
|
||||
if (GS_PARAM_ADDR(rows) > GS_PARAM_ADDR(last_row)) {
|
||||
last_row = rows;
|
||||
}
|
||||
}
|
||||
return (GS_PARAM_ADDR(last_row) + (GS_PARAM_SIZE(last_row) * GS_PARAM_ARRAY_SIZE(last_row)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * gs_param_row_by_name(const char * name, const gs_param_table_row_t * rows, size_t row_count)
|
||||
{
|
||||
if (rows) {
|
||||
for (unsigned int i = 0; i < row_count; ++i, ++rows) {
|
||||
if (GS_PGM_STRNCASECMP(name, rows->name, GS_PARAM_MAX_NAME) == 0) {
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * gs_param_row_by_address(uint16_t addr, const gs_param_table_row_t * rows, size_t row_count)
|
||||
{
|
||||
if (rows) {
|
||||
for (unsigned int i = 0; i < row_count; ++i, ++rows) {
|
||||
const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(rows);
|
||||
const unsigned int param_size = GS_PARAM_SIZE(rows);
|
||||
const unsigned int param_addr = GS_PARAM_ADDR(rows);
|
||||
for (unsigned int j = 0; j < param_array_size; ++j) {
|
||||
if ((param_addr + (j * param_size)) == addr) {
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
memcpy is used, because data/value may not be aligned correctly and cause crash if accessed directly.
|
||||
*/
|
||||
gs_error_t gs_param_to_string_buffer(const gs_param_table_row_t * param, const void * value, bool with_type, uint32_t flags, gs_bytebuffer_t *bb)
|
||||
{
|
||||
flags |= param->flags;
|
||||
const uint8_t param_type = GS_PARAM_TYPE(param);
|
||||
switch (param_type) {
|
||||
case GS_PARAM_BOOL: {
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "BL ");
|
||||
}
|
||||
gs_bytebuffer_printf(bb, "%s", *(uint8_t *) value ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
case GS_PARAM_INT8: {
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "I8 ");
|
||||
}
|
||||
gs_bytebuffer_printf(bb, "%d", *(int8_t *) value);
|
||||
break;
|
||||
}
|
||||
case PARAM_X8:
|
||||
flags |= GS_PARAM_F_SHOW_HEX;
|
||||
// fallthrough
|
||||
case GS_PARAM_UINT8: {
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "U8 ");
|
||||
}
|
||||
if (flags & GS_PARAM_F_SHOW_HEX) {
|
||||
gs_bytebuffer_printf(bb, "0x%02"PRIx8, *(uint8_t *) value);
|
||||
} else {
|
||||
gs_bytebuffer_printf(bb, "%u", *(uint8_t *) value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GS_PARAM_INT16: {
|
||||
int16_t tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "I16 ");
|
||||
}
|
||||
gs_bytebuffer_printf(bb, "%"PRId16, tmp);
|
||||
break;
|
||||
}
|
||||
case PARAM_X16:
|
||||
flags |= GS_PARAM_F_SHOW_HEX;
|
||||
// fallthrough
|
||||
case GS_PARAM_UINT16: {
|
||||
uint16_t tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "U16 ");
|
||||
}
|
||||
if (flags & GS_PARAM_F_SHOW_HEX) {
|
||||
gs_bytebuffer_printf(bb, "0x%04"PRIx16, tmp);
|
||||
} else {
|
||||
gs_bytebuffer_printf(bb, "%"PRIu16, tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GS_PARAM_INT32: {
|
||||
int32_t tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "I32 ");
|
||||
}
|
||||
gs_bytebuffer_printf(bb, "%"PRId32, tmp);
|
||||
break;
|
||||
}
|
||||
case PARAM_X32:
|
||||
flags |= GS_PARAM_F_SHOW_HEX;
|
||||
// fallthrough
|
||||
case GS_PARAM_UINT32: {
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "U32 ");
|
||||
}
|
||||
if (flags & GS_PARAM_F_SHOW_HEX) {
|
||||
gs_bytebuffer_printf(bb, "0x%08"PRIx32, tmp);
|
||||
} else {
|
||||
gs_bytebuffer_printf(bb, "%"PRIu32, tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef PRIu64
|
||||
case GS_PARAM_INT64: {
|
||||
int64_t tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "I64 ");
|
||||
}
|
||||
gs_bytebuffer_printf(bb, "%"PRId64, tmp);
|
||||
break;
|
||||
}
|
||||
case PARAM_X64:
|
||||
flags |= GS_PARAM_F_SHOW_HEX;
|
||||
// fallthrough
|
||||
case GS_PARAM_UINT64: {
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "U64 ");
|
||||
}
|
||||
if (flags & GS_PARAM_F_SHOW_HEX) {
|
||||
gs_bytebuffer_printf(bb, "0x%016"PRIx64, tmp);
|
||||
} else {
|
||||
gs_bytebuffer_printf(bb, "%"PRIu64, tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case GS_PARAM_FLOAT: {
|
||||
float tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "FLT ");
|
||||
}
|
||||
if (flags & GS_PARAM_F_SHOW_SCIENTIFIC) {
|
||||
gs_bytebuffer_printf(bb, "%e", (double) tmp);
|
||||
} else {
|
||||
gs_bytebuffer_printf(bb, "%f", (double) tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GS_PARAM_DOUBLE: {
|
||||
double tmp;
|
||||
memcpy(&tmp, value, sizeof(tmp));
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "DBL ");
|
||||
}
|
||||
if (flags & GS_PARAM_F_SHOW_SCIENTIFIC) {
|
||||
gs_bytebuffer_printf(bb, "%e", tmp);
|
||||
} else {
|
||||
gs_bytebuffer_printf(bb, "%f", tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GS_PARAM_STRING: {
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "STR ");
|
||||
}
|
||||
gs_bytebuffer_append(bb, "\"", 1);
|
||||
// handle missing NUL termination.
|
||||
const size_t len = strnlen((const char*)value, GS_PARAM_SIZE(param));
|
||||
gs_bytebuffer_append(bb, value, len);
|
||||
gs_bytebuffer_append(bb, "\"", 1);
|
||||
break;
|
||||
}
|
||||
case GS_PARAM_DATA: {
|
||||
if (with_type == 1) {
|
||||
gs_bytebuffer_printf(bb, "DAT ");
|
||||
}
|
||||
for (int i = 0; i < GS_PARAM_SIZE(param); i++) {
|
||||
gs_bytebuffer_printf(bb, "%02"PRIX8, ((uint8_t *) value)[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
log_error("%s: Unknown param type %u", __FUNCTION__, param_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_to_string2(const gs_param_table_row_t * param, const void * value, bool with_type, uint32_t flags, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * buf_written)
|
||||
{
|
||||
GS_CHECK_ARG(buf_pos <= buf_size);
|
||||
gs_bytebuffer_t bb;
|
||||
gs_bytebuffer_init(&bb, &buf[buf_pos], (buf_size - buf_pos));
|
||||
gs_error_t error = gs_param_to_string_buffer(param, value, with_type, flags, &bb);
|
||||
if (error == GS_OK) {
|
||||
gs_bytebuffer_get_as_string(&bb, &error); // this will add NUL termination, but may truncate buffer
|
||||
error = gs_bytebuffer_get_state(&bb);
|
||||
if (buf_written) {
|
||||
*buf_written = bb.used;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
const char * gs_param_type_to_string(gs_param_type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case GS_PARAM_BOOL: return "bool";
|
||||
case GS_PARAM_UINT8: return "uint8_t";
|
||||
case GS_PARAM_UINT16: return "uint16_t";
|
||||
case GS_PARAM_UINT32: return "uint32_t";
|
||||
case GS_PARAM_UINT64: return "uint65_t";
|
||||
case GS_PARAM_INT8: return "int8_t";
|
||||
case GS_PARAM_INT16: return "int16_t";
|
||||
case GS_PARAM_INT32: return "int32_t";
|
||||
case GS_PARAM_INT64: return "int64_t";
|
||||
case PARAM_X8: return "uint8_t";
|
||||
case PARAM_X16: return "uint16_t";
|
||||
case PARAM_X32: return "uint32_t";
|
||||
case PARAM_X64: return "uint64_t";
|
||||
case GS_PARAM_FLOAT: return "float";
|
||||
case GS_PARAM_DOUBLE: return "double";
|
||||
case GS_PARAM_STRING: return "char";
|
||||
case GS_PARAM_DATA: return "char";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static inline int to_int(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return 10 + c - 'A';
|
||||
if (c >= 'a' && c <= 'f') return 10 + c - 'a';
|
||||
return -1;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_from_string(const gs_param_table_row_t * param, const char * string, void * value)
|
||||
{
|
||||
if ((param == NULL) || (string == NULL) || (value == NULL)) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (GS_PARAM_TYPE(param) != GS_PARAM_STRING) {
|
||||
// skip only space - not white-space, e.g. isspace()
|
||||
for (; *string == ' '; ++string);
|
||||
}
|
||||
|
||||
gs_error_t error = GS_OK;
|
||||
|
||||
switch(GS_PARAM_TYPE(param)) {
|
||||
|
||||
case GS_PARAM_BOOL:
|
||||
{
|
||||
bool parsein = false;
|
||||
error = gs_string_to_bool(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((uint8_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_UINT8:
|
||||
{
|
||||
uint8_t parsein;
|
||||
error = gs_string_to_uint8(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((uint8_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_UINT16:
|
||||
{
|
||||
uint16_t parsein;
|
||||
error = gs_string_to_uint16(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((uint16_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_UINT32:
|
||||
{
|
||||
uint32_t parsein;
|
||||
error = gs_string_to_uint32(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((uint32_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_UINT64:
|
||||
{
|
||||
uint64_t parsein;
|
||||
error = gs_string_to_uint64(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((uint64_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_INT8:
|
||||
{
|
||||
int8_t parsein;
|
||||
error = gs_string_to_int8(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((int8_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_INT16:
|
||||
{
|
||||
int16_t parsein;
|
||||
error = gs_string_to_int16(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((int16_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_INT32:
|
||||
{
|
||||
int32_t parsein;
|
||||
error = gs_string_to_int32(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((int32_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_INT64:
|
||||
{
|
||||
int64_t parsein;
|
||||
error = gs_string_to_int64(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((int64_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_X8:
|
||||
{
|
||||
uint32_t parsein;
|
||||
error = gs_string_hex_to_uint32(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
if (parsein <= UINT8_MAX) {
|
||||
*((uint8_t *) value) = parsein;
|
||||
} else {
|
||||
error = GS_ERROR_OVERFLOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_X16:
|
||||
{
|
||||
uint32_t parsein;
|
||||
error = gs_string_hex_to_uint32(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
if (parsein <= UINT16_MAX) {
|
||||
*((uint16_t *) value) = parsein;
|
||||
} else {
|
||||
error = GS_ERROR_OVERFLOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_X32:
|
||||
{
|
||||
uint32_t parsein;
|
||||
error = gs_string_hex_to_uint32(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((uint32_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_X64:
|
||||
{
|
||||
uint64_t parsein;
|
||||
error = gs_string_hex_to_uint64(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((uint64_t *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_FLOAT:
|
||||
{
|
||||
float parsein;
|
||||
error = gs_string_to_float(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((float *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_DOUBLE:
|
||||
{
|
||||
double parsein;
|
||||
error = gs_string_to_double(string, &parsein);
|
||||
if (error == GS_OK) {
|
||||
*((double *) value) = parsein;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_STRING:
|
||||
{
|
||||
const size_t ilen = strnlen(string, GS_PARAM_SIZE(param) + 1); // 0 terminator
|
||||
if (ilen <= GS_PARAM_SIZE(param)) {
|
||||
memset(value, 0, GS_PARAM_SIZE(param));
|
||||
memcpy(value, string, ilen);
|
||||
} else {
|
||||
error = GS_ERROR_OVERFLOW;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_DATA:
|
||||
{
|
||||
const size_t MAX_LEN = (GS_PARAM_SIZE(param) * 2);
|
||||
const size_t ilen = strnlen(string, MAX_LEN + 1);
|
||||
if (ilen > MAX_LEN) {
|
||||
error = GS_ERROR_OVERFLOW;
|
||||
} else if ((ilen % 2) == 0) {
|
||||
|
||||
// validate data first - not to end up with invalid/strange data
|
||||
for (unsigned int i = 0; i < ilen; ++i) {
|
||||
if (to_int(string[i]) < 0) {
|
||||
error = GS_ERROR_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (error == GS_OK) {
|
||||
uint8_t * out = (uint8_t *) value;
|
||||
memset(out, 0, GS_PARAM_SIZE(param));
|
||||
for (unsigned int i = 0; i < ilen; i += 2, ++out) {
|
||||
*out = (16 * to_int(string[i])) + to_int(string[i+1]);
|
||||
}
|
||||
error = GS_OK;
|
||||
}
|
||||
} else {
|
||||
error = GS_ERROR_DATA;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_list_single_to_stream(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param,
|
||||
bool list_data, uint32_t flags, FILE * out)
|
||||
{
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
|
||||
gs_error_t error = GS_OK;
|
||||
const uint16_t addr = GS_PARAM_ADDR(param);
|
||||
|
||||
fprintf(out, " 0x%04X %-16.14"GS_PGM_FMT_STR, addr, param->name); // ensure missing NUL termination doesn't cause problems.
|
||||
|
||||
if (list_data) {
|
||||
const gs_param_type_t param_type = GS_PARAM_TYPE(param);
|
||||
const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param);
|
||||
const unsigned int param_size = GS_PARAM_SIZE(param);
|
||||
uint8_t value[param_size];
|
||||
char buf[100];
|
||||
for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) {
|
||||
error = gs_param_get(tinst, addr + (param_size * j), param_type, value, param_size, 0);
|
||||
if (error == GS_OK) {
|
||||
gs_param_to_string2(param, value, (j == 0) ? 1 : 0, flags, buf, sizeof(buf), 0, NULL);
|
||||
fprintf(out, "%s ", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(out, "\r\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_list_to_stream(gs_param_table_instance_t * tinst, bool list_data, uint32_t flags, FILE * out)
|
||||
{
|
||||
GS_CHECK_HANDLE(tinst != NULL);
|
||||
|
||||
gs_error_t error = GS_OK;
|
||||
for (unsigned int i = 0; (i < tinst->row_count) && (error == GS_OK); ++i) {
|
||||
error = gs_param_list_single_to_stream(tinst, &tinst->rows[i], list_data, flags, out);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_parse_name_and_array_index(const char * inp, char * name, size_t size_name, uint8_t * return_index, bool * return_is_array)
|
||||
{
|
||||
if (inp == NULL) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
uint8_t a_index;
|
||||
size_t name_len;
|
||||
gs_error_t error;
|
||||
bool is_array;
|
||||
const char * pai = strchr(inp, '['); // look for array index
|
||||
if (pai) {
|
||||
name_len = pai - inp;
|
||||
char tmp[20];
|
||||
GS_STRNCPY(tmp, pai+1);
|
||||
char * endp = strchr(tmp, ']');
|
||||
if (endp) {
|
||||
*endp = 0;
|
||||
}
|
||||
error = gs_string_to_uint8(tmp, &a_index);
|
||||
is_array = true;
|
||||
} else {
|
||||
error = GS_OK;
|
||||
name_len = strlen(inp);
|
||||
is_array = false;
|
||||
a_index = 0;
|
||||
}
|
||||
|
||||
if (error == GS_OK) {
|
||||
if (name_len >= size_name) {
|
||||
error = GS_ERROR_OVERFLOW;
|
||||
} else {
|
||||
strncpy(name, inp, name_len);
|
||||
name[name_len] = 0;
|
||||
|
||||
// remove trailing white-space
|
||||
if (name_len) {
|
||||
for (int i = name_len-1; i >= 0; --i) {
|
||||
if (name[i] && isspace((int)name[i])) {
|
||||
name[i] = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (return_index) {
|
||||
*return_index = (is_array) ? a_index : 0;
|
||||
}
|
||||
if (return_is_array) {
|
||||
*return_is_array = is_array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
393
gomspace/libparam_client/src/table.c
Normal file
393
gomspace/libparam_client/src/table.c
Normal file
@ -0,0 +1,393 @@
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#define GS_PARAM_INTERNAL_USE 1
|
||||
|
||||
#include <gs/param/internal/types.h>
|
||||
#include <gs/param/internal/table.h>
|
||||
#include <gs/param/serialize.h>
|
||||
#include <gs/util/check.h>
|
||||
#include <gs/util/byteorder.h>
|
||||
#include <gs/util/endian.h>
|
||||
#include <gs/util/fletcher.h>
|
||||
|
||||
#include <alloca.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void _copy_data(gs_param_type_t type, void * dst, const void * src, size_t size)
|
||||
{
|
||||
#if (GS_PARAM_ATOMIC_ACCESS)
|
||||
switch (type) {
|
||||
case GS_PARAM_UINT8:
|
||||
case GS_PARAM_INT8:
|
||||
case PARAM_X8:
|
||||
case GS_PARAM_STRING:
|
||||
case GS_PARAM_DATA:
|
||||
case GS_PARAM_BOOL:
|
||||
break;
|
||||
|
||||
case GS_PARAM_UINT16:
|
||||
case GS_PARAM_INT16:
|
||||
case PARAM_X16:
|
||||
if (!((intptr_t)src & 1) && !((intptr_t)dst & 1)) {
|
||||
// (u)int16 aligned correctly
|
||||
const uint16_t * s = src;
|
||||
uint16_t * d = dst;
|
||||
const unsigned int count = (size / sizeof(*d));
|
||||
for (unsigned int i = 0; i < count; ++i, ++d, ++s) {
|
||||
*d = *s;
|
||||
}
|
||||
//printf("%s:int16\r\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_UINT32:
|
||||
case GS_PARAM_INT32:
|
||||
case PARAM_X32:
|
||||
case GS_PARAM_FLOAT:
|
||||
if (!((intptr_t)src & 3) && !((intptr_t)dst & 3)) {
|
||||
// (u)int32 aligned correctly
|
||||
const uint32_t * s = src;
|
||||
uint32_t * d = dst;
|
||||
const unsigned int count = (size / sizeof(*d));
|
||||
for (unsigned int i = 0; i < count; ++i, ++d, ++s) {
|
||||
*d = *s;
|
||||
}
|
||||
//printf("%s:int32\r\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PARAM_UINT64:
|
||||
case GS_PARAM_INT64:
|
||||
case PARAM_X64:
|
||||
case GS_PARAM_DOUBLE:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// fallback - do byte copy
|
||||
memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
gs_error_t gs_param_table_lock(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (tinst->lock) {
|
||||
return gs_mutex_lock(tinst->lock);
|
||||
}
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_table_unlock(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (tinst->lock) {
|
||||
return gs_mutex_unlock(tinst->lock);
|
||||
}
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static gs_error_t gs_param_table_lock_free(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (tinst && tinst->lock) {
|
||||
gs_mutex_destroy(tinst->lock);
|
||||
tinst->lock = NULL;
|
||||
}
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_table_free(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (tinst) {
|
||||
if (tinst->flags & GS_PARAM_TABLE_F_ALLOC_MEMORY) {
|
||||
free(tinst->memory);
|
||||
}
|
||||
if (tinst->flags & GS_PARAM_TABLE_F_ALLOC_ROWS) {
|
||||
free((void*)tinst->rows);
|
||||
}
|
||||
if (tinst->lock) {
|
||||
gs_param_table_lock_free(tinst);
|
||||
}
|
||||
memset(tinst, 0, sizeof(*tinst));
|
||||
}
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
static void checksum_update(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
const uint16_t no_swap = gs_fletcher16(tinst->rows, (sizeof(*tinst->rows) * tinst->row_count));
|
||||
|
||||
// fletcher16 with swapped fields > 1 byte
|
||||
gs_fletcher16_t f16;
|
||||
gs_fletcher16_init(&f16);
|
||||
for (unsigned int i = 0; i < tinst->row_count; ++i) {
|
||||
gs_param_table_row_t row = tinst->rows[i];
|
||||
row.addr = gs_bswap_16(row.addr);
|
||||
gs_fletcher16_update(&f16, &row, sizeof(row));
|
||||
}
|
||||
const uint16_t swap = gs_fletcher16_finalize(&f16);
|
||||
|
||||
if (gs_endian_big()) {
|
||||
tinst->checksum_be = no_swap;
|
||||
tinst->checksum_le = swap;
|
||||
} else {
|
||||
tinst->checksum_be = swap;
|
||||
tinst->checksum_le = no_swap;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t gs_param_table_checksum_be(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (tinst && tinst->rows && tinst->row_count) {
|
||||
if (tinst->checksum_be == 0) {
|
||||
checksum_update(tinst);
|
||||
}
|
||||
return tinst->checksum_be;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t gs_param_table_checksum_le(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (tinst && tinst->rows && tinst->row_count) {
|
||||
if (tinst->checksum_le == 0) {
|
||||
checksum_update(tinst);
|
||||
}
|
||||
return tinst->checksum_le;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t gs_param_table_checksum(gs_param_table_instance_t * tinst)
|
||||
{
|
||||
if (gs_endian_big()) {
|
||||
return gs_param_table_checksum_be(tinst);
|
||||
} else {
|
||||
return gs_param_table_checksum_le(tinst);
|
||||
}
|
||||
}
|
||||
|
||||
gs_error_t gs_param_get(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
if (tinst == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
|
||||
if ((addr + value_size) > tinst->memory_size) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
gs_error_t error = GS_ERROR_NOT_SUPPORTED;
|
||||
if (tinst->function_interface.get) {
|
||||
error = (tinst->function_interface.get)(tinst->function_interface.context, tinst, addr, type, value, value_size, flags);
|
||||
} else if (tinst->memory) {
|
||||
gs_param_table_lock(tinst);
|
||||
_copy_data(type, value, ((uint8_t*)(tinst->memory)) + addr, value_size);
|
||||
gs_param_table_unlock(tinst);
|
||||
error = GS_OK;
|
||||
}
|
||||
|
||||
if ((error == GS_OK) && (flags & GS_PARAM_SF_TO_BIG_ENDIAN) && !gs_endian_big()) {
|
||||
gs_param_htobe(type, value);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_set(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
if (tinst == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
|
||||
if ((addr + value_size) > tinst->memory_size) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
if ((flags & GS_PARAM_SF_FROM_BIG_ENDIAN) && !gs_endian_big()) {
|
||||
void * tmp = alloca(value_size); // this must be aligned
|
||||
memcpy(tmp, value, value_size);
|
||||
value = tmp;
|
||||
gs_param_betoh(type, tmp);
|
||||
}
|
||||
|
||||
gs_error_t error = GS_ERROR_NOT_SUPPORTED;
|
||||
if (tinst->function_interface.set) {
|
||||
error = (tinst->function_interface.set)(tinst->function_interface.context, tinst, addr, type, value, value_size, flags);
|
||||
} else if (tinst->memory) {
|
||||
gs_param_table_lock(tinst);
|
||||
_copy_data(type, ((uint8_t*)(tinst->memory)) + addr, value, value_size);
|
||||
gs_param_table_unlock(tinst);
|
||||
|
||||
if (tinst->auto_persist.set && (flags & GS_PARAM_F_AUTO_PERSIST)) {
|
||||
(tinst->auto_persist.set)(tinst, addr, type, value, value_size, flags);
|
||||
}
|
||||
error = GS_OK;
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
if ((error == GS_OK) && tinst->callback && ((flags & GS_PARAM_F_NO_CALLBACK) == 0)) {
|
||||
(tinst->callback)(addr, tinst);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t gs_param_type_size(gs_param_type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case GS_PARAM_UINT8:
|
||||
case GS_PARAM_INT8:
|
||||
case PARAM_X8:
|
||||
case GS_PARAM_STRING:
|
||||
case GS_PARAM_DATA:
|
||||
return sizeof(int8_t);
|
||||
case GS_PARAM_INT16:
|
||||
case GS_PARAM_UINT16:
|
||||
case PARAM_X16:
|
||||
return sizeof(int16_t);
|
||||
case GS_PARAM_INT32:
|
||||
case GS_PARAM_UINT32:
|
||||
case PARAM_X32:
|
||||
return sizeof(int32_t);
|
||||
case GS_PARAM_INT64:
|
||||
case GS_PARAM_UINT64:
|
||||
case PARAM_X64:
|
||||
return sizeof(int64_t);
|
||||
case GS_PARAM_DOUBLE:
|
||||
return sizeof(double);
|
||||
case GS_PARAM_FLOAT:
|
||||
return sizeof(float);
|
||||
case GS_PARAM_BOOL:
|
||||
return sizeof(bool);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void * gs_param_table_get_memory(gs_param_table_instance_t * tinst, size_t * return_size)
|
||||
{
|
||||
if (tinst && tinst->memory) {
|
||||
if (return_size) {
|
||||
*return_size = tinst->memory_size;
|
||||
}
|
||||
return tinst->memory;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * gs_param_table_get_rows(gs_param_table_instance_t * tinst, size_t * return_count)
|
||||
{
|
||||
if (tinst && tinst->rows && tinst->row_count) {
|
||||
if (return_count) {
|
||||
*return_count = tinst->row_count;
|
||||
}
|
||||
return tinst->rows;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t gs_param_table_instance_size(void)
|
||||
{
|
||||
return sizeof(gs_param_table_instance_t);
|
||||
}
|
||||
|
||||
gs_param_table_instance_t * gs_param_table_instance_clear(void * var, size_t var_size)
|
||||
{
|
||||
gs_param_table_instance_t * tinst = NULL;
|
||||
if (var && (var_size >= sizeof(*tinst))) {
|
||||
tinst = (gs_param_table_instance_t *) var;
|
||||
memset(tinst, 0, sizeof(*tinst));
|
||||
}
|
||||
return tinst;
|
||||
}
|
||||
|
||||
gs_param_table_instance_t * gs_param_table_instance_alloc(void)
|
||||
{
|
||||
return calloc(1, sizeof(gs_param_table_instance_t));
|
||||
}
|
||||
|
||||
gs_error_t gs_param_get_string(gs_param_table_instance_t * tinst, uint16_t addr, char * buf, size_t buf_size, uint32_t flags)
|
||||
{
|
||||
if (tinst == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
if (buf == NULL) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
if (buf_size <= param->size) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
|
||||
gs_error_t error = gs_param_get(tinst, addr, param->type, buf, param->size, flags);
|
||||
buf[param->size] = 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
gs_error_t gs_param_set_string(gs_param_table_instance_t * tinst, uint16_t addr, const char * value, uint32_t flags)
|
||||
{
|
||||
if (tinst == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
if (value == NULL) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
const size_t len = strlen(value) + 1;
|
||||
if (len > GS_PARAM_SIZE(param)) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
|
||||
return gs_param_set(tinst, addr, param->type, value, len, flags); // flags have full control
|
||||
}
|
||||
|
||||
gs_error_t gs_param_get_data(gs_param_table_instance_t * tinst, uint16_t addr, void * buf, size_t buf_size, uint32_t flags)
|
||||
{
|
||||
if (tinst == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
if (buf == NULL) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
if (buf_size < param->size) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
|
||||
return gs_param_get(tinst, addr, param->type, buf, param->size, flags);
|
||||
}
|
||||
|
||||
gs_error_t gs_param_set_data(gs_param_table_instance_t * tinst, uint16_t addr, const void * value, size_t value_size, uint32_t flags)
|
||||
{
|
||||
if (tinst == NULL) {
|
||||
return GS_ERROR_HANDLE;
|
||||
}
|
||||
if (value == NULL) {
|
||||
return GS_ERROR_ARG;
|
||||
}
|
||||
|
||||
const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count);
|
||||
if (param == NULL) {
|
||||
return GS_ERROR_RANGE;
|
||||
}
|
||||
|
||||
if (value_size > GS_PARAM_SIZE(param)) {
|
||||
return GS_ERROR_OVERFLOW;
|
||||
}
|
||||
|
||||
return gs_param_set(tinst, addr, param->type, value, value_size, flags); // flags have full control
|
||||
}
|
69
gomspace/libparam_client/wscript
Normal file
69
gomspace/libparam_client/wscript
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved.
|
||||
|
||||
import os
|
||||
import gs_gcc
|
||||
import gs_doc
|
||||
|
||||
APPNAME = 'param_client'
|
||||
|
||||
|
||||
def options(ctx):
|
||||
ctx.load('gs_gcc gs_doc')
|
||||
gs_gcc.gs_recurse(ctx)
|
||||
|
||||
gr = ctx.add_option_group('libparam client options')
|
||||
gr.add_option('--param_client-disable-cmd', action='store_true', help='Disable GOSH commands')
|
||||
gr.add_option('--param-enable-atomic-access', action='store_true', help='Enable atomic read/write of 16/32/float')
|
||||
|
||||
|
||||
def configure(ctx):
|
||||
ctx.load('gs_gcc gs_doc')
|
||||
|
||||
ctx.env.append_unique('USE_PARAM_CLIENT', ['gscsp', 'util'])
|
||||
|
||||
ctx.env.append_unique('FILES_PARAM_CLIENT', ['src/*.c', 'src/rparam/*.c',
|
||||
'src/pp/*.c', 'src/pp/i2c/*.c', 'src/pp/spi/*.c'])
|
||||
|
||||
if not ctx.options.param_client_disable_cmd:
|
||||
ctx.env.append_unique('FILES_PARAM_CLIENT', ['src/rparam/cmd/*.c', 'src/pp/cmd/*.c'])
|
||||
|
||||
if ctx.options.param_enable_atomic_access:
|
||||
ctx.env.append_unique('DEFINES_PARAM_CLIENT', ['GS_PARAM_ATOMIC_ACCESS=1'])
|
||||
|
||||
ctx.gs_register_handler(function='param_gen_4_0', filepath='./tools/waf_param.py')
|
||||
ctx.gs_register_handler(function='param_gen_4_2', filepath='./tools/waf_param.py')
|
||||
ctx.gs_register_handler(function='param_gen_4_3', filepath='./tools/waf_param.py')
|
||||
|
||||
ctx.gs_add_doxygen(exclude=['*/include/deprecated/param/*', '*/include/gs/param/internal/*'])
|
||||
|
||||
gs_gcc.gs_recurse(ctx)
|
||||
|
||||
|
||||
def build(ctx):
|
||||
gs_gcc.gs_recurse(ctx)
|
||||
|
||||
public_include = ctx.gs_include(name=APPNAME,
|
||||
includes=['include', 'include/deprecated', 'include/deprecated/param'])
|
||||
|
||||
if ctx.env.GS_ARCH not in ['avr8']:
|
||||
ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_PARAM_CLIENT),
|
||||
target=APPNAME,
|
||||
defines=ctx.env.DEFINES_PARAM_CLIENT,
|
||||
use=ctx.env.USE_PARAM_CLIENT + [public_include])
|
||||
|
||||
ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_PARAM_CLIENT),
|
||||
target=APPNAME,
|
||||
defines=ctx.env.DEFINES_PARAM_CLIENT,
|
||||
gs_use_shlib=ctx.env.USE_PARAM_CLIENT + [public_include])
|
||||
|
||||
ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/pyparam.c'),
|
||||
target=APPNAME,
|
||||
gs_use_shlib=ctx.env.USE_PARAM_CLIENT + [APPNAME, public_include],
|
||||
package='libparam')
|
||||
|
||||
|
||||
def gs_dist(ctx):
|
||||
gs_gcc.gs_recurse(ctx)
|
||||
ctx.add_default_files(source_module=True)
|
12
gomspace/libutil/include/conf_util.h
Normal file
12
gomspace/libutil/include/conf_util.h
Normal file
@ -0,0 +1,12 @@
|
||||
/* WARNING! All changes made to this file will be lost! */
|
||||
|
||||
#ifndef W_INCLUDE_CONF_UTIL_H_WAF
|
||||
#define W_INCLUDE_CONF_UTIL_H_WAF
|
||||
|
||||
#define UTIL_LITTLE_ENDIAN 1
|
||||
/* #undef UTIL_BIG_ENDIAN */
|
||||
#define GS_CONSOLE_HISTORY_LEN 10
|
||||
#define GS_CONSOLE_INPUT_LEN 100
|
||||
/* #undef GS_LOG_ENABLE_ISR_LOGS */
|
||||
|
||||
#endif /* W_INCLUDE_CONF_UTIL_H_WAF */
|
@ -0,0 +1,49 @@
|
||||
#ifndef GS_GOSH_COMMAND_COMMAND_H
|
||||
#define GS_GOSH_COMMAND_COMMAND_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
Legacy header file - use gs/util/gosh/command.h
|
||||
*/
|
||||
|
||||
#include <gs/util/gosh/command.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CMD_ERROR_NONE GS_OK
|
||||
#define CMD_ERROR_FAIL GS_ERROR_UNKNOWN
|
||||
#define CMD_ERROR_SYNTAX GS_ERROR_ARG
|
||||
#define CMD_ERROR_NOMEM GS_ERROR_ALLOC
|
||||
#define CMD_ERROR_INVALID GS_ERROR_DATA
|
||||
#define CMD_ERROR_NOTFOUND GS_ERROR_NOT_FOUND
|
||||
|
||||
#define CMD_HIDDEN GS_COMMAND_FLAG_HIDDEN
|
||||
|
||||
#define __root_command GS_COMMAND_ROOT
|
||||
#define __sub_command GS_COMMAND_SUB
|
||||
|
||||
#define INIT_CHAIN(__list) GS_COMMAND_INIT_CHAIN(__list)
|
||||
#define command_register(__cmd) GS_COMMAND_REGISTER(__cmd)
|
||||
|
||||
typedef struct command command_t;
|
||||
|
||||
static inline const char * command_args(gs_command_context_t *ctx)
|
||||
{
|
||||
return gs_command_args(ctx);
|
||||
}
|
||||
|
||||
static inline int command_run(char *line)
|
||||
{
|
||||
gs_error_t result = GS_OK;
|
||||
gs_error_t error = gs_command_run(line, &result);
|
||||
if (error == GS_OK) {
|
||||
return result;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
22
gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h
Normal file
22
gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef GS_GOSH_GOSH_GETOPT_H
|
||||
#define GS_GOSH_GOSH_GETOPT_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
Legacy header file - use gs/util/gosh/getopt.h
|
||||
*/
|
||||
|
||||
#include <gs/util/gosh/command.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int gosh_getopt(gs_command_context_t *ctx, const char *opts)
|
||||
{
|
||||
return gs_command_getopt(ctx, opts);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
43
gomspace/libutil/include/deprecated/gs/gosh/util/console.h
Normal file
43
gomspace/libutil/include/deprecated/gs/gosh/util/console.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef GS_GOSH_UTIL_CONSOLE_H
|
||||
#define GS_GOSH_UTIL_CONSOLE_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
Legacy header file - use gs/util/gosh/console.h
|
||||
*/
|
||||
|
||||
#include <gs/util/gosh/console.h>
|
||||
#include <gs/gosh/command/command.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int console_init(void)
|
||||
{
|
||||
return gs_console_init();
|
||||
}
|
||||
|
||||
static inline int console_exit(void)
|
||||
{
|
||||
return gs_console_exit();
|
||||
}
|
||||
|
||||
static inline void console_set_hostname(const char *host)
|
||||
{
|
||||
gs_console_set_prompt(host);
|
||||
}
|
||||
|
||||
static inline void console_clear(void)
|
||||
{
|
||||
gs_console_clear();
|
||||
}
|
||||
|
||||
static inline void console_update(void)
|
||||
{
|
||||
gs_console_update();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
26
gomspace/libutil/include/deprecated/util/color_printf.h
Normal file
26
gomspace/libutil/include/deprecated/util/color_printf.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef DEPRECATED_UTIL_COLOR_PRINTF_H
|
||||
#define DEPRECATED_UTIL_COLOR_PRINTF_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
|
||||
#include <gs/util/stdio.h>
|
||||
|
||||
typedef enum color_printf_e {
|
||||
/* Colors */
|
||||
COLOR_COLORS = GS_COLOR_COLORS,
|
||||
COLOR_NONE = GS_COLOR_NONE,
|
||||
COLOR_BLACK = GS_COLOR_BLACK,
|
||||
COLOR_RED = GS_COLOR_RED,
|
||||
COLOR_GREEN = GS_COLOR_GREEN,
|
||||
COLOR_YELLOW = GS_COLOR_YELLOW,
|
||||
COLOR_BLUE = GS_COLOR_BLUE,
|
||||
COLOR_MAGENTA = GS_COLOR_MAGENTA,
|
||||
COLOR_CYAN = GS_COLOR_CYAN,
|
||||
COLOR_WHITE = GS_COLOR_WHITE,
|
||||
/* Attributes */
|
||||
COLOR_ATTRS = GS_COLOR_ATTRS,
|
||||
COLOR_BOLD = GS_COLOR_BOLD,
|
||||
} color_printf_t;
|
||||
|
||||
#define color_printf gs_color_printf
|
||||
|
||||
#endif
|
231
gomspace/libutil/include/gs/uthash/utarray.h
Normal file
231
gomspace/libutil/include/gs/uthash/utarray.h
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* a dynamic array implementation using macros
|
||||
*/
|
||||
#ifndef UTARRAY_H
|
||||
#define UTARRAY_H
|
||||
|
||||
#define UTARRAY_VERSION 1.9.9
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define _UNUSED_ __attribute__ ((__unused__))
|
||||
#else
|
||||
#define _UNUSED_
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <string.h> /* memset, etc */
|
||||
#include <stdlib.h> /* exit */
|
||||
|
||||
#define oom() exit(-1)
|
||||
|
||||
typedef void (ctor_f)(void *dst, const void *src);
|
||||
typedef void (dtor_f)(void *elt);
|
||||
typedef void (init_f)(void *elt);
|
||||
typedef struct {
|
||||
size_t sz;
|
||||
init_f *init;
|
||||
ctor_f *copy;
|
||||
dtor_f *dtor;
|
||||
} UT_icd;
|
||||
|
||||
typedef struct {
|
||||
unsigned i,n;/* i: index of next available slot, n: num slots */
|
||||
UT_icd icd; /* initializer, copy and destructor functions */
|
||||
char *d; /* n slots of size icd->sz*/
|
||||
} UT_array;
|
||||
|
||||
#define utarray_init(a,_icd) do { \
|
||||
memset(a,0,sizeof(UT_array)); \
|
||||
(a)->icd=*_icd; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_done(a) do { \
|
||||
if ((a)->n) { \
|
||||
if ((a)->icd.dtor) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
free((a)->d); \
|
||||
} \
|
||||
(a)->n=0; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_new(a,_icd) do { \
|
||||
a=(UT_array*)malloc(sizeof(UT_array)); \
|
||||
utarray_init(a,_icd); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_free(a) do { \
|
||||
utarray_done(a); \
|
||||
free(a); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_reserve(a,by) do { \
|
||||
if (((a)->i+by) > ((a)->n)) { \
|
||||
while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
|
||||
if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utarray_push_back(a,p) do { \
|
||||
utarray_reserve(a,1); \
|
||||
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \
|
||||
else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_pop_back(a) do { \
|
||||
if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \
|
||||
else { (a)->i--; } \
|
||||
} while(0)
|
||||
|
||||
#define utarray_extend_back(a) do { \
|
||||
utarray_reserve(a,1); \
|
||||
if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \
|
||||
else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \
|
||||
(a)->i++; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_len(a) ((a)->i)
|
||||
|
||||
#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
|
||||
#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) )))
|
||||
|
||||
#define utarray_insert(a,p,j) do { \
|
||||
if (j > (a)->i) utarray_resize(a,j); \
|
||||
utarray_reserve(a,1); \
|
||||
if ((j) < (a)->i) { \
|
||||
memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
|
||||
((a)->i - (j))*((a)->icd.sz)); \
|
||||
} \
|
||||
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \
|
||||
else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \
|
||||
(a)->i++; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_inserta(a,w,j) do { \
|
||||
if (utarray_len(w) == 0) break; \
|
||||
if (j > (a)->i) utarray_resize(a,j); \
|
||||
utarray_reserve(a,utarray_len(w)); \
|
||||
if ((j) < (a)->i) { \
|
||||
memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
|
||||
_utarray_eltptr(a,j), \
|
||||
((a)->i - (j))*((a)->icd.sz)); \
|
||||
} \
|
||||
if ((a)->icd.copy) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
|
||||
(a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \
|
||||
} \
|
||||
} else { \
|
||||
memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
|
||||
utarray_len(w)*((a)->icd.sz)); \
|
||||
} \
|
||||
(a)->i += utarray_len(w); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_resize(dst,num) do { \
|
||||
size_t _ut_i; \
|
||||
if (dst->i > (size_t)(num)) { \
|
||||
if ((dst)->icd.dtor) { \
|
||||
for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \
|
||||
(dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
} else if (dst->i < (size_t)(num)) { \
|
||||
utarray_reserve(dst,num-dst->i); \
|
||||
if ((dst)->icd.init) { \
|
||||
for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \
|
||||
(dst)->icd.init(utarray_eltptr(dst,_ut_i)); \
|
||||
} \
|
||||
} else { \
|
||||
memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \
|
||||
} \
|
||||
} \
|
||||
dst->i = num; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_concat(dst,src) do { \
|
||||
utarray_inserta((dst),(src),utarray_len(dst)); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_erase(a,pos,len) do { \
|
||||
if ((a)->icd.dtor) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0; _ut_i < len; _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
if ((a)->i > (pos+len)) { \
|
||||
memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \
|
||||
(((a)->i)-(pos+len))*((a)->icd.sz)); \
|
||||
} \
|
||||
(a)->i -= (len); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_renew(a,u) do { \
|
||||
if (a) utarray_clear(a); \
|
||||
else utarray_new((a),(u)); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_clear(a) do { \
|
||||
if ((a)->i > 0) { \
|
||||
if ((a)->icd.dtor) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
(a)->i = 0; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utarray_sort(a,cmp) do { \
|
||||
qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
|
||||
|
||||
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
|
||||
#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
|
||||
#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
|
||||
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
|
||||
#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(size_t)(a)->icd.sz) : -1)
|
||||
|
||||
/* last we pre-define a few icd for common utarrays of ints and strings */
|
||||
static void utarray_str_cpy(void *dst, const void *src) {
|
||||
char **_src = (char**)src, **_dst = (char**)dst;
|
||||
*_dst = (*_src == NULL) ? NULL : strdup(*_src);
|
||||
}
|
||||
static void utarray_str_dtor(void *elt) {
|
||||
char **eltc = (char**)elt;
|
||||
if (*eltc) free(*eltc);
|
||||
}
|
||||
static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
|
||||
static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL};
|
||||
static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL};
|
||||
|
||||
#endif /* UTARRAY_H */
|
960
gomspace/libutil/include/gs/uthash/uthash.h
Normal file
960
gomspace/libutil/include/gs/uthash/uthash.h
Normal file
@ -0,0 +1,960 @@
|
||||
/*
|
||||
Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UTHASH_H
|
||||
#define UTHASH_H
|
||||
|
||||
#include <string.h> /* memcmp,strlen */
|
||||
#include <stddef.h> /* ptrdiff_t */
|
||||
#include <stdlib.h> /* exit() */
|
||||
|
||||
/* These macros use decltype or the earlier __typeof GNU extension.
|
||||
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
|
||||
when compiling c++ source) this code uses whatever method is needed
|
||||
or, for VS2008 where neither is available, uses casting workarounds. */
|
||||
#if defined(_MSC_VER) /* MS compiler */
|
||||
#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
|
||||
#define DECLTYPE(x) (decltype(x))
|
||||
#else /* VS2008 or older (or VS2010 in C mode) */
|
||||
#define NO_DECLTYPE
|
||||
#define DECLTYPE(x)
|
||||
#endif
|
||||
#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__)
|
||||
#define NO_DECLTYPE
|
||||
#define DECLTYPE(x)
|
||||
#else /* GNU, Sun and other compilers */
|
||||
#define DECLTYPE(x) (__typeof(x))
|
||||
#endif
|
||||
|
||||
#ifdef NO_DECLTYPE
|
||||
#define DECLTYPE_ASSIGN(dst,src) \
|
||||
do { \
|
||||
char **_da_dst = (char**)(&(dst)); \
|
||||
*_da_dst = (char*)(src); \
|
||||
} while(0)
|
||||
#else
|
||||
#define DECLTYPE_ASSIGN(dst,src) \
|
||||
do { \
|
||||
(dst) = DECLTYPE(dst)(src); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
|
||||
#if defined (_WIN32)
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600
|
||||
#include <stdint.h>
|
||||
#elif defined(__WATCOMC__)
|
||||
#include <stdint.h>
|
||||
#else
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
#endif
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#define UTHASH_VERSION 1.9.9
|
||||
|
||||
#ifndef uthash_fatal
|
||||
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
|
||||
#endif
|
||||
#ifndef uthash_malloc
|
||||
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
|
||||
#endif
|
||||
#ifndef uthash_free
|
||||
#define uthash_free(ptr,sz) free(ptr) /* free fcn */
|
||||
#endif
|
||||
|
||||
#ifndef uthash_noexpand_fyi
|
||||
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
|
||||
#endif
|
||||
#ifndef uthash_expand_fyi
|
||||
#define uthash_expand_fyi(tbl) /* can be defined to log expands */
|
||||
#endif
|
||||
|
||||
/* initial number of buckets */
|
||||
#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
|
||||
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
|
||||
#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
|
||||
|
||||
/* calculate the element whose hash handle address is hhe */
|
||||
#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
|
||||
|
||||
#define HASH_FIND(hh,head,keyptr,keylen,out) \
|
||||
do { \
|
||||
out=NULL; \
|
||||
if (head) { \
|
||||
unsigned _hf_bkt,_hf_hashv; \
|
||||
HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
|
||||
if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
|
||||
HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
|
||||
keyptr,keylen,out); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef HASH_BLOOM
|
||||
#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
|
||||
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
|
||||
#define HASH_BLOOM_MAKE(tbl) \
|
||||
do { \
|
||||
(tbl)->bloom_nbits = HASH_BLOOM; \
|
||||
(tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
|
||||
if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
|
||||
memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
|
||||
(tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
|
||||
} while (0)
|
||||
|
||||
#define HASH_BLOOM_FREE(tbl) \
|
||||
do { \
|
||||
uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
|
||||
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
|
||||
|
||||
#define HASH_BLOOM_ADD(tbl,hashv) \
|
||||
HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
|
||||
|
||||
#define HASH_BLOOM_TEST(tbl,hashv) \
|
||||
HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
|
||||
|
||||
#else
|
||||
#define HASH_BLOOM_MAKE(tbl)
|
||||
#define HASH_BLOOM_FREE(tbl)
|
||||
#define HASH_BLOOM_ADD(tbl,hashv)
|
||||
#define HASH_BLOOM_TEST(tbl,hashv) (1)
|
||||
#define HASH_BLOOM_BYTELEN 0
|
||||
#endif
|
||||
|
||||
#define HASH_MAKE_TABLE(hh,head) \
|
||||
do { \
|
||||
(head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
|
||||
sizeof(UT_hash_table)); \
|
||||
if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
|
||||
memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
|
||||
(head)->hh.tbl->tail = &((head)->hh); \
|
||||
(head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
|
||||
(head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
|
||||
(head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
|
||||
(head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
|
||||
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
|
||||
if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
|
||||
memset((head)->hh.tbl->buckets, 0, \
|
||||
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
|
||||
HASH_BLOOM_MAKE((head)->hh.tbl); \
|
||||
(head)->hh.tbl->signature = HASH_SIGNATURE; \
|
||||
} while(0)
|
||||
|
||||
#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
|
||||
HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
|
||||
|
||||
#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
|
||||
do { \
|
||||
replaced=NULL; \
|
||||
HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \
|
||||
if (replaced!=NULL) { \
|
||||
HASH_DELETE(hh,head,replaced); \
|
||||
}; \
|
||||
HASH_ADD(hh,head,fieldname,keylen_in,add); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
|
||||
do { \
|
||||
unsigned _ha_bkt; \
|
||||
(add)->hh.next = NULL; \
|
||||
(add)->hh.key = (char*)(keyptr); \
|
||||
(add)->hh.keylen = (unsigned)(keylen_in); \
|
||||
if (!(head)) { \
|
||||
head = (add); \
|
||||
(head)->hh.prev = NULL; \
|
||||
HASH_MAKE_TABLE(hh,head); \
|
||||
} else { \
|
||||
(head)->hh.tbl->tail->next = (add); \
|
||||
(add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
|
||||
(head)->hh.tbl->tail = &((add)->hh); \
|
||||
} \
|
||||
(head)->hh.tbl->num_items++; \
|
||||
(add)->hh.tbl = (head)->hh.tbl; \
|
||||
HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
|
||||
(add)->hh.hashv, _ha_bkt); \
|
||||
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
|
||||
HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
|
||||
HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
|
||||
HASH_FSCK(hh,head); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
|
||||
do { \
|
||||
bkt = ((hashv) & ((num_bkts) - 1)); \
|
||||
} while(0)
|
||||
|
||||
/* delete "delptr" from the hash table.
|
||||
* "the usual" patch-up process for the app-order doubly-linked-list.
|
||||
* The use of _hd_hh_del below deserves special explanation.
|
||||
* These used to be expressed using (delptr) but that led to a bug
|
||||
* if someone used the same symbol for the head and deletee, like
|
||||
* HASH_DELETE(hh,users,users);
|
||||
* We want that to work, but by changing the head (users) below
|
||||
* we were forfeiting our ability to further refer to the deletee (users)
|
||||
* in the patch-up process. Solution: use scratch space to
|
||||
* copy the deletee pointer, then the latter references are via that
|
||||
* scratch pointer rather than through the repointed (users) symbol.
|
||||
*/
|
||||
#define HASH_DELETE(hh,head,delptr) \
|
||||
do { \
|
||||
struct UT_hash_handle *_hd_hh_del; \
|
||||
if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
|
||||
uthash_free((head)->hh.tbl->buckets, \
|
||||
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
|
||||
HASH_BLOOM_FREE((head)->hh.tbl); \
|
||||
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
|
||||
head = NULL; \
|
||||
} else { \
|
||||
unsigned _hd_bkt; \
|
||||
_hd_hh_del = &((delptr)->hh); \
|
||||
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
|
||||
(head)->hh.tbl->tail = \
|
||||
(UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
|
||||
(head)->hh.tbl->hho); \
|
||||
} \
|
||||
if ((delptr)->hh.prev) { \
|
||||
((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
|
||||
(head)->hh.tbl->hho))->next = (delptr)->hh.next; \
|
||||
} else { \
|
||||
DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
|
||||
} \
|
||||
if (_hd_hh_del->next) { \
|
||||
((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \
|
||||
(head)->hh.tbl->hho))->prev = \
|
||||
_hd_hh_del->prev; \
|
||||
} \
|
||||
HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
|
||||
HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
|
||||
(head)->hh.tbl->num_items--; \
|
||||
} \
|
||||
HASH_FSCK(hh,head); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
|
||||
#define HASH_FIND_STR(head,findstr,out) \
|
||||
HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out)
|
||||
#define HASH_ADD_STR(head,strfield,add) \
|
||||
HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add)
|
||||
#define HASH_REPLACE_STR(head,strfield,add,replaced) \
|
||||
HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced)
|
||||
#define HASH_FIND_INT(head,findint,out) \
|
||||
HASH_FIND(hh,head,findint,sizeof(int),out)
|
||||
#define HASH_ADD_INT(head,intfield,add) \
|
||||
HASH_ADD(hh,head,intfield,sizeof(int),add)
|
||||
#define HASH_REPLACE_INT(head,intfield,add,replaced) \
|
||||
HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
|
||||
#define HASH_FIND_PTR(head,findptr,out) \
|
||||
HASH_FIND(hh,head,findptr,sizeof(void *),out)
|
||||
#define HASH_ADD_PTR(head,ptrfield,add) \
|
||||
HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
|
||||
#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \
|
||||
HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
|
||||
#define HASH_DEL(head,delptr) \
|
||||
HASH_DELETE(hh,head,delptr)
|
||||
|
||||
/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
|
||||
* This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
|
||||
*/
|
||||
#ifdef HASH_DEBUG
|
||||
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
|
||||
#define HASH_FSCK(hh,head) \
|
||||
do { \
|
||||
struct UT_hash_handle *_thh; \
|
||||
if (head) { \
|
||||
unsigned _bkt_i; \
|
||||
unsigned _count; \
|
||||
char *_prev; \
|
||||
_count = 0; \
|
||||
for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
|
||||
unsigned _bkt_count = 0; \
|
||||
_thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
|
||||
_prev = NULL; \
|
||||
while (_thh) { \
|
||||
if (_prev != (char*)(_thh->hh_prev)) { \
|
||||
HASH_OOPS("invalid hh_prev %p, actual %p\n", \
|
||||
_thh->hh_prev, _prev ); \
|
||||
} \
|
||||
_bkt_count++; \
|
||||
_prev = (char*)(_thh); \
|
||||
_thh = _thh->hh_next; \
|
||||
} \
|
||||
_count += _bkt_count; \
|
||||
if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
|
||||
HASH_OOPS("invalid bucket count %u, actual %u\n", \
|
||||
(head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
|
||||
} \
|
||||
} \
|
||||
if (_count != (head)->hh.tbl->num_items) { \
|
||||
HASH_OOPS("invalid hh item count %u, actual %u\n", \
|
||||
(head)->hh.tbl->num_items, _count ); \
|
||||
} \
|
||||
/* traverse hh in app order; check next/prev integrity, count */ \
|
||||
_count = 0; \
|
||||
_prev = NULL; \
|
||||
_thh = &(head)->hh; \
|
||||
while (_thh) { \
|
||||
_count++; \
|
||||
if (_prev !=(char*)(_thh->prev)) { \
|
||||
HASH_OOPS("invalid prev %p, actual %p\n", \
|
||||
_thh->prev, _prev ); \
|
||||
} \
|
||||
_prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
|
||||
_thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
|
||||
(head)->hh.tbl->hho) : NULL ); \
|
||||
} \
|
||||
if (_count != (head)->hh.tbl->num_items) { \
|
||||
HASH_OOPS("invalid app item count %u, actual %u\n", \
|
||||
(head)->hh.tbl->num_items, _count ); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define HASH_FSCK(hh,head)
|
||||
#endif
|
||||
|
||||
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
|
||||
* the descriptor to which this macro is defined for tuning the hash function.
|
||||
* The app can #include <unistd.h> to get the prototype for write(2). */
|
||||
#ifdef HASH_EMIT_KEYS
|
||||
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
|
||||
do { \
|
||||
unsigned _klen = fieldlen; \
|
||||
write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
|
||||
write(HASH_EMIT_KEYS, keyptr, fieldlen); \
|
||||
} while (0)
|
||||
#else
|
||||
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
|
||||
#endif
|
||||
|
||||
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
|
||||
#ifdef HASH_FUNCTION
|
||||
#define HASH_FCN HASH_FUNCTION
|
||||
#else
|
||||
#define HASH_FCN HASH_JEN
|
||||
#endif
|
||||
|
||||
/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
|
||||
#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _hb_keylen=keylen; \
|
||||
char *_hb_key=(char*)(key); \
|
||||
(hashv) = 0; \
|
||||
while (_hb_keylen--) { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; } \
|
||||
bkt = (hashv) & (num_bkts-1); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
|
||||
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
|
||||
#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _sx_i; \
|
||||
char *_hs_key=(char*)(key); \
|
||||
hashv = 0; \
|
||||
for(_sx_i=0; _sx_i < keylen; _sx_i++) \
|
||||
hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while (0)
|
||||
/* FNV-1a variation */
|
||||
#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _fn_i; \
|
||||
char *_hf_key=(char*)(key); \
|
||||
hashv = 2166136261UL; \
|
||||
for(_fn_i=0; _fn_i < keylen; _fn_i++) { \
|
||||
hashv = hashv ^ _hf_key[_fn_i]; \
|
||||
hashv = hashv * 16777619; \
|
||||
} \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _ho_i; \
|
||||
char *_ho_key=(char*)(key); \
|
||||
hashv = 0; \
|
||||
for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
|
||||
hashv += _ho_key[_ho_i]; \
|
||||
hashv += (hashv << 10); \
|
||||
hashv ^= (hashv >> 6); \
|
||||
} \
|
||||
hashv += (hashv << 3); \
|
||||
hashv ^= (hashv >> 11); \
|
||||
hashv += (hashv << 15); \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_JEN_MIX(a,b,c) \
|
||||
do { \
|
||||
a -= b; a -= c; a ^= ( c >> 13 ); \
|
||||
b -= c; b -= a; b ^= ( a << 8 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 13 ); \
|
||||
a -= b; a -= c; a ^= ( c >> 12 ); \
|
||||
b -= c; b -= a; b ^= ( a << 16 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 5 ); \
|
||||
a -= b; a -= c; a ^= ( c >> 3 ); \
|
||||
b -= c; b -= a; b ^= ( a << 10 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 15 ); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _hj_i,_hj_j,_hj_k; \
|
||||
unsigned char *_hj_key=(unsigned char*)(key); \
|
||||
hashv = 0xfeedbeef; \
|
||||
_hj_i = _hj_j = 0x9e3779b9; \
|
||||
_hj_k = (unsigned)(keylen); \
|
||||
while (_hj_k >= 12) { \
|
||||
_hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[2] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[3] << 24 ) ); \
|
||||
_hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[6] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[7] << 24 ) ); \
|
||||
hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[10] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[11] << 24 ) ); \
|
||||
\
|
||||
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
|
||||
\
|
||||
_hj_key += 12; \
|
||||
_hj_k -= 12; \
|
||||
} \
|
||||
hashv += keylen; \
|
||||
switch ( _hj_k ) { \
|
||||
case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
|
||||
case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
|
||||
case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
|
||||
case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
|
||||
case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
|
||||
case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
|
||||
case 5: _hj_j += _hj_key[4]; \
|
||||
case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
|
||||
case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
|
||||
case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
|
||||
case 1: _hj_i += _hj_key[0]; \
|
||||
} \
|
||||
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
/* The Paul Hsieh hash function */
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned char *_sfh_key=(unsigned char*)(key); \
|
||||
uint32_t _sfh_tmp, _sfh_len = keylen; \
|
||||
\
|
||||
int _sfh_rem = _sfh_len & 3; \
|
||||
_sfh_len >>= 2; \
|
||||
hashv = 0xcafebabe; \
|
||||
\
|
||||
/* Main loop */ \
|
||||
for (;_sfh_len > 0; _sfh_len--) { \
|
||||
hashv += get16bits (_sfh_key); \
|
||||
_sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \
|
||||
hashv = (hashv << 16) ^ _sfh_tmp; \
|
||||
_sfh_key += 2*sizeof (uint16_t); \
|
||||
hashv += hashv >> 11; \
|
||||
} \
|
||||
\
|
||||
/* Handle end cases */ \
|
||||
switch (_sfh_rem) { \
|
||||
case 3: hashv += get16bits (_sfh_key); \
|
||||
hashv ^= hashv << 16; \
|
||||
hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \
|
||||
hashv += hashv >> 11; \
|
||||
break; \
|
||||
case 2: hashv += get16bits (_sfh_key); \
|
||||
hashv ^= hashv << 11; \
|
||||
hashv += hashv >> 17; \
|
||||
break; \
|
||||
case 1: hashv += *_sfh_key; \
|
||||
hashv ^= hashv << 10; \
|
||||
hashv += hashv >> 1; \
|
||||
} \
|
||||
\
|
||||
/* Force "avalanching" of final 127 bits */ \
|
||||
hashv ^= hashv << 3; \
|
||||
hashv += hashv >> 5; \
|
||||
hashv ^= hashv << 4; \
|
||||
hashv += hashv >> 17; \
|
||||
hashv ^= hashv << 25; \
|
||||
hashv += hashv >> 6; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
#ifdef HASH_USING_NO_STRICT_ALIASING
|
||||
/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
|
||||
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
|
||||
* MurmurHash uses the faster approach only on CPU's where we know it's safe.
|
||||
*
|
||||
* Note the preprocessor built-in defines can be emitted using:
|
||||
*
|
||||
* gcc -m64 -dM -E - < /dev/null (on gcc)
|
||||
* cc -## a.c (where a.c is a simple test file) (Sun Studio)
|
||||
*/
|
||||
#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
|
||||
#define MUR_GETBLOCK(p,i) p[i]
|
||||
#else /* non intel */
|
||||
#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
|
||||
#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
|
||||
#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
|
||||
#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
|
||||
#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
|
||||
#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
|
||||
#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
|
||||
#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
|
||||
#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
|
||||
#else /* assume little endian non-intel */
|
||||
#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
|
||||
#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
|
||||
#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
|
||||
#endif
|
||||
#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
|
||||
(MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
|
||||
(MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
|
||||
MUR_ONE_THREE(p))))
|
||||
#endif
|
||||
#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
|
||||
#define MUR_FMIX(_h) \
|
||||
do { \
|
||||
_h ^= _h >> 16; \
|
||||
_h *= 0x85ebca6b; \
|
||||
_h ^= _h >> 13; \
|
||||
_h *= 0xc2b2ae35l; \
|
||||
_h ^= _h >> 16; \
|
||||
} while(0)
|
||||
|
||||
#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
const uint8_t *_mur_data = (const uint8_t*)(key); \
|
||||
const int _mur_nblocks = (keylen) / 4; \
|
||||
uint32_t _mur_h1 = 0xf88D5353; \
|
||||
uint32_t _mur_c1 = 0xcc9e2d51; \
|
||||
uint32_t _mur_c2 = 0x1b873593; \
|
||||
uint32_t _mur_k1 = 0; \
|
||||
const uint8_t *_mur_tail; \
|
||||
const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
|
||||
int _mur_i; \
|
||||
for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
|
||||
_mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
|
||||
_mur_k1 *= _mur_c1; \
|
||||
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
|
||||
_mur_k1 *= _mur_c2; \
|
||||
\
|
||||
_mur_h1 ^= _mur_k1; \
|
||||
_mur_h1 = MUR_ROTL32(_mur_h1,13); \
|
||||
_mur_h1 = _mur_h1*5+0xe6546b64; \
|
||||
} \
|
||||
_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \
|
||||
_mur_k1=0; \
|
||||
switch((keylen) & 3) { \
|
||||
case 3: _mur_k1 ^= _mur_tail[2] << 16; \
|
||||
case 2: _mur_k1 ^= _mur_tail[1] << 8; \
|
||||
case 1: _mur_k1 ^= _mur_tail[0]; \
|
||||
_mur_k1 *= _mur_c1; \
|
||||
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
|
||||
_mur_k1 *= _mur_c2; \
|
||||
_mur_h1 ^= _mur_k1; \
|
||||
} \
|
||||
_mur_h1 ^= (keylen); \
|
||||
MUR_FMIX(_mur_h1); \
|
||||
hashv = _mur_h1; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
#endif /* HASH_USING_NO_STRICT_ALIASING */
|
||||
|
||||
/* key comparison function; return 0 if keys equal */
|
||||
#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
|
||||
|
||||
/* iterate over items in a known bucket to find desired item */
|
||||
#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
|
||||
do { \
|
||||
if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
|
||||
else out=NULL; \
|
||||
while (out) { \
|
||||
if ((out)->hh.keylen == keylen_in) { \
|
||||
if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \
|
||||
} \
|
||||
if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
|
||||
else out = NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* add an item to a bucket */
|
||||
#define HASH_ADD_TO_BKT(head,addhh) \
|
||||
do { \
|
||||
head.count++; \
|
||||
(addhh)->hh_next = head.hh_head; \
|
||||
(addhh)->hh_prev = NULL; \
|
||||
if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
|
||||
(head).hh_head=addhh; \
|
||||
if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
|
||||
&& (addhh)->tbl->noexpand != 1) { \
|
||||
HASH_EXPAND_BUCKETS((addhh)->tbl); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* remove an item from a given bucket */
|
||||
#define HASH_DEL_IN_BKT(hh,head,hh_del) \
|
||||
(head).count--; \
|
||||
if ((head).hh_head == hh_del) { \
|
||||
(head).hh_head = hh_del->hh_next; \
|
||||
} \
|
||||
if (hh_del->hh_prev) { \
|
||||
hh_del->hh_prev->hh_next = hh_del->hh_next; \
|
||||
} \
|
||||
if (hh_del->hh_next) { \
|
||||
hh_del->hh_next->hh_prev = hh_del->hh_prev; \
|
||||
}
|
||||
|
||||
/* Bucket expansion has the effect of doubling the number of buckets
|
||||
* and redistributing the items into the new buckets. Ideally the
|
||||
* items will distribute more or less evenly into the new buckets
|
||||
* (the extent to which this is true is a measure of the quality of
|
||||
* the hash function as it applies to the key domain).
|
||||
*
|
||||
* With the items distributed into more buckets, the chain length
|
||||
* (item count) in each bucket is reduced. Thus by expanding buckets
|
||||
* the hash keeps a bound on the chain length. This bounded chain
|
||||
* length is the essence of how a hash provides constant time lookup.
|
||||
*
|
||||
* The calculation of tbl->ideal_chain_maxlen below deserves some
|
||||
* explanation. First, keep in mind that we're calculating the ideal
|
||||
* maximum chain length based on the *new* (doubled) bucket count.
|
||||
* In fractions this is just n/b (n=number of items,b=new num buckets).
|
||||
* Since the ideal chain length is an integer, we want to calculate
|
||||
* ceil(n/b). We don't depend on floating point arithmetic in this
|
||||
* hash, so to calculate ceil(n/b) with integers we could write
|
||||
*
|
||||
* ceil(n/b) = (n/b) + ((n%b)?1:0)
|
||||
*
|
||||
* and in fact a previous version of this hash did just that.
|
||||
* But now we have improved things a bit by recognizing that b is
|
||||
* always a power of two. We keep its base 2 log handy (call it lb),
|
||||
* so now we can write this with a bit shift and logical AND:
|
||||
*
|
||||
* ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
|
||||
*
|
||||
*/
|
||||
#define HASH_EXPAND_BUCKETS(tbl) \
|
||||
do { \
|
||||
unsigned _he_bkt; \
|
||||
unsigned _he_bkt_i; \
|
||||
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
|
||||
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
|
||||
_he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
|
||||
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
|
||||
if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
|
||||
memset(_he_new_buckets, 0, \
|
||||
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
|
||||
tbl->ideal_chain_maxlen = \
|
||||
(tbl->num_items >> (tbl->log2_num_buckets+1)) + \
|
||||
((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
|
||||
tbl->nonideal_items = 0; \
|
||||
for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
|
||||
{ \
|
||||
_he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
|
||||
while (_he_thh) { \
|
||||
_he_hh_nxt = _he_thh->hh_next; \
|
||||
HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
|
||||
_he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
|
||||
if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
|
||||
tbl->nonideal_items++; \
|
||||
_he_newbkt->expand_mult = _he_newbkt->count / \
|
||||
tbl->ideal_chain_maxlen; \
|
||||
} \
|
||||
_he_thh->hh_prev = NULL; \
|
||||
_he_thh->hh_next = _he_newbkt->hh_head; \
|
||||
if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
|
||||
_he_thh; \
|
||||
_he_newbkt->hh_head = _he_thh; \
|
||||
_he_thh = _he_hh_nxt; \
|
||||
} \
|
||||
} \
|
||||
uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
|
||||
tbl->num_buckets *= 2; \
|
||||
tbl->log2_num_buckets++; \
|
||||
tbl->buckets = _he_new_buckets; \
|
||||
tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
|
||||
(tbl->ineff_expands+1) : 0; \
|
||||
if (tbl->ineff_expands > 1) { \
|
||||
tbl->noexpand=1; \
|
||||
uthash_noexpand_fyi(tbl); \
|
||||
} \
|
||||
uthash_expand_fyi(tbl); \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
|
||||
/* Note that HASH_SORT assumes the hash handle name to be hh.
|
||||
* HASH_SRT was added to allow the hash handle name to be passed in. */
|
||||
#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
|
||||
#define HASH_SRT(hh,head,cmpfcn) \
|
||||
do { \
|
||||
unsigned _hs_i; \
|
||||
unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
|
||||
struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
|
||||
if (head) { \
|
||||
_hs_insize = 1; \
|
||||
_hs_looping = 1; \
|
||||
_hs_list = &((head)->hh); \
|
||||
while (_hs_looping) { \
|
||||
_hs_p = _hs_list; \
|
||||
_hs_list = NULL; \
|
||||
_hs_tail = NULL; \
|
||||
_hs_nmerges = 0; \
|
||||
while (_hs_p) { \
|
||||
_hs_nmerges++; \
|
||||
_hs_q = _hs_p; \
|
||||
_hs_psize = 0; \
|
||||
for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
|
||||
_hs_psize++; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
if (! (_hs_q) ) break; \
|
||||
} \
|
||||
_hs_qsize = _hs_insize; \
|
||||
while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
|
||||
if (_hs_psize == 0) { \
|
||||
_hs_e = _hs_q; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_qsize--; \
|
||||
} else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
|
||||
_hs_e = _hs_p; \
|
||||
if (_hs_p){ \
|
||||
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
|
||||
((void*)((char*)(_hs_p->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
} \
|
||||
_hs_psize--; \
|
||||
} else if (( \
|
||||
cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
|
||||
DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
|
||||
) <= 0) { \
|
||||
_hs_e = _hs_p; \
|
||||
if (_hs_p){ \
|
||||
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
|
||||
((void*)((char*)(_hs_p->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
} \
|
||||
_hs_psize--; \
|
||||
} else { \
|
||||
_hs_e = _hs_q; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_qsize--; \
|
||||
} \
|
||||
if ( _hs_tail ) { \
|
||||
_hs_tail->next = ((_hs_e) ? \
|
||||
ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
|
||||
} else { \
|
||||
_hs_list = _hs_e; \
|
||||
} \
|
||||
if (_hs_e) { \
|
||||
_hs_e->prev = ((_hs_tail) ? \
|
||||
ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
|
||||
} \
|
||||
_hs_tail = _hs_e; \
|
||||
} \
|
||||
_hs_p = _hs_q; \
|
||||
} \
|
||||
if (_hs_tail){ \
|
||||
_hs_tail->next = NULL; \
|
||||
} \
|
||||
if ( _hs_nmerges <= 1 ) { \
|
||||
_hs_looping=0; \
|
||||
(head)->hh.tbl->tail = _hs_tail; \
|
||||
DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
|
||||
} \
|
||||
_hs_insize *= 2; \
|
||||
} \
|
||||
HASH_FSCK(hh,head); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* This function selects items from one hash into another hash.
|
||||
* The end result is that the selected items have dual presence
|
||||
* in both hashes. There is no copy of the items made; rather
|
||||
* they are added into the new hash through a secondary hash
|
||||
* hash handle that must be present in the structure. */
|
||||
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
|
||||
do { \
|
||||
unsigned _src_bkt, _dst_bkt; \
|
||||
void *_last_elt=NULL, *_elt; \
|
||||
UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
|
||||
ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
|
||||
if (src) { \
|
||||
for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
|
||||
for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
|
||||
_src_hh; \
|
||||
_src_hh = _src_hh->hh_next) { \
|
||||
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
|
||||
if (cond(_elt)) { \
|
||||
_dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
|
||||
_dst_hh->key = _src_hh->key; \
|
||||
_dst_hh->keylen = _src_hh->keylen; \
|
||||
_dst_hh->hashv = _src_hh->hashv; \
|
||||
_dst_hh->prev = _last_elt; \
|
||||
_dst_hh->next = NULL; \
|
||||
if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
|
||||
if (!dst) { \
|
||||
DECLTYPE_ASSIGN(dst,_elt); \
|
||||
HASH_MAKE_TABLE(hh_dst,dst); \
|
||||
} else { \
|
||||
_dst_hh->tbl = (dst)->hh_dst.tbl; \
|
||||
} \
|
||||
HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
|
||||
HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
|
||||
(dst)->hh_dst.tbl->num_items++; \
|
||||
_last_elt = _elt; \
|
||||
_last_elt_hh = _dst_hh; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
HASH_FSCK(hh_dst,dst); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_CLEAR(hh,head) \
|
||||
do { \
|
||||
if (head) { \
|
||||
uthash_free((head)->hh.tbl->buckets, \
|
||||
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
|
||||
HASH_BLOOM_FREE((head)->hh.tbl); \
|
||||
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
|
||||
(head)=NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define HASH_OVERHEAD(hh,head) \
|
||||
((head) ? ( \
|
||||
(size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
|
||||
((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
|
||||
(sizeof(UT_hash_table)) + \
|
||||
(HASH_BLOOM_BYTELEN)))) : 0)
|
||||
|
||||
#ifdef NO_DECLTYPE
|
||||
#define HASH_ITER(hh,head,el,tmp) \
|
||||
for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \
|
||||
el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
|
||||
#else
|
||||
#define HASH_ITER(hh,head,el,tmp) \
|
||||
for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \
|
||||
el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
|
||||
#endif
|
||||
|
||||
/* obtain a count of items in the hash */
|
||||
#define HASH_COUNT(head) HASH_CNT(hh,head)
|
||||
#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
|
||||
|
||||
typedef struct UT_hash_bucket {
|
||||
struct UT_hash_handle *hh_head;
|
||||
unsigned count;
|
||||
|
||||
/* expand_mult is normally set to 0. In this situation, the max chain length
|
||||
* threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
|
||||
* the bucket's chain exceeds this length, bucket expansion is triggered).
|
||||
* However, setting expand_mult to a non-zero value delays bucket expansion
|
||||
* (that would be triggered by additions to this particular bucket)
|
||||
* until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
|
||||
* (The multiplier is simply expand_mult+1). The whole idea of this
|
||||
* multiplier is to reduce bucket expansions, since they are expensive, in
|
||||
* situations where we know that a particular bucket tends to be overused.
|
||||
* It is better to let its chain length grow to a longer yet-still-bounded
|
||||
* value, than to do an O(n) bucket expansion too often.
|
||||
*/
|
||||
unsigned expand_mult;
|
||||
|
||||
} UT_hash_bucket;
|
||||
|
||||
/* random signature used only to find hash tables in external analysis */
|
||||
#define HASH_SIGNATURE 0xa0111fe1
|
||||
#define HASH_BLOOM_SIGNATURE 0xb12220f2
|
||||
|
||||
typedef struct UT_hash_table {
|
||||
UT_hash_bucket *buckets;
|
||||
unsigned num_buckets, log2_num_buckets;
|
||||
unsigned num_items;
|
||||
struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
|
||||
ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
|
||||
|
||||
/* in an ideal situation (all buckets used equally), no bucket would have
|
||||
* more than ceil(#items/#buckets) items. that's the ideal chain length. */
|
||||
unsigned ideal_chain_maxlen;
|
||||
|
||||
/* nonideal_items is the number of items in the hash whose chain position
|
||||
* exceeds the ideal chain maxlen. these items pay the penalty for an uneven
|
||||
* hash distribution; reaching them in a chain traversal takes >ideal steps */
|
||||
unsigned nonideal_items;
|
||||
|
||||
/* ineffective expands occur when a bucket doubling was performed, but
|
||||
* afterward, more than half the items in the hash had nonideal chain
|
||||
* positions. If this happens on two consecutive expansions we inhibit any
|
||||
* further expansion, as it's not helping; this happens when the hash
|
||||
* function isn't a good fit for the key domain. When expansion is inhibited
|
||||
* the hash will still work, albeit no longer in constant time. */
|
||||
unsigned ineff_expands, noexpand;
|
||||
|
||||
uint32_t signature; /* used only to find hash tables in external analysis */
|
||||
#ifdef HASH_BLOOM
|
||||
uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
|
||||
uint8_t *bloom_bv;
|
||||
char bloom_nbits;
|
||||
#endif
|
||||
|
||||
} UT_hash_table;
|
||||
|
||||
typedef struct UT_hash_handle {
|
||||
struct UT_hash_table *tbl;
|
||||
void *prev; /* prev element in app order */
|
||||
void *next; /* next element in app order */
|
||||
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
|
||||
struct UT_hash_handle *hh_next; /* next hh in bucket order */
|
||||
void *key; /* ptr to enclosing struct's key */
|
||||
unsigned keylen; /* enclosing struct's key len */
|
||||
unsigned hashv; /* result of hash-fcn(key) */
|
||||
} UT_hash_handle;
|
||||
|
||||
#endif /* UTHASH_H */
|
757
gomspace/libutil/include/gs/uthash/utlist.h
Normal file
757
gomspace/libutil/include/gs/uthash/utlist.h
Normal file
@ -0,0 +1,757 @@
|
||||
/*
|
||||
Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UTLIST_H
|
||||
#define UTLIST_H
|
||||
|
||||
#define UTLIST_VERSION 1.9.9
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* This file contains macros to manipulate singly and doubly-linked lists.
|
||||
*
|
||||
* 1. LL_ macros: singly-linked lists.
|
||||
* 2. DL_ macros: doubly-linked lists.
|
||||
* 3. CDL_ macros: circular doubly-linked lists.
|
||||
*
|
||||
* To use singly-linked lists, your structure must have a "next" pointer.
|
||||
* To use doubly-linked lists, your structure must "prev" and "next" pointers.
|
||||
* Either way, the pointer to the head of the list must be initialized to NULL.
|
||||
*
|
||||
* ----------------.EXAMPLE -------------------------
|
||||
* struct item {
|
||||
* int id;
|
||||
* struct item *prev, *next;
|
||||
* }
|
||||
*
|
||||
* struct item *list = NULL:
|
||||
*
|
||||
* int main() {
|
||||
* struct item *item;
|
||||
* ... allocate and populate item ...
|
||||
* DL_APPEND(list, item);
|
||||
* }
|
||||
* --------------------------------------------------
|
||||
*
|
||||
* For doubly-linked lists, the append and delete macros are O(1)
|
||||
* For singly-linked lists, append and delete are O(n) but prepend is O(1)
|
||||
* The sort macro is O(n log(n)) for all types of single/double/circular lists.
|
||||
*/
|
||||
|
||||
/* These macros use decltype or the earlier __typeof GNU extension.
|
||||
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
|
||||
when compiling c++ code), this code uses whatever method is needed
|
||||
or, for VS2008 where neither is available, uses casting workarounds. */
|
||||
#ifdef _MSC_VER /* MS compiler */
|
||||
#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
|
||||
#define LDECLTYPE(x) decltype(x)
|
||||
#else /* VS2008 or older (or VS2010 in C mode) */
|
||||
#define NO_DECLTYPE
|
||||
#define LDECLTYPE(x) char*
|
||||
#endif
|
||||
#elif defined(__ICCARM__)
|
||||
#define NO_DECLTYPE
|
||||
#define LDECLTYPE(x) char*
|
||||
#else /* GNU, Sun and other compilers */
|
||||
#define LDECLTYPE(x) __typeof(x)
|
||||
#endif
|
||||
|
||||
/* for VS2008 we use some workarounds to get around the lack of decltype,
|
||||
* namely, we always reassign our tmp variable to the list head if we need
|
||||
* to dereference its prev/next pointers, and save/restore the real head.*/
|
||||
#ifdef NO_DECLTYPE
|
||||
#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
|
||||
#define _NEXT(elt,list,next) ((char*)((list)->next))
|
||||
#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
|
||||
/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
|
||||
#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
|
||||
#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
|
||||
#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
|
||||
#else
|
||||
#define _SV(elt,list)
|
||||
#define _NEXT(elt,list,next) ((elt)->next)
|
||||
#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
|
||||
/* #define _PREV(elt,list,prev) ((elt)->prev) */
|
||||
#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
|
||||
#define _RS(list)
|
||||
#define _CASTASGN(a,b) (a)=(b)
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
|
||||
* Unwieldy variable names used here to avoid shadowing passed-in variables. *
|
||||
*****************************************************************************/
|
||||
#define LL_SORT(list, cmp) \
|
||||
LL_SORT2(list, cmp, next)
|
||||
|
||||
#define LL_SORT2(list, cmp, next) \
|
||||
do { \
|
||||
LDECLTYPE(list) _ls_p; \
|
||||
LDECLTYPE(list) _ls_q; \
|
||||
LDECLTYPE(list) _ls_e; \
|
||||
LDECLTYPE(list) _ls_tail; \
|
||||
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
|
||||
if (list) { \
|
||||
_ls_insize = 1; \
|
||||
_ls_looping = 1; \
|
||||
while (_ls_looping) { \
|
||||
_CASTASGN(_ls_p,list); \
|
||||
list = NULL; \
|
||||
_ls_tail = NULL; \
|
||||
_ls_nmerges = 0; \
|
||||
while (_ls_p) { \
|
||||
_ls_nmerges++; \
|
||||
_ls_q = _ls_p; \
|
||||
_ls_psize = 0; \
|
||||
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
|
||||
_ls_psize++; \
|
||||
_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
|
||||
if (!_ls_q) break; \
|
||||
} \
|
||||
_ls_qsize = _ls_insize; \
|
||||
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
|
||||
if (_ls_psize == 0) { \
|
||||
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
|
||||
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
|
||||
} else if (_ls_qsize == 0 || !_ls_q) { \
|
||||
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
|
||||
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
|
||||
} else if (cmp(_ls_p,_ls_q) <= 0) { \
|
||||
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
|
||||
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
|
||||
} else { \
|
||||
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
|
||||
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
|
||||
} \
|
||||
if (_ls_tail) { \
|
||||
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
|
||||
} else { \
|
||||
_CASTASGN(list,_ls_e); \
|
||||
} \
|
||||
_ls_tail = _ls_e; \
|
||||
} \
|
||||
_ls_p = _ls_q; \
|
||||
} \
|
||||
if (_ls_tail) { \
|
||||
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
|
||||
} \
|
||||
if (_ls_nmerges <= 1) { \
|
||||
_ls_looping=0; \
|
||||
} \
|
||||
_ls_insize *= 2; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define DL_SORT(list, cmp) \
|
||||
DL_SORT2(list, cmp, prev, next)
|
||||
|
||||
#define DL_SORT2(list, cmp, prev, next) \
|
||||
do { \
|
||||
LDECLTYPE(list) _ls_p; \
|
||||
LDECLTYPE(list) _ls_q; \
|
||||
LDECLTYPE(list) _ls_e; \
|
||||
LDECLTYPE(list) _ls_tail; \
|
||||
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
|
||||
if (list) { \
|
||||
_ls_insize = 1; \
|
||||
_ls_looping = 1; \
|
||||
while (_ls_looping) { \
|
||||
_CASTASGN(_ls_p,list); \
|
||||
list = NULL; \
|
||||
_ls_tail = NULL; \
|
||||
_ls_nmerges = 0; \
|
||||
while (_ls_p) { \
|
||||
_ls_nmerges++; \
|
||||
_ls_q = _ls_p; \
|
||||
_ls_psize = 0; \
|
||||
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
|
||||
_ls_psize++; \
|
||||
_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
|
||||
if (!_ls_q) break; \
|
||||
} \
|
||||
_ls_qsize = _ls_insize; \
|
||||
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
|
||||
if (_ls_psize == 0) { \
|
||||
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
|
||||
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
|
||||
} else if (_ls_qsize == 0 || !_ls_q) { \
|
||||
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
|
||||
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
|
||||
} else if (cmp(_ls_p,_ls_q) <= 0) { \
|
||||
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
|
||||
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
|
||||
} else { \
|
||||
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
|
||||
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
|
||||
} \
|
||||
if (_ls_tail) { \
|
||||
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
|
||||
} else { \
|
||||
_CASTASGN(list,_ls_e); \
|
||||
} \
|
||||
_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
|
||||
_ls_tail = _ls_e; \
|
||||
} \
|
||||
_ls_p = _ls_q; \
|
||||
} \
|
||||
_CASTASGN(list->prev, _ls_tail); \
|
||||
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
|
||||
if (_ls_nmerges <= 1) { \
|
||||
_ls_looping=0; \
|
||||
} \
|
||||
_ls_insize *= 2; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CDL_SORT(list, cmp) \
|
||||
CDL_SORT2(list, cmp, prev, next)
|
||||
|
||||
#define CDL_SORT2(list, cmp, prev, next) \
|
||||
do { \
|
||||
LDECLTYPE(list) _ls_p; \
|
||||
LDECLTYPE(list) _ls_q; \
|
||||
LDECLTYPE(list) _ls_e; \
|
||||
LDECLTYPE(list) _ls_tail; \
|
||||
LDECLTYPE(list) _ls_oldhead; \
|
||||
LDECLTYPE(list) _tmp; \
|
||||
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
|
||||
if (list) { \
|
||||
_ls_insize = 1; \
|
||||
_ls_looping = 1; \
|
||||
while (_ls_looping) { \
|
||||
_CASTASGN(_ls_p,list); \
|
||||
_CASTASGN(_ls_oldhead,list); \
|
||||
list = NULL; \
|
||||
_ls_tail = NULL; \
|
||||
_ls_nmerges = 0; \
|
||||
while (_ls_p) { \
|
||||
_ls_nmerges++; \
|
||||
_ls_q = _ls_p; \
|
||||
_ls_psize = 0; \
|
||||
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
|
||||
_ls_psize++; \
|
||||
_SV(_ls_q,list); \
|
||||
if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \
|
||||
_ls_q = NULL; \
|
||||
} else { \
|
||||
_ls_q = _NEXT(_ls_q,list,next); \
|
||||
} \
|
||||
_RS(list); \
|
||||
if (!_ls_q) break; \
|
||||
} \
|
||||
_ls_qsize = _ls_insize; \
|
||||
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
|
||||
if (_ls_psize == 0) { \
|
||||
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
|
||||
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
|
||||
if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
|
||||
} else if (_ls_qsize == 0 || !_ls_q) { \
|
||||
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
|
||||
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
|
||||
if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
|
||||
} else if (cmp(_ls_p,_ls_q) <= 0) { \
|
||||
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
|
||||
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
|
||||
if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
|
||||
} else { \
|
||||
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
|
||||
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
|
||||
if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
|
||||
} \
|
||||
if (_ls_tail) { \
|
||||
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
|
||||
} else { \
|
||||
_CASTASGN(list,_ls_e); \
|
||||
} \
|
||||
_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
|
||||
_ls_tail = _ls_e; \
|
||||
} \
|
||||
_ls_p = _ls_q; \
|
||||
} \
|
||||
_CASTASGN(list->prev,_ls_tail); \
|
||||
_CASTASGN(_tmp,list); \
|
||||
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \
|
||||
if (_ls_nmerges <= 1) { \
|
||||
_ls_looping=0; \
|
||||
} \
|
||||
_ls_insize *= 2; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/******************************************************************************
|
||||
* singly linked list macros (non-circular) *
|
||||
*****************************************************************************/
|
||||
#define LL_PREPEND(head,add) \
|
||||
LL_PREPEND2(head,add,next)
|
||||
|
||||
#define LL_PREPEND2(head,add,next) \
|
||||
do { \
|
||||
(add)->next = head; \
|
||||
head = add; \
|
||||
} while (0)
|
||||
|
||||
#define LL_CONCAT(head1,head2) \
|
||||
LL_CONCAT2(head1,head2,next)
|
||||
|
||||
#define LL_CONCAT2(head1,head2,next) \
|
||||
do { \
|
||||
LDECLTYPE(head1) _tmp; \
|
||||
if (head1) { \
|
||||
_tmp = head1; \
|
||||
while (_tmp->next) { _tmp = _tmp->next; } \
|
||||
_tmp->next=(head2); \
|
||||
} else { \
|
||||
(head1)=(head2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LL_APPEND(head,add) \
|
||||
LL_APPEND2(head,add,next)
|
||||
|
||||
#define LL_APPEND2(head,add,next) \
|
||||
do { \
|
||||
LDECLTYPE(head) _tmp; \
|
||||
(add)->next=NULL; \
|
||||
if (head) { \
|
||||
_tmp = head; \
|
||||
while (_tmp->next) { _tmp = _tmp->next; } \
|
||||
_tmp->next=(add); \
|
||||
} else { \
|
||||
(head)=(add); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LL_DELETE(head,del) \
|
||||
LL_DELETE2(head,del,next)
|
||||
|
||||
#define LL_DELETE2(head,del,next) \
|
||||
do { \
|
||||
LDECLTYPE(head) _tmp; \
|
||||
if ((head) == (del)) { \
|
||||
(head)=(head)->next; \
|
||||
} else { \
|
||||
_tmp = head; \
|
||||
while (_tmp->next && (_tmp->next != (del))) { \
|
||||
_tmp = _tmp->next; \
|
||||
} \
|
||||
if (_tmp->next) { \
|
||||
_tmp->next = ((del)->next); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
|
||||
#define LL_APPEND_VS2008(head,add) \
|
||||
LL_APPEND2_VS2008(head,add,next)
|
||||
|
||||
#define LL_APPEND2_VS2008(head,add,next) \
|
||||
do { \
|
||||
if (head) { \
|
||||
(add)->next = head; /* use add->next as a temp variable */ \
|
||||
while ((add)->next->next) { (add)->next = (add)->next->next; } \
|
||||
(add)->next->next=(add); \
|
||||
} else { \
|
||||
(head)=(add); \
|
||||
} \
|
||||
(add)->next=NULL; \
|
||||
} while (0)
|
||||
|
||||
#define LL_DELETE_VS2008(head,del) \
|
||||
LL_DELETE2_VS2008(head,del,next)
|
||||
|
||||
#define LL_DELETE2_VS2008(head,del,next) \
|
||||
do { \
|
||||
if ((head) == (del)) { \
|
||||
(head)=(head)->next; \
|
||||
} else { \
|
||||
char *_tmp = (char*)(head); \
|
||||
while ((head)->next && ((head)->next != (del))) { \
|
||||
head = (head)->next; \
|
||||
} \
|
||||
if ((head)->next) { \
|
||||
(head)->next = ((del)->next); \
|
||||
} \
|
||||
{ \
|
||||
char **_head_alias = (char**)&(head); \
|
||||
*_head_alias = _tmp; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#ifdef NO_DECLTYPE
|
||||
#undef LL_APPEND
|
||||
#define LL_APPEND LL_APPEND_VS2008
|
||||
#undef LL_DELETE
|
||||
#define LL_DELETE LL_DELETE_VS2008
|
||||
#undef LL_DELETE2
|
||||
#define LL_DELETE2 LL_DELETE2_VS2008
|
||||
#undef LL_APPEND2
|
||||
#define LL_APPEND2 LL_APPEND2_VS2008
|
||||
#undef LL_CONCAT /* no LL_CONCAT_VS2008 */
|
||||
#undef DL_CONCAT /* no DL_CONCAT_VS2008 */
|
||||
#endif
|
||||
/* end VS2008 replacements */
|
||||
|
||||
#define LL_COUNT(head,el,counter) \
|
||||
LL_COUNT2(head,el,counter,next) \
|
||||
|
||||
#define LL_COUNT2(head,el,counter,next) \
|
||||
{ \
|
||||
counter = 0; \
|
||||
LL_FOREACH2(head,el,next){ ++counter; } \
|
||||
}
|
||||
|
||||
#define LL_FOREACH(head,el) \
|
||||
LL_FOREACH2(head,el,next)
|
||||
|
||||
#define LL_FOREACH2(head,el,next) \
|
||||
for(el=head;el;el=(el)->next)
|
||||
|
||||
#define LL_FOREACH_SAFE(head,el,tmp) \
|
||||
LL_FOREACH_SAFE2(head,el,tmp,next)
|
||||
|
||||
#define LL_FOREACH_SAFE2(head,el,tmp,next) \
|
||||
for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
|
||||
|
||||
#define LL_SEARCH_SCALAR(head,out,field,val) \
|
||||
LL_SEARCH_SCALAR2(head,out,field,val,next)
|
||||
|
||||
#define LL_SEARCH_SCALAR2(head,out,field,val,next) \
|
||||
do { \
|
||||
LL_FOREACH2(head,out,next) { \
|
||||
if ((out)->field == (val)) break; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define LL_SEARCH(head,out,elt,cmp) \
|
||||
LL_SEARCH2(head,out,elt,cmp,next)
|
||||
|
||||
#define LL_SEARCH2(head,out,elt,cmp,next) \
|
||||
do { \
|
||||
LL_FOREACH2(head,out,next) { \
|
||||
if ((cmp(out,elt))==0) break; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define LL_REPLACE_ELEM(head, el, add) \
|
||||
do { \
|
||||
LDECLTYPE(head) _tmp; \
|
||||
assert(head != NULL); \
|
||||
assert(el != NULL); \
|
||||
assert(add != NULL); \
|
||||
(add)->next = (el)->next; \
|
||||
if ((head) == (el)) { \
|
||||
(head) = (add); \
|
||||
} else { \
|
||||
_tmp = head; \
|
||||
while (_tmp->next && (_tmp->next != (el))) { \
|
||||
_tmp = _tmp->next; \
|
||||
} \
|
||||
if (_tmp->next) { \
|
||||
_tmp->next = (add); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LL_PREPEND_ELEM(head, el, add) \
|
||||
do { \
|
||||
LDECLTYPE(head) _tmp; \
|
||||
assert(head != NULL); \
|
||||
assert(el != NULL); \
|
||||
assert(add != NULL); \
|
||||
(add)->next = (el); \
|
||||
if ((head) == (el)) { \
|
||||
(head) = (add); \
|
||||
} else { \
|
||||
_tmp = head; \
|
||||
while (_tmp->next && (_tmp->next != (el))) { \
|
||||
_tmp = _tmp->next; \
|
||||
} \
|
||||
if (_tmp->next) { \
|
||||
_tmp->next = (add); \
|
||||
} \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* doubly linked list macros (non-circular) *
|
||||
*****************************************************************************/
|
||||
#define DL_PREPEND(head,add) \
|
||||
DL_PREPEND2(head,add,prev,next)
|
||||
|
||||
#define DL_PREPEND2(head,add,prev,next) \
|
||||
do { \
|
||||
(add)->next = head; \
|
||||
if (head) { \
|
||||
(add)->prev = (head)->prev; \
|
||||
(head)->prev = (add); \
|
||||
} else { \
|
||||
(add)->prev = (add); \
|
||||
} \
|
||||
(head) = (add); \
|
||||
} while (0)
|
||||
|
||||
#define DL_APPEND(head,add) \
|
||||
DL_APPEND2(head,add,prev,next)
|
||||
|
||||
#define DL_APPEND2(head,add,prev,next) \
|
||||
do { \
|
||||
if (head) { \
|
||||
(add)->prev = (head)->prev; \
|
||||
(head)->prev->next = (add); \
|
||||
(head)->prev = (add); \
|
||||
(add)->next = NULL; \
|
||||
} else { \
|
||||
(head)=(add); \
|
||||
(head)->prev = (head); \
|
||||
(head)->next = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DL_CONCAT(head1,head2) \
|
||||
DL_CONCAT2(head1,head2,prev,next)
|
||||
|
||||
#define DL_CONCAT2(head1,head2,prev,next) \
|
||||
do { \
|
||||
LDECLTYPE(head1) _tmp; \
|
||||
if (head2) { \
|
||||
if (head1) { \
|
||||
_tmp = (head2)->prev; \
|
||||
(head2)->prev = (head1)->prev; \
|
||||
(head1)->prev->next = (head2); \
|
||||
(head1)->prev = _tmp; \
|
||||
} else { \
|
||||
(head1)=(head2); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DL_DELETE(head,del) \
|
||||
DL_DELETE2(head,del,prev,next)
|
||||
|
||||
#define DL_DELETE2(head,del,prev,next) \
|
||||
do { \
|
||||
assert((del)->prev != NULL); \
|
||||
if ((del)->prev == (del)) { \
|
||||
(head)=NULL; \
|
||||
} else if ((del)==(head)) { \
|
||||
(del)->next->prev = (del)->prev; \
|
||||
(head) = (del)->next; \
|
||||
} else { \
|
||||
(del)->prev->next = (del)->next; \
|
||||
if ((del)->next) { \
|
||||
(del)->next->prev = (del)->prev; \
|
||||
} else { \
|
||||
(head)->prev = (del)->prev; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DL_COUNT(head,el,counter) \
|
||||
DL_COUNT2(head,el,counter,next) \
|
||||
|
||||
#define DL_COUNT2(head,el,counter,next) \
|
||||
{ \
|
||||
counter = 0; \
|
||||
DL_FOREACH2(head,el,next){ ++counter; } \
|
||||
}
|
||||
|
||||
#define DL_FOREACH(head,el) \
|
||||
DL_FOREACH2(head,el,next)
|
||||
|
||||
#define DL_FOREACH2(head,el,next) \
|
||||
for(el=head;el;el=(el)->next)
|
||||
|
||||
/* this version is safe for deleting the elements during iteration */
|
||||
#define DL_FOREACH_SAFE(head,el,tmp) \
|
||||
DL_FOREACH_SAFE2(head,el,tmp,next)
|
||||
|
||||
#define DL_FOREACH_SAFE2(head,el,tmp,next) \
|
||||
for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
|
||||
|
||||
/* these are identical to their singly-linked list counterparts */
|
||||
#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
|
||||
#define DL_SEARCH LL_SEARCH
|
||||
#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
|
||||
#define DL_SEARCH2 LL_SEARCH2
|
||||
|
||||
#define DL_REPLACE_ELEM(head, el, add) \
|
||||
do { \
|
||||
assert(head != NULL); \
|
||||
assert(el != NULL); \
|
||||
assert(add != NULL); \
|
||||
if ((head) == (el)) { \
|
||||
(head) = (add); \
|
||||
(add)->next = (el)->next; \
|
||||
if ((el)->next == NULL) { \
|
||||
(add)->prev = (add); \
|
||||
} else { \
|
||||
(add)->prev = (el)->prev; \
|
||||
(add)->next->prev = (add); \
|
||||
} \
|
||||
} else { \
|
||||
(add)->next = (el)->next; \
|
||||
(add)->prev = (el)->prev; \
|
||||
(add)->prev->next = (add); \
|
||||
if ((el)->next == NULL) { \
|
||||
(head)->prev = (add); \
|
||||
} else { \
|
||||
(add)->next->prev = (add); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DL_PREPEND_ELEM(head, el, add) \
|
||||
do { \
|
||||
assert(head != NULL); \
|
||||
assert(el != NULL); \
|
||||
assert(add != NULL); \
|
||||
(add)->next = (el); \
|
||||
(add)->prev = (el)->prev; \
|
||||
(el)->prev = (add); \
|
||||
if ((head) == (el)) { \
|
||||
(head) = (add); \
|
||||
} else { \
|
||||
(add)->prev->next = (add); \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* circular doubly linked list macros *
|
||||
*****************************************************************************/
|
||||
#define CDL_PREPEND(head,add) \
|
||||
CDL_PREPEND2(head,add,prev,next)
|
||||
|
||||
#define CDL_PREPEND2(head,add,prev,next) \
|
||||
do { \
|
||||
if (head) { \
|
||||
(add)->prev = (head)->prev; \
|
||||
(add)->next = (head); \
|
||||
(head)->prev = (add); \
|
||||
(add)->prev->next = (add); \
|
||||
} else { \
|
||||
(add)->prev = (add); \
|
||||
(add)->next = (add); \
|
||||
} \
|
||||
(head)=(add); \
|
||||
} while (0)
|
||||
|
||||
#define CDL_DELETE(head,del) \
|
||||
CDL_DELETE2(head,del,prev,next)
|
||||
|
||||
#define CDL_DELETE2(head,del,prev,next) \
|
||||
do { \
|
||||
if ( ((head)==(del)) && ((head)->next == (head))) { \
|
||||
(head) = 0L; \
|
||||
} else { \
|
||||
(del)->next->prev = (del)->prev; \
|
||||
(del)->prev->next = (del)->next; \
|
||||
if ((del) == (head)) (head)=(del)->next; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CDL_COUNT(head,el,counter) \
|
||||
CDL_COUNT2(head,el,counter,next) \
|
||||
|
||||
#define CDL_COUNT2(head, el, counter,next) \
|
||||
{ \
|
||||
counter = 0; \
|
||||
CDL_FOREACH2(head,el,next){ ++counter; } \
|
||||
}
|
||||
|
||||
#define CDL_FOREACH(head,el) \
|
||||
CDL_FOREACH2(head,el,next)
|
||||
|
||||
#define CDL_FOREACH2(head,el,next) \
|
||||
for(el=head;el;el=((el)->next==head ? 0L : (el)->next))
|
||||
|
||||
#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
|
||||
CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
|
||||
|
||||
#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \
|
||||
for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \
|
||||
(el) && ((tmp2)=(el)->next, 1); \
|
||||
((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
|
||||
|
||||
#define CDL_SEARCH_SCALAR(head,out,field,val) \
|
||||
CDL_SEARCH_SCALAR2(head,out,field,val,next)
|
||||
|
||||
#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \
|
||||
do { \
|
||||
CDL_FOREACH2(head,out,next) { \
|
||||
if ((out)->field == (val)) break; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CDL_SEARCH(head,out,elt,cmp) \
|
||||
CDL_SEARCH2(head,out,elt,cmp,next)
|
||||
|
||||
#define CDL_SEARCH2(head,out,elt,cmp,next) \
|
||||
do { \
|
||||
CDL_FOREACH2(head,out,next) { \
|
||||
if ((cmp(out,elt))==0) break; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CDL_REPLACE_ELEM(head, el, add) \
|
||||
do { \
|
||||
assert(head != NULL); \
|
||||
assert(el != NULL); \
|
||||
assert(add != NULL); \
|
||||
if ((el)->next == (el)) { \
|
||||
(add)->next = (add); \
|
||||
(add)->prev = (add); \
|
||||
(head) = (add); \
|
||||
} else { \
|
||||
(add)->next = (el)->next; \
|
||||
(add)->prev = (el)->prev; \
|
||||
(add)->next->prev = (add); \
|
||||
(add)->prev->next = (add); \
|
||||
if ((head) == (el)) { \
|
||||
(head) = (add); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CDL_PREPEND_ELEM(head, el, add) \
|
||||
do { \
|
||||
assert(head != NULL); \
|
||||
assert(el != NULL); \
|
||||
assert(add != NULL); \
|
||||
(add)->next = (el); \
|
||||
(add)->prev = (el)->prev; \
|
||||
(el)->prev = (add); \
|
||||
(add)->prev->next = (add); \
|
||||
if ((head) == (el)) { \
|
||||
(head) = (add); \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
#endif /* UTLIST_H */
|
||||
|
393
gomspace/libutil/include/gs/uthash/utstring.h
Normal file
393
gomspace/libutil/include/gs/uthash/utstring.h
Normal file
@ -0,0 +1,393 @@
|
||||
/*
|
||||
Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* a dynamic string implementation using macros
|
||||
*/
|
||||
#ifndef UTSTRING_H
|
||||
#define UTSTRING_H
|
||||
|
||||
#define UTSTRING_VERSION 1.9.9
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define _UNUSED_ __attribute__ ((__unused__))
|
||||
#else
|
||||
#define _UNUSED_
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#define oom() exit(-1)
|
||||
|
||||
typedef struct {
|
||||
char *d;
|
||||
size_t n; /* allocd size */
|
||||
size_t i; /* index of first unused byte */
|
||||
} UT_string;
|
||||
|
||||
#define utstring_reserve(s,amt) \
|
||||
do { \
|
||||
if (((s)->n - (s)->i) < (size_t)(amt)) { \
|
||||
(s)->d = (char*)realloc((s)->d, (s)->n + amt); \
|
||||
if ((s)->d == NULL) oom(); \
|
||||
(s)->n += amt; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utstring_init(s) \
|
||||
do { \
|
||||
(s)->n = 0; (s)->i = 0; (s)->d = NULL; \
|
||||
utstring_reserve(s,100); \
|
||||
(s)->d[0] = '\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_done(s) \
|
||||
do { \
|
||||
if ((s)->d != NULL) free((s)->d); \
|
||||
(s)->n = 0; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_free(s) \
|
||||
do { \
|
||||
utstring_done(s); \
|
||||
free(s); \
|
||||
} while(0)
|
||||
|
||||
#define utstring_new(s) \
|
||||
do { \
|
||||
s = (UT_string*)calloc(sizeof(UT_string),1); \
|
||||
if (!s) oom(); \
|
||||
utstring_init(s); \
|
||||
} while(0)
|
||||
|
||||
#define utstring_renew(s) \
|
||||
do { \
|
||||
if (s) { \
|
||||
utstring_clear(s); \
|
||||
} else { \
|
||||
utstring_new(s); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utstring_clear(s) \
|
||||
do { \
|
||||
(s)->i = 0; \
|
||||
(s)->d[0] = '\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_bincpy(s,b,l) \
|
||||
do { \
|
||||
utstring_reserve((s),(l)+1); \
|
||||
if (l) memcpy(&(s)->d[(s)->i], b, l); \
|
||||
(s)->i += l; \
|
||||
(s)->d[(s)->i]='\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_concat(dst,src) \
|
||||
do { \
|
||||
utstring_reserve((dst),((src)->i)+1); \
|
||||
if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \
|
||||
(dst)->i += (src)->i; \
|
||||
(dst)->d[(dst)->i]='\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_len(s) ((unsigned)((s)->i))
|
||||
|
||||
#define utstring_body(s) ((s)->d)
|
||||
|
||||
_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) {
|
||||
int n;
|
||||
va_list cp;
|
||||
while (1) {
|
||||
#ifdef _WIN32
|
||||
cp = ap;
|
||||
#else
|
||||
va_copy(cp, ap);
|
||||
#endif
|
||||
n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp);
|
||||
va_end(cp);
|
||||
|
||||
if ((n > -1) && ((size_t) n < (s->n-s->i))) {
|
||||
s->i += n;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) utstring_reserve(s,n+1); /* exact */
|
||||
else utstring_reserve(s,(s->n)*2); /* 2x */
|
||||
}
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
/* support printf format checking (2=the format string, 3=start of varargs) */
|
||||
static void utstring_printf(UT_string *s, const char *fmt, ...)
|
||||
__attribute__ (( format( printf, 2, 3) ));
|
||||
#endif
|
||||
_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,fmt);
|
||||
utstring_printf_va(s,fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* begin substring search functions *
|
||||
******************************************************************************/
|
||||
/* Build KMP table from left to right. */
|
||||
_UNUSED_ static void _utstring_BuildTable(
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
|
||||
i = 0;
|
||||
j = i - 1;
|
||||
P_KMP_Table[i] = j;
|
||||
while (i < (long) P_NeedleLen)
|
||||
{
|
||||
while ( (j > -1) && (P_Needle[i] != P_Needle[j]) )
|
||||
{
|
||||
j = P_KMP_Table[j];
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
if (i < (long) P_NeedleLen)
|
||||
{
|
||||
if (P_Needle[i] == P_Needle[j])
|
||||
{
|
||||
P_KMP_Table[i] = P_KMP_Table[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Build KMP table from right to left. */
|
||||
_UNUSED_ static void _utstring_BuildTableR(
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
|
||||
i = P_NeedleLen - 1;
|
||||
j = i + 1;
|
||||
P_KMP_Table[i + 1] = j;
|
||||
while (i >= 0)
|
||||
{
|
||||
while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) )
|
||||
{
|
||||
j = P_KMP_Table[j + 1];
|
||||
}
|
||||
i--;
|
||||
j--;
|
||||
if (i >= 0)
|
||||
{
|
||||
if (P_Needle[i] == P_Needle[j])
|
||||
{
|
||||
P_KMP_Table[i + 1] = P_KMP_Table[j + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i + 1] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i + 1] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from left to right. ( Multiple search mode. ) */
|
||||
_UNUSED_ static long _utstring_find(
|
||||
const char *P_Haystack,
|
||||
size_t P_HaystackLen,
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
/* Search from left to right. */
|
||||
i = j = 0;
|
||||
while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) )
|
||||
{
|
||||
while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) )
|
||||
{
|
||||
i = P_KMP_Table[i];
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
if (i >= (int)P_NeedleLen)
|
||||
{
|
||||
/* Found. */
|
||||
V_FindPosition = j - i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from right to left. ( Multiple search mode. ) */
|
||||
_UNUSED_ static long _utstring_findR(
|
||||
const char *P_Haystack,
|
||||
size_t P_HaystackLen,
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
/* Search from right to left. */
|
||||
j = (P_HaystackLen - 1);
|
||||
i = (P_NeedleLen - 1);
|
||||
while ( (j >= 0) && (j >= i) )
|
||||
{
|
||||
while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) )
|
||||
{
|
||||
i = P_KMP_Table[i + 1];
|
||||
}
|
||||
i--;
|
||||
j--;
|
||||
if (i < 0)
|
||||
{
|
||||
/* Found. */
|
||||
V_FindPosition = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from left to right. ( One time search mode. ) */
|
||||
_UNUSED_ static long utstring_find(
|
||||
UT_string *s,
|
||||
long P_StartPosition, /* Start from 0. -1 means last position. */
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen)
|
||||
{
|
||||
long V_StartPosition;
|
||||
long V_HaystackLen;
|
||||
long *V_KMP_Table;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
if (P_StartPosition < 0)
|
||||
{
|
||||
V_StartPosition = s->i + P_StartPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_StartPosition = P_StartPosition;
|
||||
}
|
||||
V_HaystackLen = s->i - V_StartPosition;
|
||||
if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
|
||||
{
|
||||
V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
|
||||
if (V_KMP_Table != NULL)
|
||||
{
|
||||
_utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table);
|
||||
|
||||
V_FindPosition = _utstring_find(s->d + V_StartPosition,
|
||||
V_HaystackLen,
|
||||
P_Needle,
|
||||
P_NeedleLen,
|
||||
V_KMP_Table);
|
||||
if (V_FindPosition >= 0)
|
||||
{
|
||||
V_FindPosition += V_StartPosition;
|
||||
}
|
||||
|
||||
free(V_KMP_Table);
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from right to left. ( One time search mode. ) */
|
||||
_UNUSED_ static long utstring_findR(
|
||||
UT_string *s,
|
||||
long P_StartPosition, /* Start from 0. -1 means last position. */
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen)
|
||||
{
|
||||
long V_StartPosition;
|
||||
long V_HaystackLen;
|
||||
long *V_KMP_Table;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
if (P_StartPosition < 0)
|
||||
{
|
||||
V_StartPosition = s->i + P_StartPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_StartPosition = P_StartPosition;
|
||||
}
|
||||
V_HaystackLen = V_StartPosition + 1;
|
||||
if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
|
||||
{
|
||||
V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
|
||||
if (V_KMP_Table != NULL)
|
||||
{
|
||||
_utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table);
|
||||
|
||||
V_FindPosition = _utstring_findR(s->d,
|
||||
V_HaystackLen,
|
||||
P_Needle,
|
||||
P_NeedleLen,
|
||||
V_KMP_Table);
|
||||
|
||||
free(V_KMP_Table);
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* end substring search functions *
|
||||
******************************************************************************/
|
||||
|
||||
#endif /* UTSTRING_H */
|
90
gomspace/libutil/include/gs/util/base16.h
Normal file
90
gomspace/libutil/include/gs/util/base16.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef GS_UTIL_BASE16_H
|
||||
#define GS_UTIL_BASE16_H
|
||||
/*
|
||||
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/**
|
||||
@file
|
||||
|
||||
Encoding and decoding base16 arrays to and from strings.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Calculate length of base16-encoded data
|
||||
|
||||
@param raw_len Raw data length
|
||||
@return Encoded string length (excluding NUL)
|
||||
*/
|
||||
static inline size_t base16_encoded_len(size_t raw_len)
|
||||
{
|
||||
return (2 * raw_len);
|
||||
}
|
||||
|
||||
/**
|
||||
Calculate maximum length of base16-decoded string
|
||||
@param encoded Encoded string
|
||||
@return Maximum length of raw data
|
||||
*/
|
||||
static inline size_t base16_decoded_max_len(const char *encoded)
|
||||
{
|
||||
return ((strlen(encoded) + 1) / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
Base16-encode data
|
||||
|
||||
The buffer must be the correct length for the encoded string. Use
|
||||
something like
|
||||
|
||||
char buf[ base16_encoded_len ( len ) + 1 ];
|
||||
|
||||
(the +1 is for the terminating NUL) to provide a buffer of the
|
||||
correct size.
|
||||
|
||||
@param raw Raw data
|
||||
@param len Length of raw data
|
||||
@param encoded Buffer for encoded string
|
||||
*/
|
||||
void base16_encode(const uint8_t *raw, size_t len, char *encoded);
|
||||
|
||||
/**
|
||||
Base16-decode data
|
||||
|
||||
The buffer must be large enough to contain the decoded data. Use
|
||||
something like
|
||||
|
||||
char buf[ base16_decoded_max_len ( encoded ) ];
|
||||
|
||||
to provide a buffer of the correct size.
|
||||
|
||||
@param encoded Encoded string
|
||||
@param raw Raw data
|
||||
@return Length of raw data, or negative error (gs_error_t)
|
||||
*/
|
||||
int base16_decode(const char *encoded, uint8_t *raw);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
173
gomspace/libutil/include/gs/util/bytebuffer.h
Normal file
173
gomspace/libutil/include/gs/util/bytebuffer.h
Normal file
@ -0,0 +1,173 @@
|
||||
#ifndef GS_UTIL_BYTEBUFFER_h
|
||||
#define GS_UTIL_BYTEBUFFER_h
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Byte buffer provides formatting/serialzing of text/binary data. The buffer keeps track of used space, and prevents overrun.
|
||||
|
||||
The current buffer state can be checked using gs_bytebuffer_state().
|
||||
|
||||
@dontinclude bytebuffer/bytebuffer_test.c
|
||||
@skip TEST_gs_bytebuffer_use_case
|
||||
@until }
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Buffer handle.
|
||||
Never access handle members directly.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Internal: Pointer to user supplied buffer.
|
||||
@see gs_bytebuffer_init()
|
||||
*/
|
||||
uint8_t * buffer;
|
||||
/**
|
||||
Internal: Size of user supplied buffer.
|
||||
@see gs_bytebuffer_init()
|
||||
*/
|
||||
size_t size;
|
||||
/**
|
||||
Internal: Number of bytes used.
|
||||
*/
|
||||
size_t used;
|
||||
/**
|
||||
Internal: FUTURE: Committed used
|
||||
*/
|
||||
size_t committed_used;
|
||||
/**
|
||||
Internal: flags to keep track of buffer state.
|
||||
*/
|
||||
uint8_t flags;
|
||||
} gs_bytebuffer_t;
|
||||
|
||||
/**
|
||||
Initialize buffer.
|
||||
|
||||
@param[in] bb handle.
|
||||
@param[in] buffer user supplied buffer of \a buffer_size size (bytes). If NULL, the buffer will keep track of required bytes.
|
||||
@param[in] buffer_size size of \a buffer.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
Insert data using vprintf.
|
||||
|
||||
@param[in] bb handle.
|
||||
@param[in] format printf syntax for formatting data
|
||||
@param[in] ap variable argument list.
|
||||
*/
|
||||
void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap);
|
||||
|
||||
/**
|
||||
Insert data using printf.
|
||||
|
||||
@param[in] bb handle.
|
||||
@param[in] format printf syntax for formatting data
|
||||
*/
|
||||
void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) __attribute__ ((format (__printf__, 2, 3)));
|
||||
|
||||
/**
|
||||
Append data to buffer.
|
||||
|
||||
@param[in] bb handle.
|
||||
@param[in] data data to append to buffer.
|
||||
@param[in] length length of data (bytes).
|
||||
*/
|
||||
void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length);
|
||||
|
||||
/**
|
||||
Append string to buffer.
|
||||
|
||||
@param[in] bb handle.
|
||||
@param[in] string string to append to buffer.
|
||||
*/
|
||||
void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string);
|
||||
|
||||
/**
|
||||
Append string to buffer.
|
||||
|
||||
@param[in] bb handle.
|
||||
@param[in] string string to append to buffer.
|
||||
@param[in] max_length max characters to append from \a string.
|
||||
*/
|
||||
void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length);
|
||||
|
||||
/**
|
||||
Return buffer as string - enforcing NUL termination.
|
||||
|
||||
This will always add a NUL termination (zero), which may lead to overflow/truncation of the string.
|
||||
The NUL termination is NOT added to \a used count.
|
||||
|
||||
@param[in] bb handle.
|
||||
@param[out] error optional, state of buffer - see gs_bytebuffer_error().
|
||||
@return C-string (NUL terminated)
|
||||
*/
|
||||
char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error);
|
||||
|
||||
/**
|
||||
Return buffer state.
|
||||
|
||||
@param[in] bb handle.
|
||||
@return GS_ERROR_OVERFLOW if data has been truncated.
|
||||
@return GS_ERROR_DATA in case of error during formatting.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb);
|
||||
|
||||
/**
|
||||
Return buffer (user supplied).
|
||||
|
||||
@param[in] bb handle.
|
||||
*/
|
||||
static inline void * gs_bytebuffer_get_buffer(gs_bytebuffer_t * bb)
|
||||
{
|
||||
return bb->buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Return buffer size (user supplied).
|
||||
|
||||
@param[in] bb handle.
|
||||
@return buffer size
|
||||
*/
|
||||
static inline size_t gs_bytebuffer_get_size(gs_bytebuffer_t * bb)
|
||||
{
|
||||
return bb->size;
|
||||
}
|
||||
|
||||
/**
|
||||
Return number of free bytes.
|
||||
|
||||
@param[in] bb handle.
|
||||
@return number of free bytes.
|
||||
*/
|
||||
static inline size_t gs_bytebuffer_get_free(gs_bytebuffer_t * bb)
|
||||
{
|
||||
return (bb->size) ? (bb->size - bb->used) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Return number of used bytes.
|
||||
|
||||
@param[in] bb handle.
|
||||
@return used bytes.
|
||||
*/
|
||||
static inline size_t gs_bytebuffer_get_used(gs_bytebuffer_t * bb)
|
||||
{
|
||||
return bb->used;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
341
gomspace/libutil/include/gs/util/byteorder.h
Normal file
341
gomspace/libutil/include/gs/util/byteorder.h
Normal file
@ -0,0 +1,341 @@
|
||||
#ifndef GS_UTIL_BYTEORDER_H
|
||||
#define GS_UTIL_BYTEORDER_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Convert numbers between host and network order.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_htons(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_ntohs(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_htonl(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_ntohl(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_hton16(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_ntoh16(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_hton32(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_ntoh32(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint64_t util_hton64(uint64_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint64_t util_ntoh64(uint64_t value);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
float util_htonflt(float value);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_htonflt_array(const float * from, float * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
float util_ntohflt(float value);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_ntohflt_array(const float * from, float * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
double util_htondbl(double value);
|
||||
|
||||
/**
|
||||
Convert value from host order to network order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_htondbl_array(const double * from, double * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
double util_ntohdbl(double value);
|
||||
|
||||
/**
|
||||
Convert value from network order to host order
|
||||
@param[in] from value to convert.
|
||||
@param[out] to value converted.
|
||||
@param[in] count element count
|
||||
*/
|
||||
void util_ntohdbl_array(const double * from, double * to, size_t count);
|
||||
|
||||
/**
|
||||
Convert value from host order to big endian.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_htobe16(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to little endian.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_htole16(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from big endian to host order.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_betoh16(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from little endian to host order.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint16_t util_letoh16(uint16_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to big endian.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_htobe32(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to little endian.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_htole32(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from big endian to host order.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_betoh32(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from little endian to host order.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint32_t util_letoh32(uint32_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to big endian.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint64_t util_htobe64(uint64_t value);
|
||||
|
||||
/**
|
||||
Convert value from host order to little endian.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint64_t util_htole64(uint64_t value);
|
||||
|
||||
/**
|
||||
Convert value from big endian to host order.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint64_t util_betoh64(uint64_t value);
|
||||
|
||||
/**
|
||||
Convert value from little endian to host order.
|
||||
@param[in] value value to convert.
|
||||
@return converted value.
|
||||
*/
|
||||
uint64_t util_letoh64(uint64_t value);
|
||||
|
||||
/**
|
||||
Byte swap.
|
||||
@param[in] value value to byteswap.
|
||||
@return swapped value
|
||||
*/
|
||||
uint16_t gs_bswap_16(uint16_t value);
|
||||
|
||||
/**
|
||||
Byte swap array.
|
||||
@param[in] from from address.
|
||||
@param[out] to to address.
|
||||
@param[in] count element count.
|
||||
*/
|
||||
void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Byte swap.
|
||||
@param[in] value value to byteswap.
|
||||
@return swapped value
|
||||
*/
|
||||
uint32_t gs_bswap_32(uint32_t value);
|
||||
|
||||
/**
|
||||
Byte swap array.
|
||||
@param[in] from from address.
|
||||
@param[out] to to address.
|
||||
@param[in] count element count.
|
||||
*/
|
||||
void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Byte swap.
|
||||
@param[in] value value to byteswap.
|
||||
@return swapped value
|
||||
*/
|
||||
uint64_t gs_bswap_64(uint64_t value);
|
||||
|
||||
/**
|
||||
Byte swap array.
|
||||
@param[in] from from address.
|
||||
@param[out] to to address.
|
||||
@param[in] count element count.
|
||||
*/
|
||||
void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count);
|
||||
|
||||
/**
|
||||
Byte swap.
|
||||
@param[in] value value to byteswap.
|
||||
@return swapped value
|
||||
*/
|
||||
float gs_bswap_float(float value);
|
||||
|
||||
/**
|
||||
Byte swap array.
|
||||
@param[in] from from address.
|
||||
@param[out] to to address.
|
||||
@param[in] count element count.
|
||||
*/
|
||||
void gs_bswap_float_array(const float * from, float * to, size_t count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
54
gomspace/libutil/include/gs/util/check.h
Normal file
54
gomspace/libutil/include/gs/util/check.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef GS_UTIL_CHECK_H
|
||||
#define GS_UTIL_CHECK_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Argument checking.
|
||||
|
||||
Logs can be enabled through a define.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <gs/util/log.h>
|
||||
#include <gs/util/string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (GS_CHECK_LOG)
|
||||
#define GS_CHECK_HANDLE(check) if (!(check)) { log_error("Invalid handle - assert: " GS_DEF2STRING(check)); return GS_ERROR_HANDLE;}
|
||||
#define GS_CHECK_ARG(check) if (!(check)) { log_error("Invalid argument - assert: " GS_DEF2STRING(check)); return GS_ERROR_ARG;}
|
||||
#define GS_CHECK_SUPPORTED(check) if (!(check)) { log_error("Not supported - assert: " GS_DEF2STRING(check)); return GS_ERROR_NOT_SUPPORTED;}
|
||||
#define GS_CHECK_RANGE(check) if (!(check)) { log_error("Invalid range - assert: " GS_DEF2STRING(check)); return GS_ERROR_RANGE;}
|
||||
#else
|
||||
/**
|
||||
Perform evalution of 'check' and return GS_ERROR_HANDLE if not 'true'.
|
||||
*/
|
||||
#define GS_CHECK_HANDLE(check) if (!(check)) { return GS_ERROR_HANDLE;}
|
||||
/**
|
||||
Perform evalution of 'check' and return GS_ERROR_ARG if not 'true'.
|
||||
*/
|
||||
#define GS_CHECK_ARG(check) if (!(check)) { return GS_ERROR_ARG;}
|
||||
/**
|
||||
Perform evalution of 'check' and return GS_ERROR_NOT_SUPPORTED if not 'true'.
|
||||
*/
|
||||
#define GS_CHECK_SUPPORTED(check) if (!(check)) { return GS_ERROR_NOT_SUPPORTED;}
|
||||
/**
|
||||
Perform evalution of 'check' and return GS_ERROR_RANGE if not 'true'.
|
||||
*/
|
||||
#define GS_CHECK_RANGE(check) if (!(check)) { return GS_ERROR_RANGE;}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Assert on 'value'.
|
||||
|
||||
@deprecated use GS_STATIC_ASSERT()
|
||||
*/
|
||||
#define GS_CHECK_STATIC_ASSERT(condition, name) GS_STATIC_ASSERT(condition, name)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
88
gomspace/libutil/include/gs/util/clock.h
Normal file
88
gomspace/libutil/include/gs/util/clock.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef GS_UTIL_CLOCK_H
|
||||
#define GS_UTIL_CLOCK_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Get/set time (including RTC), convert to/from string.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <gs/util/timestamp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Returns real time/clock (UTC - time since Epoch/1970).
|
||||
|
||||
If the platform supports a Real Time Clock, the RTC is normally read on first call. An offset is calculated for the relative clock, which
|
||||
then is used to calculate the actual time.
|
||||
|
||||
@note clock_get_time() is proto-typed in libcsp as weak, but with different argument which MUST match gs_timestamp_t.
|
||||
@param[out] time user allocated buffer, contaning the current UTC time.
|
||||
*/
|
||||
void gs_clock_get_time(gs_timestamp_t * time);
|
||||
|
||||
/**
|
||||
Set real time/clock (UTC).
|
||||
If the platform supports a Real Time Clock, the RTC is also updated.
|
||||
@param[in] time UTC time.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_clock_set_time(const gs_timestamp_t * time);
|
||||
|
||||
/**
|
||||
Returns elapsed time since some unspecified starting point.
|
||||
@param[out] time user allocated buffer, receives elapsed time.
|
||||
@see gs_time_rel_ms()
|
||||
*/
|
||||
void gs_clock_get_monotonic(gs_timestamp_t * time);
|
||||
|
||||
/**
|
||||
Returns number of elapsed nano-seconds since some unspecified starting point.
|
||||
@return nano-seconds.
|
||||
*/
|
||||
uint64_t gs_clock_get_nsec(void);
|
||||
|
||||
/**
|
||||
Buffer length for containing full ISO8601 timestamp - including zero (0) termination.
|
||||
*/
|
||||
#define GS_CLOCK_ISO8601_BUFFER_LENGTH 21
|
||||
|
||||
/**
|
||||
Convert UTC to a ISO8601 string.
|
||||
ISO8601 timestamp: 2017-03-30T06:20:45Z
|
||||
@param[in] utc_time UTC time.
|
||||
@param[out] buffer user allocated buffer.
|
||||
@param[in] buffer_size size of \a buf.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
Convert UTC to a ISO8601 string.
|
||||
ISO8601 timestamp: 2017-03-30T06:20:45Z
|
||||
@param[in] utc_sec UTC seconds.
|
||||
@param[out] buffer user allocated buffer.
|
||||
@param[in] buffer_size size of \a buf.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
Convert string (UTC time) to timstamp.
|
||||
Parse string as:
|
||||
1. \<seconds\>.\<nano-seconds\> - number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
|
||||
2. YYYY-MM-DDTHH:MM:SSZ - ISO8601
|
||||
@param[in] str time
|
||||
@param[out] ts time
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
55
gomspace/libutil/include/gs/util/crc32.h
Normal file
55
gomspace/libutil/include/gs/util/crc32.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef GS_UTIL_CRC32_H
|
||||
#define GS_UTIL_CRC32_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
CRC32 checksumes.
|
||||
|
||||
https://en.wikipedia.org/wiki/Cyclic_redundancy_check.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Return init/seed value for CRC-32.
|
||||
@return initial/seed value for CRC-32, using 0xffffffff.
|
||||
@see gs_crc32_update(), gs_crc32_finalize()
|
||||
*/
|
||||
uint32_t gs_crc32_init(void);
|
||||
|
||||
/**
|
||||
Update CRC-32.
|
||||
@param[in] crc current CRC-32
|
||||
@param[in] block start of memory block.
|
||||
@param[in] length length of \a block.
|
||||
@return updated CRC-32.
|
||||
@see gs_crc32_init(), gs_crc32_finalize()
|
||||
*/
|
||||
uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length);
|
||||
|
||||
/**
|
||||
Return finalized CRC-32.
|
||||
@param[in] crc Checksum is finalized by xor'ing 0xffffffff.
|
||||
@return finalized CRC-32.
|
||||
@see gs_crc32_init(), gs_crc32_update()
|
||||
*/
|
||||
uint32_t gs_crc32_finalize(uint32_t crc);
|
||||
|
||||
/**
|
||||
Return finalized CRC-32 on amemory block.
|
||||
|
||||
@param[in] block block to calculate CRC-32 on.
|
||||
@param[in] length length/size of \a block.
|
||||
@return finalized CRC-32.
|
||||
*/
|
||||
uint32_t gs_crc32(const void *block, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
55
gomspace/libutil/include/gs/util/crc8.h
Normal file
55
gomspace/libutil/include/gs/util/crc8.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef GS_UTIL_CRC8_H
|
||||
#define GS_UTIL_CRC8_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
CRC8 checksumes.
|
||||
|
||||
https://en.wikipedia.org/wiki/Cyclic_redundancy_check.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Return init/seed value for CRC-8.
|
||||
@return initial/seed value for CRC-8, using 0xff.
|
||||
@see gs_crc8_update(), gs_crc8_finalize()
|
||||
*/
|
||||
uint8_t gs_crc8_init(void);
|
||||
|
||||
/**
|
||||
Update CRC-8.
|
||||
@param[in] crc current CRC-8
|
||||
@param[in] block start of memory block.
|
||||
@param[in] length length of \a block.
|
||||
@return updated CRC-8.
|
||||
@see gs_crc8_init(), gs_crc8_finalize()
|
||||
*/
|
||||
uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length);
|
||||
|
||||
/**
|
||||
Return finalized CRC-8.
|
||||
@param[in] crc Checksum is finalized by xor'ing 0xffffffff.
|
||||
@return finalized CRC-8.
|
||||
@see gs_crc8_init(), gs_crc8_update()
|
||||
*/
|
||||
uint8_t gs_crc8_finalize(uint8_t crc);
|
||||
|
||||
/**
|
||||
Return finalized CRC-8 on amemory block.
|
||||
|
||||
@param[in] block block to calculate CRC-8 on.
|
||||
@param[in] length length/size of \a block.
|
||||
@return finalized CRC-8.
|
||||
*/
|
||||
uint8_t gs_crc8(const void *block, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
42
gomspace/libutil/include/gs/util/delay.h
Normal file
42
gomspace/libutil/include/gs/util/delay.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef GS_UTIL_DELAY_H
|
||||
#define GS_UTIL_DELAY_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Delay execution.
|
||||
|
||||
@note Most implementations uses busy waiting.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Delay for number of microseconds.
|
||||
@note Linux doesn't busy wait.
|
||||
@param us Number of microseconds to wait
|
||||
*/
|
||||
void gs_delay_us(uint32_t us);
|
||||
|
||||
/**
|
||||
Return current counter used for us delays
|
||||
@return timestamp in us
|
||||
*/
|
||||
uint16_t gs_delay_ts_get(void);
|
||||
|
||||
/**
|
||||
Wait until delay has passed since timestamp
|
||||
|
||||
@param[in] ts Timestamp in us
|
||||
@param[in] delay The requested delay since ts
|
||||
*/
|
||||
void gs_delay_from_ts(uint16_t ts, uint16_t delay);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
122
gomspace/libutil/include/gs/util/drivers/can/can.h
Normal file
122
gomspace/libutil/include/gs/util/drivers/can/can.h
Normal file
@ -0,0 +1,122 @@
|
||||
#ifndef GS_UTIL_DRIVERS_CAN_CAN_H
|
||||
#define GS_UTIL_DRIVERS_CAN_CAN_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
CAN interface.
|
||||
*/
|
||||
|
||||
#include <gs/util/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Default log group for CAN driver.
|
||||
*/
|
||||
GS_LOG_GROUP_EXTERN(gs_can_log);
|
||||
|
||||
/**
|
||||
Bit-rate (default).
|
||||
*/
|
||||
#define GS_CAN_DEFAULT_BPS 1000000
|
||||
|
||||
/**
|
||||
Callback for handling received data (from CAN driver).
|
||||
@param[in] device hardware device
|
||||
@param[in] canMsgId standard or extended message id.
|
||||
@param[in] extendedMsgId \a true if extended id, \a false if standard id.
|
||||
@param[in] data pointer to data.
|
||||
@param[in] data_size size of data.
|
||||
@param[in] nowMs current relative time in mS.
|
||||
@param[in] user_data user data.
|
||||
@param[in] cswitch If called from within an ISR (embedded platform), this will none NULL.
|
||||
*/
|
||||
typedef void (*gs_can_rxdata_callback_t)(int hdl,
|
||||
uint32_t canMsgId,
|
||||
bool extendedMsgId,
|
||||
const void * data,
|
||||
size_t data_size,
|
||||
uint32_t nowMs,
|
||||
void * user_data,
|
||||
gs_context_switch_t * cswitch);
|
||||
|
||||
/**
|
||||
Send CAN message with standard id (11 bits).
|
||||
@param[in] device hardware device
|
||||
@param[in] canMsgId standard CAN message id.
|
||||
@param[in] data pointer to data.
|
||||
@param[in] data_size size of data.
|
||||
@param[in] timeout_ms timeout in mS.
|
||||
@return GS_ERROR_FULL if Tx queue is full
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_send_standard(uint8_t device, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms);
|
||||
|
||||
/**
|
||||
Send CAN message with exended id (29 bits).
|
||||
@param[in] device hardware device
|
||||
@param[in] canExtMsgId exteneded message id.
|
||||
@param[in] data pointer to data.
|
||||
@param[in] data_size size of data.
|
||||
@param[in] timeout_ms timeout in mS.
|
||||
@return GS_ERROR_FULL if Tx queue is full
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_send_extended(uint8_t device, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms);
|
||||
|
||||
/**
|
||||
Set filter and callback for standard message id.
|
||||
@param[in] device hardware device
|
||||
@param[in] canMsgId standard message id.
|
||||
@param[in] mask filter mask.
|
||||
@param[in] rx_callback callback function.
|
||||
@param[in] rx_user_data user data provided in callback.
|
||||
@return GS_ERROR_FULL if all message id slots are used.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_set_standard_filter_mask(uint8_t device, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data);
|
||||
|
||||
/**
|
||||
Set filter and callback for extended message id.
|
||||
@param[in] device hardware device
|
||||
@param[in] canExtMsgId extended message id.
|
||||
@param[in] mask filter mask.
|
||||
@param[in] rx_callback callback function.
|
||||
@param[in] rx_user_data user data provided in callback.
|
||||
@return GS_ERROR_FULL if all message id slots are used.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_set_extended_filter_mask(uint8_t device, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data);
|
||||
|
||||
/**
|
||||
Stop CAN layer.
|
||||
If a CAN transceiver is present and controlled, it will be disabled.
|
||||
@param[in] device hardware device
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_stop(uint8_t device);
|
||||
|
||||
/**
|
||||
Start CAN layer.
|
||||
Clear all buffers and start CAN.
|
||||
If a CAN transceiver is present and controlled, it will be enabled.
|
||||
@param[in] device hardware device
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_start(uint8_t device);
|
||||
|
||||
/**
|
||||
Get current CAN layer error state.
|
||||
@param[in] device hardware device
|
||||
@param[out] restart_required \a true if CAN layer should be re-started. Pass NULL, if not wanted.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_error_state(uint8_t device, bool * restart_required);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
91
gomspace/libutil/include/gs/util/drivers/gpio/gpio.h
Normal file
91
gomspace/libutil/include/gs/util/drivers/gpio/gpio.h
Normal file
@ -0,0 +1,91 @@
|
||||
#ifndef GS_UTIL_DRIVERS_GPIO_GPIO_H
|
||||
#define GS_UTIL_DRIVERS_GPIO_GPIO_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
GPIO interface provides a generic interface toward hardware GPIO's.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
GPIO definition.
|
||||
*/
|
||||
typedef struct {
|
||||
//! Chip/group/port number which the GPIO belongs to.
|
||||
uint16_t port;
|
||||
//! The pin number of the GPIO.
|
||||
uint16_t pin;
|
||||
} gs_gpio_t;
|
||||
|
||||
/**
|
||||
GPIO interrupt function.
|
||||
*/
|
||||
typedef void (*gs_gpio_isr_t)(gs_context_switch_t * cswitch);
|
||||
|
||||
/**
|
||||
Configuration for interrupt related to a GPIO.
|
||||
*/
|
||||
typedef struct {
|
||||
//! True if it shall trigger on rising edge.
|
||||
bool rising_edge;
|
||||
//! True if it shall trigger on falling edge.
|
||||
bool falling_edge;
|
||||
//! True if it shall have high priority (if nested isr supported).
|
||||
bool high_priority;
|
||||
//! ISR to be called on trigger.
|
||||
gs_gpio_isr_t isr;
|
||||
} gs_interrupt_conf_t;
|
||||
|
||||
/**
|
||||
GPIO get value
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@param[in] value Returned GPIO value (true/false = High/Low)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value);
|
||||
|
||||
/**
|
||||
GPIO get value without error check
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@return GPIO value (true/false = High/Low)
|
||||
*/
|
||||
bool gs_gpio_get_nc(gs_gpio_t gpio);
|
||||
|
||||
/**
|
||||
GPIO set value
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value);
|
||||
|
||||
/**
|
||||
GPIO set value without error check
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
*/
|
||||
void gs_gpio_set_nc(gs_gpio_t gpio, bool value);
|
||||
|
||||
/**
|
||||
Initialize GPIO as an external interrupt pin.
|
||||
|
||||
@param[in] gpio The gpio to configure
|
||||
@param[in] conf Configuration of interrupt pin
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
88
gomspace/libutil/include/gs/util/drivers/i2c/common.h
Normal file
88
gomspace/libutil/include/gs/util/drivers/i2c/common.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef GS_UTIL_DRIVERS_I2C_COMMON_H
|
||||
#define GS_UTIL_DRIVERS_I2C_COMMON_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Common (master and slave) I2C definitions.
|
||||
*/
|
||||
|
||||
#include <gs/util/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Default log group for I2C driver.
|
||||
*/
|
||||
GS_LOG_GROUP_EXTERN(gs_i2c_log);
|
||||
|
||||
/**
|
||||
I2C mode.
|
||||
*/
|
||||
typedef enum {
|
||||
//! Master mode
|
||||
GS_I2C_MASTER = 0,
|
||||
//! Multimaster mode
|
||||
GS_I2C_MULTI_MASTER = 1,
|
||||
//! Slave mode
|
||||
GS_I2C_SLAVE = 2,
|
||||
} gs_i2c_mode_t;
|
||||
|
||||
/**
|
||||
Cross-platform I2C configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
//! Data order, True: MSB first, False: LSB first (default = True)
|
||||
bool data_order_msb;
|
||||
//! Device mode (master, multimaster, or slave)
|
||||
gs_i2c_mode_t mode;
|
||||
//! Address of node in multimaster and slave mode (not used in master mode)
|
||||
uint16_t addr;
|
||||
//! Bits per second (default is #GS_I2C_DEFAULT_BPS)
|
||||
uint32_t bps;
|
||||
//! Address size in bits, 7, 8 or 10 bits (default/prefered is #GS_I2C_DEFAULT_ADDRESS_SIZE)
|
||||
uint8_t addrbits;
|
||||
} gs_i2c_config_t;
|
||||
|
||||
/**
|
||||
Cross-platform I2C configuration.
|
||||
@deprecated use gs_i2c_config_t.
|
||||
*/
|
||||
typedef gs_i2c_config_t gs_i2c_bus_config_t;
|
||||
|
||||
/**
|
||||
Default bit-rate.
|
||||
*/
|
||||
#define GS_I2C_DEFAULT_BPS 100000
|
||||
|
||||
/**
|
||||
Default address size.
|
||||
*/
|
||||
#define GS_I2C_DEFAULT_ADDRESS_SIZE 7
|
||||
|
||||
/**
|
||||
Default data order (MSB).
|
||||
*/
|
||||
#define GS_I2C_DEFAULT_DATA_ORDER_MSB 1
|
||||
|
||||
/**
|
||||
Speed (command line sub-option).
|
||||
*/
|
||||
#define GS_I2C_COMMAND_LINE_SPEED "speed"
|
||||
|
||||
/**
|
||||
Device (command line sub-option).
|
||||
*/
|
||||
#define GS_I2C_COMMAND_LINE_DEVICE "device"
|
||||
|
||||
/**
|
||||
Address (command line sub-option).
|
||||
*/
|
||||
#define GS_I2C_COMMAND_LINE_ADDRESS "address"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
32
gomspace/libutil/include/gs/util/drivers/i2c/master.h
Normal file
32
gomspace/libutil/include/gs/util/drivers/i2c/master.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef GS_UTIL_DRIVERS_I2C_MASTER_H
|
||||
#define GS_UTIL_DRIVERS_I2C_MASTER_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
I2C master interface.
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/i2c/common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Perform transaction to I2C slave.
|
||||
@param[in] device hardware device (bus)
|
||||
@param[in] addr slave address
|
||||
@param[in] tx transmit buffer
|
||||
@param[in] txlen number of bytes to transmit
|
||||
@param[out] rx receive buffer - can be NULL.
|
||||
@param[in] rxlen number of bytes to receive.
|
||||
@param[in] timeout_ms timeout in milliseconds, primarily for locking the I2C channel.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, size_t txlen, void * rx, size_t rxlen, int timeout_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
79
gomspace/libutil/include/gs/util/drivers/i2c/slave.h
Normal file
79
gomspace/libutil/include/gs/util/drivers/i2c/slave.h
Normal file
@ -0,0 +1,79 @@
|
||||
#ifndef GS_UTIL_DRIVERS_I2C_SLAVE_H
|
||||
#define GS_UTIL_DRIVERS_I2C_SLAVE_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
I2C slave interface.
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/i2c/common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Start/enable I2C bus reception.
|
||||
|
||||
Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks.
|
||||
|
||||
@param[in] device I2C bus (handle)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_i2c_slave_start(uint8_t device);
|
||||
|
||||
/**
|
||||
Rx callback.
|
||||
|
||||
Function called when data has been received on the bus (I2C write operation complete).
|
||||
|
||||
@param[in] device I2C bus (handle).
|
||||
@param[in] rx receive buffer.
|
||||
@param[in] rx_length number of bytes received.
|
||||
@param_cswitch
|
||||
*/
|
||||
typedef void (* gs_i2c_slave_receive_t)(uint8_t device, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch);
|
||||
|
||||
/**
|
||||
Set rx callback.
|
||||
|
||||
@param[in] device I2C bus (handle).
|
||||
@param[in] rx Rx callback.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx);
|
||||
|
||||
/**
|
||||
Get rx buffer callback.
|
||||
|
||||
Function called from driver, for getting a pointer to the rx buffer.
|
||||
|
||||
@param[in] device I2C bus (handle).
|
||||
*/
|
||||
typedef void * (* gs_i2c_slave_get_rx_buf_t)(uint8_t device);
|
||||
|
||||
/**
|
||||
Set rx buffer get callback.
|
||||
|
||||
@param[in] device I2C bus (handle).
|
||||
@param[in] get_rx_buf get rx buffer callback.
|
||||
@param[in] buf_length length of buffer retrieved with this callback.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length);
|
||||
|
||||
/**
|
||||
Set response data.
|
||||
|
||||
@param[in] device I2C bus (handle).
|
||||
@param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent.
|
||||
@param[in] tx_length length of data.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
66
gomspace/libutil/include/gs/util/drivers/spi/common.h
Normal file
66
gomspace/libutil/include/gs/util/drivers/spi/common.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef GS_UTIL_DRIVERS_SPI_COMMON_H
|
||||
#define GS_UTIL_DRIVERS_SPI_COMMON_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Common (master and slave) SPI definitions.
|
||||
*/
|
||||
|
||||
#include <gs/util/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Default log group for SPI driver.
|
||||
*/
|
||||
GS_LOG_GROUP_EXTERN(gs_spi_log);
|
||||
|
||||
/**
|
||||
SPI mode - clock polarity and phase.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Polarity = 0, Phase = 0 (default).
|
||||
*/
|
||||
GS_SPI_MODE_CPOL0_CPHA0 = 0,
|
||||
/**
|
||||
Polarity = 0, Phase = 1.
|
||||
*/
|
||||
GS_SPI_MODE_CPOL0_CPHA1 = 1,
|
||||
/**
|
||||
Polarity = 1, Phase = 0.
|
||||
*/
|
||||
GS_SPI_MODE_CPOL1_CPHA0 = 2,
|
||||
/**
|
||||
Polarity = 1, Phase = 1.
|
||||
*/
|
||||
GS_SPI_MODE_CPOL1_CPHA1 = 3
|
||||
} gs_spi_mode_t;
|
||||
|
||||
/**
|
||||
Default bit-rate.
|
||||
*/
|
||||
#define GS_SPI_DEFAULT_BPS 400000
|
||||
|
||||
/**
|
||||
Speed (command line sub-option).
|
||||
*/
|
||||
#define GS_SPI_COMMAND_LINE_SPEED "speed"
|
||||
|
||||
/**
|
||||
Slave (command line sub-option).
|
||||
*/
|
||||
#define GS_SPI_COMMAND_LINE_SLAVE "slave"
|
||||
|
||||
/**
|
||||
Device (command line sub-option).
|
||||
*/
|
||||
#define GS_SPI_COMMAND_LINE_DEVICE "device"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
95
gomspace/libutil/include/gs/util/drivers/spi/master.h
Normal file
95
gomspace/libutil/include/gs/util/drivers/spi/master.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef GS_UTIL_DRIVERS_SPI_MASTER_H
|
||||
#define GS_UTIL_DRIVERS_SPI_MASTER_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
SPI master interface.
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/spi/common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Cross-platform master SPI configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Data order, \a True: MSB first, \a False: LSB first
|
||||
Default: \a True.
|
||||
*/
|
||||
bool data_order_msb;
|
||||
/**
|
||||
Bits per second.
|
||||
Default: #GS_SPI_DEFAULT_BPS.
|
||||
*/
|
||||
uint32_t bps;
|
||||
/**
|
||||
Mode, specifying polarity and phase.
|
||||
Default: #GS_SPI_MODE_CPOL0_CPHA0.
|
||||
*/
|
||||
gs_spi_mode_t mode;
|
||||
/**
|
||||
Character size in bits, 8-16 bits.
|
||||
Default: 8 bits (prefered).
|
||||
*/
|
||||
uint8_t bits;
|
||||
} gs_spi_master_slave_config_t;
|
||||
|
||||
/**
|
||||
Single master transaction.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Pointer to tx data, or NULL if no tx.
|
||||
*/
|
||||
const void *tx;
|
||||
/**
|
||||
Pointer to rx buffer, or NULL if no rx.
|
||||
*/
|
||||
void *rx;
|
||||
/**
|
||||
Size/length of rx/tx (bytes).
|
||||
*/
|
||||
size_t size;
|
||||
} gs_spi_master_trans_t;
|
||||
|
||||
/**
|
||||
Close/free slave.
|
||||
Freeing resources associated with the slave.
|
||||
@param[in] slave SPI slave
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_master_close_slave(uint8_t slave);
|
||||
|
||||
/**
|
||||
Perform transaction to/from a pre-configured SPI slave.
|
||||
Basically for i < size: send tx[i] and receive rx[i].
|
||||
@note: 8 bit SPI character size required!
|
||||
@param[in] slave SPI slave
|
||||
@param[in] tx tx buffer
|
||||
@param[out] rx rx buffer - can be NULL.
|
||||
@param[in] size number of to send and also receive.
|
||||
@param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms);
|
||||
|
||||
/**
|
||||
Perform N transaction to/from a pre-configured SPI slave within one chip selection
|
||||
@note: 8 bit SPI character size required!
|
||||
@param[in] slave SPI slave
|
||||
@param[in] trans Pointer to transactions
|
||||
@param[in] count Number of transactions (rx and/or tx) to complete
|
||||
@param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
84
gomspace/libutil/include/gs/util/drivers/spi/slave.h
Normal file
84
gomspace/libutil/include/gs/util/drivers/spi/slave.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef GS_UTIL_DRIVERS_SPI_SLAVE_H
|
||||
#define GS_UTIL_DRIVERS_SPI_SLAVE_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
SPI slave interface.
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/spi/common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Cross-platform slave SPI configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Data order, \a True: MSB first, \a False: LSB first
|
||||
Default: \a True.
|
||||
*/
|
||||
bool data_order_msb;
|
||||
/**
|
||||
Mode, specifying polarity and phase.
|
||||
Default: #GS_SPI_MODE_CPOL0_CPHA0.
|
||||
*/
|
||||
gs_spi_mode_t mode;
|
||||
/**
|
||||
Character size in bits, 8-16 bits.
|
||||
Default: 8 bits (prefered).
|
||||
*/
|
||||
uint8_t bits;
|
||||
} gs_spi_slave_config_t;
|
||||
|
||||
/**
|
||||
Start/enable SPI device reception.
|
||||
|
||||
Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks.
|
||||
|
||||
@param[in] device SPI device (handle)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_slave_start(uint8_t device);
|
||||
|
||||
/**
|
||||
Rx callback.
|
||||
|
||||
Function called as data is recevied on the device.
|
||||
|
||||
@param[in] device SPI device (handle).
|
||||
@param[in] rx_buffer Pointer to start of rx buffer.
|
||||
@param[in] rx number of bytes received so far.
|
||||
@param[in] new_request \a true on the first callback of new data, \a false on receiving additional data during same \a chip-select. Can be used to bring receiver back in sync with new request.
|
||||
@param_cswitch
|
||||
@return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction.
|
||||
*/
|
||||
typedef uint8_t (* gs_spi_slave_receive_t)(uint8_t device, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch);
|
||||
|
||||
/**
|
||||
Set rx callback.
|
||||
|
||||
@param[in] device SPI device (handle).
|
||||
@param[in] rx Rx callback.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx);
|
||||
|
||||
/**
|
||||
Set response data.
|
||||
|
||||
@param[in] device SPI device (handle).
|
||||
@param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte.
|
||||
@param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent.
|
||||
@param[in] size size of data.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
92
gomspace/libutil/include/gs/util/drivers/sys/memory.h
Normal file
92
gomspace/libutil/include/gs/util/drivers/sys/memory.h
Normal file
@ -0,0 +1,92 @@
|
||||
#ifndef GS_UTIL_DRIVERS_SYS_MEMORY_H
|
||||
#define GS_UTIL_DRIVERS_SYS_MEMORY_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Cross platform memory status API.
|
||||
*/
|
||||
|
||||
#include <gs/util/stdio.h>
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
RAM status
|
||||
Containing different size parameters describing RAM usage.
|
||||
All sizes are in bytes.
|
||||
If a parameter is not available/supported on a specific platform, the parameter is set to -1.
|
||||
*/
|
||||
typedef struct {
|
||||
//! total size of RAM
|
||||
long total;
|
||||
//! max available RAM for allocation after initialization of of global/static variables
|
||||
long max_available;
|
||||
//! available RAM at runtime for dynamic allocation
|
||||
long available;
|
||||
//! Lowest registered available RAM since boot
|
||||
long min_available;
|
||||
} gs_mem_ram_stat_t;
|
||||
|
||||
/**
|
||||
RAM types
|
||||
Defines the different RAM types (external/internal) supported on
|
||||
the various platforms.
|
||||
*/
|
||||
typedef enum {
|
||||
GS_MEM_RAM_TYPE_INTERNAL = 0,//!< Internal RAM type
|
||||
GS_MEM_RAM_TYPE_EXTERNAL //!< External RAM type
|
||||
} gs_mem_ram_type_t;
|
||||
|
||||
/**
|
||||
Get status of internal RAM
|
||||
|
||||
@param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat);
|
||||
|
||||
/**
|
||||
Get status of external RAM
|
||||
|
||||
@param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat);
|
||||
|
||||
|
||||
/**
|
||||
Get status of selected RAM
|
||||
|
||||
@param[in] type RAM type to query status for
|
||||
@param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat);
|
||||
|
||||
|
||||
/**
|
||||
Get default RAM type
|
||||
|
||||
returns the default RAM type used for allocations (Heap).
|
||||
@return gs_mem_ram_type_t
|
||||
*/
|
||||
gs_mem_ram_type_t gs_mem_get_ram_default();
|
||||
|
||||
|
||||
/**
|
||||
Print RAM status.
|
||||
|
||||
@param[in] ram_stat RAM status
|
||||
@param[in] out output stream
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
61
gomspace/libutil/include/gs/util/drivers/watchdog/device.h
Normal file
61
gomspace/libutil/include/gs/util/drivers/watchdog/device.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef GS_UTIL_DRIVERS_HW_WATCHDOG_H
|
||||
#define GS_UTIL_DRIVERS_HW_WATCHDOG_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Hardward watchdog (HWWD) device interface.
|
||||
|
||||
Hardware Watchdog interface which provides a generic interface towards
|
||||
any HWWD. Most HWWD implementation should be able to fit behind
|
||||
this interface, with just a small "adaption" layer needed.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Hardware watchdog driver interface.
|
||||
*/
|
||||
typedef struct gs_watchdog_dev_ops gs_watchdog_dev_ops_t;
|
||||
|
||||
/**
|
||||
Hardware watchdog (HWWD) device structure
|
||||
|
||||
Structure that describes the HWWD device and holds
|
||||
the parameters needed for storing e.g. timeout values etc.
|
||||
*/
|
||||
typedef struct gs_watchdog_device {
|
||||
int id; /**< An ID for the HWWD device - This is currently not used. */
|
||||
const gs_watchdog_dev_ops_t *ops; /**< Pointer to ops struct defining the operations a HWWD device supports. */
|
||||
unsigned int timeout; /**< The timeout value that the HWWD device should be configured with. */
|
||||
unsigned int pretimeout; /**< The pretimeout (if supported) by the HWWD device */
|
||||
unsigned int min_timeout; /**< Minimum timeout value supported by the HWWD device */
|
||||
unsigned int max_timeout; /**< Maximum timeout value supported by the HWWD device */
|
||||
void *driver_data; /**< Pointer to driver specific data can be used by the HWWD driver impl. */
|
||||
} gs_watchdog_device_t;
|
||||
|
||||
/**
|
||||
Hardware watchdog driver interface.
|
||||
*/
|
||||
struct gs_watchdog_dev_ops
|
||||
{
|
||||
/* mandatory operations */
|
||||
gs_error_t (*start)(gs_watchdog_device_t *); /**< Starts the HWWD device */
|
||||
gs_error_t (*stop)(gs_watchdog_device_t *); /**< Stops the HWWD device */
|
||||
gs_error_t (*ping)(gs_watchdog_device_t *); /**< Polls the HWWD device and restart count-down */
|
||||
/* optional operations */
|
||||
gs_error_t (*set_timeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set timeout of the HWWD device */
|
||||
gs_error_t (*set_pretimeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set Pre-timeout of the HWWD device */
|
||||
gs_error_t (*restart)(gs_watchdog_device_t *); /**< (Optional) Restart the HWWD device */
|
||||
unsigned int (*get_timeleft)(gs_watchdog_device_t *); /**< (Optional) Get time left until HWWD device times out. */
|
||||
int (*status)(gs_watchdog_device_t *); /**< (Optional) Reads status of the HWWD device */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
53
gomspace/libutil/include/gs/util/endian.h
Normal file
53
gomspace/libutil/include/gs/util/endian.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef GS_UTIL_ENDIAN_H
|
||||
#define GS_UTIL_ENDIAN_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Detecting endian type.
|
||||
*/
|
||||
|
||||
// generated by waf configure, defines either UTIL_BIG_ENDIAN or UTIL_LITTLE_ENDIAN
|
||||
#include "../../conf_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !UTIL_BIG_ENDIAN && !UTIL_LITTLE_ENDIAN
|
||||
#error No endian defined
|
||||
#endif
|
||||
#if UTIL_BIG_ENDIAN && UTIL_LITTLE_ENDIAN
|
||||
#error Both big and little endian defined
|
||||
#endif
|
||||
|
||||
#include <gs/util/byteorder.h>
|
||||
|
||||
/**
|
||||
Returns \a true if platform is big endian.
|
||||
*/
|
||||
static inline bool gs_endian_big(void)
|
||||
{
|
||||
#if (UTIL_BIG_ENDIAN)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Returns \a true if platform is little endian.
|
||||
*/
|
||||
static inline bool gs_endian_little(void)
|
||||
{
|
||||
#if (UTIL_LITTLE_ENDIAN)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
199
gomspace/libutil/include/gs/util/error.h
Normal file
199
gomspace/libutil/include/gs/util/error.h
Normal file
@ -0,0 +1,199 @@
|
||||
#ifndef GS_UTIL_ERROR_H
|
||||
#define GS_UTIL_ERROR_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Common error code definitions.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Common/generic error codes.
|
||||
Based on POSIX \a errno values, but negative instead of positive.
|
||||
*/
|
||||
typedef enum gs_error_t {
|
||||
/**
|
||||
Success - ok (POSIX).
|
||||
*/
|
||||
GS_OK = 0,
|
||||
/**
|
||||
Operation not permitted (POSIX.1: EPERM).
|
||||
*/
|
||||
GS_ERROR_PERM = -1,
|
||||
/**
|
||||
Interrupted system call (or Interrupted function call) (POSIX: EINTR).
|
||||
*/
|
||||
GS_ERROR_INTR = -4,
|
||||
/**
|
||||
Input/output error (POSIX.1: EIO)
|
||||
*/
|
||||
GS_ERROR_IO = -5,
|
||||
/**
|
||||
Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1: EAGAIN).
|
||||
*/
|
||||
GS_ERROR_AGAIN = -11,
|
||||
/**
|
||||
Cannot allocate memory (or Not enough space) (POSIX.1: ENOMEM).
|
||||
*/
|
||||
GS_ERROR_ALLOC = -12,
|
||||
/**
|
||||
Permission denied (POSIX.1: EACCES).
|
||||
*/
|
||||
GS_ERROR_ACCESS = -13,
|
||||
/**
|
||||
Device or resource busy (POSIX.1: EBUSY).
|
||||
*/
|
||||
GS_ERROR_BUSY = -16,
|
||||
/**
|
||||
File exists (POSIX.1-2001: EEXIST).
|
||||
*/
|
||||
GS_ERROR_EXIST = -17,
|
||||
/**
|
||||
Invalid argument (POSIX.1: EINVAL).
|
||||
*/
|
||||
GS_ERROR_ARG = -22,
|
||||
/**
|
||||
Function not implemented (POSIX.1: ENOSYS)
|
||||
*/
|
||||
GS_ERROR_NOT_IMPLEMENTED = -38,
|
||||
/**
|
||||
Value too large to be stored in data type (POSIX.1: EOVERFLOW).
|
||||
Example: trying to put 50 characters into a 10 character array.
|
||||
@see GS_ERROR_RANGE.
|
||||
*/
|
||||
GS_ERROR_OVERFLOW = -75,
|
||||
/**
|
||||
Operation not supported (POSIX.1: ENOTSUP)
|
||||
*/
|
||||
GS_ERROR_NOT_SUPPORTED = -95,
|
||||
/**
|
||||
Address already in use (POSIX.1: EADDRINUSE).
|
||||
*/
|
||||
GS_ERROR_IN_USE = -98,
|
||||
/**
|
||||
Connection reset (POSIX.1-2001: ECONNRESET).
|
||||
*/
|
||||
GS_ERROR_CONNECTION_RESET = -104,
|
||||
/**
|
||||
No buffer space available (POSIX.1 (XSI STREAMS option): ENOBUFS).
|
||||
*/
|
||||
GS_ERROR_NO_BUFFERS = -105,
|
||||
/**
|
||||
Timeout (POSIX.1-2001: ETIMEDOUT).
|
||||
*/
|
||||
GS_ERROR_TIMEOUT = -110,
|
||||
/**
|
||||
Connection already in progress (POSIX.1-2001: EALREADY).
|
||||
*/
|
||||
GS_ERROR_ALREADY_IN_PROGRESS = -114,
|
||||
|
||||
/**
|
||||
Handle error (GOMspace).
|
||||
*/
|
||||
GS_ERROR_HANDLE = -2000, // from errno.h: #define __ELASTERROR 2000 /* Users can add values starting here */
|
||||
/**
|
||||
Not found (GOMspace).
|
||||
*/
|
||||
GS_ERROR_NOT_FOUND = -2001,
|
||||
/**
|
||||
Full (GOMspace).
|
||||
*/
|
||||
GS_ERROR_FULL = -2002,
|
||||
/**
|
||||
Range error (GOMspace).
|
||||
Example: specifying 120 hours, where only 0-23 is valid.
|
||||
@see GS_ERROR_OVERFLOW
|
||||
*/
|
||||
GS_ERROR_RANGE = -2003,
|
||||
/**
|
||||
Data error (GOMspace).
|
||||
*/
|
||||
GS_ERROR_DATA = -2004,
|
||||
/**
|
||||
Unknown error (GOMspace).
|
||||
@note avoid use - use specific error to improve debugging/troubleshooting.
|
||||
*/
|
||||
GS_ERROR_UNKNOWN = -2005,
|
||||
/**
|
||||
No data available (GOMspace).
|
||||
*/
|
||||
GS_ERROR_NO_DATA = -2006,
|
||||
/**
|
||||
Stale data - not updated (GOMspace).
|
||||
*/
|
||||
GS_ERROR_STALE = -2007,
|
||||
/**
|
||||
Type error (GOMspace).
|
||||
*/
|
||||
GS_ERROR_TYPE = -2008,
|
||||
/**
|
||||
Ambiguous error (GOMspace).
|
||||
*/
|
||||
GS_ERROR_AMBIGUOUS = -2009,
|
||||
/**
|
||||
State error (GOMspace).
|
||||
*/
|
||||
GS_ERROR_STATE = -2010,
|
||||
|
||||
} gs_error_t;
|
||||
|
||||
/**
|
||||
* Convert an error code to a string.
|
||||
* Uses standard POSIX strerror() under the hood.
|
||||
* @param[in] error error to convert. If negative (e.g. \a gs_error_t), it is first converted to a positive value.
|
||||
* @return string usefull for logging purposes (should not be used for programatically processing).
|
||||
*/
|
||||
const char * gs_error_string(int error);
|
||||
|
||||
/**
|
||||
Convert standard POSIX \a errno to gs_error_t.
|
||||
@param[in] error POSIX error code (errno).
|
||||
@return convert error code, by simply converting to a negative number.
|
||||
*/
|
||||
gs_error_t gs_error(int error);
|
||||
|
||||
#if (GS_UTIL_DEPRECATED_ERROR_CODES)
|
||||
/**
|
||||
Legacy error definitions.
|
||||
@deprecated Use standard gs_error_t codes - these defines are only kept, so very old code (not yet update to use #gs_error_t) can compile.
|
||||
@{
|
||||
*/
|
||||
#define E_NO_ERR -1
|
||||
#define E_NO_DEVICE -2
|
||||
#define E_MALLOC_FAIL -3
|
||||
#define E_THREAD_FAIL -4
|
||||
#define E_NO_QUEUE -5
|
||||
#define E_INVALID_BUF_SIZE -6
|
||||
#define E_INVALID_PARAM -7
|
||||
#define E_NO_SS -8
|
||||
#define E_GARBLED_BUFFER -9
|
||||
#define E_FLASH_ERROR -10
|
||||
#define E_BOOT_SER -13
|
||||
#define E_BOOT_DEBUG -14
|
||||
#define E_BOOT_FLASH -15
|
||||
#define E_TIMEOUT -16
|
||||
#define E_NO_BUFFER -17
|
||||
#define E_OUT_OF_MEM -18
|
||||
#define E_FAIL -19
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
Converts legacy error definitions to string.
|
||||
@deprecated Use standard gs_error_t codes - this function is only kept, so very old code (not yet update to use #gs_error_t) can compile.
|
||||
@param[in] code error code
|
||||
@return string describing the error.
|
||||
*/
|
||||
const char * error_string(int code) __attribute__((deprecated));
|
||||
|
||||
#endif // GS_UTIL_DEPRECATED_ERROR_CODES
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
89
gomspace/libutil/include/gs/util/fletcher.h
Normal file
89
gomspace/libutil/include/gs/util/fletcher.h
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef GS_UTIL_FLETCHER_H
|
||||
#define GS_UTIL_FLETCHER_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Fletcher16 checksum,
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Fletcher16 checksum (read using copy function).
|
||||
|
||||
Data is read from \a data, using the specified \a memcpyfcn function.
|
||||
|
||||
@param[in] data data.
|
||||
@param[in] size number of \a data bytes.
|
||||
@param[in] memcpyfcn memory copy function. If NULL is specified, standard memcpy will be used.
|
||||
@returns fletcher16 checksum
|
||||
*/
|
||||
uint16_t gs_fletcher16_memcpy(const void * data, size_t size, void * (*memcpyfcn)(void *, const void *, size_t));
|
||||
|
||||
/**
|
||||
Fletcher16 checksum (read from program memory).
|
||||
|
||||
AVR8: reads from program memory.
|
||||
Other architectures: identical to gs_fletcher16().
|
||||
|
||||
@param[in] data_in data.
|
||||
@param[in] size number of \a data bytes.
|
||||
@returns fletcher16 checksum
|
||||
*/
|
||||
uint16_t gs_fletcher16_P(const void * data_in, size_t size);
|
||||
|
||||
/**
|
||||
Fletcher16 checksum.
|
||||
|
||||
@param[in] data data.
|
||||
@param[in] size number of \a data bytes.
|
||||
@returns fletcher16 checksum
|
||||
*/
|
||||
uint16_t gs_fletcher16(const void * data, size_t size);
|
||||
|
||||
/**
|
||||
Fletcher16 working set.
|
||||
@see gs_fletcher16_init(), gs_fletcher16_update(), gs_fletcher16_finalize()
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Sum1 - internal.
|
||||
*/
|
||||
uint16_t sum1;
|
||||
/**
|
||||
Sum2 - internal.
|
||||
*/
|
||||
uint16_t sum2;
|
||||
} gs_fletcher16_t;
|
||||
|
||||
/**
|
||||
Initialize fletcher16 working set.
|
||||
@param[in] f16 working set.
|
||||
*/
|
||||
void gs_fletcher16_init(gs_fletcher16_t * f16);
|
||||
|
||||
/**
|
||||
Update fletcher16 checksum.
|
||||
@param[in] f16 working set.
|
||||
@param[in] data data.
|
||||
@param[in] size number of \a data bytes.
|
||||
*/
|
||||
void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data, size_t size);
|
||||
|
||||
/**
|
||||
Finalize fletcher16 checksum and return it.
|
||||
|
||||
@param[in] f16 working set.
|
||||
@returns fletcher16 checksum
|
||||
*/
|
||||
uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
79
gomspace/libutil/include/gs/util/function_scheduler.h
Normal file
79
gomspace/libutil/include/gs/util/function_scheduler.h
Normal file
@ -0,0 +1,79 @@
|
||||
#ifndef GS_UTIL_FUNCTION_SCHEDULER
|
||||
#define GS_UTIL_FUNCTION_SCHEDULER
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Function scheduler.
|
||||
|
||||
Simple framework for invoking functions at intervals.
|
||||
|
||||
Instead of creating a lot of tasks (which uses memory), this framework can be used to schedule execution of functions at specified intervals.
|
||||
|
||||
Once setup, calling gs_function_scheduler_execute_ms() will execute all functions timed out and return the time, until the next function has
|
||||
to be executed or max timeout specified (or max wait time supported on the platform).
|
||||
|
||||
The API supports multiple schedulers, but is not thread-safe.
|
||||
|
||||
@note Do NOT use for time critical control, as the actual time interval is influenced by the host thread and other scheduled functions.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Scheduler handle.
|
||||
*/
|
||||
typedef struct gs_function_scheduler gs_function_scheduler_t;
|
||||
|
||||
/**
|
||||
Function callback.
|
||||
|
||||
@return timeout in mS until next callback.
|
||||
*/
|
||||
typedef uint32_t (*gs_function_scheduler_function_t)(void * user_data);
|
||||
|
||||
/**
|
||||
Initialize scheduler.
|
||||
Memory is allocated once for \a max_entries.
|
||||
@param[in] max_timeout_ms max timeout in mS.
|
||||
@param[in] max_entries max number of entries for this scheduler.
|
||||
@param[out] scheduler reference to created scheduler.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** scheduler);
|
||||
|
||||
/**
|
||||
Free scheduler (release resources).
|
||||
@param[in] scheduler scheduler.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler);
|
||||
|
||||
/**
|
||||
Execute scheduled function(s) and returns number of mS until next execute must be called again.
|
||||
|
||||
@note Return type is \a int to prevent overflow on platforms where int is less than 32 bits.
|
||||
|
||||
@param[in] scheduler scheduler.
|
||||
@return next timeout in mS.
|
||||
*/
|
||||
int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler);
|
||||
|
||||
/**
|
||||
Register function to be executed at mS intervals.
|
||||
@param[in] scheduler scheduler.
|
||||
@param[in] first_timeout_ms mS until first execution.
|
||||
@param[in] func function to execute.
|
||||
@param[in] user_data function user data.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
503
gomspace/libutil/include/gs/util/gosh/command.h
Normal file
503
gomspace/libutil/include/gs/util/gosh/command.h
Normal file
@ -0,0 +1,503 @@
|
||||
#ifndef GS_UTIL_GOSH_COMMAND_H
|
||||
#define GS_UTIL_GOSH_COMMAND_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Command framework.
|
||||
|
||||
Provides a simple way of organizing commands in a hierarchy. A command is a text string mapping to a function - supporting arguments.
|
||||
*/
|
||||
|
||||
#include <gs/util/stdio.h>
|
||||
#include <gs/util/pgm.h>
|
||||
#include <gs/util/check.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Max langth of a command (including NUL termination).
|
||||
*/
|
||||
#define GS_COMMAND_MAX_LEN_COMMAND 20
|
||||
|
||||
/**
|
||||
Flag for hiding command in help and tab-complete.
|
||||
*/
|
||||
#define GS_COMMAND_FLAG_HIDDEN 0x02
|
||||
|
||||
/**
|
||||
'root' command attribute.
|
||||
|
||||
On embedded (none Linux) systems, it is prefered to store as much as possible in \a program memory, in order to save RAM.
|
||||
This is accomplished by tagging all \a root commands with this attribute, which instructs the linker to put all commands in a named
|
||||
section. This section is then through the linker-script, placed in \a program memory.
|
||||
The command framework can read commands directly from this section, and therefore doesn't need an RAM to maintain the list.
|
||||
|
||||
The gs_command_register() must still be called for all \a root commands, which ensures that the linker doesn't throw away the
|
||||
command objects, due to missing code reference.
|
||||
|
||||
On a Linux system, the commands are not group in a section. Instead gs_command_register() dynamicly builds a list with the commands.
|
||||
|
||||
@see gs_command_register()
|
||||
*/
|
||||
#if (__linux__ == 0)
|
||||
#define GS_COMMAND_ROOT __attribute__ ((section(".commands")))
|
||||
#else
|
||||
#define GS_COMMAND_ROOT
|
||||
#endif
|
||||
|
||||
/**
|
||||
Sub command attribute,
|
||||
|
||||
Only necesasry on AVR8, due to its memory model.
|
||||
*/
|
||||
#define GS_COMMAND_SUB GS_PGM_OBJECT
|
||||
|
||||
/**
|
||||
Macro for initializing command chains.
|
||||
*/
|
||||
#define GS_COMMAND_INIT_CHAIN(__list) {.list = __list, .count = GS_ARRAY_SIZE(__list)}
|
||||
|
||||
/**
|
||||
Macro for registering commands.
|
||||
|
||||
@see gs_command_register()
|
||||
*/
|
||||
#define GS_COMMAND_REGISTER(__cmd) gs_command_register(__cmd, GS_ARRAY_SIZE(__cmd))
|
||||
|
||||
/**
|
||||
Command reference.
|
||||
@note Use gs_command_t instead of 'struct command'.
|
||||
*/
|
||||
typedef struct command gs_command_t;
|
||||
|
||||
/**
|
||||
Commands context reference
|
||||
@note Use gs_command_context_t instead of struct command_context
|
||||
*/
|
||||
typedef struct command_context gs_command_context_t;
|
||||
|
||||
/**
|
||||
Command output interface
|
||||
*/
|
||||
typedef struct command_io_functions {
|
||||
/**
|
||||
Function interface for setting result
|
||||
@param output_ctx pointer to output context for the given impl.
|
||||
@param group Group name specifies the group that a given key/value pair belongs to.
|
||||
@param key key name
|
||||
@param value string value of the result
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t (*set_result)(gs_command_context_t *ctx, const char *group, const char *key, const char *value);
|
||||
/**
|
||||
Function interface for flushing results. Used by the command handler to ensure output/results
|
||||
are flushed to stdout/File or any other receiver of the output.
|
||||
@param output_ctx pointer to output context for the given impl.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t (*flush)(gs_command_context_t *ctx);
|
||||
/**
|
||||
Function interface for waiting for key/input
|
||||
@param output_ctx pointer to output context for the given impl.
|
||||
@param ch pointer to character returned by function
|
||||
@param timeout_ms maximum time to wait of the character.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t (*wait_for_key)(gs_command_context_t *ctx, int *ch, int timeout_ms);
|
||||
} gs_command_io_functions_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Command context for executing a command.
|
||||
*/
|
||||
struct command_context {
|
||||
/**
|
||||
Input (raw) command line, including arguments.
|
||||
*/
|
||||
const char * command_line;
|
||||
|
||||
/**
|
||||
Command being executed.
|
||||
*/
|
||||
const gs_command_t * command;
|
||||
|
||||
/**
|
||||
Number of arguments (standard argc style).
|
||||
*/
|
||||
int argc;
|
||||
|
||||
/**
|
||||
Argument array (standard argv style).
|
||||
*/
|
||||
char **argv;
|
||||
|
||||
/**
|
||||
FILE handle for capturing stdout from command.
|
||||
*/
|
||||
FILE* out;
|
||||
|
||||
/**
|
||||
getopt variable.
|
||||
*/
|
||||
int optind;
|
||||
|
||||
/**
|
||||
getopt variable.
|
||||
*/
|
||||
int optopt;
|
||||
|
||||
/**
|
||||
getopt variable.
|
||||
*/
|
||||
char *optarg;
|
||||
|
||||
/**
|
||||
getopt variable.
|
||||
*/
|
||||
int optsp;
|
||||
|
||||
/**
|
||||
Function interface for I/O operations
|
||||
*/
|
||||
const gs_command_io_functions_t *io_functions;
|
||||
|
||||
/**
|
||||
Pointer for storing the context used by the I/O functions
|
||||
*/
|
||||
void * io_ctx;
|
||||
};
|
||||
|
||||
/**
|
||||
Command logging call-back
|
||||
|
||||
logs information on the command called.
|
||||
@param[in] cmd_line command line string
|
||||
@param[in] ret return code from command execution framework
|
||||
@param[in] cmd_ret return code from the executed command
|
||||
@param[in] start time_stamp when command execution started.
|
||||
@param[in] end time_stamp when command execution completed.
|
||||
@param[in] ctx context pointer for the logger.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_command_log_t)(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t start, gs_timestamp_t end, void * ctx);
|
||||
|
||||
/**
|
||||
Command handler.
|
||||
*/
|
||||
typedef int (*gs_command_handler_t)(gs_command_context_t * ctx);
|
||||
|
||||
/**
|
||||
Completer call-back (tab complete).
|
||||
|
||||
@param[in] ctx command context.
|
||||
@param[in] arg_to_complete argument to complete
|
||||
@return #GS_OK Found at least 1 match.
|
||||
The \a completer is expected to have completed more of the command line.
|
||||
If the framework detects multiple matches, the framework will proceed as if #GS_ERROR_AMBIGUOUS was returned.
|
||||
The framework doesn't expect anything to be printed to \a out, but will update/refresh the console line.
|
||||
@return #GS_ERROR_AMBIGUOUS Ambiguous - multiple matches or force the framework to show help.
|
||||
The \a completer may have extended/completed more of the command line.
|
||||
The framework expects the \a completer to have printed to \a out, and will show help/usage for the command on a new line.
|
||||
@return #GS_ERROR_NOT_FOUND (or others) No matches found or no more arguments to complete.
|
||||
The framewrok doesn't expect anything to be printed to \a out, and will not update the console.
|
||||
*/
|
||||
typedef gs_error_t (*gs_command_completer_t)(gs_command_context_t * ctx, int arg_to_complete);
|
||||
|
||||
/**
|
||||
Add token - helper to 'tab complete' argument(s).
|
||||
|
||||
@param[in] ctx command context.
|
||||
@param[in] token possible completion - the API will find the common part.
|
||||
@param[in] exact \a true if \a token is an exact match - all other added tokens will be ignored.
|
||||
@return number of tokens added.
|
||||
*/
|
||||
unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact);
|
||||
|
||||
/**
|
||||
Chain element for chaning sub-commands.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Command list.
|
||||
*/
|
||||
const gs_command_t * list;
|
||||
/**
|
||||
Number of commands in the \a list.
|
||||
*/
|
||||
unsigned int count;
|
||||
} gs_command_chain_t;
|
||||
|
||||
/**
|
||||
Signals no command arguments in command definition, see mandatory arguments.
|
||||
*/
|
||||
#define GS_COMMAND_NO_ARGS 255
|
||||
|
||||
/**
|
||||
Command definition.
|
||||
*/
|
||||
struct command {
|
||||
#if (__AVR__)
|
||||
char name[GS_COMMAND_MAX_LEN_COMMAND];
|
||||
char help[50];
|
||||
char usage[50];
|
||||
#else
|
||||
/**
|
||||
Name.
|
||||
*/
|
||||
const char * const name;
|
||||
/**
|
||||
Help text.
|
||||
*/
|
||||
const char * const help;
|
||||
/**
|
||||
Usage text.
|
||||
*/
|
||||
const char * const usage;
|
||||
#endif
|
||||
/**
|
||||
Command handler - the "actual command function".
|
||||
*/
|
||||
gs_command_handler_t handler;
|
||||
#if (__AVR__ == 0)
|
||||
/**
|
||||
Completer function - helps completing an argument.
|
||||
*/
|
||||
gs_command_completer_t completer;
|
||||
#endif
|
||||
/**
|
||||
Sub-command (if any).
|
||||
*/
|
||||
gs_command_chain_t chain;
|
||||
/**
|
||||
Mode/flags.
|
||||
See #GS_COMMAND_FLAG_HIDDEN.
|
||||
*/
|
||||
unsigned int mode;
|
||||
/**
|
||||
Number of mandatory (minimum) arguments.
|
||||
|
||||
@note Due to backwards compatibility, 0 (zero) cannot be used to signal no arguments - use #GS_COMMAND_NO_ARGS instead, if command doesn't take any arguments (mandatory or optional).
|
||||
*/
|
||||
uint8_t mandatory_args;
|
||||
/**
|
||||
Number of optional arguments.
|
||||
*/
|
||||
uint8_t optional_args;
|
||||
/**
|
||||
Filler for future use.
|
||||
*/
|
||||
uint8_t filler[2];
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the arguments as a string, where arguments are separated by spaces.
|
||||
@param ctx command context.
|
||||
@return Pointer to concatenated arguments
|
||||
*/
|
||||
const char * gs_command_args(gs_command_context_t *ctx);
|
||||
|
||||
/**
|
||||
Execute command.
|
||||
@deprecated Replaced by gs_command_execute & gs_command_execute_stdio
|
||||
|
||||
Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return
|
||||
result is stored in \a command_result.
|
||||
|
||||
@param[in] command Command to execute, including arguments separated by spaces.
|
||||
@param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result.
|
||||
@return #GS_ERROR_NOT_FOUND if command wasn't found.
|
||||
@return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_run(const char * command, gs_error_t * command_result);
|
||||
|
||||
/**
|
||||
Execute command.
|
||||
|
||||
Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return
|
||||
result is stored in \a command_result.
|
||||
|
||||
@param[in] command Command to execute, including arguments separated by spaces.
|
||||
@param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result.
|
||||
@param[in] out output (FILE) stream
|
||||
@param[in] iof Pointer to function interface of IO operations
|
||||
@param[in] iof_ctx Pointer to context used by the IO function interface
|
||||
@return #GS_ERROR_NOT_FOUND if command wasn't found.
|
||||
@return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_execute(const char * command, gs_error_t * command_result, FILE *out, const gs_command_io_functions_t * iof, void * iof_ctx);
|
||||
|
||||
/**
|
||||
Execute command.
|
||||
|
||||
Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return
|
||||
result is stored in \a command_result. The results are printed on stdout and input captured on stdin.
|
||||
|
||||
@param[in] command Command to execute, including arguments separated by spaces.
|
||||
@param[out] command_result Result from command. Use \a NULL to ignore result.
|
||||
@return #GS_OK if command was executed - result returned in \a command_result. Otherwise an error indicating why the command wasn't executed.
|
||||
*/
|
||||
gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * command_result);
|
||||
|
||||
/**
|
||||
Set output
|
||||
|
||||
Sets output from command, using the io function struct in ctx.
|
||||
|
||||
@param[in] ctx the command context
|
||||
@param[in] group a string specifying the group of the result. Leave blank if not used.
|
||||
@param[in] key a string specifying the key/name of the result variable.
|
||||
@param[in] value a string representation of the result value.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value);
|
||||
|
||||
/**
|
||||
Set output
|
||||
|
||||
Sets output from command using printf formatting, using the io function struct in ctx.
|
||||
|
||||
@param[in] ctx the command context
|
||||
@param[in] group a string specifying the group of the result. Leave blank if not used.
|
||||
@param[in] key a string specifying the key/name of the result variable.
|
||||
@param[in] format printf syntax for formatting data
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...);
|
||||
|
||||
/**
|
||||
Flush output/Results
|
||||
|
||||
Instruct the command output stream & results to be flushed from it's buffers.
|
||||
|
||||
@param[in] ctx the command context
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_flush_output(gs_command_context_t *ctx);
|
||||
|
||||
/**
|
||||
Wait for any key input
|
||||
|
||||
Instruct the command input stream to wait for any key.
|
||||
|
||||
@param[in] ctx the command context
|
||||
@param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds.
|
||||
@return true if command should proceed (either because of key press present or if no input stream available)
|
||||
*/
|
||||
bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms);
|
||||
|
||||
/**
|
||||
Wait for key input
|
||||
|
||||
Instruct the io stream to wait for a key, and return the pressed key in ch.
|
||||
|
||||
@param[in] ctx the command context
|
||||
@param[out] ch the character that was read on the input stream
|
||||
@param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds.
|
||||
@return #GS_OK if key was read
|
||||
@return #GS_ERROR_HANDLE if no input stream is present
|
||||
@return #GS_ERROR_TIMEOUT on timeout.
|
||||
*/
|
||||
gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms);
|
||||
|
||||
/**
|
||||
Register commands.
|
||||
|
||||
gs_command_init() must be called prior to registering any commands.
|
||||
|
||||
See #GS_COMMAND_ROOT for details.
|
||||
|
||||
@param[in] cmds Pointer to command array
|
||||
@param[in] cmd_count Number of commands in command array
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_register(const gs_command_t * cmds, size_t cmd_count);
|
||||
|
||||
/**
|
||||
Initialize command system and register default commands.
|
||||
|
||||
Registers following commands: gs_log_register_commands() and gs_command_register_default_commands().
|
||||
|
||||
@param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux.
|
||||
@return_gs_error_t
|
||||
@see gs_command_init_no_commands()
|
||||
*/
|
||||
gs_error_t gs_command_init(size_t min_stack_size);
|
||||
|
||||
/**
|
||||
Initialize command system (without any default commands).
|
||||
|
||||
@param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux.
|
||||
@return_gs_error_t
|
||||
@see gs_command_init()
|
||||
*/
|
||||
gs_error_t gs_command_init_no_commands(size_t min_stack_size);
|
||||
|
||||
|
||||
/**
|
||||
Register a call-back used for logging of command execution.
|
||||
|
||||
@param[in] log_cb the logging call back.
|
||||
@param[in] log_ctx pointer to context data. Set to NULL if not used.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx);
|
||||
|
||||
/**
|
||||
Default implementation of the command logger, that can be used if no other
|
||||
custom command logger is provided by the system.
|
||||
|
||||
@param[in] cmd_line command line string
|
||||
@param[in] ret return code provided by the command execution function.
|
||||
@param[in] cmd_ret return code provided by the executed command.
|
||||
@param[in] t_start time stamp when command execution started.
|
||||
@param[in] t_end time stamp when command execution completed.
|
||||
@param[in] log_ctx context for the command logger.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void * log_ctx);
|
||||
|
||||
/**
|
||||
Return minimum stack size.
|
||||
@return minimm stack size required for executing commands. The minimum stack size is set by call to gs_command_init().
|
||||
*/
|
||||
size_t gs_command_get_stack_size(void);
|
||||
|
||||
/**
|
||||
Register set of default commands.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_command_register_default_commands(void);
|
||||
|
||||
/**
|
||||
Split line into argc/argv.
|
||||
|
||||
@param[in] line line to split - the line will be chop up into argv.
|
||||
@param[out] argc argc count.
|
||||
@param[out] argv argv array.
|
||||
@param[in] max_argc max argv elements.
|
||||
@return \a true if successfull, else \a false.
|
||||
*/
|
||||
bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc);
|
||||
|
||||
/**
|
||||
Parse options.
|
||||
|
||||
Adapted from AT&T public domain source from:
|
||||
http://www.informatica.co.cr/unix-source-code/research/1985/1103.html
|
||||
|
||||
@param[in] ctx command context.
|
||||
@param[in] opts options
|
||||
@return option character
|
||||
*/
|
||||
int gs_command_getopt(gs_command_context_t *ctx, const char *opts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
123
gomspace/libutil/include/gs/util/gosh/console.h
Normal file
123
gomspace/libutil/include/gs/util/gosh/console.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
#ifndef GS_UTIL_GOSH_CONSOLE_H
|
||||
#define GS_UTIL_GOSH_CONSOLE_H
|
||||
/**
|
||||
@file
|
||||
|
||||
Console (stdin/stdout) interface for running commands.
|
||||
|
||||
This assumes a VT102 terminal emulator, and tries to fix some of minicom's quirks with e.g. home/end keys.
|
||||
*/
|
||||
|
||||
#include <gs/util/thread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Initialize the API and console.
|
||||
|
||||
@deprecated version 3.4, use gs_console_start()
|
||||
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_console_init(void);
|
||||
|
||||
/**
|
||||
Restores terminal settings (only relevant on Linux).
|
||||
|
||||
@deprecated version 3.4, this is handled by an installed exit-handler in gs_console_start().
|
||||
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_console_exit(void);
|
||||
|
||||
/**
|
||||
Set console prompt.
|
||||
|
||||
@param[in] prompt user prompt - the API only stores the pointer, so do not modify/delete content. NULL or empty string is ignored (no change).
|
||||
*/
|
||||
void gs_console_set_prompt(const char * prompt);
|
||||
|
||||
/**
|
||||
Clear the console screen
|
||||
*/
|
||||
void gs_console_clear(void);
|
||||
|
||||
/**
|
||||
Update console.
|
||||
*/
|
||||
void gs_console_update(void);
|
||||
|
||||
/**
|
||||
Create console thread.
|
||||
|
||||
The console thread reads from stdin and writes to stdout.
|
||||
|
||||
The thread is created with low priority, #GS_THREAD_PRIORITY_LOW.
|
||||
|
||||
@deprecated version 3.4, use gs_console_start()
|
||||
|
||||
@param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_console_create_thread(gs_thread_t * handle);
|
||||
|
||||
/**
|
||||
Create console thread with priority.
|
||||
|
||||
The console thread reads from stdin and writes to stdout.
|
||||
|
||||
@deprecated version 3.4, use gs_console_start()
|
||||
|
||||
@param[in] priority thread priority, normally #GS_THREAD_PRIORITY_LOW.
|
||||
@param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle);
|
||||
|
||||
/**
|
||||
@anchor GS_CONSOLE_F
|
||||
@defgroup GS_CONSOLE_F Console flags.
|
||||
Use with gs_console_start() to configure behaviour.
|
||||
@{
|
||||
*/
|
||||
/**
|
||||
Linux only: no signal handlers installed (e.g. to catch SIG_TERM).
|
||||
@see gs_console_start()
|
||||
*/
|
||||
#define GS_CONSOLE_F_NO_SIGNAL_HANDLER 0x0001
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
Start console thread (priority: #GS_THREAD_PRIORITY_LOW).
|
||||
|
||||
The console thread reads from stdin and writes to stdout. The thread is created with low priority, #GS_THREAD_PRIORITY_LOW.
|
||||
|
||||
Linux: Changes terminal settings and installs an atexit() handler to restore the settings, Signal handlers will be installed to catch SIG_TERM -> exit() and ignore SIG_INT (controlled by option on command line) - unless #GS_CONSOLE_F_NO_SIGNAL_HANDLER is specified.
|
||||
|
||||
@param[in] prompt set console prompt by calling gs_console_set_prompt().
|
||||
@param[in] flags configure behaviour, see @ref GS_CONSOLE_F definitions.
|
||||
@return #GS_ERROR_EXIST if console thread already created.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_console_start(const char * prompt, uint32_t flags);
|
||||
|
||||
/**
|
||||
Stop (and join with) console thread.
|
||||
|
||||
@note This is only supported on Linux.
|
||||
|
||||
The thread is interrupted using pthread_cancel(), which does not guarantee \a clean shutdown if the thread is busy executing a command.
|
||||
|
||||
@return #GS_ERROR_NOT_SUPPORTED if not supported on current platform.
|
||||
@return #GS_ERROR_HANDLE if no console has been started with gs_console_start().
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_console_stop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
53
gomspace/libutil/include/gs/util/hexdump.h
Normal file
53
gomspace/libutil/include/gs/util/hexdump.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef GS_UTIL_HEXDUMP_H
|
||||
#define GS_UTIL_HEXDUMP_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Dump memory as hex numbers and ascii characters.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Dump memory to an output stream.
|
||||
@param[in] src memory address.
|
||||
@param[in] len number of bytes to dump.
|
||||
@param[in] disp_addr display address, used instead of \a src.
|
||||
@param[in] out output stream.
|
||||
*/
|
||||
void gs_hexdump_to_stream(const void * src, size_t len, const void * disp_addr, FILE* out);
|
||||
|
||||
/**
|
||||
Dump memory on stdout.
|
||||
|
||||
@param[in] src memory address.
|
||||
@param[in] len number of bytes to dump.
|
||||
*/
|
||||
static inline void gs_hexdump(const void *src, size_t len)
|
||||
{
|
||||
gs_hexdump_to_stream(src, len, src, stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
Dump memory on stdout.
|
||||
@param[in] src memory address.
|
||||
@param[in] len number of bytes to dump.
|
||||
@param[in] disp_addr display address, used instead of \a src.
|
||||
*/
|
||||
static inline void gs_hexdump_addr(const void * src, size_t len, const void * disp_addr)
|
||||
{
|
||||
gs_hexdump_to_stream(src, len, disp_addr, stdout);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
40
gomspace/libutil/include/gs/util/linux/argp.h
Normal file
40
gomspace/libutil/include/gs/util/linux/argp.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef GS_UTIL_LINUX_ARGP_H
|
||||
#define GS_UTIL_LINUX_ARGP_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Extensions to GNU argp parser (convenience functions).
|
||||
*/
|
||||
|
||||
#include <argp.h>
|
||||
#include <gs/util/linux/exitcode.h>
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Wrapper for argp_parse.
|
||||
|
||||
This function will call exit/terminate the process, if parsing fails.
|
||||
|
||||
\a argv may be re-organized.
|
||||
|
||||
@param[in] argp argp struct.
|
||||
@param[in] argc argument count, i.e. standard argc.
|
||||
@param[in] argv argument array, i.e. standard argv.
|
||||
@param[in] flags future use.
|
||||
@param[out] arg_index first unparsed option (-> argv modified).
|
||||
@param[in] revision program revision, e.g. 3.0.1-12-g0cf1b59+.
|
||||
*/
|
||||
void gs_argp_parse(const struct argp * argp,
|
||||
int argc, char ** argv,
|
||||
unsigned int flags, int * arg_index,
|
||||
const char * revision);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
42
gomspace/libutil/include/gs/util/linux/command_line.h
Normal file
42
gomspace/libutil/include/gs/util/linux/command_line.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef GS_UTIL_LINUX_COMMAND_LINE_H
|
||||
#define GS_UTIL_LINUX_COMMAND_LINE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Command line support.
|
||||
*/
|
||||
|
||||
#include <gs/util/linux/argp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Command line options for ignoring CTRL-C
|
||||
*/
|
||||
extern const struct argp_child gs_console_command_line_ignore_ctrlc_argp;
|
||||
|
||||
/**
|
||||
Command line options for adding -h (help).
|
||||
*/
|
||||
const struct argp_child gs_help_command_line_argp;
|
||||
|
||||
/**
|
||||
Return if ctrl-c ignored on command line.
|
||||
@return \a true i ctrl-c ignored.
|
||||
*/
|
||||
bool gs_command_line_ignore_ctrlc(void);
|
||||
|
||||
/**
|
||||
Return program name based on argv[0].
|
||||
@param[in] argv expected to be argv[0] amd point to the program name (possibly with full path).
|
||||
@return program name.
|
||||
*/
|
||||
const char * gs_command_line_program_name(const char * argv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
29
gomspace/libutil/include/gs/util/linux/drivers/can/can.h
Normal file
29
gomspace/libutil/include/gs/util/linux/drivers/can/can.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef GS_UTIL_LINUX_DRIVERS_CAN_CAN_H
|
||||
#define GS_UTIL_LINUX_DRIVERS_CAN_CAN_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Linux CAN interface.
|
||||
|
||||
@note Only 1 filter/mask can be set, using gs_can_set_standard_filter_mask() or gs_can_set_extended_filter_mask()
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/can/can.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Open and initialize a CAN handle.
|
||||
@param[in] ifname name of CAN interface.
|
||||
@param[out] handle opened CAN handle.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_can_open(const char * ifname, int * handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
146
gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h
Normal file
146
gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h
Normal file
@ -0,0 +1,146 @@
|
||||
#ifndef GS_UTIL_LINUX_DRIVERS_GPIO_H
|
||||
#define GS_UTIL_LINUX_DRIVERS_GPIO_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
@brief GPIO interface
|
||||
|
||||
GPIO interface provides a generic interface where specific GPIO drivers can be plugged in.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <gs/util/drivers/gpio/gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
GomSpace linux driver GPIO get value
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@param[in] value Returned GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to specific driver
|
||||
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_gpio_get_t)(gs_gpio_t gpio, bool *value, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver GPIO get value without error check
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@param[in] driver_data data to specific driver
|
||||
|
||||
@return GPIO value (true/false = High/Low)
|
||||
*/
|
||||
typedef bool (*gs_gpio_get_nc_t)(gs_gpio_t gpio, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver GPIO set value
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to specific driver
|
||||
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_gpio_set_t)(gs_gpio_t gpio, bool value, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver GPIO set value without error check
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to specific driver
|
||||
*/
|
||||
typedef void (*gs_gpio_set_nc_t)(gs_gpio_t gpio, bool value, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver initialize GPIO as an external interrupt pin
|
||||
|
||||
@param[in] gpio The gpio to configure
|
||||
@param[in] conf Configuration of interrupt pin
|
||||
@param[in] driver_data data to specific driver
|
||||
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_gpio_init_as_interrupt_t)(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data);
|
||||
|
||||
|
||||
/**
|
||||
Every port.
|
||||
*/
|
||||
#define GS_GPIO_ALL_PORTS UINT16_MAX
|
||||
|
||||
/**
|
||||
Every pin.
|
||||
*/
|
||||
#define GS_GPIO_ALL_PINS UINT16_MAX
|
||||
|
||||
/**
|
||||
GPIO driver.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Function for handling GPIO get.
|
||||
*/
|
||||
gs_gpio_get_t get_handler;
|
||||
/**
|
||||
Function for handling GPIO get no check.
|
||||
*/
|
||||
gs_gpio_get_nc_t get_nc_handler;
|
||||
/**
|
||||
Function for handling GPIO set.
|
||||
*/
|
||||
gs_gpio_set_t set_handler;
|
||||
/**
|
||||
Function for handling GPIO set no check.
|
||||
*/
|
||||
gs_gpio_set_nc_t set_nc_handler;
|
||||
/**
|
||||
Function for handling GPIO initialize as interrupt.
|
||||
*/
|
||||
gs_gpio_init_as_interrupt_t init_as_interrupt_handler;
|
||||
} gs_gpio_driver_t;
|
||||
|
||||
|
||||
/**
|
||||
GPIO driver entry
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
GPIO port, to which the driver is used (if GS_GPIO_ALL_PORTS, then all ports uses this driver).
|
||||
*/
|
||||
uint16_t port;
|
||||
/**
|
||||
GPIO pin, to which the driver is used (if GS_GPIO_ALL_PINS, then all pins uses this driver).
|
||||
*/
|
||||
uint16_t pin;
|
||||
/**
|
||||
GPIO driver.
|
||||
*/
|
||||
const gs_gpio_driver_t * driver;
|
||||
/**
|
||||
Driver specific data.
|
||||
*/
|
||||
void * driver_data;
|
||||
} gs_gpio_driver_entry_t;
|
||||
|
||||
/**
|
||||
Register a driver.
|
||||
|
||||
A specific driver can be assigned to a port and pin or it can be assigned to all pins and/or all ports.
|
||||
|
||||
The latest registered driver, which fit the GPIO, is the one used.
|
||||
|
||||
@param[in] driver_entry driver and configuration to be registered
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,91 @@
|
||||
#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_
|
||||
#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
@brief Linux GPIO driver based on sysfs.
|
||||
This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h'
|
||||
*/
|
||||
|
||||
#include <gs/util/linux/drivers/gpio/gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
GPIO sysfs driver data.
|
||||
|
||||
@note Driver takes no driver data, so a NULL pointer is valid
|
||||
*/
|
||||
typedef void * gs_gpio_sysfs_driver_data_t;
|
||||
|
||||
/**
|
||||
GPIO sysfs driver interface.
|
||||
*/
|
||||
extern const gs_gpio_driver_t gs_gpio_sysfs_driver;
|
||||
|
||||
/**
|
||||
GPIO sysfs initialize
|
||||
|
||||
@param[in] gpio The gpio to initialize
|
||||
@param[in] output Direction of pin (True/False = Output/Input)
|
||||
@param[in] init_value Pin state if configured as output (True/False = High/Low)
|
||||
@param[in] active_low if set pin is configured as active low (so a gs_gpio_sysfs_set with 1 will actually set value low)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output, bool init_value, bool active_low);
|
||||
|
||||
/**
|
||||
GPIO sysfs get value
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@param[in] value Returned GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data);
|
||||
|
||||
/**
|
||||
GPIO sysfs get value without error check
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return GPIO value (true/false = High/Low)
|
||||
*/
|
||||
bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data);
|
||||
|
||||
/**
|
||||
GPIO sysfs set value
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data);
|
||||
|
||||
/**
|
||||
GPIO sysfs set value without error check
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to driver (not used)
|
||||
*/
|
||||
void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data);
|
||||
|
||||
/**
|
||||
Initialize GPIO sysfs as an external interrupt pin
|
||||
|
||||
@param[in] gpio The gpio to configure
|
||||
@param[in] conf Configuration of interrupt pin
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,125 @@
|
||||
#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_
|
||||
#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
@brief Linux GPIO driver to be used in unit tests.
|
||||
This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h'
|
||||
*/
|
||||
|
||||
#include <gs/util/linux/drivers/gpio/gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
GPIO virtual driver data.
|
||||
|
||||
@note Driver takes no driver data, so a NULL pointer is valid
|
||||
*/
|
||||
typedef void * gs_gpio_virtual_driver_data_t;
|
||||
|
||||
/**
|
||||
GPIO virtual driver interface.
|
||||
*/
|
||||
extern const gs_gpio_driver_t gs_gpio_virtual_driver;
|
||||
|
||||
/**
|
||||
GPIO virtual driver entry, where all ports and pins are routed to virtual driver
|
||||
*/
|
||||
extern const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all;
|
||||
|
||||
/**
|
||||
GPIO virtual initialize
|
||||
|
||||
@param[in] gpio The gpio to initialize
|
||||
@param[in] output Direction of pin (True/False = Output/Input)
|
||||
@param[in] value Pin state if configured as output (True/False = High/Low)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value);
|
||||
|
||||
/**
|
||||
GPIO virtual get value
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@param[in] value Returned GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data);
|
||||
|
||||
/**
|
||||
GPIO virtual get value without error check
|
||||
|
||||
@param[in] gpio The gpio to read
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return GPIO value (true/false = High/Low)
|
||||
*/
|
||||
bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data);
|
||||
|
||||
/**
|
||||
GPIO virtual set value
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data);
|
||||
|
||||
/**
|
||||
GPIO virtual set value without error check
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@param[in] driver_data data to driver (not used)
|
||||
*/
|
||||
void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data);
|
||||
|
||||
/**
|
||||
Initialize GPIO virtual as an external interrupt pin
|
||||
|
||||
@param[in] gpio The gpio to configure
|
||||
@param[in] conf Configuration of interrupt pin
|
||||
@param[in] driver_data data to driver (not used)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data);
|
||||
|
||||
/**
|
||||
Force set a pin
|
||||
|
||||
This sets a pin regardless if it is configured as input, output or interrupt
|
||||
If the pin is configured as interrupt, the registered ISR's will be called within this function,
|
||||
if the transition matches (rising/falling)
|
||||
|
||||
@note This function is specific to this driver and is should not be registered.
|
||||
|
||||
@param[in] gpio The gpio to set
|
||||
@param[in] value GPIO value (true/false = High/Low)
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value);
|
||||
|
||||
/**
|
||||
Get transitions
|
||||
|
||||
This gives the number of transitions ((high -> low) + (low -> high)),
|
||||
since last time this function was called at this pin. This function resets the counter of the pin.
|
||||
An even number means, that the pin has the same state as it was initialized to.
|
||||
|
||||
@note This function is specific to this driver and should not be registered
|
||||
|
||||
@param[in] gpio The gpio, of which transitions are given
|
||||
@param[out] transitions Number of transitions
|
||||
@return
|
||||
*/
|
||||
gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
198
gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h
Normal file
198
gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h
Normal file
@ -0,0 +1,198 @@
|
||||
#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_
|
||||
#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
@brief Linux I2C plugin driver
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/i2c/master.h>
|
||||
#include <gs/util/drivers/i2c/slave.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
GomSpace linux driver I2C master transaction.
|
||||
|
||||
@see 'gs/util/drivers/i2c/master.h'
|
||||
|
||||
@param[in] device I2C device
|
||||
@param[in] addr I2C address
|
||||
@param[in] tx tx buffer
|
||||
@param[in] txlen bytes to be sent
|
||||
@param[out] rx rx buffer
|
||||
@param[in] rxlen bytes to be received
|
||||
@param[in] timeout_ms timeout in milliseconds
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_i2c_master_transaction_t)(uint8_t device, uint8_t addr, const void * tx, size_t txlen,
|
||||
void * rx, size_t rxlen, int timeout_ms, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver I2C slave start.
|
||||
|
||||
@see 'gs/util/drivers/i2c/slave.h'
|
||||
|
||||
@param[in] device I2C device
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_i2c_slave_start_t)(uint8_t device, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver I2C set rx callback
|
||||
|
||||
@see 'gs/util/drivers/i2c/slave.h'
|
||||
|
||||
@param[in] device I2C device
|
||||
@param[in] rx rx callback
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_i2c_slave_set_rx_t)(uint8_t device, gs_i2c_slave_receive_t rx, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver I2C slave set 'get_rx_buffer' callback.
|
||||
|
||||
@see 'gs/util/drivers/i2c/slave.h'
|
||||
|
||||
@param[in] device I2C device
|
||||
@param[in] get_rx_buf get_rx_buf callback
|
||||
@param[in] buf_length length of buffer received by calling callback
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_i2c_slave_set_get_rx_buf_t)(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length, void * driver_data);
|
||||
|
||||
/**
|
||||
GomSpace linux driver I2C slave set slave response.
|
||||
|
||||
@see 'gs/util/drivers/i2c/slave.h'
|
||||
|
||||
@param[in] device I2C device
|
||||
@param[in] tx tx buffer
|
||||
@param[in] tx_length bytes to be send
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_i2c_slave_set_response_t)(uint8_t device, const uint8_t * tx, size_t tx_length, void * driver_data);
|
||||
|
||||
/**
|
||||
Every I2C device ([0 : 254]).
|
||||
*/
|
||||
#define GS_I2C_ALL_DEVICES 255
|
||||
|
||||
/**
|
||||
Every I2C address (0 : 127]).
|
||||
*/
|
||||
#define GS_I2C_ALL_ADDR 255
|
||||
|
||||
/**
|
||||
I2C master driver.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Function for handling master transactions.
|
||||
*/
|
||||
gs_i2c_master_transaction_t master_transaction_handler;
|
||||
} gs_i2c_master_driver_t;
|
||||
|
||||
|
||||
/**
|
||||
I2C master driver entry
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver).
|
||||
*/
|
||||
uint8_t device;
|
||||
/**
|
||||
I2C addr, to which the driver is used (if GS_I2C_ALL_ADDR, then all addr on given device uses this driver).
|
||||
*/
|
||||
uint8_t addr;
|
||||
/**
|
||||
I2C master driver.
|
||||
*/
|
||||
const gs_i2c_master_driver_t * driver;
|
||||
/**
|
||||
Driver specific data.
|
||||
*/
|
||||
void * driver_data;
|
||||
} gs_i2c_master_driver_entry_t;
|
||||
|
||||
|
||||
/**
|
||||
I2C slave driver
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Function for handling slave start.
|
||||
*/
|
||||
gs_i2c_slave_start_t start_handler;
|
||||
/**
|
||||
Function for handling the 'setting of rx callback'.
|
||||
*/
|
||||
gs_i2c_slave_set_rx_t set_rx_handler;
|
||||
/**
|
||||
Function for handling setting of an 'rx buff get' function.
|
||||
*/
|
||||
gs_i2c_slave_set_get_rx_buf_t set_get_rx_buf_handler;
|
||||
/**
|
||||
Function for handling 'set response'.
|
||||
*/
|
||||
gs_i2c_slave_set_response_t set_response_handler;
|
||||
} gs_i2c_slave_driver_t;
|
||||
|
||||
|
||||
/**
|
||||
I2C slave driver entry.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver).
|
||||
*/
|
||||
uint8_t device;
|
||||
/**
|
||||
I2C slave driver.
|
||||
*/
|
||||
const gs_i2c_slave_driver_t * driver;
|
||||
/**
|
||||
Driver specific data.
|
||||
*/
|
||||
void * driver_data;
|
||||
} gs_i2c_slave_driver_entry_t;
|
||||
|
||||
|
||||
/**
|
||||
Register a master driver.
|
||||
|
||||
A specific driver can be assigned to a specific address and device
|
||||
or it can be registered to every address on a device or every address on every device.
|
||||
|
||||
The latest registered driver, which fit the device an address, is the one used.
|
||||
|
||||
@param[in] driver_entry driver and configuration to be registered
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry);
|
||||
|
||||
/**
|
||||
Register a slave driver
|
||||
|
||||
A specific driver can be assigned to a specific device or a driver can be assigned to every device.
|
||||
|
||||
The latest registered driver, which fit the device, is the one used.
|
||||
|
||||
@param[in] driver_entry driver and configuration to be registered
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
175
gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h
Normal file
175
gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h
Normal file
@ -0,0 +1,175 @@
|
||||
#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_
|
||||
#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Linux SPI plugin driver
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/spi/master.h>
|
||||
#include <gs/util/drivers/spi/slave.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Linux driver SPI master transactions.
|
||||
|
||||
@see 'gs/util/drivers/spi/master.h'
|
||||
|
||||
@param[in] slave SPI slave
|
||||
@param[in] trans Pointer to transactions
|
||||
@param[in] count Number of transactions (rx and/or tx) to complete
|
||||
@param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device.
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_spi_master_transactions_t)(uint8_t slave, gs_spi_master_trans_t *trans, size_t count,
|
||||
int timeout_ms, void * driver_data);
|
||||
|
||||
/**
|
||||
Linux driver SPI slave start.
|
||||
|
||||
@see 'gs/util/drivers/spi/slave.h'
|
||||
|
||||
@param[in] device SPI device (handle)
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_spi_slave_start_t)(uint8_t device, void * driver_data);
|
||||
|
||||
/**
|
||||
Linux driver SPI set rx callback
|
||||
|
||||
@see 'gs/util/drivers/spi/slave.h'
|
||||
|
||||
@param[in] device SPI device (handle).
|
||||
@param[in] rx Rx callback.
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_spi_slave_set_rx_t)(uint8_t device, gs_spi_slave_receive_t rx, void * driver_data);
|
||||
|
||||
/**
|
||||
Linux driver SPI slave set slave response.
|
||||
|
||||
@see 'gs/util/drivers/spi/slave.h'
|
||||
|
||||
@param[in] device SPI device (handle).
|
||||
@param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte.
|
||||
@param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent.
|
||||
@param[in] size size of data.
|
||||
@param[in] driver_data data to specific driver
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (* gs_spi_slave_set_response_t)(uint8_t device, size_t offset, const uint8_t * tx, size_t size, void * driver_data);
|
||||
|
||||
/**
|
||||
Every SPI slave ([0 : 254]).
|
||||
*/
|
||||
#define GS_SPI_ALL_SLAVES 255
|
||||
|
||||
/**
|
||||
Every SPI device (0 : 254]).
|
||||
*/
|
||||
#define GS_SPI_ALL_DEVICES 255
|
||||
|
||||
|
||||
/**
|
||||
SPI master driver.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Function for handling master transactions.
|
||||
*/
|
||||
gs_spi_master_transactions_t master_transactions_handler;
|
||||
} gs_spi_master_driver_t;
|
||||
|
||||
|
||||
/**
|
||||
SPI master driver entry
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
SPI slave, to which the driver is used (if #GS_SPI_ALL_SLAVES, then all slaves uses this driver).
|
||||
*/
|
||||
uint8_t slave;
|
||||
/**
|
||||
SPI master driver.
|
||||
*/
|
||||
const gs_spi_master_driver_t * driver;
|
||||
/**
|
||||
Driver specific data.
|
||||
*/
|
||||
void * driver_data;
|
||||
} gs_spi_master_driver_entry_t;
|
||||
|
||||
|
||||
/**
|
||||
SPI slave driver
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Function for handling slave start.
|
||||
*/
|
||||
gs_spi_slave_start_t start_handler;
|
||||
/**
|
||||
Function for handling the 'setting of rx callback'.
|
||||
*/
|
||||
gs_spi_slave_set_rx_t set_rx_handler;
|
||||
/**
|
||||
Function for handling 'set response'.
|
||||
*/
|
||||
gs_spi_slave_set_response_t set_response_handler;
|
||||
} gs_spi_slave_driver_t;
|
||||
|
||||
|
||||
/**
|
||||
SPI slave driver entry.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
SPI device, to which the driver is used (if #GS_SPI_ALL_DEVICES, then all devices uses this driver).
|
||||
*/
|
||||
uint8_t device;
|
||||
/**
|
||||
SPI slave driver.
|
||||
*/
|
||||
const gs_spi_slave_driver_t * driver;
|
||||
/**
|
||||
Driver specific data.
|
||||
*/
|
||||
void * driver_data;
|
||||
} gs_spi_slave_driver_entry_t;
|
||||
|
||||
|
||||
/**
|
||||
Register a master driver.
|
||||
|
||||
A specific driver can be assigned to a slave or it can be assigned to every slave.
|
||||
|
||||
The latest registered driver, which fit the slave, is the one used.
|
||||
|
||||
@param[in] driver_entry driver and configuration to be registered
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry);
|
||||
|
||||
/**
|
||||
Register a slave driver
|
||||
|
||||
A specific driver can be assigned to a specific device or a driver can be assigned to every device.
|
||||
|
||||
The latest registered driver, which fit the device, is the one used.
|
||||
|
||||
@param[in] driver_entry driver and configuration to be registered
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
40
gomspace/libutil/include/gs/util/linux/exitcode.h
Normal file
40
gomspace/libutil/include/gs/util/linux/exitcode.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef GS_UTIL_LINUX_EXITCODE_H
|
||||
#define GS_UTIL_LINUX_EXITCODE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
"standard" Linux exit codes.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Program completed ok (from stdlib.h)
|
||||
*/
|
||||
#define GS_EXITCODE_OK EXIT_SUCCESS
|
||||
|
||||
/**
|
||||
Program terminated due to an error (from stdlib.h).
|
||||
*/
|
||||
#define GS_EXITCODE_ERROR EXIT_FAILURE
|
||||
|
||||
/**
|
||||
Program terminated due to invalid usage, eg argument (from sysexits.h).
|
||||
*/
|
||||
#define GS_EXITCODE_USAGE EX_USAGE
|
||||
|
||||
/**
|
||||
Program terminated due to a signal (from [TLDP](http://www.tldp.org/LDP/abs/html/exitcodes.html)).
|
||||
*/
|
||||
#define GS_EXITCODE_SIGNAL(sig) (128 + sig)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
49
gomspace/libutil/include/gs/util/linux/function.h
Normal file
49
gomspace/libutil/include/gs/util/linux/function.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef GS_UTIL_LINUX_FUNCTION_H
|
||||
#define GS_UTIL_LINUX_FUNCTION_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Function interface - invokes a function by name.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Function prototype.
|
||||
@param[in] arg argument provided to gs_function_invoke().
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_function_t)(void * arg);
|
||||
|
||||
/**
|
||||
Register \a function by name.
|
||||
|
||||
@param[in] short_name short name for function, used by gs_function_invoke() to find function to invoke.
|
||||
@param[in] long_name long name (unique) for function, used by gs_function_invoke() to find function to invoke.
|
||||
@param[in] function function to be invoked by gs_function_invoke()
|
||||
@return #GS_ERROR_FULL if registry is full.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function);
|
||||
|
||||
/**
|
||||
Invoke \a function by name.
|
||||
|
||||
The return value is from the registered function, except for #GS_ERROR_NOT_IMPLEMENTED.
|
||||
|
||||
@param[in] name registered function name.
|
||||
@param[in] arg argument for function.
|
||||
@return #GS_ERROR_NOT_IMPLEMENTED if the \a name isn't found.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_function_invoke(const char * name, void * arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
28
gomspace/libutil/include/gs/util/linux/rtc.h
Normal file
28
gomspace/libutil/include/gs/util/linux/rtc.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef GS_UTIL_LINUX_RTC_H
|
||||
#define GS_UTIL_LINUX_RTC_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Real Time Clock interface (linux).
|
||||
*/
|
||||
|
||||
#include <gs/util/rtc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Register Real Time Clock interface.
|
||||
@note Setting the RTC will normally require special permission.
|
||||
@param[in] get if true, get will be registered.
|
||||
@param[in] set if true, set will be registered.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rtc_register_linux(bool get, bool set);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
40
gomspace/libutil/include/gs/util/linux/signal.h
Normal file
40
gomspace/libutil/include/gs/util/linux/signal.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef GS_UTIL_LINUX_SIGNAL_H
|
||||
#define GS_UTIL_LINUX_SIGNAL_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Signal helpers - catch and ignore.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Standard Linux signal handler.
|
||||
*/
|
||||
typedef void (*gs_signal_handler)(int signal, siginfo_t *si, void *context);
|
||||
|
||||
/**
|
||||
Register/catch signal and invoke handler.
|
||||
@param[in] signal signal to catch.
|
||||
@param[in] handler signal handler. If \a handler is NULL, a default handler will be invoked, which calls exit(#GS_EXITCODE_SIGNAL + signal).
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_signal_catch(int signal, gs_signal_handler handler);
|
||||
|
||||
/**
|
||||
Ignore signal
|
||||
@param[in] signal signal to ignore.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_signal_ignore(int signal);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
30
gomspace/libutil/include/gs/util/linux/sysfs_helper.h
Normal file
30
gomspace/libutil/include/gs/util/linux/sysfs_helper.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef GS_UTIL_SYSFS_HELPER_H
|
||||
#define GS_UTIL_SYSFS_HELPER_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Sysfs interface.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Sysfs write (GPIO).
|
||||
*/
|
||||
gs_error_t gs_sysfs_write_file(const char *path, const char *value);
|
||||
|
||||
/**
|
||||
Sysfs read (GPIO).
|
||||
*/
|
||||
gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
15
gomspace/libutil/include/gs/util/log.h
Normal file
15
gomspace/libutil/include/gs/util/log.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef GS_UTIL_LOG_H
|
||||
#define GS_UTIL_LOG_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Log interface.
|
||||
|
||||
The log interface supports logging to different group.
|
||||
|
||||
Logging is done through groups (domains), which can runtime be re-configured with level.
|
||||
*/
|
||||
#include <gs/util/log/log.h>
|
||||
|
||||
#endif
|
189
gomspace/libutil/include/gs/util/log/appender/appender.h
Normal file
189
gomspace/libutil/include/gs/util/log/appender/appender.h
Normal file
@ -0,0 +1,189 @@
|
||||
#ifndef GS_UTIL_LOG_APPENDER_APPENDER_H
|
||||
#define GS_UTIL_LOG_APPENDER_APPENDER_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Log Appender interface.
|
||||
|
||||
The log appender interface supports logging to different "stores".
|
||||
Logging is done through groups, which can be registered to different log appenders.
|
||||
Each log appender has it's own filter (level mask).
|
||||
Examples of log appenders could be: console, file, vmem, ...
|
||||
*/
|
||||
|
||||
#include <gs/util/log/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Log appender (forward declaration)
|
||||
All log groups log to one or more appenders. The Log appender is responsible
|
||||
for putting the actual log data to a store/console or some other log medium.
|
||||
*/
|
||||
typedef struct gs_log_appender gs_log_appender_t;
|
||||
|
||||
/**
|
||||
Log appender record iterator callback function
|
||||
|
||||
@param[in] ctx context data for iterator.
|
||||
@param[in] level log level of record being iterated
|
||||
@param[in] ts timestamp of record being iterated
|
||||
@param[in] group group string (zero terminated) of record being iterated
|
||||
@param[in] msg message string (zero terminated) of record being iterated
|
||||
@return true/false: Return false to discontinue iteration.
|
||||
*/
|
||||
typedef bool (*gs_log_record_iterator_t)(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg);
|
||||
|
||||
/**
|
||||
Log appender driver interface
|
||||
*/
|
||||
typedef struct {
|
||||
/** appender init function */
|
||||
gs_error_t (*init)(gs_log_appender_t *appender);
|
||||
/** appender function */
|
||||
void (*append)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va);
|
||||
/** appender function for isr context */
|
||||
void (*append_isr)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va);
|
||||
/** appender function for getting appender details string */
|
||||
void (*info)(gs_log_appender_t *appender, char * info_str, uint8_t str_size);
|
||||
/** appender function for iterating stored appenders log history */
|
||||
void (*hist)(gs_log_appender_t *appender, void * ctx, gs_log_record_iterator_t iter);
|
||||
/** appender function for clearing it's log history */
|
||||
void (*clear)(gs_log_appender_t *appender);
|
||||
/** appender function for flushing cached log entries to it's store.
|
||||
This is only relevant for appenders implementing a log cache. */
|
||||
void (*flush)(gs_log_appender_t *appender);
|
||||
} gs_log_appender_driver_t;
|
||||
|
||||
/**
|
||||
Log appender
|
||||
All log groups log to one or more appenders. The Log appender is responsible
|
||||
for putting the actual log data to a store/console or some other log medium.
|
||||
*/
|
||||
struct gs_log_appender {
|
||||
/** Name of the appender */
|
||||
const char * name;
|
||||
/** appender driver interface */
|
||||
const gs_log_appender_driver_t * drv;
|
||||
/** appender driver configuration data */
|
||||
const void * drv_config;
|
||||
/** appender driver data - dynamic/internal data */
|
||||
void * drv_data;
|
||||
/** appender level mask */
|
||||
uint8_t mask;
|
||||
};
|
||||
|
||||
/**
|
||||
Register an appender for the given log group.
|
||||
All logging, where the mask matches the groups \a level_mask, will be forwarded to this appender.
|
||||
|
||||
@param[in] group_name Name of the group.
|
||||
@param[in] appender_name Name of appender to register for this group.
|
||||
@return gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name);
|
||||
|
||||
/**
|
||||
Log appender iterator callback function
|
||||
|
||||
@param[in] ctx context data for iterator.
|
||||
@param[in] appender log appender being iterated
|
||||
|
||||
@return true/false: Return false to discontinue iteration.
|
||||
*/
|
||||
typedef bool (*gs_log_appender_iterator_t)(void *ctx, gs_log_appender_t * appender);
|
||||
|
||||
/**
|
||||
Iterate all or specific log appender(s).
|
||||
|
||||
@param[in] name name of log appender, or NULL/\"all\" for all groups.
|
||||
@param[in] ctx user context data.
|
||||
@param[in] iter iterator, return \a true to continue, \a false to break iteration.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter);
|
||||
|
||||
/**
|
||||
Iterate registered appenders for a specific group.
|
||||
|
||||
@param[in] group log group to iterate appenders on.
|
||||
@param[in] ctx user context data.
|
||||
@param[in] iter appender iterator, return \a true to continue, \a false to break iteration.
|
||||
@return gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter);
|
||||
|
||||
/**
|
||||
Register log appender.
|
||||
|
||||
The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t)
|
||||
|
||||
The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender()
|
||||
|
||||
@param[in] appender appender - must stay in memory during the life-time of the application
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_register(gs_log_appender_t *appender);
|
||||
|
||||
/**
|
||||
Add log appender(s).
|
||||
|
||||
The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t)
|
||||
|
||||
The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender()
|
||||
|
||||
@deprecated impossible to determine which appender fails, use gs_log_appender_register()
|
||||
@param[in] appenders array of appender(s) - must stay in memory during the life-time of the application
|
||||
@param[in] count array count - number of appenders.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_add(gs_log_appender_t *appenders, uint16_t count);
|
||||
|
||||
/**
|
||||
Set log appender level mask.
|
||||
|
||||
@param[in] appender_name log appender name
|
||||
@param[in] mask level mask to set.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask);
|
||||
|
||||
/**
|
||||
Get log appender level mask.
|
||||
|
||||
@param[in] appender_name log appender name
|
||||
@param[out] mask returned current level mask.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask);
|
||||
|
||||
/**
|
||||
Iterate log history for all or specific log appender.
|
||||
|
||||
@param[in] name name of log appender, or NULL/\"all\" for all appenders.
|
||||
@param[in] ctx user context data for iterator.
|
||||
@param[in] iter iterator, return \a true to continue, \a false to break iteration.
|
||||
@return gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter);
|
||||
|
||||
/**
|
||||
Flush all log appenders data to storage.
|
||||
|
||||
This will call the flush API (if implemented) for all log appenders
|
||||
available on the system. This should be called on regular basis from
|
||||
a system thread to ensure all cached data is correctly flushed to their
|
||||
stores.
|
||||
|
||||
@return gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_flush_all();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
57
gomspace/libutil/include/gs/util/log/appender/console.h
Normal file
57
gomspace/libutil/include/gs/util/log/appender/console.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef GS_UTIL_LOG_APPENDER_CONSOLE_H
|
||||
#define GS_UTIL_LOG_APPENDER_CONSOLE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Console log appender - logs to stdout.
|
||||
*/
|
||||
|
||||
#include <gs/util/log/appender/appender.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Log appender for console
|
||||
|
||||
This log appender is the standard appender which is always available
|
||||
on any system. The appender should be registered to the root group,
|
||||
in order to get console/stdio logs.
|
||||
*/
|
||||
extern gs_log_appender_t gs_log_appender_console;
|
||||
|
||||
/**
|
||||
Log appender for console callback type
|
||||
|
||||
This callback function can be used for registering a user defined logger function if
|
||||
the default can not be used for the given system.
|
||||
|
||||
@param[in] appender pointer to the console appender.
|
||||
@param[in] level log level for log message
|
||||
@param[in] group log group for log message
|
||||
@param[in] ts timestamp for log message
|
||||
@param[in] format format of message in printf style
|
||||
@param[in] va variable argument list in printf style
|
||||
|
||||
@return void
|
||||
*/
|
||||
typedef void (*gs_log_appender_console_cb_t)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va);
|
||||
|
||||
/**
|
||||
Set Log appender for console callback
|
||||
|
||||
When set, the given callback is called instead of the default console log function.
|
||||
To revert back to the default console log function, call this function with NULL as parameter.
|
||||
|
||||
@param[in] cb callback to use for console logging.
|
||||
|
||||
@return gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
41
gomspace/libutil/include/gs/util/log/appender/simple_file.h
Normal file
41
gomspace/libutil/include/gs/util/log/appender/simple_file.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H
|
||||
#define GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Simple log-file appender.
|
||||
*/
|
||||
#include <gs/util/log/appender/appender.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Simple File Log Appender driver configuration
|
||||
*/
|
||||
typedef struct gs_log_appender_simple_file_config {
|
||||
/**
|
||||
Name of file to create/write logs to
|
||||
*/
|
||||
const char *filename;
|
||||
/**
|
||||
Truncate the file, when opening the log file.
|
||||
*/
|
||||
bool truncate;
|
||||
/**
|
||||
Uee local time stamps when logging to log file, otherwise UTC.
|
||||
*/
|
||||
bool use_local_time;
|
||||
} gs_log_appender_simple_file_config_t;
|
||||
|
||||
/**
|
||||
Log appender for file.
|
||||
*/
|
||||
extern const gs_log_appender_driver_t gs_log_appender_simple_file_driver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
853
gomspace/libutil/include/gs/util/log/log.h
Normal file
853
gomspace/libutil/include/gs/util/log/log.h
Normal file
@ -0,0 +1,853 @@
|
||||
#ifndef GS_UTIL_LOG_LOG_H
|
||||
#define GS_UTIL_LOG_LOG_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Log interface.
|
||||
|
||||
Logging is done through groups (domains), where the level mask can be changed runtime.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <gs/util/timestamp.h>
|
||||
#include <gs/util/pgm.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Name of the root log group
|
||||
*/
|
||||
#define GS_LOG_GROUP_ROOT "root"
|
||||
|
||||
/**
|
||||
Log levels.
|
||||
|
||||
The levels can easily be mapped to standard syslog severity levels (https://en.wikipedia.org/wiki/Syslog).
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Trace (more detailed than \a debug).
|
||||
|
||||
syslog: maps to \a debug (or \a trace if supported).
|
||||
*/
|
||||
GS_LOG_TRACE = 0,
|
||||
/**
|
||||
Debug.
|
||||
|
||||
syslog: maps to \a debug.
|
||||
*/
|
||||
GS_LOG_DEBUG = 1,
|
||||
/**
|
||||
Informational.
|
||||
|
||||
syslog: maps to \a informational.
|
||||
*/
|
||||
GS_LOG_INFO = 2,
|
||||
/**
|
||||
Normal but significant conditions.
|
||||
|
||||
syslog: maps to \a notice.
|
||||
*/
|
||||
GS_LOG_NOTICE = 3,
|
||||
/**
|
||||
Warning.
|
||||
|
||||
syslog: maps to \a warning.
|
||||
*/
|
||||
GS_LOG_WARNING = 4,
|
||||
/**
|
||||
Error.
|
||||
|
||||
syslog: maps to \a error.
|
||||
*/
|
||||
GS_LOG_ERROR = 5,
|
||||
|
||||
/**
|
||||
Trace (more detailed than \a debug).
|
||||
@deprecated use #GS_LOG_TRACE
|
||||
*/
|
||||
LOG_TRACE = GS_LOG_TRACE,
|
||||
/**
|
||||
Debug.
|
||||
@deprecated use #GS_LOG_DEBUG
|
||||
*/
|
||||
LOG_DEBUG = GS_LOG_DEBUG,
|
||||
/**
|
||||
Informational.
|
||||
@deprecated use #GS_LOG_INFO
|
||||
*/
|
||||
LOG_INFO = GS_LOG_INFO,
|
||||
/**
|
||||
Normal but significant conditions.
|
||||
@deprecated use #GS_LOG_NOTICE
|
||||
*/
|
||||
LOG_NOTICE = GS_LOG_NOTICE,
|
||||
/**
|
||||
Warning.
|
||||
@deprecated use #GS_LOG_WARNING
|
||||
*/
|
||||
LOG_WARNING = GS_LOG_WARNING,
|
||||
/**
|
||||
Error.
|
||||
@deprecated use #GS_LOG_ERROR
|
||||
*/
|
||||
LOG_ERROR = GS_LOG_ERROR,
|
||||
} gs_log_level_t;
|
||||
|
||||
/**
|
||||
Log categories.
|
||||
|
||||
The category is a way of grouping information about which sub-systems have logged. It is primarily used in the \a
|
||||
telemetry table, to indicate what sub-systems have logged an \a error or \a warning - indicating a possible problem.
|
||||
|
||||
Up to 32 categories are supported (stored in a uint32).
|
||||
|
||||
Categories should be unique within a single node. However, nothing happens if categories clashes - it will only be more difficult to determine what part of the system logged.
|
||||
|
||||
Standard categories are defined from #GS_LOG_CAT_1 and up. Products or mission specific software should start from #GS_LOG_CAT_32 and down.
|
||||
*/
|
||||
typedef enum {
|
||||
//! Standard, used for #GS_LOG_CAT_DEFAULT
|
||||
GS_LOG_CAT_1 = 1 << 0,
|
||||
//! Standard, used for #GS_LOG_CAT_DRIVER
|
||||
GS_LOG_CAT_2 = 1 << 1,
|
||||
//! Standard, used for #GS_LOG_CAT_CSP
|
||||
GS_LOG_CAT_3 = 1 << 2,
|
||||
//! Standard, used for #GS_LOG_CAT_PARAM
|
||||
GS_LOG_CAT_4 = 1 << 3,
|
||||
//! Standard, used for #GS_LOG_CAT_FILE_SYSTEM
|
||||
GS_LOG_CAT_5 = 1 << 4,
|
||||
//! Standard, used for #GS_LOG_CAT_COMMAND
|
||||
GS_LOG_CAT_6 = 1 << 5,
|
||||
//! Standard, used for #GS_LOG_CAT_HK
|
||||
GS_LOG_CAT_7 = 1 << 6,
|
||||
//! Standard, used for #GS_LOG_CAT_FP
|
||||
GS_LOG_CAT_8 = 1 << 7,
|
||||
//! Standard, used for #GS_LOG_CAT_ADCS
|
||||
GS_LOG_CAT_9 = 1 << 8,
|
||||
GS_LOG_CAT_10 = 1 << 9,
|
||||
GS_LOG_CAT_11 = 1 << 10,
|
||||
GS_LOG_CAT_12 = 1 << 11,
|
||||
GS_LOG_CAT_13 = 1 << 12,
|
||||
GS_LOG_CAT_14 = 1 << 13,
|
||||
GS_LOG_CAT_15 = 1 << 14,
|
||||
GS_LOG_CAT_16 = 1 << 15,
|
||||
#if (__AVR__ == 0)
|
||||
GS_LOG_CAT_17 = 1 << 16,
|
||||
GS_LOG_CAT_18 = 1 << 17,
|
||||
GS_LOG_CAT_19 = 1 << 18,
|
||||
GS_LOG_CAT_20 = 1 << 19,
|
||||
GS_LOG_CAT_21 = 1 << 20,
|
||||
GS_LOG_CAT_22 = 1 << 21,
|
||||
GS_LOG_CAT_23 = 1 << 22,
|
||||
GS_LOG_CAT_24 = 1 << 23,
|
||||
GS_LOG_CAT_25 = 1 << 24,
|
||||
GS_LOG_CAT_26 = 1 << 25,
|
||||
GS_LOG_CAT_27 = 1 << 26,
|
||||
GS_LOG_CAT_28 = 1 << 27,
|
||||
GS_LOG_CAT_29 = 1 << 28,
|
||||
GS_LOG_CAT_30 = 1 << 29,
|
||||
GS_LOG_CAT_31 = 1 << 30,
|
||||
//! Product or mission specific - start here and down
|
||||
GS_LOG_CAT_32 = 1 << 31,
|
||||
#endif
|
||||
} gs_log_category_t;
|
||||
|
||||
/**
|
||||
@defgroup reserved_log_categories Reserved/assigned log categories.
|
||||
These categories are assigned/reserved for certain sub-systems.
|
||||
@{
|
||||
*/
|
||||
/**
|
||||
Default, used if nothing else fits.
|
||||
*/
|
||||
#define GS_LOG_CAT_DEFAULT GS_LOG_CAT_1
|
||||
/**
|
||||
Driver layer.
|
||||
*/
|
||||
#define GS_LOG_CAT_DRIVER GS_LOG_CAT_2
|
||||
/**
|
||||
CSP.
|
||||
*/
|
||||
#define GS_LOG_CAT_CSP GS_LOG_CAT_3
|
||||
/**
|
||||
Parameter system.
|
||||
*/
|
||||
#define GS_LOG_CAT_PARAM GS_LOG_CAT_4
|
||||
/**
|
||||
File system.
|
||||
*/
|
||||
#define GS_LOG_CAT_FILE_SYSTEM GS_LOG_CAT_5
|
||||
/**
|
||||
Command framework and execution.
|
||||
*/
|
||||
#define GS_LOG_CAT_COMMAND GS_LOG_CAT_6
|
||||
/**
|
||||
Housekeeping System.
|
||||
*/
|
||||
#define GS_LOG_CAT_HK GS_LOG_CAT_7
|
||||
/**
|
||||
Flight Planner.
|
||||
*/
|
||||
#define GS_LOG_CAT_FP GS_LOG_CAT_8
|
||||
/**
|
||||
ADCS
|
||||
*/
|
||||
#define GS_LOG_CAT_ADCS GS_LOG_CAT_9
|
||||
/** @} */
|
||||
|
||||
struct gs_log_list; /* forward declared private log list struct */
|
||||
/**
|
||||
Log list type (private)
|
||||
|
||||
Private gs_log_list type.
|
||||
*/
|
||||
typedef struct gs_log_list gs_log_list_t;
|
||||
|
||||
/**
|
||||
Log group.
|
||||
All logs are logged to a \a group. The group contains the current log level mask,
|
||||
which controls whether the log is carried through or not.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Name of log group.
|
||||
*/
|
||||
const char * name;
|
||||
/**
|
||||
Category, see #gs_log_category_t.
|
||||
*/
|
||||
uint32_t category;
|
||||
/**
|
||||
Current level mask, see #gs_log_level_t.
|
||||
*/
|
||||
uint8_t mask;
|
||||
/**
|
||||
Is group additive, if \a true (default) logging will be done on both root appenders and this groups appenders - if \a false, logging will only be done to this groups appenders.
|
||||
*/
|
||||
bool additivity;
|
||||
/**
|
||||
Private list of appenders.
|
||||
*/
|
||||
gs_log_list_t * appenders;
|
||||
#if (__AVR__)
|
||||
uint16_t dummy_align;
|
||||
#endif
|
||||
} gs_log_group_t;
|
||||
|
||||
/**
|
||||
Log masks (levels converted to mask).
|
||||
@{
|
||||
*/
|
||||
/**
|
||||
Trace level enabled.
|
||||
*/
|
||||
#define GS_LOG_TRACE_MASK (1 << GS_LOG_TRACE)
|
||||
/**
|
||||
Debug level enabled.
|
||||
*/
|
||||
#define GS_LOG_DEBUG_MASK (1 << GS_LOG_DEBUG)
|
||||
/**
|
||||
Info level enabled.
|
||||
*/
|
||||
#define GS_LOG_INFO_MASK (1 << GS_LOG_INFO)
|
||||
/**
|
||||
Notice level enabled.
|
||||
*/
|
||||
#define GS_LOG_NOTICE_MASK (1 << GS_LOG_NOTICE)
|
||||
/**
|
||||
Warning level enabled.
|
||||
*/
|
||||
#define GS_LOG_WARNING_MASK (1 << GS_LOG_WARNING)
|
||||
/**
|
||||
Error level enabled.
|
||||
*/
|
||||
#define GS_LOG_ERROR_MASK (1 << GS_LOG_ERROR)
|
||||
/**
|
||||
All levels enabled.
|
||||
*/
|
||||
#define GS_LOG_ALL_MASK (GS_LOG_TRACE_MASK | GS_LOG_DEBUG_MASK | GS_LOG_INFO_MASK | GS_LOG_NOTICE_MASK | GS_LOG_WARNING_MASK | GS_LOG_ERROR_MASK)
|
||||
/**
|
||||
Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE.
|
||||
*/
|
||||
#define GS_LOG_DEFAULT_MASK (GS_LOG_ERROR_MASK | GS_LOG_WARNING_MASK | GS_LOG_NOTICE_MASK)
|
||||
/**
|
||||
Trace level enabled.
|
||||
@deprecated use #GS_LOG_TRACE_MASK
|
||||
*/
|
||||
#define LOG_TRACE_MASK GS_LOG_TRACE_MASK
|
||||
/**
|
||||
Debug level enabled.
|
||||
@deprecated use #GS_LOG_DEBUG_MASK
|
||||
*/
|
||||
#define LOG_DEBUG_MASK GS_LOG_DEBUG_MASK
|
||||
/**
|
||||
Info level enabled.
|
||||
@deprecated use #GS_LOG_INFO_MASK
|
||||
*/
|
||||
#define LOG_INFO_MASK GS_LOG_INFO_MASK
|
||||
/**
|
||||
Notice level enabled.
|
||||
@deprecated use #GS_LOG_NOTICE_MASK
|
||||
*/
|
||||
#define LOG_NOTICE_MASK GS_LOG_NOTICE_MASK
|
||||
/**
|
||||
Warning level enabled.
|
||||
@deprecated use #GS_LOG_WARNING_MASK
|
||||
*/
|
||||
#define LOG_WARNING_MASK GS_LOG_WARNING_MASK
|
||||
/**
|
||||
Error level enabled.
|
||||
@deprecated use #GS_LOG_ERROR_MASK
|
||||
*/
|
||||
#define LOG_ERROR_MASK GS_LOG_ERROR_MASK
|
||||
/**
|
||||
All levels enabled.
|
||||
@deprecated use #GS_LOG_ALL_MASK
|
||||
*/
|
||||
#define LOG_ALL_MASK GS_LOG_ALL_MASK
|
||||
/**
|
||||
Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE.
|
||||
@deprecated use #GS_LOG_DEFAULT_MASK
|
||||
*/
|
||||
#define LOG_DEFAULT_MASK GS_LOG_DEFAULT_MASK
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
Define/Create a log group.
|
||||
|
||||
@note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always
|
||||
be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library.
|
||||
|
||||
@param[in] group name of variables created. See note above about name clash.
|
||||
@param[in] name_in display name
|
||||
@param[in] cat_in log group category
|
||||
@param[in] level_mask log level mask.
|
||||
*/
|
||||
#define GS_LOG_GROUP(group, name_in, cat_in, level_mask) \
|
||||
gs_log_group_t group##_s = {.name = name_in, .category = cat_in, \
|
||||
.mask = level_mask, .additivity = true, \
|
||||
.appenders = NULL}; \
|
||||
gs_log_group_t * group = &group##_s
|
||||
|
||||
/**
|
||||
Define log group with initial mask for \a print and \a store.
|
||||
|
||||
@note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always
|
||||
be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library.
|
||||
|
||||
@deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(...) instead.
|
||||
|
||||
@param[in] group name of variables created. See note above about name clash.
|
||||
@param[in] name_in display name
|
||||
@param[in] print_mask enable mask for \a print.
|
||||
@param[in] store_mask enable mask for \a store.
|
||||
*/
|
||||
#define LOG_GROUP_MASKED(group, name_in, print_mask, store_mask) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, (print_mask | store_mask))
|
||||
|
||||
/**
|
||||
Declare log group as external (defined else where).
|
||||
|
||||
@param[in] group the log group variable defined elsewhere.
|
||||
*/
|
||||
#define GS_LOG_GROUP_EXTERN(group) extern gs_log_group_t * group
|
||||
|
||||
/**
|
||||
Define log group - levels are #GS_LOG_DEFAULT_MASK
|
||||
|
||||
@deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead.
|
||||
*/
|
||||
#define LOG_GROUP(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_DEFAULT_MASK)
|
||||
|
||||
/**
|
||||
Define verbose log group - all levels are enabled (#GS_LOG_ALL_MASK)
|
||||
|
||||
@deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead.
|
||||
*/
|
||||
#define LOG_GROUP_VERBOSE(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_ALL_MASK)
|
||||
|
||||
/**
|
||||
Define silent log group - all levels are disabled.
|
||||
|
||||
@deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead.
|
||||
*/
|
||||
#define LOG_GROUP_SILENT(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, 0)
|
||||
|
||||
/**
|
||||
Declare log group as external (defined else where).
|
||||
|
||||
@deprecated use #GS_LOG_GROUP_EXTERN(...) instead.
|
||||
*/
|
||||
#define LOG_GROUP_EXTERN(group) GS_LOG_GROUP_EXTERN(group)
|
||||
|
||||
/**
|
||||
Default log group.
|
||||
This can be overridden by a define
|
||||
*/
|
||||
extern gs_log_group_t * LOG_DEFAULT;
|
||||
|
||||
/**
|
||||
Initializes the log system.
|
||||
|
||||
@param[in] with_console_appender Enable/Disable console log appender
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_init(bool with_console_appender);
|
||||
|
||||
/**
|
||||
Set log group level mask.
|
||||
|
||||
@param[in] group_name log group name
|
||||
@param[in] mask level mask to set.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask);
|
||||
|
||||
/**
|
||||
Get log group level mask.
|
||||
|
||||
@param[in] group_name log group name
|
||||
@param[out] mask returned current level mask.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask);
|
||||
|
||||
/**
|
||||
Log group iterator callback function
|
||||
|
||||
@param[in] ctx context data for iterator.
|
||||
@param[in] group log group being iterated.
|
||||
|
||||
@return true/false: Return false to discontinue iteration.
|
||||
*/
|
||||
typedef bool (*gs_log_group_iterator_t)(void *ctx, gs_log_group_t * group);
|
||||
|
||||
/**
|
||||
Iterate all or specific log group(s).
|
||||
|
||||
@param[in] group_name name of log group, or NULL/\"all\" for all groups.
|
||||
@param[in] ctx user context data.
|
||||
@param[in] iter iterator, return \a true to continue, \a false to break iteration.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter);
|
||||
|
||||
/**
|
||||
Register a log group in the log system.
|
||||
|
||||
The log group will be added to a system wide list of log groups, enabling list and set of level.
|
||||
|
||||
@note The group must remain valid during the life-time of the application.
|
||||
|
||||
@param[in] group The log group to be added to the system.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_group_register(gs_log_group_t *group);
|
||||
|
||||
/**
|
||||
Register a log group in the log system.
|
||||
|
||||
@note The group must stay in memory during the life-time of the application
|
||||
@see gs_log_group_register()
|
||||
@param[in] group The log group to be added to the system.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
static inline gs_error_t gs_log_group_add(gs_log_group_t *group)
|
||||
{
|
||||
return gs_log_group_register(group);
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if a level is enabled on a log group
|
||||
|
||||
@param[in] group The log group to check.
|
||||
@param[in] level The log level to check if it's set on the group.
|
||||
@return bool (true if enabled / false if not enabled)
|
||||
*/
|
||||
bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level);
|
||||
|
||||
/**
|
||||
Convert string to log level.
|
||||
|
||||
@param[in] str log level.
|
||||
@param[out] return_level converted log level.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level);
|
||||
|
||||
/**
|
||||
Convert level to single character.
|
||||
|
||||
@param[in] level log level
|
||||
@return single character representing the \a level.
|
||||
*/
|
||||
char gs_log_level_to_char(gs_log_level_t level);
|
||||
|
||||
|
||||
/**
|
||||
Register Log commands.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_register_commands(void);
|
||||
|
||||
/**
|
||||
Generic log.
|
||||
@note This function should not be called directly, use log macros.
|
||||
|
||||
@param level log level
|
||||
@param group log group. If NULL, the \a default log group will be used.
|
||||
@param format Format string (printf style).
|
||||
*/
|
||||
void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4)));
|
||||
|
||||
/**
|
||||
Generic log from ISR.
|
||||
@note This function should not be called directly, use log macros.
|
||||
|
||||
@param level log level
|
||||
@param group log group. If NULL, the \a default log group will be used.
|
||||
@param format Format string (printf style).
|
||||
*/
|
||||
void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4)));
|
||||
|
||||
/**
|
||||
Generic log (va_list).
|
||||
@note This function should not be called directly, use log macros.
|
||||
|
||||
@param level log level
|
||||
@param group log group. If NULL, the \a default log group will be used.
|
||||
@param format Format string (printf style).
|
||||
@param args arguments for \a format.
|
||||
*/
|
||||
void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args);
|
||||
|
||||
/**
|
||||
Enable/disable color in \a print logs.
|
||||
Default is \a enabled/true.
|
||||
|
||||
@param[in] color \a true to enable color, \a false disable color.
|
||||
*/
|
||||
void gs_log_set_print_color(bool color);
|
||||
|
||||
/**
|
||||
Level to color (begin).
|
||||
|
||||
@param[in] level log level.
|
||||
@return color string.
|
||||
*/
|
||||
const char * gs_log_level_to_color_begin(gs_log_level_t level);
|
||||
|
||||
/**
|
||||
Level to color (end).
|
||||
|
||||
@return color string.
|
||||
*/
|
||||
const char * gs_log_level_to_color_end(void);
|
||||
|
||||
/**
|
||||
Take a level as input an create a level mask enabling all
|
||||
levels with priority >= level.
|
||||
|
||||
If level is e.g. LOG_INFO, the mask will enable Error, Warn & Info.
|
||||
|
||||
* @param level the log level.
|
||||
* @return level mask
|
||||
*/
|
||||
uint8_t gs_log_level_to_mask(gs_log_level_t level);
|
||||
|
||||
/**
|
||||
Convert string to log mask.
|
||||
|
||||
Format: [+-]level[,[+-]level]
|
||||
|
||||
+ add level, - remove level.
|
||||
|
||||
@param[in] str log mask
|
||||
@param[in] current_mask current mask, used when input format contains + or -.
|
||||
@param[out] return_mask converted log mask.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_log_string_to_mask(const char *str, uint8_t current_mask, uint8_t * return_mask);
|
||||
|
||||
#if !(__DOXYGEN__)
|
||||
/**
|
||||
Internal macro for checking if log is enabled, before making log.
|
||||
*/
|
||||
#define __gs_log(level, group, format, ...) \
|
||||
if (group->mask & (1 << level)) { \
|
||||
gs_log(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
/**
|
||||
Internal macro for checking if log is enabled for isr, before making log.
|
||||
*/
|
||||
#define __gs_log_isr(level, group, format, ...) \
|
||||
if (group->mask & (1 << level)) { \
|
||||
gs_log_isr(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
/**
|
||||
Internal macro used for performing a log only once.
|
||||
@note This creates a \a static \a variable.
|
||||
*/
|
||||
#define __gs_log_once(level, group, format, ...) \
|
||||
({ \
|
||||
static bool print_once; \
|
||||
if (!print_once) { \
|
||||
print_once = true; \
|
||||
__gs_log(level, group, format, ##__VA_ARGS__); \
|
||||
} \
|
||||
})
|
||||
#endif // __DOXYGEN__
|
||||
|
||||
/**
|
||||
Default compile-time enabling/disabling of all levels
|
||||
Unless levels are individually defined, this will be the default value.
|
||||
*/
|
||||
#if !defined(GS_LOG_DISABLE_ALL)
|
||||
#define GS_LOG_DISABLE_ALL 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
Disable \a error level compile-time by defining a value > 0
|
||||
*/
|
||||
#if !defined(GS_LOG_DISABLE_ERROR)
|
||||
#define GS_LOG_DISABLE_ERROR GS_LOG_DISABLE_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
Disable \a warning level compile-time by defining a value > 0
|
||||
*/
|
||||
#if !defined(GS_LOG_DISABLE_WARNING)
|
||||
#define GS_LOG_DISABLE_WARNING GS_LOG_DISABLE_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
Disable \a notice level compile-time by defining a value > 0
|
||||
*/
|
||||
#if !defined(GS_LOG_DISABLE_NOTICE)
|
||||
#define GS_LOG_DISABLE_NOTICE GS_LOG_DISABLE_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
Disable \a info level compile-time by defining a value > 0
|
||||
*/
|
||||
#if !defined(GS_LOG_DISABLE_INFO)
|
||||
#define GS_LOG_DISABLE_INFO GS_LOG_DISABLE_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
Disable \a debug level compile-time by defining a value > 0
|
||||
*/
|
||||
#if !defined(GS_LOG_DISABLE_DEBUG)
|
||||
#define GS_LOG_DISABLE_DEBUG GS_LOG_DISABLE_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
Disable \a trace level compile-time by defining a value > 0
|
||||
*/
|
||||
#if !defined(GS_LOG_DISABLE_TRACE)
|
||||
#define GS_LOG_DISABLE_TRACE GS_LOG_DISABLE_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
Log \a error to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_error(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a error from ISR to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_error_isr(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_isr(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a error to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_error_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a error only once to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_error_once(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a error only once to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_error_once_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a warning to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_warning(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a warning from ISR to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_warning_isr(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_isr(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a warning to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_warning_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a warning only once to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_warning_once(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a warning only once to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_warning_once_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a notice to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_notice(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a notice from ISR to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_notice_isr(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_isr(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a notice to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_notice_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a notice only once to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_notice_once(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a notice only once to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_notice_once_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a info to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_info(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a info from ISR to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_info_isr(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_isr(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a info to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_info_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a info only once to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_info_once(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a info only once to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_info_once_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a debug to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_debug(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a debug from ISR to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_debug_isr(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_isr(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a debug to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_debug_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a debug only once to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_debug_once(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a debug only once to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_debug_once_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a trace to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_trace(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a trace from ISR to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_trace_isr(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_isr(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a trace to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_trace_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a trace only once to default group (LOG_DEFAULT).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_trace_once(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
Log \a trace only once to group.
|
||||
@param[in] group log group (gs_log_group_t *).
|
||||
@param[in] format Format string (printf style).
|
||||
*/
|
||||
#define log_trace_once_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, (group), format, ##__VA_ARGS__); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
67
gomspace/libutil/include/gs/util/minmax.h
Normal file
67
gomspace/libutil/include/gs/util/minmax.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef GS_UTIL_MINMAX_H
|
||||
#define GS_UTIL_MINMAX_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Min/max utilities.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Return minimum value.
|
||||
@param[in] x value
|
||||
@param[in] y value
|
||||
@return the lowest value of the input parameters.
|
||||
*/
|
||||
#define gs_min(x,y) ({ \
|
||||
__typeof__ (x) _x = (x); \
|
||||
__typeof__ (y) _y = (y); \
|
||||
_x < _y ? _x : _y; })
|
||||
|
||||
/**
|
||||
Return maximum value.
|
||||
@param[in] x value
|
||||
@param[in] y value
|
||||
@return the maximum value of the input parameters.
|
||||
*/
|
||||
#define gs_max(x,y) ({ \
|
||||
__typeof__ (x) _x = (x); \
|
||||
__typeof__ (y) _y = (y); \
|
||||
_x > _y ? _x : _y; })
|
||||
|
||||
/**
|
||||
Return minimum value.
|
||||
@param[in] x value
|
||||
@param[in] y value
|
||||
@param[in] z value
|
||||
@return the lowest value of the input parameters.
|
||||
*/
|
||||
#define gs_min3(x,y,z) gs_min(gs_min((x),(y)), (z))
|
||||
|
||||
/**
|
||||
Return maximum value.
|
||||
@param[in] x value
|
||||
@param[in] y value
|
||||
@param[in] z value
|
||||
@return the maximum value of the input parameters.
|
||||
*/
|
||||
#define gs_max3(x,y,z) gs_max(gs_max((x),(y)), (z))
|
||||
|
||||
/**
|
||||
Clamp value within min/max.
|
||||
@param[in] x value
|
||||
@param[in] _max max value
|
||||
@param[in] _min min value
|
||||
@return value between min and max.
|
||||
*/
|
||||
#define gs_clamp(x, _min, _max) ({ \
|
||||
gs_min(gs_max((x), (_min)), (_max)); })
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
63
gomspace/libutil/include/gs/util/mutex.h
Normal file
63
gomspace/libutil/include/gs/util/mutex.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef GS_UTIL_MUTEX_H
|
||||
#define GS_UTIL_MUTEX_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Mutex (recursive).
|
||||
|
||||
The mutex API wraps POSIX \a pthread_mutex and FreeRTOS \a mutex.
|
||||
|
||||
@note Mutex can not be used from within an ISR routine - use gs_sem instead.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#if __linux__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
/**
|
||||
Mutex handle.
|
||||
*/
|
||||
typedef pthread_mutex_t * gs_mutex_t;
|
||||
#else
|
||||
typedef struct gs_freertos_mutex_t * gs_mutex_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
Create mutex.
|
||||
@param[out] mutex handle.
|
||||
@return error code.
|
||||
*/
|
||||
gs_error_t gs_mutex_create(gs_mutex_t * mutex);
|
||||
|
||||
/**
|
||||
Destroy mutex - free resources.
|
||||
@param[in] mutex handle.
|
||||
@return error code.
|
||||
*/
|
||||
gs_error_t gs_mutex_destroy(gs_mutex_t mutex);
|
||||
|
||||
/**
|
||||
Lock mutex.
|
||||
@param[in] mutex handle.
|
||||
@return error code.
|
||||
*/
|
||||
gs_error_t gs_mutex_lock(gs_mutex_t mutex);
|
||||
|
||||
/**
|
||||
Unlock mutex.
|
||||
@param[in] mutex handle.
|
||||
@return error code.
|
||||
*/
|
||||
gs_error_t gs_mutex_unlock(gs_mutex_t mutex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
162
gomspace/libutil/include/gs/util/pgm.h
Normal file
162
gomspace/libutil/include/gs/util/pgm.h
Normal file
@ -0,0 +1,162 @@
|
||||
#ifndef GS_UTIL_PROGMEM_H
|
||||
#define GS_UTIL_PROGMEM_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Macros for handling special memory access.
|
||||
|
||||
On most targets/processors, constant data/strings are located in the program space and can be read in the same way as data in the data space.
|
||||
However, on a few targets (e.g. avr/avr8), data/strings must be marked in a special way in order to go into the program space, see #GS_PGM_STR()
|
||||
|
||||
Using following macros, will make it easier to make cross-platform code and avoid \#if/\#endif.
|
||||
These macros should only be used where the code also needs to run on avr/avr8.
|
||||
|
||||
@note Including this header on avr/avr8 will REDEFINE printf!.
|
||||
|
||||
http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__pgmspace.html.
|
||||
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html.
|
||||
*/
|
||||
|
||||
#include <gs/util/stdio.h>
|
||||
#if defined(__AVR__)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__AVR__) || (__DOXYGEN__)
|
||||
/**
|
||||
Special program/data memory handling.
|
||||
*/
|
||||
#define GS_PGM 1
|
||||
|
||||
/**
|
||||
Place object in program space (must be const).
|
||||
Example: static const uint8_t data8[] GS_PGM_OBJECT = {1, 255};
|
||||
*/
|
||||
#define GS_PGM_OBJECT PROGMEM
|
||||
|
||||
/**
|
||||
Place const string in program space.
|
||||
By default the string goes into data, uses thereby uses up space.
|
||||
Once the string is placed in program space, xx_P functions must be used to access them - see #GS_PGM_PRINTF.
|
||||
@note printf is re-defined by including this header
|
||||
*/
|
||||
#define GS_PGM_STR(str) PSTR(str)
|
||||
|
||||
/**
|
||||
Read uint8 from program space (near).
|
||||
*/
|
||||
#define GS_PGM_UINT8(value) pgm_read_byte(&(value))
|
||||
|
||||
/**
|
||||
Read uint8 from program space using a pointer (near).
|
||||
*/
|
||||
#define GS_PGM_UINT8_BY_PTR(value) pgm_read_byte(value)
|
||||
|
||||
/**
|
||||
Read word from program space (near).
|
||||
*/
|
||||
#define GS_PGM_UINT16(value) pgm_read_word(&(value))
|
||||
/**
|
||||
Read word from program space using a pointer (near).
|
||||
*/
|
||||
#define GS_PGM_UINT16_BY_PTR(value) pgm_read_word(value)
|
||||
|
||||
/**
|
||||
Read dword from program space (near).
|
||||
*/
|
||||
#define GS_PGM_UINT32(value) pgm_read_dword(&(value))
|
||||
/**
|
||||
Read word from program space using a pointer (near).
|
||||
*/
|
||||
#define GS_PGM_UINT32_BY_PTR(value) pgm_read_dword(value)
|
||||
|
||||
/**
|
||||
Memcpy from program space (near).
|
||||
@param[in] dst destination.
|
||||
@param[in] src source - program space.
|
||||
@param[in] n number of bytes to copy
|
||||
*/
|
||||
#define GS_PGM_MEMCPY(dst, src, n) memcpy_P(dst, src, n)
|
||||
|
||||
/**
|
||||
String compare (program space)
|
||||
@param[in] s1 string 1
|
||||
@param[in] s2 string 2 - program space.
|
||||
@param[in] n max number of bytes to compare
|
||||
*/
|
||||
#define GS_PGM_STRNCMP(s1,s2,n) strncmp_P(s1, s2, n)
|
||||
|
||||
/**
|
||||
String compare (program space)
|
||||
@param[in] s1 string 1
|
||||
@param[in] s2 string 2 - program space.
|
||||
@param[in] n max number of bytes to compare
|
||||
*/
|
||||
#define GS_PGM_STRNCASECMP(s1,s2,n) strncasecmp_P(s1, s2, n)
|
||||
|
||||
/**
|
||||
String formatting character for referencing a string placed in programs space.
|
||||
*/
|
||||
#define GS_PGM_FMT_STR "S"
|
||||
|
||||
/**
|
||||
printf (format string in program space).
|
||||
Example: print \a param->name (from prgram space) and \a value from data space, using a format string in program space.
|
||||
GS_PGM_PRINTF(GS_PGM_STR("%"GS_PGM_FMT_STR", %d"), param->name, value)
|
||||
*/
|
||||
#define GS_PGM_PRINTF(format, ...) printf_P(format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
vprintf (format string in program space).
|
||||
*/
|
||||
#define GS_PGM_VPRINTF(format, va) vfprintf_P(stdout, format, va)
|
||||
|
||||
/**
|
||||
snprintf (format string in program space).
|
||||
*/
|
||||
#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf_P(buf, bufsize, format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
vsnprintf (format string in program space).
|
||||
*/
|
||||
#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf_P(buf, bufsize, format, va)
|
||||
|
||||
/**
|
||||
redefines printf (puts format string in program space)
|
||||
*/
|
||||
#undef printf
|
||||
#define printf(format, ...) GS_PGM_PRINTF(GS_PGM_STR(format), ## __VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#undef GS_PGM
|
||||
|
||||
#define GS_PGM_OBJECT
|
||||
#define GS_PGM_STR(str) (str)
|
||||
#define GS_PGM_UINT8(value) (value)
|
||||
#define GS_PGM_UINT8_BY_PTR(value) (*(value))
|
||||
#define GS_PGM_UINT16(value) (value)
|
||||
#define GS_PGM_UINT16_BY_PTR(value) (*(value))
|
||||
#define GS_PGM_UINT32(value) (value)
|
||||
#define GS_PGM_UINT32_BY_PTR(value) (*(value))
|
||||
#define GS_PGM_MEMCPY(dst, src, size) memcpy(dst, src, size)
|
||||
#define GS_PGM_STRNCMP(s1,pgmstr,size) strncmp(s1, pgmstr, size)
|
||||
#define GS_PGM_STRNCASECMP(s1,pgmstr,size) strncasecmp(s1, pgmstr, size)
|
||||
|
||||
#define GS_PGM_FMT_STR "s"
|
||||
#define GS_PGM_PRINTF(format, ...) printf(format, ## __VA_ARGS__)
|
||||
#define GS_PGM_VPRINTF(format, va) vprintf(format, va)
|
||||
#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf(buf, bufsize, format, ##__VA_ARGS__)
|
||||
#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf(buf, bufsize, format, va)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
102
gomspace/libutil/include/gs/util/queue.h
Normal file
102
gomspace/libutil/include/gs/util/queue.h
Normal file
@ -0,0 +1,102 @@
|
||||
#ifndef GS_UTIL_QUEUE_H
|
||||
#define GS_UTIL_QUEUE_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Queue.
|
||||
|
||||
The queue API wraps FreeRTOS \a queue.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
/**
|
||||
Queue handle.
|
||||
*/
|
||||
typedef struct gs_pthread_queue * gs_queue_t;
|
||||
#else
|
||||
typedef struct gs_freertos_queue_t * gs_queue_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
Create queue.
|
||||
|
||||
@param[in] items max number of items on the queue.
|
||||
@param[in] item_size size of item (bytes).
|
||||
@param[out] queue created queue.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue);
|
||||
|
||||
/**
|
||||
Destroy queue - free resources.
|
||||
|
||||
@param[in] queue handle.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_queue_destroy(gs_queue_t queue);
|
||||
|
||||
/**
|
||||
Enqueue object on queue.
|
||||
@param[in] queue handle.
|
||||
@param[in] value pointer to object, size specified at gs_queue_create().
|
||||
@param_int_timeout_ms
|
||||
@return_gs_error_timeout
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms);
|
||||
|
||||
/**
|
||||
Enqueue object on queue from within an ISR.
|
||||
@param[in] queue handle.
|
||||
@param[in] value pointer to object, size specified at gs_queue_create().
|
||||
@param[in] cswitch context switch.
|
||||
@return GS_ERROR_FULL if queue is full.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch);
|
||||
|
||||
/**
|
||||
Dequeue object from queue.
|
||||
@param[in] queue handle.
|
||||
@param[out] buf element - size specified in gs_queue_create().
|
||||
@param_int_timeout_ms
|
||||
@return_gs_error_timeout
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf);
|
||||
|
||||
/**
|
||||
Dequeue object from queue from within an ISR.
|
||||
@param[in] queue handle.
|
||||
@param[in] cswitch context switch.
|
||||
@param[out] buf element - size specified in gs_queue_create().
|
||||
@return GS_ERROR_NOT_FOUND if no elements in queue.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void * buf);
|
||||
|
||||
/**
|
||||
Return queue size.
|
||||
@param[in] queue handle.
|
||||
@return queue size
|
||||
*/
|
||||
unsigned int gs_queue_size(gs_queue_t queue);
|
||||
|
||||
/**
|
||||
Return queue size from within an ISR.
|
||||
@param[in] queue handle.
|
||||
@return queue size
|
||||
*/
|
||||
unsigned int gs_queue_size_isr(gs_queue_t queue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user