save failed integration state
This commit is contained in:
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
|
62
gomspace/libutil/include/gs/util/rtc.h
Normal file
62
gomspace/libutil/include/gs/util/rtc.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef GS_UTIL_RTC_H
|
||||
#define GS_UTIL_RTC_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Real Time Clock interface.
|
||||
|
||||
The RTC driver is used by gs_clock_get_time() and gs_clock_set_time().
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <gs/util/timestamp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Platform supporting RTC must register the driver, before the rest of the system can access it.
|
||||
@see gs_rtc_register()
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Call-back for getting RTC time.
|
||||
@param[out] time user allocated struct for returning time.
|
||||
*/
|
||||
gs_error_t (*get_time)(void * driver_data, gs_timestamp_t * time);
|
||||
/**
|
||||
Call-back for setting RTC time.
|
||||
@param[in] time user allocated struct for returning time.
|
||||
*/
|
||||
gs_error_t (*set_time)(void * driver_data, const gs_timestamp_t * time);
|
||||
} gs_rtc_driver_t;
|
||||
|
||||
/**
|
||||
Register RTC driver.
|
||||
@param[in] driver driver - data/struct must remain valid as long as registered.
|
||||
@param[in] driver_data driver specific data, forwarded to driver when set/get is called.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data);
|
||||
|
||||
/**
|
||||
Return GS_OK if RTC is supported.
|
||||
*/
|
||||
gs_error_t gs_rtc_supported(void);
|
||||
|
||||
/**
|
||||
Set RTC.
|
||||
*/
|
||||
gs_error_t gs_rtc_get_time(gs_timestamp_t * time);
|
||||
|
||||
/**
|
||||
Get RTC.
|
||||
*/
|
||||
gs_error_t gs_rtc_set_time(const gs_timestamp_t * time);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
75
gomspace/libutil/include/gs/util/sem.h
Normal file
75
gomspace/libutil/include/gs/util/sem.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef GS_UTIL_SEM_H
|
||||
#define GS_UTIL_SEM_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Semaphore.
|
||||
|
||||
The semaphore API wraps POSIX \a semaphore and FreeRTOS \a counted semaphore.
|
||||
|
||||
Main difference is that FreeRTOS uses different API calls, when called from within
|
||||
an ISR routine.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#if __linux__
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
/**
|
||||
Semaphore handle.
|
||||
*/
|
||||
typedef sem_t * gs_sem_t;
|
||||
#else
|
||||
typedef struct gs_freertos_sem_t * gs_sem_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
Create semaphore.
|
||||
@param[in] initialValue initial value.
|
||||
@param[out] sem created semaphore.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem);
|
||||
|
||||
/**
|
||||
Destroy semaphore - free resources.
|
||||
@param[in] sem handle.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_sem_destroy(gs_sem_t sem);
|
||||
|
||||
/**
|
||||
Wait for semaphore to be signaled.
|
||||
@param[in] sem handle.
|
||||
@param_int_timeout_ms
|
||||
@return_gs_error_timeout
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms);
|
||||
|
||||
/**
|
||||
Post/signal semaphore.
|
||||
@param[in] sem handle.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_sem_post(gs_sem_t sem);
|
||||
|
||||
/**
|
||||
Post/signal semaphore from within a ISR.
|
||||
@param[in] sem handle.
|
||||
@param[in] cswitch context switch.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
117
gomspace/libutil/include/gs/util/stdio.h
Normal file
117
gomspace/libutil/include/gs/util/stdio.h
Normal file
@ -0,0 +1,117 @@
|
||||
#ifndef GS_UTIL_STDIO_H
|
||||
#define GS_UTIL_STDIO_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
GomSpace extensions to standard \a stdio.h.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Put character on stdout.
|
||||
*/
|
||||
gs_error_t gs_stdio_putchar(int ch);
|
||||
|
||||
/**
|
||||
Read character from stdin with timeout.
|
||||
@param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milli seconds.
|
||||
@param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned.
|
||||
@return GS_ERROR_TIMEOUT on timeout
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_stdio_getchar_timed(int timeout_ms, int *ch);
|
||||
|
||||
/**
|
||||
Read character from stdin.
|
||||
Blocks until a character is available.
|
||||
@param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
static inline gs_error_t gs_stdio_getchar(int * ch)
|
||||
{
|
||||
return gs_stdio_getchar_timed(-1, ch);
|
||||
}
|
||||
|
||||
/**
|
||||
Read characters from stdin.
|
||||
Blocks until all characters are read.
|
||||
@param[in,out] buf user supplied buffer for receiving characters.
|
||||
@param[in] n number of characters to read.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_stdio_get(char * buf, size_t n);
|
||||
|
||||
/**
|
||||
Write characters to stdout.
|
||||
Blocks until characters are written.
|
||||
@param[in] buf characters to write.
|
||||
@param[in] n number of characters to write.
|
||||
@param[in] text if \a true, new lines (\\n) are converted to \\r\\n.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_stdio_put(const char * buf, size_t n, bool text);
|
||||
|
||||
/**
|
||||
Pattern for printing a byte as binary.
|
||||
@see GS_STDIO_BYTETOBINARY()
|
||||
*/
|
||||
#define GS_STDIO_BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
|
||||
|
||||
/**
|
||||
Macro for splitting a byte info 'bits'.
|
||||
*/
|
||||
#define GS_STDIO_BYTETOBINARY(byte) \
|
||||
(byte & 0x80 ? 1 : 0), \
|
||||
(byte & 0x40 ? 1 : 0), \
|
||||
(byte & 0x20 ? 1 : 0), \
|
||||
(byte & 0x10 ? 1 : 0), \
|
||||
(byte & 0x08 ? 1 : 0), \
|
||||
(byte & 0x04 ? 1 : 0), \
|
||||
(byte & 0x02 ? 1 : 0), \
|
||||
(byte & 0x01 ? 1 : 0)
|
||||
|
||||
/**
|
||||
Color definitions for gs_color_printf()
|
||||
@see gs_color_printf()
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Colors.
|
||||
*/
|
||||
GS_COLOR_COLORS = 0x00ff,
|
||||
GS_COLOR_NONE = 0,
|
||||
GS_COLOR_BLACK = 1,
|
||||
GS_COLOR_RED = 2,
|
||||
GS_COLOR_GREEN = 3,
|
||||
GS_COLOR_YELLOW = 4,
|
||||
GS_COLOR_BLUE = 5,
|
||||
GS_COLOR_MAGENTA = 6,
|
||||
GS_COLOR_CYAN = 7,
|
||||
GS_COLOR_WHITE = 8,
|
||||
/**
|
||||
Attributes
|
||||
*/
|
||||
GS_COLOR_ATTRS = 0xff00,
|
||||
GS_COLOR_BOLD = 0x100,
|
||||
} gs_color_printf_t;
|
||||
|
||||
/**
|
||||
Printf with colors on stdout.
|
||||
|
||||
Using the standard terminal escape sequences for setting the color.
|
||||
@param[in] color color settings.
|
||||
@param[in] format standard printf format string.
|
||||
*/
|
||||
void gs_color_printf(gs_color_printf_t color, const char * format, ...) __attribute__ ((format (__printf__, 2, 3)));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
391
gomspace/libutil/include/gs/util/string.h
Normal file
391
gomspace/libutil/include/gs/util/string.h
Normal file
@ -0,0 +1,391 @@
|
||||
#ifndef GS_UTIL_STRING_H
|
||||
#define GS_UTIL_STRING_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
String utilitizes.
|
||||
|
||||
All string parsing functions will return #GS_OK if the string was parsed entirely.
|
||||
If the string contains characters that are not part of the selected base, the functions will return #GS_ERROR_DATA.
|
||||
If the value parsed is bigger than the output type, the functions will return #GS_ERROR_OVERFLOW.
|
||||
Spaces are ignored by all functions.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Macro helper for concatening tokens.
|
||||
*/
|
||||
#define GS_STRINGZ(x) #x
|
||||
|
||||
/**
|
||||
Stringify a preprocessing token.
|
||||
*/
|
||||
#define GS_DEF2STRING(x) GS_STRINGZ(x)
|
||||
|
||||
/**
|
||||
* Strncpy (using size of destination) and forced zero termination.
|
||||
*/
|
||||
#define GS_STRNCPY(dst,src) strncpy(dst,src,GS_ARRAY_SIZE(dst));dst[GS_ARRAY_SIZE(dst)-1] = 0
|
||||
|
||||
/**
|
||||
Convert string to int32 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_int32(const char * string, int32_t * value);
|
||||
|
||||
/**
|
||||
Convert string to uint32 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_uint32(const char * string, uint32_t * value);
|
||||
|
||||
/**
|
||||
Convert string to int64 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_int64(const char * string, int64_t * value);
|
||||
|
||||
/**
|
||||
Convert string to uint64 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_uint64(const char * string, uint64_t * value);
|
||||
|
||||
/**
|
||||
Convert string to int8 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_int8(const char * string, int8_t * value);
|
||||
|
||||
/**
|
||||
Convert string to uint8 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_uint8(const char * string, uint8_t * value);
|
||||
|
||||
/**
|
||||
Convert string to int16 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_int16(const char * string, int16_t * value);
|
||||
|
||||
/**
|
||||
Convert string to uint16 (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_uint16(const char * string, uint16_t * value);
|
||||
|
||||
/**
|
||||
Convert string to uint32 (hexadecimal).
|
||||
Accepts: hexadecimal (no leading 0x), e.g. a123, A123.
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * value);
|
||||
|
||||
/**
|
||||
Convert string to uint64 (hexadecimal).
|
||||
Accepts: hexadecimal (no leading 0x), e.g. a123, A123.
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * value);
|
||||
|
||||
/**
|
||||
Convert string to boolean.
|
||||
Accepts: true, false, on, off, 1, 0 (ignores case)
|
||||
@param[in] string string to convert.
|
||||
@param[out] pvalue converted value
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_bool(const char * string, bool * pvalue);
|
||||
|
||||
/**
|
||||
Convert string to float.
|
||||
@param[in] string string to convert.
|
||||
@param[out] pvalue converted value
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_float(const char * string, float * pvalue);
|
||||
|
||||
/**
|
||||
Convert string to double.
|
||||
@param[in] string string to convert.
|
||||
@param[out] pvalue converted value
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_double(const char * string, double * pvalue);
|
||||
|
||||
/**
|
||||
Return string for boolean value (true or false).
|
||||
@param[in] value value
|
||||
@return \a 'true' if input is true, else \a 'false'.
|
||||
*/
|
||||
const char * gs_string_from_bool(bool value);
|
||||
|
||||
/**
|
||||
Convert string to pointer (decimal or hexadecimal).
|
||||
Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal)
|
||||
@param[in] string string to convert.
|
||||
@param[out] value converted value
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
gs_error_t gs_string_to_pointer(const char * string, void ** value);
|
||||
|
||||
/**
|
||||
Format size as Bytes, Kilo or Mega.
|
||||
|
||||
Output examples: \a 512.0B, \a 1.0K and \a 1.0M.
|
||||
|
||||
@param[in] size size in bytes
|
||||
@param[out] buffer formatted size
|
||||
@param[in] buffer_size size of \a buf
|
||||
@return GS_ERROR_OVERFLOW if the resulting value is larger than the output type
|
||||
@return GS_ERROR_DATA if the input string could not be parsed completely
|
||||
@return GS_ERROR_ARG if the input string is a NULL pointer
|
||||
*/
|
||||
char * gs_string_bytesize(long size, char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
GS implementation of gcc's strtol
|
||||
Instead of setting errno this function takes a pointer to err which is set
|
||||
the same way as with gcc's strtol
|
||||
|
||||
@param[in] nptr input string
|
||||
@param[out] endptr the pointer to the end of the string parsed
|
||||
@param[in] base number system (10 or 16)
|
||||
@param[out] err return value if overflow
|
||||
@return converted value
|
||||
*/
|
||||
int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err);
|
||||
|
||||
/**
|
||||
GS implementation of gcc's strtoul
|
||||
Instead of setting errno this function takes a pointer to err which is set
|
||||
the same way as with gcc's strtoul
|
||||
|
||||
@param[in] nptr input string
|
||||
@param[out] endptr the pointer to the end of the string parsed
|
||||
@param[in] base number system (10 or 16)
|
||||
@param[out] err return value if overflow
|
||||
@return converted value
|
||||
*/
|
||||
uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err);
|
||||
|
||||
/**
|
||||
GS implementation of gcc's strtoul
|
||||
Instead of setting errno this function takes a pointer to err which is set
|
||||
the same way as with gcc's strtoul
|
||||
|
||||
@param[in] nptr input string
|
||||
@param[out] endptr the pointer to the end of the string parsed
|
||||
@param[in] base number system (10 or 16)
|
||||
@param[out] err return value if overflow
|
||||
@return converted value
|
||||
*/
|
||||
int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err);
|
||||
|
||||
/**
|
||||
GS implementation of gcc's strtoul
|
||||
Instead of setting errno this function takes a pointer to err which is set
|
||||
the same way as with gcc's strtoul
|
||||
|
||||
@param[in] nptr input string
|
||||
@param[out] endptr the pointer to the end of the string parsed
|
||||
@param[in] base number system (10 or 16)
|
||||
@param[out] err return value if overflow
|
||||
@return converted value
|
||||
*/
|
||||
uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err);
|
||||
|
||||
/**
|
||||
Returns pointer to first none-space character.
|
||||
|
||||
@param[in] string string
|
||||
@return NULL if \a string is NULL, otherwise first none-space character.
|
||||
*/
|
||||
const char * gs_string_skip_leading_spaces(const char * string);
|
||||
|
||||
/**
|
||||
Check if a string is NULL or empty.
|
||||
|
||||
@param[in] string string
|
||||
@return true if string is empty or NULL.
|
||||
*/
|
||||
bool gs_string_empty(const char * string);
|
||||
|
||||
/**
|
||||
Case-insentive wilcard match (similiar to fnmatch).
|
||||
|
||||
Supports following wildcard(s):
|
||||
- * (asterix) zero or more characters.
|
||||
|
||||
This may be extended in future versions and will not be considered a break of the API.
|
||||
|
||||
@param[in] pattern pattern to match against \a string.
|
||||
@param[in] string string to match against \a pattern
|
||||
@return \a true if match, else \ false
|
||||
*/
|
||||
bool gs_string_match(const char * pattern, const char * string);
|
||||
|
||||
/**
|
||||
Returns \a true if string contains wildcards.
|
||||
|
||||
@param[in] string string to check for wildcards.
|
||||
@return \a true if string contains wildcards recognized by gs_string_match().
|
||||
*/
|
||||
bool gs_string_has_wildcards(const char * string);
|
||||
|
||||
/**
|
||||
Trim string in buffer by removing leading/trailing white space.
|
||||
|
||||
Uses isspace(c).
|
||||
|
||||
@param[in] buffer buffer to trim.
|
||||
@param[in] buffer_size size of \a buffer.
|
||||
*/
|
||||
void gs_string_trim(char * buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
Returns \a true if string ends with endswith.
|
||||
|
||||
@param[in] string string to check
|
||||
@param[in] endswith string that string should end with
|
||||
@return \a true if string endswith endswith
|
||||
*/
|
||||
bool gs_string_endswith(const char * string, const char * endswith);
|
||||
|
||||
/**
|
||||
Extract suboption from a string.
|
||||
|
||||
@param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\".
|
||||
@param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present).
|
||||
@param[out] buf user buffer for returning value of sub-option.
|
||||
@param[in] buf_size size of \a buf user buffer.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size);
|
||||
|
||||
/**
|
||||
Extract suboption (as string) from a string.
|
||||
|
||||
@param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\".
|
||||
@param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present).
|
||||
@param[in] def default value, returned if sub-option isn't found.
|
||||
@param[out] buf user buffer for returning value of sub-option.
|
||||
@param[in] buf_size size of \a buf user buffer.
|
||||
@return If the sub-option isn't found, the \a def default value will be copied to \a buf and #GS_OK will be returned.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size);
|
||||
|
||||
/**
|
||||
Extract suboption (as uint8) from a string.
|
||||
|
||||
@param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\".
|
||||
@param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present).
|
||||
@param[in] def default value, returned if sub-option isn't found.
|
||||
@param[out] value user supplied buffer for returning the value.
|
||||
@return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value);
|
||||
|
||||
/**
|
||||
Extract suboption (as uint16) from a string.
|
||||
|
||||
@param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\".
|
||||
@param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present).
|
||||
@param[in] def default value, returned if sub-option isn't found.
|
||||
@param[out] value user supplied buffer for returning the value.
|
||||
@return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value);
|
||||
|
||||
/**
|
||||
Extract suboption (as uint32) from a string.
|
||||
|
||||
@param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\".
|
||||
@param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present).
|
||||
@param[in] def default value, returned if sub-option isn't found.
|
||||
@param[out] value user supplied buffer for returning the value.
|
||||
@return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value);
|
||||
|
||||
/**
|
||||
Extract suboption (as bool) from a string.
|
||||
|
||||
@param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\".
|
||||
@param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present).
|
||||
@param[in] def default value, returned if sub-option isn't found.
|
||||
@param[out] value user supplied buffer for returning the value.
|
||||
@return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
136
gomspace/libutil/include/gs/util/test/cmocka.h
Normal file
136
gomspace/libutil/include/gs/util/test/cmocka.h
Normal file
@ -0,0 +1,136 @@
|
||||
#ifndef GS_UTIL_TEST_CMOCKA_H
|
||||
#define GS_UTIL_TEST_CMOCKA_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Cmocka extensions.
|
||||
|
||||
Official site for cmocka https://cmocka.org.
|
||||
*/
|
||||
|
||||
#include <gs/util/string.h>
|
||||
|
||||
// cmocka
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !(__DOXYGEN__)
|
||||
// internal helpers - use macros
|
||||
void _gs_assert_int_equal(const intptr_t a, const intptr_t b, bool equal, const char * const file, const int line);
|
||||
void _gs_assert_uint_equal(const uintptr_t a, const uintptr_t b, bool equal, bool hex, const char * const file, const int line);
|
||||
void _gs_assert_error_equal(const int a, const int b, bool equal, const char * const file, const int line);
|
||||
void _gs_assert_float_equal(const float a, const float b, const float diff, bool equal, const char * const file, const int line);
|
||||
void _gs_assert_double_equal(const double a, const double b, const double diff, bool equal, const char * const file, const int line);
|
||||
#endif
|
||||
|
||||
/**
|
||||
Assert int (print value as signed).
|
||||
*/
|
||||
#define GS_ASSERT_INT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert unsigned int (print value as unsigned).
|
||||
*/
|
||||
#define GS_ASSERT_UINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert int (print value as hex).
|
||||
*/
|
||||
#define GS_ASSERT_XINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert #gs_error_t (print value and error text).
|
||||
*/
|
||||
#define GS_ASSERT_ERROR_EQUAL(a,b) _gs_assert_error_equal(a, b, true, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert #GS_OK (print value and error text).
|
||||
*/
|
||||
#define GS_ASSERT_ERROR_OK(a) _gs_assert_error_equal(a, GS_OK, true, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert float (print value as signed).
|
||||
*/
|
||||
#define GS_ASSERT_FLOAT_EQUAL(a,b,diff) _gs_assert_float_equal(a, b, diff, true, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert double (print value as signed).
|
||||
*/
|
||||
#define GS_ASSERT_DOUBLE_EQUAL(a,b,diff) _gs_assert_double_equal(a, b, diff, true, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
Assert int (print value as signed).
|
||||
*/
|
||||
#define GS_ASSERT_INT_NOT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), false, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert unsigned int (print value as unsigned).
|
||||
*/
|
||||
#define GS_ASSERT_UINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, false, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert int (print value as hex).
|
||||
*/
|
||||
#define GS_ASSERT_XINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, true, __FILE__, __LINE__)
|
||||
/**
|
||||
Assert #GS_OK (print value and error text).
|
||||
*/
|
||||
#define GS_ASSERT_ERROR_NOT_EQUAL(a,b) _gs_assert_error_equal(a, b, false, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
Code reference.
|
||||
*/
|
||||
#define GS_REF() __FILE__,__LINE__
|
||||
/**
|
||||
Assert int with code reference (print value as signed).
|
||||
*/
|
||||
#define GS_ASSERT_INT_EQUAL_REF(a,b,file,line) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, file, file, line)
|
||||
/**
|
||||
Assert unsigned int with code reference (print value as unsigned).
|
||||
*/
|
||||
#define GS_ASSERT_UINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, file, line)
|
||||
/**
|
||||
Assert int with code reference (print value as hex).
|
||||
*/
|
||||
#define GS_ASSERT_XINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, file, line)
|
||||
/**
|
||||
Assert #gs_error_t with code reference (print value and error text).
|
||||
*/
|
||||
#define GS_ASSERT_ERROR_EQUAL_REF(a,b,file,line) _gs_assert_error_equal(a, b, true, file, line)
|
||||
/**
|
||||
Assert #GS_OK with code reference (print value and error text).
|
||||
*/
|
||||
#define GS_ASSERT_ERROR_OK_REF(a,file,line) _gs_assert_error_equal(a, GS_OK, true, file, line)
|
||||
|
||||
/**
|
||||
Run \a cmocka test group.
|
||||
|
||||
@param[in] name name of test. If name is \a tests and GS_TEST_NAME is set, GS_TEST_NAME will be used instead.
|
||||
@param[in] tests array of tests.
|
||||
@param[in] num_tests number of tests.
|
||||
@param[in] setup setup function, can be NULL.
|
||||
@param[in] teardown teardown function, can be NULL.
|
||||
@return 0 on success.
|
||||
*/
|
||||
static inline int gs_cmocka_run_group_tests(const char *name,
|
||||
const struct CMUnitTest * const tests,
|
||||
const size_t num_tests,
|
||||
CMFixtureFunction setup,
|
||||
CMFixtureFunction teardown)
|
||||
{
|
||||
#ifdef GS_TEST_NAME // set by buildtools::gs_test_cmocka.py
|
||||
if (strcasecmp(name, "tests") == 0) {
|
||||
name = GS_DEF2STRING(GS_TEST_NAME);
|
||||
}
|
||||
#endif
|
||||
return _cmocka_run_group_tests(name, tests, num_tests, setup, teardown);
|
||||
}
|
||||
|
||||
#ifdef GS_TEST_NAME
|
||||
// hi-jack cmocka's macro
|
||||
#undef cmocka_run_group_tests
|
||||
#define cmocka_run_group_tests(tests, setup, teardown) gs_cmocka_run_group_tests(GS_DEF2STRING(tests), tests, GS_ARRAY_SIZE(tests), setup, teardown)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
80
gomspace/libutil/include/gs/util/test/command.h
Normal file
80
gomspace/libutil/include/gs/util/test/command.h
Normal file
@ -0,0 +1,80 @@
|
||||
#ifndef GS_UTIL_TEST_COMMAND_H
|
||||
#define GS_UTIL_TEST_COMMAND_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Command Test framework.
|
||||
|
||||
Provides a simple way of unit-testing/validating commands.
|
||||
*/
|
||||
|
||||
#include <gs/util/gosh/command.h>
|
||||
#include <gs/util/test/cmocka.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Validate command execution.
|
||||
|
||||
Runs a commands and validates the output/results agains the inputs.
|
||||
Asserts if the results does not match.
|
||||
|
||||
@param[in] cmd command (including arguments) to execute.
|
||||
@param[in] ret expected return code from the command execution framework.
|
||||
@param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK).
|
||||
@param[in] std_in string with expected command input.
|
||||
@param[in] std_out string with expected command output. Wildcards (*\/?) are supported.
|
||||
@param[in] file string with file name.
|
||||
@param[in] line string with line no.
|
||||
@return void
|
||||
*/
|
||||
void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, const char * const file, const int line);
|
||||
|
||||
/**
|
||||
Validate command results returned from last command execution.
|
||||
Asserts if the results does not match.
|
||||
|
||||
@param[in] no the result no to verify.
|
||||
@param[in] group string with expected group id. Wildcards (*\/?) are supported.
|
||||
@param[in] key string with expected key. Wildcards (*\/?) are supported.
|
||||
@param[in] value string with expected value. Wildcards (*\/?) are supported.
|
||||
@param[in] file string with file name.
|
||||
@param[in] line string with line no.
|
||||
@return void
|
||||
*/
|
||||
void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, const char * const file, const int line);
|
||||
|
||||
/**
|
||||
Validate command execution.
|
||||
|
||||
Runs a commands and validates the output/results agains the inputs.
|
||||
Asserts if the results does not match.
|
||||
|
||||
@param[in] cmd command (including arguments) to execute.
|
||||
@param[in] ret expected return code from the command execution framework.
|
||||
@param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK).
|
||||
@param[in] std_in string with expected command input.
|
||||
@param[in] std_out string with expected command output. Wildcards (*\/?) are supported.
|
||||
@return void
|
||||
*/
|
||||
#define GS_ASSERT_COMMAND(cmd,ret,cmd_ret,std_in,std_out) _gs_assert_command_validate(cmd,ret,cmd_ret,std_in,std_out, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Validate command results returned from last command execution.
|
||||
Asserts if the results does not match.
|
||||
|
||||
@param[in] no the result no to verify.
|
||||
@param[in] group string with expected group id. Wildcards (*\/?) are supported.
|
||||
@param[in] key string with expected key. Wildcards (*\/?) are supported.
|
||||
@param[in] value string with expected value. Wildcards (*\/?) are supported.
|
||||
@return void
|
||||
*/
|
||||
#define GS_ASSERT_COMMAND_RESULT(no,group,key,value) _gs_assert_command_validate_last_result(no,group,key,value, __FILE__, __LINE__);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
88
gomspace/libutil/include/gs/util/test/log.h
Normal file
88
gomspace/libutil/include/gs/util/test/log.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef GS_UTIL_TEST_LOG_H
|
||||
#define GS_UTIL_TEST_LOG_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Log Test framework.
|
||||
|
||||
Provides a simple way of veriyfing logs generated during unit-testing.
|
||||
*/
|
||||
|
||||
#include <gs/util/log/log.h>
|
||||
#include <gs/util/test/cmocka.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Assert log count - internal helper function.
|
||||
*/
|
||||
void gs_assert_log_count(int level, unsigned int count, const char * file, int line);
|
||||
|
||||
/**
|
||||
Assert log messag and count - internal helper function.
|
||||
*/
|
||||
void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line);
|
||||
|
||||
/**
|
||||
Initialize framework, by installing a callback for \a print.
|
||||
@param[in] verbose of \a true, logs will be printed on stdout.
|
||||
*/
|
||||
void gs_test_log_init(bool verbose);
|
||||
|
||||
/**
|
||||
Clear log stats.
|
||||
*/
|
||||
void gs_test_log_clear(void);
|
||||
|
||||
/**
|
||||
Assert number of error logs.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_ERROR(cnt) gs_assert_log_count(LOG_ERROR, cnt, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Assert number of warning logs.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_WARNING(cnt) gs_assert_log_count(LOG_WARNING, cnt, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Assert number of notice logs.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_NOTICE(cnt) gs_assert_log_count(LOG_NOTICE, cnt, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Assert number of info logs.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_INFO(cnt) gs_assert_log_count(LOG_INFO, cnt, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Assert number of debug logs.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_DEBUG(cnt) gs_assert_log_count(LOG_DEBUG, cnt, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Assert number of trace logs.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_TRACE(cnt) gs_assert_log_count(LOG_TRACE, cnt, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Assert number of all logs.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_ALL(cnt) gs_assert_log_count(-1, cnt, __FILE__, __LINE__);
|
||||
|
||||
/**
|
||||
Assert/find number of entries matching level and pattern.
|
||||
*/
|
||||
#define GS_ASSERT_LOG(count,level,pattern) gs_assert_log(-1, count, level, pattern, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
Assert log at stack index against matching level and pattern.
|
||||
*/
|
||||
#define GS_ASSERT_LOG_AT(stack_index,level,pattern) gs_assert_log(stack_index, 1, level, pattern, __FILE__, __LINE__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
173
gomspace/libutil/include/gs/util/thread.h
Normal file
173
gomspace/libutil/include/gs/util/thread.h
Normal file
@ -0,0 +1,173 @@
|
||||
#ifndef GS_UTIL_THREAD_H
|
||||
#define GS_UTIL_THREAD_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Thread/task API based on POSIX standard.
|
||||
|
||||
The thread API wraps POSIX \a pthread and FreeRTOS \a task.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
#if __linux__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
/**
|
||||
Thread handle.
|
||||
*/
|
||||
typedef pthread_t gs_thread_t;
|
||||
#else
|
||||
typedef struct gs_freertos_task_t * gs_thread_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
Type used to declare thread stack buffer for gs_thread_create_with_stack.
|
||||
*/
|
||||
typedef uint32_t gs_stack_type_t;
|
||||
|
||||
/**
|
||||
Thread priorities.
|
||||
These values are mapped to platform specific values.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Idle (lowest) priority.
|
||||
Typical use: Not much - runs when nothing else runs.
|
||||
FreeRTOS: Idle thread.
|
||||
*/
|
||||
GS_THREAD_PRIORITY_IDLE = 5,
|
||||
/**
|
||||
Low priority.
|
||||
Typical use: Service applications, e.g. servicing requests from the outside.
|
||||
GOMspace: housekeeping, GOSH.
|
||||
*/
|
||||
GS_THREAD_PRIORITY_LOW = 10,
|
||||
/**
|
||||
Normal priority.
|
||||
Typical use: Control - the primary application(s).
|
||||
*/
|
||||
GS_THREAD_PRIORITY_NORMAL = 15,
|
||||
/**
|
||||
High priority.
|
||||
Typical use: Drivers off loading data from hardware to software buffers.
|
||||
GOMspace: csp_route_task.
|
||||
*/
|
||||
GS_THREAD_PRIORITY_HIGH = 20,
|
||||
/**
|
||||
High priority.
|
||||
Typical use: Very time critical threads. No long, time consuming processing.
|
||||
FreeRTOS: Timer thread.
|
||||
*/
|
||||
GS_THREAD_PRIORITY_CRITICAL = 25,
|
||||
} gs_thread_priority_t;
|
||||
|
||||
/**
|
||||
Thread function.
|
||||
*/
|
||||
typedef void * (*gs_thread_func_t)(void * parameter);
|
||||
|
||||
/**
|
||||
Create thread as joinable.
|
||||
@note only supported on linux. The thread must be joined to free all resources.
|
||||
*/
|
||||
#define GS_THREAD_CREATE_JOINABLE 0x0001
|
||||
|
||||
/**
|
||||
Create thread (or task on some platforms).
|
||||
|
||||
pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix.
|
||||
|
||||
FreeRTOS: a thread must always terminate with a call to gs_thread_exit().
|
||||
linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified.
|
||||
|
||||
@param[in] name name of thread. Ignored on Linux.
|
||||
@param[in] func function for thread to execute.
|
||||
@param[in] parameter parameter parsed to the thread function.
|
||||
@param[in] stack_size number of bytes to allocate for stack - not used/supported on all platforms. Ignored on Linux.
|
||||
@param[in] priority thread priority. Ignored on Linux.
|
||||
@param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE.
|
||||
@param[out] handle handle to the created thread, use NULL if not wanted.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_thread_create(const char * const name,
|
||||
gs_thread_func_t func,
|
||||
void * parameter,
|
||||
size_t stack_size,
|
||||
gs_thread_priority_t priority,
|
||||
uint32_t flags,
|
||||
gs_thread_t * handle);
|
||||
|
||||
/**
|
||||
Create thread (or task on some platforms) with user supplied buffer for stack.
|
||||
|
||||
pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix.
|
||||
|
||||
FreeRTOS: a thread must always terminate with a call to gs_thread_exit().
|
||||
FreeRTOS v9.0 must be compiled with configSUPPORT_STATIC_ALLOCTION set to 1 - otherwise warning log is printed and user supplied
|
||||
stack buffer is discarded
|
||||
linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified.
|
||||
stack_buf is ignored.
|
||||
|
||||
@param[in] name name of thread. Ignored on Linux.
|
||||
@param[in] func function for thread to execute.
|
||||
@param[in] parameter parameter parsed to the thread function.
|
||||
@param[in] stack_size size of the user supplied stack buffer - not used/supported on all platforms. Ignored on Linux.
|
||||
@param[in] stack_buf User supplied stack buffer - not used/supported on all platforms. Ignored on Linux.
|
||||
@param[in] priority thread priority. Ignored on Linux.
|
||||
@param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE.
|
||||
@param[out] handle handle to the created thread, use NULL if not wanted.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_thread_create_with_stack(const char * const name,
|
||||
gs_thread_func_t func,
|
||||
void * parameter,
|
||||
size_t stack_size,
|
||||
gs_stack_type_t *stack_buf,
|
||||
gs_thread_priority_t priority,
|
||||
uint32_t flags,
|
||||
gs_thread_t * handle);
|
||||
|
||||
/**
|
||||
Exit current thread.
|
||||
@param[in] exit_value exit value.
|
||||
*/
|
||||
void gs_thread_exit(void * exit_value) __attribute__ ((noreturn));
|
||||
|
||||
/**
|
||||
Sleep for X milli-seconds.
|
||||
@note FreeRTOS: minimum sleep time depends on ticks per milli-second. A thread is suspended minimum 1 tick - unless \a time_ms is 0, in which case yield is called.
|
||||
@deprecated use gs_time_sleep_ms()
|
||||
@param[in] time_ms milli-seconds to sleep.
|
||||
*/
|
||||
void gs_thread_sleep_ms(uint32_t time_ms);
|
||||
|
||||
/**
|
||||
Join with a terminated thread.
|
||||
|
||||
@note Only supported on Linux and primarily used for testing.
|
||||
@note This is not based on pthread_cancel(), so the user must have signaled the thread to stop - otherwise this will hang forever.
|
||||
|
||||
@param[in] thread handle.
|
||||
@param[out] return_retval return value from thread, use NULL if not wanted.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval);
|
||||
|
||||
/**
|
||||
Block thread forever.
|
||||
|
||||
Primarily used in Linux applications main() to block main thread.
|
||||
*/
|
||||
void gs_thread_block(void) __attribute__ ((noreturn));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
95
gomspace/libutil/include/gs/util/time.h
Normal file
95
gomspace/libutil/include/gs/util/time.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef GS_UTIL_TIME_H
|
||||
#define GS_UTIL_TIME_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Releative time.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Converts minutes to seconds.
|
||||
*/
|
||||
#define GS_TIME_MINS_TO_SECS(m) (m * 60)
|
||||
|
||||
/**
|
||||
Converts hours to seconds.
|
||||
*/
|
||||
#define GS_TIME_HOURS_TO_SECS(h) (h * GS_TIME_MINS_TO_SECS(60))
|
||||
|
||||
/**
|
||||
Converts days to seconds.
|
||||
*/
|
||||
#define GS_TIME_DAYS_TO_SECS(d) (d * GS_TIME_HOURS_TO_SECS(24))
|
||||
|
||||
/**
|
||||
Return relative time (milli seconds).
|
||||
@note This will eventually wrap on all platforms - platform must wrap on 32 bit.
|
||||
@return relativ milli seconds
|
||||
*/
|
||||
uint32_t gs_time_rel_ms(void);
|
||||
|
||||
/**
|
||||
Return relative time (milli seconds).
|
||||
@note This will eventually wrap on all platforms - platform must wrap on 32 bit.
|
||||
@return relativ milli seconds
|
||||
*/
|
||||
uint32_t gs_time_rel_ms_isr(void);
|
||||
|
||||
/**
|
||||
Returns seconds since process started.
|
||||
@note On some platforms (e.g. Linux), first call will set offset and
|
||||
first call it therefor not thread-safe.
|
||||
@return seconds since boot (or process startup).
|
||||
*/
|
||||
uint32_t gs_time_uptime(void);
|
||||
|
||||
/**
|
||||
Return time difference, compensating for time wrap due to 32 bit.
|
||||
@note the function can not detect multiple time wraps, so function using it should
|
||||
take action within 32 bit time.
|
||||
@param[in] ref_ms reference time.
|
||||
@param[in] now_ms current time.
|
||||
@returns ms difference, compensating for time wrapping (if now_ms is less than ref_ms).
|
||||
*/
|
||||
uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms);
|
||||
|
||||
/**
|
||||
Sleep for X milli-seconds.
|
||||
No busy waiting.
|
||||
@note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called.
|
||||
@param[in] time_ms milli-seconds to sleep.
|
||||
*/
|
||||
void gs_time_sleep_ms(uint32_t time_ms);
|
||||
|
||||
/**
|
||||
Sleep X milli-seconds relative to reference.
|
||||
|
||||
This sleep function uses a reference \a ref_ms to compensate for variance in processing time.
|
||||
|
||||
No busy waiting.
|
||||
|
||||
@param[in,out] ref_ms time reference.
|
||||
@param[in] sleep_ms how many milli-seconds to sleep - relative to reference.
|
||||
@return \a true if sleep time relative to last reference couldn't be done (reference reset), \a false if normal sleep was done.
|
||||
*/
|
||||
bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms);
|
||||
|
||||
/**
|
||||
Sleep for X nano-seconds.
|
||||
No busy waiting.
|
||||
@note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called.
|
||||
@param[in] time_ns nano-seconds to sleep.
|
||||
*/
|
||||
void gs_time_sleep_ns(uint64_t time_ns);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
73
gomspace/libutil/include/gs/util/timestamp.h
Normal file
73
gomspace/libutil/include/gs/util/timestamp.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef GS_UTIL_TIMESTAMP_H
|
||||
#define GS_UTIL_TIMESTAMP_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Timestamp utilities, for add, subtract, compare, copy, etc.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Number of nano seconds per second.
|
||||
*/
|
||||
#define GS_TIMESTAMP_NSEC_PER_SEC 1000000000
|
||||
|
||||
/**
|
||||
Portable time structure.
|
||||
|
||||
Stanadard timespec_t is non-portable, so this structure must be used instead
|
||||
*/
|
||||
typedef struct {
|
||||
/** Seconds. */
|
||||
uint32_t tv_sec;
|
||||
/** Nano seconds. */
|
||||
uint32_t tv_nsec;
|
||||
} gs_timestamp_t;
|
||||
|
||||
/**
|
||||
@deprecated Use gs_timestamp_t
|
||||
*/
|
||||
typedef gs_timestamp_t timestamp_t;
|
||||
|
||||
/**
|
||||
Add 2 timestamp's (t1 = t1 + t2).
|
||||
@param[in,out] t1 timestamp
|
||||
@param[in] t2 timestamp.
|
||||
@return 0 on success, otherwise -1
|
||||
*/
|
||||
int timestamp_add(gs_timestamp_t * t1, const gs_timestamp_t * t2);
|
||||
|
||||
/**
|
||||
Subtract 2 timestamp's (t1 = t1 - t2)
|
||||
@param[in,out] t1 timestamp
|
||||
@param[in] t2 timestamp.
|
||||
@return 0 on success, otherwise -1
|
||||
*/
|
||||
int timestamp_diff(gs_timestamp_t * t1, const gs_timestamp_t * t2);
|
||||
|
||||
/**
|
||||
Check if t2 is greate than t1.
|
||||
@param[in] t1 time to compare
|
||||
@param[in] t2 time to compare
|
||||
@return 1 if t2 > t1, else 0. -1 on bad arguments.
|
||||
*/
|
||||
int timestamp_ge(const gs_timestamp_t * t1, const gs_timestamp_t * t2);
|
||||
|
||||
/**
|
||||
Copy timestamp.
|
||||
@param[in] from from timestamp
|
||||
@param[out] to to timestamp
|
||||
@return 0 on success, otherwise -1
|
||||
*/
|
||||
int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
114
gomspace/libutil/include/gs/util/types.h
Normal file
114
gomspace/libutil/include/gs/util/types.h
Normal file
@ -0,0 +1,114 @@
|
||||
#ifndef GS_UTIL_TYPES_H
|
||||
#define GS_UTIL_TYPES_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Base type definitions and functions.
|
||||
|
||||
In some rare cases, it is impossible to make code that works on all platforms. In these cases the following defines may be used to
|
||||
exclude/include code:
|
||||
| define | Platform |
|
||||
| :----: | :---- |
|
||||
| \_\_AVR\_\_ | 8 bit, e.g. atmega1281, atmega2560, attiny25, attiny44, attiny84 |
|
||||
| \_\_linux\_\_ | 32/64 bit, Linux based |
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <stdint.h> // intXX_t
|
||||
#include <stdbool.h> // bool
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Control static declaration at compile time.
|
||||
Allows unit tests to access internal functions or variables.
|
||||
@note Static declared variables are initialized to zero by the compiler - BUT if you use GS_NO_STATIC instead of static, they will not be initialized.
|
||||
*/
|
||||
#if GS_NO_STATIC
|
||||
#define GS_STATIC
|
||||
#else
|
||||
#define GS_STATIC static
|
||||
#endif
|
||||
|
||||
/**
|
||||
Convert integer to pointer.
|
||||
*/
|
||||
#define GS_TYPES_INT2PTR(value) ((void*)(intptr_t)(value))
|
||||
|
||||
/**
|
||||
Convert integer to pointer.
|
||||
*/
|
||||
#define GS_TYPES_UINT2PTR(value) ((void*)(uintptr_t)(value))
|
||||
|
||||
/**
|
||||
Convert pointer to integer.
|
||||
*/
|
||||
#define GS_TYPES_PTR2INT(value) ((intptr_t)(void*)(value))
|
||||
|
||||
/**
|
||||
Convert pointer to integer.
|
||||
*/
|
||||
#define GS_TYPES_PTR2UINT(value) ((uintptr_t)(void*)(value))
|
||||
|
||||
/**
|
||||
Assert on 'value'.
|
||||
|
||||
Example:
|
||||
GS_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit);
|
||||
fails if size of (int) is less than 2 bytes.
|
||||
*/
|
||||
#define GS_STATIC_ASSERT(condition, name) typedef char name[(condition) ? 1 : -1]
|
||||
|
||||
/**
|
||||
Context switch state.
|
||||
Used by FreeRTOS when waking a higher priority task/thread from within an ISR.
|
||||
The actual struct is defined in libembed.
|
||||
*/
|
||||
typedef struct gs_context_switch gs_context_switch_t;
|
||||
|
||||
/**
|
||||
Return element count of array.
|
||||
*/
|
||||
#define GS_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
||||
|
||||
/**
|
||||
Address union.
|
||||
*/
|
||||
typedef union {
|
||||
/**
|
||||
Normal address pointer.
|
||||
*/
|
||||
void* p;
|
||||
/**
|
||||
Address pointer as an unsigned value.
|
||||
*/
|
||||
uintptr_t u;
|
||||
} gs_address_t;
|
||||
|
||||
/**
|
||||
@cond HIDDEN_SYMBOLS
|
||||
Compile check size of primitives (just to be sure, that they are what we expect).
|
||||
*/
|
||||
GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(void*), unexpected_address_void_pointer_size);
|
||||
GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(uintptr_t), unexpected_address_uintptr_size);
|
||||
GS_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t), unexpected_bool_size);
|
||||
GS_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), unexpected_float_size);
|
||||
#if (__AVR__)
|
||||
// avr/avr8 is 8 bit
|
||||
GS_STATIC_ASSERT(sizeof(int) == sizeof(int16_t), unexpected_int_size_on_avr8);
|
||||
#else
|
||||
// rest should be 32 or 64 bit
|
||||
GS_STATIC_ASSERT(sizeof(int) == sizeof(int32_t), unexpected_int_size);
|
||||
GS_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), unexpected_double_size);
|
||||
#endif
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
32
gomspace/libutil/include/gs/util/unistd.h
Normal file
32
gomspace/libutil/include/gs/util/unistd.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef GS_UTIL_UNISTD_H
|
||||
#define GS_UTIL_UNISTD_H
|
||||
/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
GomSpace extensions to standard \a unistd.h.
|
||||
*/
|
||||
|
||||
#include <gs/util/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Get current working directory.
|
||||
|
||||
@note Linux uses standard getcwd().
|
||||
|
||||
@param[out] buf user supplied buffer for returning path.
|
||||
@param[in] bufsize size of \a buf.
|
||||
@return #GS_ERROR_NOT_FOUND if no current directory is set.
|
||||
@return #GS_ERROR_RANGE if \a buf is too small
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_getcwd(char * buf, size_t bufsize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
194
gomspace/libutil/include/gs/util/vmem.h
Normal file
194
gomspace/libutil/include/gs/util/vmem.h
Normal file
@ -0,0 +1,194 @@
|
||||
#ifndef GS_UTIL_VMEM_H
|
||||
#define GS_UTIL_VMEM_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Virtual memory interface.
|
||||
|
||||
The API provides support for accessing different hardware components using a common API, by providing a component specific driver.
|
||||
*/
|
||||
|
||||
#include <gs/util/stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Virtual memory mapping.
|
||||
*/
|
||||
typedef struct gs_vmem gs_vmem_t;
|
||||
|
||||
/**
|
||||
VMEM driver write.
|
||||
|
||||
@param[in] vmem vmem entry.
|
||||
@param[in] to Address where to write data to.
|
||||
@param[in] from Address where to write data from.
|
||||
@param[in] size Number of bytes to write.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_vmem_write_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size);
|
||||
|
||||
/**
|
||||
VMEM driver read.
|
||||
|
||||
@param[in] vmem vmem entry.
|
||||
@param[in] to Address where to read data to.
|
||||
@param[in] from Address where to read data from.
|
||||
@param[in] size Number of bytes to read.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_vmem_read_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size);
|
||||
|
||||
/**
|
||||
VMEM driver lock.
|
||||
|
||||
@param[in] vmem vmem entry.
|
||||
@param[in] on Enable/Disable lock.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_vmem_lock_function_t)(const gs_vmem_t * vmem, bool on);
|
||||
|
||||
/**
|
||||
VMEM driver information.
|
||||
|
||||
Return relevant information for the VMEM driver.
|
||||
|
||||
@param[in] vmem vmem entry.
|
||||
@param[in] buffer user allocated buffer for returning information.
|
||||
@param[in] buffer_size size (length) of \a buffer.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
typedef gs_error_t (*gs_vmem_info_function_t)(const gs_vmem_t * vmem, char * buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
VMEM driver interface.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Write function.
|
||||
*/
|
||||
const gs_vmem_write_function_t write;
|
||||
/**
|
||||
Read function.
|
||||
*/
|
||||
const gs_vmem_read_function_t read;
|
||||
/**
|
||||
Lock function.
|
||||
*/
|
||||
const gs_vmem_lock_function_t lock;
|
||||
/**
|
||||
Information function.
|
||||
*/
|
||||
const gs_vmem_info_function_t info;
|
||||
} gs_vmem_driver_t;
|
||||
|
||||
/**
|
||||
Virtual memory mapping.
|
||||
|
||||
@note Call gs_vmem_set_map() for registering mappings.
|
||||
*/
|
||||
struct gs_vmem {
|
||||
/**
|
||||
Logical name of enry.
|
||||
*/
|
||||
const char *const name;
|
||||
/**
|
||||
Virtual memory start.
|
||||
*/
|
||||
gs_address_t virtmem;
|
||||
/**
|
||||
Physical memory start.
|
||||
This address only makes sense for the VMEM driver.
|
||||
*/
|
||||
gs_address_t physmem;
|
||||
/**
|
||||
Size of memory block.
|
||||
*/
|
||||
const size_t size;
|
||||
/**
|
||||
Driver function.
|
||||
*/
|
||||
const gs_vmem_driver_t* drv;
|
||||
/**
|
||||
Driver data.
|
||||
*/
|
||||
const void* drv_data;
|
||||
};
|
||||
|
||||
/**
|
||||
Set VMEM mapping.
|
||||
Must be done for the API to work.
|
||||
@param[in] map VMEM mapping table, must be terminated with an NULL entry.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_vmem_set_map(const gs_vmem_t * map);
|
||||
|
||||
/**
|
||||
Return VMEM map.
|
||||
*/
|
||||
const gs_vmem_t * gs_vmem_get_map(void);
|
||||
|
||||
/**
|
||||
Print all VMEM entries to stdout.
|
||||
@param[in] out output stream
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_vmem_list(FILE * out);
|
||||
|
||||
/**
|
||||
Get VMEM entry by name.
|
||||
@param[in] name name of VMEM entry.
|
||||
@return VMEM mapping or NULL if not found.
|
||||
*/
|
||||
const gs_vmem_t * gs_vmem_get_by_name(const char * name);
|
||||
|
||||
/**
|
||||
Lock/un-lock VMEM area.
|
||||
@param[in] name name of VMEM entry.
|
||||
@param[in] on Enable/Disable lock.
|
||||
@return GS_ERROR_NOT_FOUND area not found.
|
||||
@return GS_ERROR_NOT_SUPPORTED if locking isn't supported.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_vmem_lock_by_name(const char * name, bool on);
|
||||
|
||||
/**
|
||||
Lock/un-lock all VMEM areas.
|
||||
@param[in] on lock on or off.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_vmem_lock_all(bool on);
|
||||
|
||||
/**
|
||||
memcpy on VMEM.
|
||||
@note if no VMEM entries are found, a normal memcpy is called with the provided pointers.
|
||||
@param[in] to to location.
|
||||
@param[in] from from location.
|
||||
@param[in] size number of bytes to copy.
|
||||
*/
|
||||
void* gs_vmem_cpy(void* to, const void* from, size_t size);
|
||||
|
||||
/**
|
||||
Macro for calling gs_vmem_cpy().
|
||||
*/
|
||||
#define GS_VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size)
|
||||
|
||||
/**
|
||||
Macro for calling gs_vmem_cpy().
|
||||
@deprecated Use gs_vmem_cpy() directly.
|
||||
*/
|
||||
#define VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size)
|
||||
|
||||
/**
|
||||
Register VMEM commands.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_vmem_register_commands(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
143
gomspace/libutil/include/gs/util/watchdog/watchdog.h
Normal file
143
gomspace/libutil/include/gs/util/watchdog/watchdog.h
Normal file
@ -0,0 +1,143 @@
|
||||
#ifndef GS_UTIL_WATCHDOG_WATCHDOG_H
|
||||
#define GS_UTIL_WATCHDOG_WATCHDOG_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Software watchdog client interface.
|
||||
|
||||
The software watchdog (SWWD) enables having multiple instances of a Watchdog.
|
||||
The software watchdog manages the HW watchdog, and will ultimately
|
||||
trigger the HW watchdog, if one or more clients are not servicing the
|
||||
software watchdog.
|
||||
*/
|
||||
|
||||
#include <gs/util/drivers/watchdog/device.h>
|
||||
#include <gs/util/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Software Watchdog handle
|
||||
*/
|
||||
typedef struct gs_swwd_hdl gs_swwd_hdl_t;
|
||||
|
||||
/**
|
||||
Software watchdog callback function.
|
||||
|
||||
Called by the SWWD upon timeout.
|
||||
@param[in] userdata user data provided on gs_swwd_register()
|
||||
*/
|
||||
typedef void (*gs_swwd_callback_function_t)(void * userdata);
|
||||
|
||||
/**
|
||||
Watchdog timeout action.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
Reset system on timeout (stops touching the hardware watchdog).
|
||||
Once the watchdog has timeout, the watchdog cannot be re-activated.
|
||||
*/
|
||||
GS_SWWD_TIMEOUT_ACTION_RESET = 0,
|
||||
/**
|
||||
Log 'warning' on timeout, but otherwise ignore the timeout.
|
||||
The watchdog can re-activated by touching the watchdog again.
|
||||
*/
|
||||
GS_SWWD_TIMEOUT_ACTION_LOG = 1,
|
||||
} gs_swwd_timeout_action_t;
|
||||
|
||||
/**
|
||||
Create the software watchdog back-end.
|
||||
|
||||
Only one SWWD back-end can exist at any given time.
|
||||
|
||||
@param[in] max_clients The maximum number of Software Watchog clients supported.
|
||||
@param[in] dev The HW Watchdog device to use.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t *dev);
|
||||
|
||||
/**
|
||||
Destroy the Software Watchdog back-end (and stop the SWWD monitor task if started).
|
||||
|
||||
@param[in] timeout_s Maximum number of seconds to allow this operation to complete.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_destroy(uint32_t timeout_s);
|
||||
|
||||
/**
|
||||
Check for expired software watchdog clients. This function is only to be used if the
|
||||
SWWD monitor task is not started. Otherwise the SWWD task will handle this in the back-
|
||||
ground. I.e:
|
||||
- In passive mode this function must be called periodically to check for expired
|
||||
clients, and service the HW watchdog.
|
||||
- In active mode this function is called in background by the SWWD monitor task.
|
||||
|
||||
The interval between these checks should be much less that the HW watchdog
|
||||
timeout period, to ensure that the HW Watchdog is correctly serviced.
|
||||
Calling this e.g. every 1-3 seconds will be a good default.
|
||||
|
||||
@param[out] num_expired The number of SW Watchog clients currently expired.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired);
|
||||
|
||||
/**
|
||||
Register/create a new software watchdog instance
|
||||
|
||||
@param[out] wdt_handle A reference to software watchdog handle
|
||||
@param[in] timeout Timeout in seconds.
|
||||
@param[in] callback Callback function which is called on timeout. NULL if unused.
|
||||
@param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL.
|
||||
@param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered.
|
||||
@param[in] action what action to take, when/if the watchdog times out.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name, gs_swwd_timeout_action_t action);
|
||||
|
||||
/**
|
||||
Register/create a software watchdog with action \a reset on timeout.
|
||||
|
||||
@param[out] wdt_handle A reference to software watchdog handle
|
||||
@param[in] timeout Timeout in seconds before the software watchdog fires.
|
||||
@param[in] callback Callback function which is called on timeout. NULL if unused.
|
||||
@param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL.
|
||||
@param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
static inline gs_error_t gs_swwd_register(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name)
|
||||
{
|
||||
return gs_swwd_register_with_action(wdt_handle, timeout, callback, userdata, client_name, GS_SWWD_TIMEOUT_ACTION_RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
De-Register a Software Watchdog instance
|
||||
|
||||
@param[in] wdt_handle A software watchdog handle
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wdt_handle);
|
||||
|
||||
/**
|
||||
Touch Software Watchdog to reset the timer
|
||||
|
||||
@param[in] wdt_handle A software watchdog handle
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wdt_handle);
|
||||
|
||||
/**
|
||||
Set timeout of the Software Watchdog.
|
||||
|
||||
@param[in] wdt_handle A software watchdog handle
|
||||
@param[in] timeout Timeout in seconds before the SWWD fires.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wdt_handle, uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
45
gomspace/libutil/include/gs/util/watchdog/watchdog_task.h
Normal file
45
gomspace/libutil/include/gs/util/watchdog/watchdog_task.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef GS_UTIL_WATCHDOG_WATCHDOG_TASK_H
|
||||
#define GS_UTIL_WATCHDOG_WATCHDOG_TASK_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Software Watchdog server/task interface
|
||||
|
||||
The Software Watchdog task implements the core (backend) functionality of the the software watchdog.
|
||||
The Client API for the SW watchdog is implemented in watchdog.h
|
||||
|
||||
@note This API is not thread safe!
|
||||
*/
|
||||
|
||||
#include <gs/util/watchdog/watchdog.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Start the Software Watchdog monitor task if the SWWD is to be used as a
|
||||
separate task (active mode).
|
||||
In this case the SWWD task will monitor expired clients in the background
|
||||
and the polling API gs_swwd_check_expired_clients() needs not to be called by
|
||||
the user.
|
||||
|
||||
@return_gs_error_t
|
||||
*/
|
||||
|
||||
gs_error_t gs_swwd_monitor_task_start();
|
||||
|
||||
/**
|
||||
Stops the Software Watchdog monitor task
|
||||
|
||||
@param[in] timeout_s Maximum number of seconds to allow this operation to complete.
|
||||
|
||||
@return_gs_error_t
|
||||
*/
|
||||
gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
62
gomspace/libutil/include/gs/util/zip/zip.h
Normal file
62
gomspace/libutil/include/gs/util/zip/zip.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef LIBUTIL_ZIP_ZIP_UTILS_H
|
||||
#define LIBUTIL_ZIP_ZIP_UTILS_H
|
||||
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
||||
/**
|
||||
@file
|
||||
|
||||
Compress/decompress API based on zlib compressed data format specification standards.
|
||||
*/
|
||||
|
||||
#include <gs/util/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Compress file.
|
||||
|
||||
@param[in] src file to be compressed.
|
||||
@param[out] dest compressed output file.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
int gs_zip_compress_file(const char *src, const char *dest);
|
||||
|
||||
/**
|
||||
Decompress file.
|
||||
|
||||
@param[in] src file to be secompressed.
|
||||
@param[out] dest decompressed output file.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
int gs_zip_decompress_file(const char *src, const char *dest);
|
||||
|
||||
/**
|
||||
Compress data.
|
||||
|
||||
@param[in] src pointer to the data to be compressed.
|
||||
@param[in] src_len size of the data.
|
||||
@param[out] dest pointer to the compressed data.
|
||||
@param[out] dest_len pointer to the size of the compressed data.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len);
|
||||
|
||||
/**
|
||||
Decompress data.
|
||||
|
||||
@param[in] src pointer to the data to be decompressed.
|
||||
@param[in] src_len size of the data.
|
||||
@param[out] dest pointer to the decompressed data.
|
||||
@param[out] dest_len size of the destination memory area.
|
||||
@param[out] decomp_len pointer to the size of the decompressed data.
|
||||
@return_gs_error_t
|
||||
*/
|
||||
int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* LIBUTIL_ZIP_ZIP_UTILS_H */
|
Reference in New Issue
Block a user