Code import

This commit is contained in:
2017-12-15 23:52:14 +01:00
commit 56a935cdd0
103 changed files with 14510 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
/* Copyright (c) 2002, Marek Michalkiewicz
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.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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. */
#include "avrlibc.h"
int
avr_atoi(const char *p)
{
return (int) avr_atol(p);
}
+36
View File
@@ -0,0 +1,36 @@
/* Copyright (c) 2002, Marek Michalkiewicz
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.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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. */
#include <stdlib.h>
#include "avrlibc.h"
long
avr_atol(const char *p)
{
return avr_strtol(p, (char **) NULL, 10);
}
+220
View File
@@ -0,0 +1,220 @@
/* Copyright (c) 2002-2005 Michael Stumpf <mistumpf@de.pepperl-fuchs.com>
Copyright (c) 2006,2008 Dmitry Xmelkov
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.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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. */
/* $Id: strtod.c 2191 2010-11-05 13:45:57Z arcanum $ */
#include <errno.h>
#include <limits.h>
#include <math.h> /* INFINITY, NAN */
#include <strings.h>
#include <stdint.h>
#include "avrlibc.h"
/* Only GCC 4.2 calls the library function to convert an unsigned long
to float. Other GCC-es (including 4.3) use a signed long to float
conversion along with a large inline code to correct the result. */
extern double __floatunsisf (unsigned long);
static const float pwr_p10 [6] = {
1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32
};
static const float pwr_m10 [6] = {
1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32
};
/* PSTR() is not used to save 1 byte per string: '\0' at the tail. */
static const char pstr_inf[] = {'I','N','F'};
static const char pstr_inity[] = {'I','N','I','T','Y'};
static const char pstr_nan[] = {'N','A','N'};
/** The strtod() function converts the initial portion of the string pointed
to by \a nptr to double representation.
The expected form of the string is an optional plus ( \c '+' ) or minus
sign ( \c '-' ) followed by a sequence of digits optionally containing
a decimal-point character, optionally followed by an exponent. An
exponent consists of an \c 'E' or \c 'e', followed by an optional plus
or minus sign, followed by a sequence of digits.
Leading white-space characters in the string are skipped.
The strtod() function returns the converted value, if any.
If \a endptr is not \c NULL, a pointer to the character after the last
character used in the conversion is stored in the location referenced by
\a endptr.
If no conversion is performed, zero is returned and the value of
\a nptr is stored in the location referenced by \a endptr.
If the correct value would cause overflow, plus or minus \c INFINITY is
returned (according to the sign of the value), and \c ERANGE is stored
in \c errno. If the correct value would cause underflow, zero is
returned and \c ERANGE is stored in \c errno.
*/
double
avr_strtod (const char * nptr, char ** endptr)
{
union {
unsigned long u32;
float flt;
} x;
unsigned char c;
int exp;
unsigned char flag;
#define FL_MINUS 0x01 /* number is negative */
#define FL_ANY 0x02 /* any digit was readed */
#define FL_OVFL 0x04 /* overflow was */
#define FL_DOT 0x08 /* decimal '.' was */
#define FL_MEXP 0x10 /* exponent 'e' is neg. */
if (endptr)
*endptr = (char *)nptr;
do {
c = *nptr++;
} while (c!=0&&c<=' ');
flag = 0;
if (c == '-') {
flag = FL_MINUS;
c = *nptr++;
} else if (c == '+') {
c = *nptr++;
}
if (!strncasecmp(nptr - 1, pstr_inf, 3)) {
nptr += 2;
if (!strncasecmp(nptr, pstr_inity, 5))
nptr += 5;
if (endptr)
*endptr = (char *)nptr;
return flag & FL_MINUS ? -INFINITY : +INFINITY;
}
/* NAN() construction is not realised.
Length would be 3 characters only. */
if (!strncasecmp(nptr - 1, pstr_nan, 3)) {
if (endptr)
*endptr = (char *)nptr + 2;
return NAN;
}
x.u32 = 0;
exp = 0;
while (1) {
c -= '0';
if (c <= 9) {
flag |= FL_ANY;
if (flag & FL_OVFL) {
if (!(flag & FL_DOT))
exp += 1;
} else {
if (flag & FL_DOT)
exp -= 1;
/* x.u32 = x.u32 * 10 + c */
x.u32 = (((x.u32 << 2) + x.u32) << 1) + c;
if (x.u32 >= (ULONG_MAX - 9) / 10)
flag |= FL_OVFL;
}
} else if (c == (('.'-'0') & 0xff) && !(flag & FL_DOT)) {
flag |= FL_DOT;
} else {
break;
}
c = *nptr++;
}
if (c == (('e'-'0') & 0xff) || c == (('E'-'0') & 0xff))
{
int i;
c = *nptr++;
i = 2;
if (c == '-') {
flag |= FL_MEXP;
c = *nptr++;
} else if (c == '+') {
c = *nptr++;
} else {
i = 1;
}
c -= '0';
if (c > 9) {
nptr -= i;
} else {
i = 0;
do {
if (i < 3200)
i = (((i << 2) + i) << 1) + c; /* i = 10*i + c */
c = *nptr++ - '0';
} while (c <= 9);
if (flag & FL_MEXP)
i = -i;
exp += i;
}
}
if ((flag & FL_ANY) && endptr)
*endptr = (char *)nptr - 1;
x.flt = __floatunsisf (x.u32); /* manually */
if ((flag & FL_MINUS) && (flag & FL_ANY))
x.flt = -x.flt;
if (x.flt != 0) {
int pwr;
if (exp < 0) {
nptr = (void *)(pwr_m10 + 5);
exp = -exp;
} else {
nptr = (void *)(pwr_p10 + 5);
}
for (pwr = 32; pwr; pwr >>= 1) {
for (; exp >= pwr; exp -= pwr) {
union {
unsigned long u32;
float flt;
} y;
y.u32 = (uint32_t) *((float *)nptr);
x.flt *= y.flt;
}
nptr -= sizeof(float);
}
if (!isfinite(x.flt) || x.flt == 0)
errno = ERANGE;
}
return x.flt;
}
+167
View File
@@ -0,0 +1,167 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2005, Dmitry Xmelkov
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* $Id: strtol.c 1944 2009-04-01 23:12:20Z arcanum $
*/
#include <limits.h>
#include <errno.h>
/*
* Convert a string to a long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
long
avr_strtol(const char *nptr, char **endptr, register int base)
{
register unsigned long acc;
register unsigned char c;
register unsigned long cutoff;
register signed char any;
unsigned char flag = 0;
#define FL_NEG 0x01 /* number is negative */
#define FL_0X 0x02 /* number has a 0x prefix */
if (endptr)
*endptr = (char *)nptr;
if (base != 0 && (base < 2 || base > 36))
return 0;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *nptr++;
} while (c!=0&&c<=' ');
if (c == '-') {
flag = FL_NEG;
c = *nptr++;
} else if (c == '+')
c = *nptr++;
if ((base == 0 || base == 16) &&
c == '0' && (*nptr == 'x' || *nptr == 'X')) {
c = nptr[1];
nptr += 2;
base = 16;
flag |= FL_0X;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the decision
* about this is done as outlined below.
*
* Overflow detections works as follows:
*
* As:
* acc_old <= cutoff
* then:
* acc_old * base <= 0x80000000 (unsigned)
* then:
* acc_old * base + c <= 0x80000000 + c
* or:
* acc_new <= 0x80000000 + 35
*
* i.e. carry from MSB (by calculating acc_new) is impossible
* and we can check result directly:
*
* if (acc_new > 0x80000000) then overflow
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
#if LONG_MIN != -LONG_MAX - 1
# error "This implementation of strtol() does not work on this platform."
#endif
switch (base) {
case 10:
cutoff = ((unsigned long)LONG_MAX + 1) / 10;
break;
case 16:
cutoff = ((unsigned long)LONG_MAX + 1) / 16;
break;
case 8:
cutoff = ((unsigned long)LONG_MAX + 1) / 8;
break;
case 2:
cutoff = ((unsigned long)LONG_MAX + 1) / 2;
break;
default:
cutoff = ((unsigned long)LONG_MAX + 1) / base;
}
for (acc = 0, any = 0;; c = *nptr++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0)
continue;
if (acc > cutoff) {
any = -1;
continue;
}
acc = acc * base + c;
if (acc > (unsigned long)LONG_MAX + 1)
any = -1;
else
any = 1;
}
if (endptr) {
if (any)
*endptr = (char *)nptr - 1;
else if (flag & FL_0X)
*endptr = (char *)nptr - 2;
}
if (any < 0) {
acc = (flag & FL_NEG) ? LONG_MIN : LONG_MAX;
errno = ERANGE;
} else if (flag & FL_NEG) {
acc = -acc;
} else if ((signed long)acc < 0) {
acc = LONG_MAX;
errno = ERANGE;
}
return (acc);
}
+145
View File
@@ -0,0 +1,145 @@
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2005, Dmitry Xmelkov
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* $Id: strtoul.c 1944 2009-04-01 23:12:20Z arcanum $
*/
#include <limits.h>
#include <errno.h>
#include "avrlibc.h"
/*
* Convert a string to an unsigned long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
unsigned long
avr_strtoul(const char *nptr, char **endptr, register int base)
{
register unsigned long acc;
register unsigned char c;
register unsigned long cutoff;
register signed char any;
unsigned char flag = 0;
#define FL_NEG 0x01 /* number is negative */
#define FL_0X 0x02 /* number has a 0x prefix */
if (endptr)
*endptr = (char *)nptr;
if (base != 0 && (base < 2 || base > 36))
return 0;
/*
* See strtol for comments as to the logic used.
*/
do {
c = *nptr++;
} while (c!=0&&c<=' ');
if (c == '-') {
flag = FL_NEG;
c = *nptr++;
} else if (c == '+')
c = *nptr++;
if ((base == 0 || base == 16) &&
c == '0' && (*nptr == 'x' || *nptr == 'X')) {
c = nptr[1];
nptr += 2;
base = 16;
flag |= FL_0X;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* cutoff computation is similar to strtol().
*
* Description of the overflow detection logic used.
*
* First, let us assume an overflow.
*
* Result of `acc_old * base + c' is cut to 32 bits:
* acc_new <-- acc_old * base + c - 0x100000000
*
* `acc_old * base' is <= 0xffffffff (cutoff control)
*
* then: acc_new <= 0xffffffff + c - 0x100000000
*
* or: acc_new <= c - 1
*
* or: acc_new < c
*
* Second:
* if (no overflow) then acc * base + c >= c
* (or: acc_new >= c)
* is clear (alls are unsigned).
*
*/
switch (base) {
case 16: cutoff = ULONG_MAX / 16; break;
case 10: cutoff = ULONG_MAX / 10; break;
case 8: cutoff = ULONG_MAX / 8; break;
default: cutoff = ULONG_MAX / base;
}
for (acc = 0, any = 0;; c = *nptr++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0)
continue;
if (acc > cutoff) {
any = -1;
continue;
}
acc = acc * base + c;
any = (c > acc) ? -1 : 1;
}
if (endptr) {
if (any)
*endptr = (char *)nptr - 1;
else if (flag & FL_0X)
*endptr = (char *)nptr - 2;
}
if (flag & FL_NEG)
acc = -acc;
if (any < 0) {
acc = ULONG_MAX;
errno = ERANGE;
}
return (acc);
}
+14
View File
@@ -0,0 +1,14 @@
//
// Created by MightyPork on 2017/11/26.
//
#ifndef GEX_AVRLIBC_H_H
#define GEX_AVRLIBC_H_H
int avr_atoi(const char *p);
long avr_strtol(const char *nptr, char **endptr, register int base);
long avr_atol(const char *p);
double avr_strtod (const char * nptr, char ** endptr);
unsigned long avr_strtoul(const char *nptr, char **endptr, register int base);
#endif //GEX_AVRLIBC_H_H
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
echo "-- Building parser from Ragel source --"
ragel -L -G0 ini_parser.rl -o ini_parser.c
+177
View File
@@ -0,0 +1,177 @@
/**
* @file circular_buffer.c
* @brief Implementation of a circular buffer
*
* DAPLink Interface Firmware
* Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "platform.h"
#include "circ_buf.h"
void circ_buf_init(circ_buf_t *circ_buf, uint8_t *buffer, uint32_t size)
{
vPortEnterCritical();
{
circ_buf->buf = buffer;
circ_buf->size = size;
circ_buf->head = 0;
circ_buf->tail = 0;
}
vPortExitCritical();
}
static void push_do(circ_buf_t *circ_buf, uint8_t data)
{
circ_buf->buf[circ_buf->tail] = data;
circ_buf->tail += 1;
if (circ_buf->tail >= circ_buf->size) {
assert_param(circ_buf->tail == circ_buf->size);
circ_buf->tail = 0;
}
}
bool circ_buf_push_try(circ_buf_t *circ_buf, uint8_t data)
{
bool success;
vPortEnterCritical();
{
if (circ_buf_count_free(circ_buf) == 0) {
success = false;
goto quit;
}
push_do(circ_buf, data);
success = true;
}
quit:
vPortExitCritical();
return success;
}
void circ_buf_push(circ_buf_t *circ_buf, uint8_t data)
{
vPortEnterCritical();
{
push_do(circ_buf, data);
// Assert no overflow
assert_param(circ_buf->head != circ_buf->tail);
}
vPortExitCritical();
}
static uint8_t pop_do(circ_buf_t *circ_buf)
{
uint8_t data;
data = circ_buf->buf[circ_buf->head];
circ_buf->head += 1;
if (circ_buf->head >= circ_buf->size) {
assert_param(circ_buf->head == circ_buf->size);
circ_buf->head = 0;
}
return data;
}
uint8_t circ_buf_pop(circ_buf_t *circ_buf)
{
uint8_t data;
vPortEnterCritical();
{
// Assert buffer isn't empty
assert_param(circ_buf->head != circ_buf->tail);
data = pop_do(circ_buf);
}
vPortExitCritical();
return data;
}
bool circ_buf_pop_try(circ_buf_t *circ_buf, uint8_t *data)
{
bool success;
vPortEnterCritical();
{
if (circ_buf->head == circ_buf->tail) {
success = false;
goto quit;
}
*data = pop_do(circ_buf);
success = true;
}
quit:
vPortExitCritical();
return success;
}
uint32_t circ_buf_count_used(circ_buf_t *circ_buf)
{
uint32_t cnt;
vPortEnterCritical();
{
if (circ_buf->tail >= circ_buf->head) {
cnt = circ_buf->tail - circ_buf->head;
} else {
cnt = circ_buf->tail + circ_buf->size - circ_buf->head;
}
}
vPortExitCritical();
return cnt;
}
uint32_t circ_buf_count_free(circ_buf_t *circ_buf)
{
uint32_t cnt;
vPortEnterCritical();
{
cnt = circ_buf->size - circ_buf_count_used(circ_buf) - 1;
}
vPortExitCritical();
return cnt;
}
uint32_t circ_buf_read(circ_buf_t *circ_buf, uint8_t *data, uint32_t size)
{
uint32_t cnt;
uint32_t i;
cnt = circ_buf_count_used(circ_buf);
cnt = MIN(size, cnt);
for (i = 0; i < cnt; i++) {
data[i] = circ_buf_pop(circ_buf);
}
return cnt;
}
uint32_t circ_buf_write(circ_buf_t *circ_buf, const uint8_t *data, uint32_t size)
{
uint32_t cnt;
uint32_t i;
cnt = circ_buf_count_free(circ_buf);
cnt = MIN(size, cnt);
for (i = 0; i < cnt; i++) {
circ_buf_push(circ_buf, data[i]);
}
return cnt;
}
+70
View File
@@ -0,0 +1,70 @@
/**
* @file circ_buf.h
* @brief Implementation of a circular buffer
*
* DAPLink Interface Firmware
* Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CIRC_BUF_H
#define CIRC_BUF_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint32_t head;
uint32_t tail;
uint32_t size;
uint8_t *buf;
} circ_buf_t;
// Initialize or reinitialize a circular buffer
void circ_buf_init(circ_buf_t *circ_buf, uint8_t *buffer, uint32_t size);
// Push a byte into the circular buffer
void circ_buf_push(circ_buf_t *circ_buf, uint8_t data);
// Return a byte from the circular buffer
uint8_t circ_buf_pop(circ_buf_t *circ_buf);
// try to read the buffer, return false if empty
bool circ_buf_pop_try(circ_buf_t *circ_buf, uint8_t *data);
// try to write the buffer, return false if full
bool circ_buf_push_try(circ_buf_t *circ_buf, uint8_t data);
// Get the number of bytes in the circular buffer
uint32_t circ_buf_count_used(circ_buf_t *circ_buf);
// Get the number of free spots left in the circular buffer
uint32_t circ_buf_count_free(circ_buf_t *circ_buf);
// Attempt to read size bytes from the buffer. Return the number of bytes read
uint32_t circ_buf_read(circ_buf_t *circ_buf, uint8_t *data, uint32_t size);
// Attempt to write size bytes to the buffer. Return the number of bytes written
uint32_t circ_buf_write(circ_buf_t *circ_buf, const uint8_t *data, uint32_t size);
#ifdef __cplusplus
}
#endif
#endif
+26
View File
@@ -0,0 +1,26 @@
//
// Created by MightyPork on 2017/11/26.
//
#ifndef GEX_CORTEX_UTILS_H
#define GEX_CORTEX_UTILS_H
#include "platform.h"
static inline bool inIRQ(void)
{
return __get_IPSR() != 0;
}
register char *__SP asm("sp");
static inline bool isDynAlloc(const void *obj)
{
// this is the 0x20000000-something address that should correspond to heap bottom
extern char heapstart __asm("end");
return ((uint32_t)obj >= (uint32_t)&heapstart)
&& ((uint32_t)obj < (uint32_t)__SP);
}
#endif //GEX_CORTEX_UTILS_H
+45
View File
@@ -0,0 +1,45 @@
/**
* @file error.c
* @brief Implementation of error.h
*
* DAPLink Interface Firmware
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "platform.h"
static const char *const error_message[] = {
#define X(name, text) text,
X_ERROR_CODES
#undef X
};
COMPILER_ASSERT(ERROR_COUNT == ELEMENTS_IN_ARRAY(error_message));
const char *error_get_string(error_t error)
{
const char *msg = 0;
if (error < ERROR_COUNT) {
msg = error_message[error];
}
if (0 == msg) {
assert_param(0);
msg = "";
}
return msg;
}
+65
View File
@@ -0,0 +1,65 @@
/**
* @file error.h
* @brief collection of known errors and accessor for the friendly string
*
* DAPLink Interface Firmware
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ERROR_H
#define ERROR_H
#ifdef __cplusplus
}
#endif
#define X_ERROR_CODES \
/* Shared errors */ \
X(SUCCESS,"OK") \
X(FAILURE,"Failure") \
X(INTERNAL,"Internal error") \
X(LOADING,"Init in progress") \
\
/* VFS user errors */ \
X(ERROR_DURING_TRANSFER,"Error during transfer") \
X(TRANSFER_TIMEOUT,"Transfer timed out") \
/*X(FILE_BOUNDS,"Possible mismatch between file size and size programmed")*/ \
X(OOO_SECTOR,"File sent out of order by PC") \
\
/* File stream errors */ \
X(SUCCESS_DONE,"End of stream") \
X(SUCCESS_DONE_OR_CONTINUE,"End of stream, or more to come") \
\
/* Unit loading */ \
X(BAD_CONFIG, "Configuration error") \
X(OUT_OF_MEM, "Not enough RAM") \
X(RESOURCE_NOT_AVAILABLE, "Required pin / peripheral not available")
// Keep in sync with the list error_message
typedef enum {
#define X(name, text) E_##name,
X_ERROR_CODES
#undef X
ERROR_COUNT
} error_t;
const char *error_get_string(error_t error) __attribute__((pure));
#ifdef __cplusplus
}
#endif
#endif
+57
View File
@@ -0,0 +1,57 @@
//
// Created by MightyPork on 2017/12/04.
//
#include "platform.h"
#include "hexdump.h"
void hexDump(const char *restrict desc, const void *restrict addr, uint32_t len)
{
uint32_t i;
uint8_t buff[17];
uint8_t *pc = (unsigned char*)addr;
// Output description if given.
if (desc != NULL)
PRINTF ("%s:\r\n", desc);
if (len == 0) {
PRINTF(" ZERO LENGTH\r\n");
return;
}
// Process every byte in the data.
for (i = 0; i < len; i++) {
// Multiple of 16 means new line (with line offset).
if ((i % 16) == 0) {
// Just don't print ASCII for the zeroth line.
if (i != 0)
PRINTF (" %s\r\n", buff);
// Output the offset.
PRINTF (" %04"PRIx32" ", i);
}
// Now the hex code for the specific character.
PRINTF (" %02x", pc[i]);
// And store a printable ASCII character for later.
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
// Pad out last line if not exactly 16 characters.
while ((i % 16) != 0) {
PRINTF (" ");
i++;
}
// And print the final ASCII bit.
PRINTF (" %s\r\n", buff);
(void)buff;
}
+19
View File
@@ -0,0 +1,19 @@
//
// Created by MightyPork on 2017/12/04.
//
#ifndef GEX_HEXDUMP_H
#define GEX_HEXDUMP_H
#include <stdint.h>
/**
* HEXDUMP https://stackoverflow.com/a/7776146/2180189
*
* @param desc - description printed above the dump
* @param addr - address to dump
* @param len - number of bytes
*/
void hexDump(const char *restrict desc, const void *restrict addr, uint32_t len);
#endif //GEX_HEXDUMP_H
+526
View File
@@ -0,0 +1,526 @@
/* #line 1 "ini_parser.rl" */
/* Ragel constants block */
#include "ini_parser.h"
// Ragel setup
/* #line 10 "ini_parser.c" */
static const char _ini_actions[] = {
0, 1, 1, 1, 2, 1, 3, 1,
4, 1, 5, 1, 6, 1, 7, 1,
8, 1, 9, 1, 10, 1, 11, 1,
13, 2, 0, 4, 2, 12, 4
};
static const char _ini_eof_actions[] = {
0, 23, 5, 5, 15, 15, 15, 15,
19, 19, 0, 0, 0, 0, 0, 0,
0
};
static const int ini_start = 1;
static const int ini_first_final = 12;
static const int ini_error = 0;
static const int ini_en_section = 2;
static const int ini_en_keyvalue = 4;
static const int ini_en_comment = 8;
static const int ini_en_discard2eol = 10;
static const int ini_en_main = 1;
/* #line 10 "ini_parser.rl" */
// Persistent state
static int8_t cs = -1; //!< Ragel's Current State variable
static uint32_t buff_i = 0; //!< Write pointer for the buffers
static char value_quote = 0; //!< Quote character of the currently collected value
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
static void *userdata = NULL; //!< Currently assigned user data for the callback
// Buffers
static char keybuf[INI_KEY_MAX];
static char secbuf[INI_KEY_MAX];
static char valbuf[INI_VALUE_MAX];
// See header for doxygen!
void
ini_parse_reset_partial(void)
{
buff_i = 0;
value_quote = 0;
value_nextesc = false;
}
void
ini_parse_reset(void)
{
ini_parse_reset_partial();
keybuf[0] = secbuf[0] = valbuf[0] = 0;
/* #line 67 "ini_parser.c" */
{
cs = ini_start;
}
/* #line 41 "ini_parser.rl" */
}
void
ini_parser_error(const char* msg)
{
ini_error("Parser error: %s", msg);
ini_parse_reset_partial();
}
void
ini_parse_begin(IniParserCallback callback, void *userData)
{
keyCallback = callback;
userdata = userData;
ini_parse_reset();
}
void
*ini_parse_end(void)
{
ini_parse("\n", 1);
if (keyCallback) {
keyCallback = NULL;
}
void *ud = userdata;
userdata = NULL;
return ud;
}
void
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
{
ini_parse_begin(callback, userData);
ini_parse(text, len);
ini_parse_end();
}
static void
rtrim_buf(char *buf, int32_t end)
{
if (end > 0) {
while ((uint8_t)buf[--end] < 33);
end++; // go past the last character
}
buf[end] = 0;
}
void
ini_parse(const char *newstr, size_t len)
{
int32_t i;
char c;
bool isnl;
bool isquot;
// Load new data to Ragel vars
const uint8_t *p;
const uint8_t *eof;
const uint8_t *pe;
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
p = (const uint8_t *) newstr;
eof = NULL;
pe = (const uint8_t *) (newstr + len);
// Init Ragel on the first run
if (cs == -1) {
ini_parse_reset();
}
// The parser
/* #line 152 "ini_parser.c" */
{
const char *_acts;
unsigned int _nacts;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
switch ( cs ) {
case 1:
switch( (*p) ) {
case 32u: goto tr1;
case 35u: goto tr3;
case 58u: goto tr0;
case 59u: goto tr3;
case 61u: goto tr0;
case 91u: goto tr4;
}
if ( (*p) < 9u ) {
if ( (*p) <= 8u )
goto tr0;
} else if ( (*p) > 13u ) {
if ( 14u <= (*p) && (*p) <= 31u )
goto tr0;
} else
goto tr1;
goto tr2;
case 0:
goto _out;
case 12:
goto tr0;
case 2:
switch( (*p) ) {
case 9u: goto tr6;
case 32u: goto tr6;
case 93u: goto tr5;
}
if ( (*p) <= 31u )
goto tr5;
goto tr7;
case 3:
if ( (*p) == 93u )
goto tr8;
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto tr5;
} else
goto tr5;
goto tr7;
case 13:
goto tr5;
case 4:
switch( (*p) ) {
case 10u: goto tr10;
case 58u: goto tr11;
case 61u: goto tr11;
}
goto tr9;
case 5:
switch( (*p) ) {
case 9u: goto tr13;
case 10u: goto tr14;
case 13u: goto tr15;
case 32u: goto tr13;
}
goto tr12;
case 6:
switch( (*p) ) {
case 10u: goto tr14;
case 13u: goto tr15;
}
goto tr12;
case 14:
goto tr10;
case 7:
if ( (*p) == 10u )
goto tr14;
goto tr10;
case 8:
switch( (*p) ) {
case 10u: goto tr17;
case 13u: goto tr18;
}
goto tr16;
case 15:
goto tr19;
case 9:
if ( (*p) == 10u )
goto tr17;
goto tr19;
case 10:
switch( (*p) ) {
case 10u: goto tr21;
case 13u: goto tr22;
}
goto tr20;
case 16:
goto tr23;
case 11:
if ( (*p) == 10u )
goto tr21;
goto tr23;
}
tr23: cs = 0; goto _again;
tr0: cs = 0; goto f0;
tr5: cs = 0; goto f4;
tr10: cs = 0; goto f7;
tr19: cs = 0; goto f11;
tr1: cs = 1; goto _again;
tr6: cs = 2; goto _again;
tr7: cs = 3; goto f5;
tr9: cs = 4; goto f8;
tr13: cs = 5; goto _again;
tr11: cs = 5; goto f9;
tr12: cs = 6; goto f10;
tr15: cs = 7; goto _again;
tr16: cs = 8; goto _again;
tr18: cs = 9; goto _again;
tr20: cs = 10; goto _again;
tr22: cs = 11; goto _again;
tr2: cs = 12; goto f1;
tr3: cs = 12; goto f2;
tr4: cs = 12; goto f3;
tr8: cs = 13; goto f6;
tr14: cs = 14; goto f10;
tr17: cs = 15; goto f12;
tr21: cs = 16; goto f13;
f5: _acts = _ini_actions + 1; goto execFuncs;
f6: _acts = _ini_actions + 3; goto execFuncs;
f4: _acts = _ini_actions + 5; goto execFuncs;
f1: _acts = _ini_actions + 7; goto execFuncs;
f8: _acts = _ini_actions + 9; goto execFuncs;
f9: _acts = _ini_actions + 11; goto execFuncs;
f10: _acts = _ini_actions + 13; goto execFuncs;
f7: _acts = _ini_actions + 15; goto execFuncs;
f12: _acts = _ini_actions + 17; goto execFuncs;
f11: _acts = _ini_actions + 19; goto execFuncs;
f13: _acts = _ini_actions + 21; goto execFuncs;
f0: _acts = _ini_actions + 23; goto execFuncs;
f3: _acts = _ini_actions + 25; goto execFuncs;
f2: _acts = _ini_actions + 28; goto execFuncs;
execFuncs:
_nacts = *_acts++;
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 0:
/* #line 130 "ini_parser.rl" */
{
buff_i = 0;
{cs = 2;goto _again;}
}
break;
case 1:
/* #line 135 "ini_parser.rl" */
{
if (buff_i >= INI_KEY_MAX) {
ini_parser_error("Section name too long");
{cs = 10;goto _again;}
}
keybuf[buff_i++] = (*p);
}
break;
case 2:
/* #line 143 "ini_parser.rl" */
{
// we need a separate buffer for the result, otherwise a failed
// partial parse would corrupt the section string
rtrim_buf(keybuf, buff_i);
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
secbuf[i] = 0;
{cs = 1;goto _again;}
}
break;
case 3:
/* #line 155 "ini_parser.rl" */
{
ini_parser_error("Syntax error in [section]");
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
break;
case 4:
/* #line 162 "ini_parser.rl" */
{
buff_i = 0;
keybuf[buff_i++] = (*p); // add the first char
{cs = 4;goto _again;}
}
break;
case 5:
/* #line 168 "ini_parser.rl" */
{
if (buff_i >= INI_KEY_MAX) {
ini_parser_error("Key too long");
{cs = 10;goto _again;}
}
keybuf[buff_i++] = (*p);
}
break;
case 6:
/* #line 176 "ini_parser.rl" */
{
rtrim_buf(keybuf, buff_i);
// --- Value begin ---
buff_i = 0;
value_quote = 0;
value_nextesc = false;
}
break;
case 7:
/* #line 185 "ini_parser.rl" */
{
isnl = ((*p) == '\r' || (*p) == '\n');
isquot = ((*p) == '\'' || (*p) == '"');
// detect our starting quote
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
value_quote = (*p);
goto valueCharDone;
}
if (buff_i >= INI_VALUE_MAX) {
ini_parser_error("Value too long");
{cs = 10;goto _again;}
}
// end of string - clean up and report
if ((!value_nextesc && (*p) == value_quote) || isnl) {
if (isnl && value_quote) {
ini_parser_error("Unterminated string");
{cs = 1;goto _again;}
}
// unquoted: trim from the end
if (!value_quote) {
rtrim_buf(valbuf, buff_i);
} else {
valbuf[buff_i] = 0;
}
if (keyCallback) {
keyCallback(secbuf, keybuf, valbuf, userdata);
}
// we don't want to discard to eol if the string was terminated by eol
// - would delete the next line
if (isnl) {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
c = (*p);
// escape...
if (value_nextesc) {
if ((*p) == 'n') c = '\n';
else if ((*p) == 'r') c = '\r';
else if ((*p) == 't') c = '\t';
else if ((*p) == 'e') c = '\033';
}
// collecting characters...
if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character
valbuf[buff_i++] = c;
}
value_nextesc = (!value_nextesc && (*p) == '\\');
valueCharDone:;
}
break;
case 8:
/* #line 247 "ini_parser.rl" */
{
ini_parser_error("Syntax error in key=value");
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
break;
case 9:
/* #line 257 "ini_parser.rl" */
{ {cs = 1;goto _again;} }
break;
case 10:
/* #line 258 "ini_parser.rl" */
{
ini_parser_error("Syntax error in comment");
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
break;
case 11:
/* #line 265 "ini_parser.rl" */
{ {cs = 1;goto _again;} }
break;
case 12:
/* #line 273 "ini_parser.rl" */
{ {cs = 8;goto _again;} }
break;
case 13:
/* #line 276 "ini_parser.rl" */
{
ini_parser_error("Syntax error in root");
{cs = 10;goto _again;}
}
break;
/* #line 458 "ini_parser.c" */
}
}
goto _again;
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
const char *__acts = _ini_actions + _ini_eof_actions[cs];
unsigned int __nacts = (unsigned int) *__acts++;
while ( __nacts-- > 0 ) {
switch ( *__acts++ ) {
case 3:
/* #line 155 "ini_parser.rl" */
{
ini_parser_error("Syntax error in [section]");
if((*p) == '\n') {cs = 1; if ( p == pe )
goto _test_eof;
goto _again;} else {cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
case 8:
/* #line 247 "ini_parser.rl" */
{
ini_parser_error("Syntax error in key=value");
if((*p) == '\n') {cs = 1; if ( p == pe )
goto _test_eof;
goto _again;} else {cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
case 10:
/* #line 258 "ini_parser.rl" */
{
ini_parser_error("Syntax error in comment");
if((*p) == '\n') {cs = 1; if ( p == pe )
goto _test_eof;
goto _again;} else {cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
case 13:
/* #line 276 "ini_parser.rl" */
{
ini_parser_error("Syntax error in root");
{cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
/* #line 517 "ini_parser.c" */
}
}
}
_out: {}
}
/* #line 283 "ini_parser.rl" */
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef INIPARSE_STREAM_H
#define INIPARSE_STREAM_H
#include "platform.h"
#ifdef DEBUG_INI
#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__)
#else
#define ini_error(fmt, ...)
#endif
// buffer sizes
#define INI_KEY_MAX 20
#define INI_VALUE_MAX 30
/**
* INI parser callback, called for each found key-value pair.
*
* @param section - current section, empty string for global keys
* @param key - found key (trimmed of whitespace)
* @param value - value, trimmed of quotes or whitespace
* @param userData - opaque user data pointer, general purpose
*/
typedef void (*IniParserCallback)(const char *section, const char *key, const char *value, void *userData);
/**
* Begin parsing a stream
*
* @param callback - key callback to assign
* @param userData - optional user data that will be passed to the callback
*/
void ini_parse_begin(IniParserCallback callback, void *userData);
/**
* End parse stream.
* Flushes what remains in the buffer and removes callback.
*
* @returns userData or NULL if none
*/
void* ini_parse_end(void);
/**
* Parse a string (needn't be complete line or file)
*
* @param data - string to parse
* @param len - string length (0 = use strlen)
*/
void ini_parse(const char *data, size_t len);
/**
* Parse a complete file loaded to string
*
* @param text - entire file as string
* @param len - file length (0 = use strlen)
* @param callback - key callback
* @param userData - optional user data for key callback
*/
void ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData);
/**
* Explicitly reset the parser
*/
void ini_parse_reset(void);
#endif // INIPARSE_STREAM_H
+284
View File
@@ -0,0 +1,284 @@
/* Ragel constants block */
#include "ini_parser.h"
// Ragel setup
%%{
machine ini;
write data;
alphtype unsigned char;
}%%
// Persistent state
static int8_t cs = -1; //!< Ragel's Current State variable
static uint32_t buff_i = 0; //!< Write pointer for the buffers
static char value_quote = 0; //!< Quote character of the currently collected value
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
static void *userdata = NULL; //!< Currently assigned user data for the callback
// Buffers
static char keybuf[INI_KEY_MAX];
static char secbuf[INI_KEY_MAX];
static char valbuf[INI_VALUE_MAX];
// See header for doxygen!
void
ini_parse_reset_partial(void)
{
buff_i = 0;
value_quote = 0;
value_nextesc = false;
}
void
ini_parse_reset(void)
{
ini_parse_reset_partial();
keybuf[0] = secbuf[0] = valbuf[0] = 0;
%% write init;
}
void
ini_parser_error(const char* msg)
{
ini_error("Parser error: %s", msg);
ini_parse_reset_partial();
}
void
ini_parse_begin(IniParserCallback callback, void *userData)
{
keyCallback = callback;
userdata = userData;
ini_parse_reset();
}
void
*ini_parse_end(void)
{
ini_parse("\n", 1);
if (keyCallback) {
keyCallback = NULL;
}
void *ud = userdata;
userdata = NULL;
return ud;
}
void
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
{
ini_parse_begin(callback, userData);
ini_parse(text, len);
ini_parse_end();
}
static void
rtrim_buf(char *buf, int32_t end)
{
if (end > 0) {
while ((uint8_t)buf[--end] < 33);
end++; // go past the last character
}
buf[end] = 0;
}
void
ini_parse(const char *newstr, size_t len)
{
int32_t i;
char c;
bool isnl;
bool isquot;
// Load new data to Ragel vars
const uint8_t *p;
const uint8_t *eof;
const uint8_t *pe;
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
p = (const uint8_t *) newstr;
eof = NULL;
pe = (const uint8_t *) (newstr + len);
// Init Ragel on the first run
if (cs == -1) {
ini_parse_reset();
}
// The parser
%%{
#/ *
ispace = [ \t]; # inline space
wchar = any - 0..8 - 10..31;
#apos = '\'';
#quot = '\"';
nonl = [^\r\n];
nl = '\r'? '\n';
# ---- [SECTION] ----
action sectionStart {
buff_i = 0;
fgoto section;
}
action sectionChar {
if (buff_i >= INI_KEY_MAX) {
ini_parser_error("Section name too long");
fgoto discard2eol;
}
keybuf[buff_i++] = fc;
}
action sectionEnd {
// we need a separate buffer for the result, otherwise a failed
// partial parse would corrupt the section string
rtrim_buf(keybuf, buff_i);
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
secbuf[i] = 0;
fgoto main;
}
section :=
(
ispace* <: ((wchar - ']')+ @sectionChar) ']' @sectionEnd
) $!{
ini_parser_error("Syntax error in [section]");
if(fc == '\n') fgoto main; else fgoto discard2eol;
};
# ---- KEY=VALUE ----
action keyStart {
buff_i = 0;
keybuf[buff_i++] = fc; // add the first char
fgoto keyvalue;
}
action keyChar {
if (buff_i >= INI_KEY_MAX) {
ini_parser_error("Key too long");
fgoto discard2eol;
}
keybuf[buff_i++] = fc;
}
action keyEnd {
rtrim_buf(keybuf, buff_i);
// --- Value begin ---
buff_i = 0;
value_quote = 0;
value_nextesc = false;
}
action valueChar {
isnl = (fc == '\r' || fc == '\n');
isquot = (fc == '\'' || fc == '"');
// detect our starting quote
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
value_quote = fc;
goto valueCharDone;
}
if (buff_i >= INI_VALUE_MAX) {
ini_parser_error("Value too long");
fgoto discard2eol;
}
// end of string - clean up and report
if ((!value_nextesc && fc == value_quote) || isnl) {
if (isnl && value_quote) {
ini_parser_error("Unterminated string");
fgoto main;
}
// unquoted: trim from the end
if (!value_quote) {
rtrim_buf(valbuf, buff_i);
} else {
valbuf[buff_i] = 0;
}
if (keyCallback) {
keyCallback(secbuf, keybuf, valbuf, userdata);
}
// we don't want to discard to eol if the string was terminated by eol
// - would delete the next line
if (isnl) fgoto main; else fgoto discard2eol;
}
c = fc;
// escape...
if (value_nextesc) {
if (fc == 'n') c = '\n';
else if (fc == 'r') c = '\r';
else if (fc == 't') c = '\t';
else if (fc == 'e') c = '\033';
}
// collecting characters...
if (value_nextesc || fc != '\\') { // is quoted, or is not a quoting backslash - literal character
valbuf[buff_i++] = c;
}
value_nextesc = (!value_nextesc && fc == '\\');
valueCharDone:;
}
# use * for key, first char is already consumed.
keyvalue :=
(
([^\n=:]* @keyChar %keyEnd)
[=:] ispace* <: nonl* @valueChar nl @valueChar
) $!{
ini_parser_error("Syntax error in key=value");
if(fc == '\n') fgoto main; else fgoto discard2eol;
};
# ---- COMMENT ----
comment :=
(
nonl* nl
@{ fgoto main; }
) $!{
ini_parser_error("Syntax error in comment");
if(fc == '\n') fgoto main; else fgoto discard2eol;
};
# ---- CLEANUP ----
discard2eol := nonl* nl @{ fgoto main; };
# ---- ROOT ----
main :=
(space*
(
'[' @sectionStart |
[#;] @{ fgoto comment; } |
(wchar - [\t =:]) @keyStart
)
) $!{
ini_parser_error("Syntax error in root");
fgoto discard2eol;
};
write exec;
#*/
}%%
}
+82
View File
@@ -0,0 +1,82 @@
//
// Created by MightyPork on 2017/12/01.
//
#include "platform.h"
#include "ini_writer.h"
#ifndef MIN
#define MIN(a,b) ((a)>(b)?(b):(a))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define IWBUFFER_LEN 128
// sprintf from varargs, allocating buffer on stack. Uses 'format' argument
#define IW_VPRINTF() do { \
char iwbuffer[IWBUFFER_LEN]; \
va_list args; \
va_start(args, format); \
uint32_t len = (int)fixup_vsnprintf(&iwbuffer[0], IWBUFFER_LEN, format, args); \
iw_buff(iw, (uint8_t *) iwbuffer, len); \
va_end(args); \
} while(0)
void iw_buff(IniWriter *iw, const uint8_t *buf, uint32_t len)
{
if (iw->count == 0) return;
uint32_t skip = 0;
if (iw->skip >= len) {
// Skip entire string
iw->skip -= len;
return;
} else {
// skip part
skip = iw->skip;
iw->skip = 0;
uint32_t count = MIN(iw->count, len-skip);
memcpy(iw->ptr, buf+skip, count);
iw->ptr += count;
iw->count -= count;
}
}
void iw_sprintf(IniWriter *iw, const char *format, ...)
{
if (iw->count == 0) return;
IW_VPRINTF();
}
// High level stuff
void iw_section(IniWriter *iw, const char *format, ...)
{
if (iw->count == 0) return;
iw_string(iw, "\r\n["); // newline before section as a separator
IW_VPRINTF();
iw_string(iw, "]\r\n");
}
void iw_comment(IniWriter *iw, const char *format, ...)
{
if (iw->count == 0) return;
iw_string(iw, "# ");
IW_VPRINTF();
iw_newline(iw);
}
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
{
if (iw->count == 0) return;
iw_string(iw, key);
iw_string(iw, "=");
IW_VPRINTF();
iw_newline(iw); // one newline after entry
}
+91
View File
@@ -0,0 +1,91 @@
//
// Created by MightyPork on 2017/12/01.
//
#ifndef INIWRITER_H
#define INIWRITER_H
#include "platform.h"
typedef struct iniwriter_ {
char *ptr;
uint32_t skip;
uint32_t count;
} IniWriter;
/**
* Initialize a IniWriter struct (macro)
*
* @param buffer - buffer backing the writer, result will be written here
* @param skip - number of written bytes to skip
* @param count - number of bytes to write, truncate rest
* @return structure initializer
*/
#define iw_init(buffer, skip, count) (IniWriter){buffer, skip, count}
/**
* Try to write a buffer to the file
*
* @param iw - iniwriter handle
* @param buf - buffer to write
* @param len - buffer len
*/
void iw_buff(IniWriter *iw, const uint8_t *buf, uint32_t len);
/**
* Try to write a string to the file
*
* @param iw - iniwriter handle
* @param str - string to write
*/
static inline void iw_string(IniWriter *iw, const char *str)
{
if (iw->count != 0) {
iw_buff(iw, (uint8_t *) str, (uint32_t) strlen(str));
}
}
#define iw_newline(iw) iw_string(iw, "\r\n")
/**
* Try to snprintf to the file
*
* @param iw - iniwriter handle
* @param format - format, like printf
* @param ... - replacements
*/
void iw_sprintf(IniWriter *iw, const char *format, ...)
__attribute__((format(printf,2,3)));
// High level stuff
/**
* Try to write a INI section header [foobar]\r\n
* @param iw - iniwriter handle
* @param format - format, like printf
* @param ... - replacements
*/
void iw_section(IniWriter *iw, const char *format, ...)
__attribute__((format(printf,2,3)));
/**
* Try to write a INI comment # blah\r\n
* @param iw - iniwriter handle
* @param format - format, like printf
* @param ... - replacements
*/
void iw_comment(IniWriter *iw, const char *format, ...)
__attribute__((format(printf,2,3)));
/**
* Try to write a key-value entry
*
* @param iw - iniwriter handle
* @param key - key
* @param format - value format (like printf)
* @param ... - replacements
*/
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
__attribute__((format(printf,3,4)));
#endif //INIWRITER_H
+74
View File
@@ -0,0 +1,74 @@
/**
* @file macro.h
* @brief useful things + Special asserts and macros
*
* DAPLink Interface Firmware
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef VFS_MACRO_H
#define VFS_MACRO_H
#ifdef __cplusplus
extern "C" {
#endif
// --------------- VFS macros and general purpose --------------------
#define ELEMENTS_IN_ARRAY(array) (sizeof(array)/sizeof(array[0]))
#define MB(size) ((size) * 1024 * 1024)
#define KB(size) ((size) * 1024)
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#define ROUND_UP(value, boundary) ((value) + ((boundary) - (value)) % (boundary))
#define ROUND_DOWN(value, boundary) ((value) - ((value) % (boundary)))
// ---------- HELPERS FOR XMACROS -----------------
#define XJOIN(a, b) a##b
#define STR_(x) #x
#define STR(x) STR_(x)
// ---------- COMPILER SPECIAL MACROS -------------
#define COMPILER_CONCAT_(a, b) a##b
#define COMPILER_CONCAT(a, b) COMPILER_CONCAT_(a, b)
// Divide by zero if the the expression is false. This
// causes an error at compile time.
//
// The special value '__COUNTER__' is used to create a unique value to
// append to 'compiler_assert_' to create a unique token. This prevents
// conflicts resulting from the same enum being declared multiple times.
#define COMPILER_ASSERT(e) enum { COMPILER_CONCAT(compiler_assert_, __COUNTER__) = 1/((e) ? 1 : 0) }
#define __at(_addr) __attribute__ ((at(_addr)))
#ifdef __cplusplus
}
#endif
#endif
+48
View File
@@ -0,0 +1,48 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include "debug.h"
#include "stm32_assert.h"
#include "malloc_safe.h"
#if 1
void *malloc_safe_do(size_t size, const char *file, uint32_t line)
{
void *mem = malloc(size);
if (mem == NULL) abort_msg("MALLOC FAILED", file, line);
return mem;
}
void *calloc_safe_do(size_t nmemb, size_t size, const char *file, uint32_t line)
{
void *mem = calloc(size, nmemb);
if (mem == NULL) abort_msg("CALLOC FAILED", file, line);
return mem;
}
void *malloc_ck_do(size_t size, bool *suc, const char *file, uint32_t line)
{
void *mem = malloc(size);
if (mem == NULL) {
warn_msg("MALLOC FAILED", file, line);
*suc = false;
mem = NULL;
}
return mem;
}
void *calloc_ck_do(size_t nmemb, size_t size, bool *suc, const char *file, uint32_t line)
{
void *mem = calloc(size, nmemb);
if (mem == NULL) {
warn_msg("CALLOC FAILED", file, line);
*suc = false;
mem = NULL;
}
return mem;
}
#endif
+22
View File
@@ -0,0 +1,22 @@
#ifndef MALLOC_SAFE_H
#define MALLOC_SAFE_H
/**
* Malloc that prints error and restarts the system on failure.
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
void *malloc_safe_do(size_t size, const char* file, uint32_t line) __attribute__((malloc));
void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line) __attribute__((malloc));
void *malloc_ck_do(size_t size, bool *suc, const char* file, uint32_t line) __attribute__((malloc));
void *calloc_ck_do(size_t nmemb, size_t size, bool *suc, const char* file, uint32_t line) __attribute__((malloc));
#define malloc_s(size) malloc_safe_do(size, __BASE_FILE__, __LINE__)
#define calloc_s(nmemb, size) calloc_safe_do(nmemb, size, __BASE_FILE__, __LINE__)
#define malloc_ck(size, suc) malloc_ck_do(size, suc, __BASE_FILE__, __LINE__)
#define calloc_ck(nmemb, size, suc) calloc_ck_do(nmemb, size, suc, __BASE_FILE__, __LINE__)
#endif // MALLOC_SAFE_H
+100
View File
@@ -0,0 +1,100 @@
#include <string.h>
#include "payload_builder.h"
#define pb_check_capacity(pb, needed) \
if ((pb)->current + (needed) > (pb)->end) { \
if ((pb)->full_handler == NULL || !(pb)->full_handler(pb, needed)) (pb)->ok = 0; \
}
/** Write from a buffer */
bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len)
{
pb_check_capacity(pb, len);
if (!pb->ok) return false;
memcpy(pb->current, buf, len);
pb->current += len;
return true;
}
/** Write s zero terminated string */
bool pb_string(PayloadBuilder *pb, const char *str)
{
uint32_t len = (uint32_t) strlen(str);
pb_check_capacity(pb, len+1);
if (!pb->ok) return false;
memcpy(pb->current, str, len+1);
pb->current += len+1;
return true;
}
/** Write uint8_t to the buffer */
bool pb_u8(PayloadBuilder *pb, uint8_t byte)
{
pb_check_capacity(pb, 1);
if (!pb->ok) return false;
*pb->current++ = byte;
return true;
}
/** Write uint16_t to the buffer. */
bool pb_u16(PayloadBuilder *pb, uint16_t word)
{
pb_check_capacity(pb, 2);
if (!pb->ok) return false;
if (pb->bigendian) {
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
*pb->current++ = (uint8_t) (word & 0xFF);
} else {
*pb->current++ = (uint8_t) (word & 0xFF);
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
}
return true;
}
/** Write uint32_t to the buffer. */
bool pb_u32(PayloadBuilder *pb, uint32_t word)
{
pb_check_capacity(pb, 4);
if (!pb->ok) return false;
if (pb->bigendian) {
*pb->current++ = (uint8_t) ((word >> 24) & 0xFF);
*pb->current++ = (uint8_t) ((word >> 16) & 0xFF);
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
*pb->current++ = (uint8_t) (word & 0xFF);
} else {
*pb->current++ = (uint8_t) (word & 0xFF);
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
*pb->current++ = (uint8_t) ((word >> 16) & 0xFF);
*pb->current++ = (uint8_t) ((word >> 24) & 0xFF);
}
return true;
}
/** Write int8_t to the buffer. */
bool pb_i8(PayloadBuilder *pb, int8_t byte)
{
return pb_u8(pb, ((union conv8){.i8 = byte}).u8);
}
/** Write int16_t to the buffer. */
bool pb_i16(PayloadBuilder *pb, int16_t word)
{
return pb_u16(pb, ((union conv16){.i16 = word}).u16);
}
/** Write int32_t to the buffer. */
bool pb_i32(PayloadBuilder *pb, int32_t word)
{
return pb_u32(pb, ((union conv32){.i32 = word}).u32);
}
/** Write 4-byte float to the buffer. */
bool pb_float(PayloadBuilder *pb, float f)
{
return pb_u32(pb, ((union conv32){.f32 = f}).u32);
}
+110
View File
@@ -0,0 +1,110 @@
#ifndef PAYLOAD_BUILDER_H
#define PAYLOAD_BUILDER_H
/**
* PayloadBuilder, part of the TinyFrame utilities collection
*
* (c) Ondřej Hruška, 2014-2017. MIT license.
*
* The builder supports big and little endian which is selected when
* initializing it or by accessing the bigendian struct field.
*
* This module helps you with building payloads (not only for TinyFrame)
*
* The builder performs bounds checking and calls the provided handler when
* the requested write wouldn't fit. Use the handler to realloc / flush the buffer
* or report an error.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "type_coerce.h"
typedef struct PayloadBuilder_ PayloadBuilder;
/**
* Full buffer handler.
*
* 'needed' more bytes should be written but the end of the buffer was reached.
*
* Return true if the problem was solved (e.g. buffer was flushed and the
* 'current' pointer moved to the beginning).
*
* If false is returned, the 'ok' flag on the struct is set to false
* and all following writes are discarded.
*/
typedef bool (*pb_full_handler)(PayloadBuilder *pb, uint32_t needed);
struct PayloadBuilder_ {
uint8_t *start; //!< Pointer to the beginning of the buffer
uint8_t *current; //!< Pointer to the next byte to be read
uint8_t *end; //!< Pointer to the end of the buffer (start + length)
pb_full_handler full_handler; //!< Callback for buffer overrun
bool bigendian; //!< Flag to use big-endian parsing
bool ok; //!< Indicates that all reads were successful
};
// --- initializer helper macros ---
/** Start the builder. */
#define pb_start_e(buf, capacity, bigendian, full_handler) ((PayloadBuilder){buf, buf, (buf)+(capacity), full_handler, bigendian, 1})
/** Start the builder in big-endian mode */
#define pb_start_be(buf, capacity, full_handler) pb_start_e(buf, capacity, 1, full_handler)
/** Start the builder in little-endian mode */
#define pb_start_le(buf, capacity, full_handler) pb_start_e(buf, capacity, 0, full_handler)
/** Start the parser in little-endian mode (default) */
#define pb_start(buf, capacity, full_handler) pb_start_le(buf, capacity, full_handler)
// --- utilities ---
/** Get already used bytes count */
#define pb_length(pb) ((pb)->current - (pb)->start)
/** Reset the current pointer to start */
#define pb_rewind(pb) do { pb->current = pb->start; } while (0)
/** Write from a buffer */
bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len);
/** Write a zero terminated string */
bool pb_string(PayloadBuilder *pb, const char *str);
/** Write uint8_t to the buffer */
bool pb_u8(PayloadBuilder *pb, uint8_t byte);
/** Write boolean to the buffer. */
static inline bool pb_bool(PayloadBuilder *pb, bool b)
{
return pb_u8(pb, (uint8_t) b);
}
/** Write uint16_t to the buffer. */
bool pb_u16(PayloadBuilder *pb, uint16_t word);
/** Write uint32_t to the buffer. */
bool pb_u32(PayloadBuilder *pb, uint32_t word);
/** Write int8_t to the buffer. */
bool pb_i8(PayloadBuilder *pb, int8_t byte);
/** Write char (int8_t) to the buffer. */
static inline bool pb_char(PayloadBuilder *pb, char c)
{
return pb_i8(pb, c);
}
/** Write int16_t to the buffer. */
bool pb_i16(PayloadBuilder *pb, int16_t word);
/** Write int32_t to the buffer. */
bool pb_i32(PayloadBuilder *pb, int32_t word);
/** Write 4-byte float to the buffer. */
bool pb_float(PayloadBuilder *pb, float f);
#endif // PAYLOAD_BUILDER_H
+121
View File
@@ -0,0 +1,121 @@
#include "payload_parser.h"
#define pp_check_capacity(pp, needed) \
if ((pp)->current + (needed) > (pp)->end) { \
if ((pp)->empty_handler == NULL || !(pp)->empty_handler(pp, needed)) {(pp)->ok = 0;} ; \
}
void pp_skip(PayloadParser *pp, uint32_t num)
{
pp->current += num;
}
uint8_t pp_u8(PayloadParser *pp)
{
pp_check_capacity(pp, 1);
if (!pp->ok) return 0;
return *pp->current++;
}
uint16_t pp_u16(PayloadParser *pp)
{
pp_check_capacity(pp, 2);
if (!pp->ok) return 0;
uint16_t x = 0;
if (pp->bigendian) {
x |= *pp->current++ << 8;
x |= *pp->current++;
} else {
x |= *pp->current++;
x |= *pp->current++ << 8;
}
return x;
}
uint32_t pp_u32(PayloadParser *pp)
{
pp_check_capacity(pp, 4);
if (!pp->ok) return 0;
uint32_t x = 0;
if (pp->bigendian) {
x |= (uint32_t) (*pp->current++ << 24);
x |= (uint32_t) (*pp->current++ << 16);
x |= (uint32_t) (*pp->current++ << 8);
x |= *pp->current++;
} else {
x |= *pp->current++;
x |= (uint32_t) (*pp->current++ << 8);
x |= (uint32_t) (*pp->current++ << 16);
x |= (uint32_t) (*pp->current++ << 24);
}
return x;
}
const uint8_t *pp_tail(PayloadParser *pp, uint32_t *length)
{
int32_t len = (int) (pp->end - pp->current);
if (!pp->ok || len <= 0) {
if (length != NULL) *length = 0;
return NULL;
}
if (length != NULL) {
*length = (uint32_t) len;
}
return pp->current;
}
/** Read int8_t from the payload. */
int8_t pp_i8(PayloadParser *pp)
{
return ((union conv8) {.u8 = pp_u8(pp)}).i8;
}
/** Read int16_t from the payload. */
int16_t pp_i16(PayloadParser *pp)
{
return ((union conv16) {.u16 = pp_u16(pp)}).i16;
}
/** Read int32_t from the payload. */
int32_t pp_i32(PayloadParser *pp)
{
return ((union conv32) {.u32 = pp_u32(pp)}).i32;
}
/** Read 4-byte float from the payload. */
float pp_float(PayloadParser *pp)
{
return ((union conv32) {.u32 = pp_u32(pp)}).f32;
}
/** Read a zstring */
uint32_t pp_string(PayloadParser *pp, char *buffer, uint32_t maxlen)
{
pp_check_capacity(pp, 1);
uint32_t len = 0;
while (len < maxlen-1 && pp->current != pp->end) {
char c = *buffer++ = *pp->current++;
if (c == 0) break;
len++;
}
*buffer = 0;
return len;
}
/** Read a buffer */
uint32_t pp_buf(PayloadParser *pp, uint8_t *buffer, uint32_t maxlen)
{
uint32_t len = 0;
while (len < maxlen && pp->current != pp->end) {
*buffer++ = *pp->current++;
len++;
}
return len;
}
+143
View File
@@ -0,0 +1,143 @@
#ifndef PAYLOAD_PARSER_H
#define PAYLOAD_PARSER_H
/**
* PayloadParser, part of the TinyFrame utilities collection
*
* (c) Ondřej Hruška, 2016-2017. MIT license.
*
* This module helps you with parsing payloads (not only from TinyFrame).
*
* The parser supports big and little-endian which is selected when
* initializing it or by accessing the bigendian struct field.
*
* The parser performs bounds checking and calls the provided handler when
* the requested read doesn't have enough data. Use the callback to take
* appropriate action, e.g. report an error.
*
* If the handler function is not defined, the pb->ok flag is set to false
* (use this to check for success), and further reads won't have any effect
* and always result in 0 or empty array.
*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "type_coerce.h"
typedef struct PayloadParser_ PayloadParser;
/**
* Empty buffer handler.
*
* 'needed' more bytes should be read but the end was reached.
*
* Return true if the problem was solved (e.g. new data loaded into
* the buffer and the 'current' pointer moved to the beginning).
*
* If false is returned, the 'ok' flag on the struct is set to false
* and all following reads will fail / return 0.
*/
typedef bool (*pp_empty_handler)(PayloadParser *pp, uint32_t needed);
struct PayloadParser_ {
uint8_t *start; //!< Pointer to the beginning of the buffer
uint8_t *current; //!< Pointer to the next byte to be read
uint8_t *end; //!< Pointer to the end of the buffer (start + length)
pp_empty_handler empty_handler; //!< Callback for buffer underrun
bool bigendian; //!< Flag to use big-endian parsing
bool ok; //!< Indicates that all reads were successful
};
// --- initializer helper macros ---
/** Start the parser. */
#define pp_start_e(buf, length, bigendian, empty_handler) ((PayloadParser){buf, buf, (buf)+(length), empty_handler, bigendian, 1})
/** Start the parser in big-endian mode */
#define pp_start_be(buf, length, empty_handler) pp_start_e(buf, length, 1, empty_handler)
/** Start the parser in little-endian mode */
#define pp_start_le(buf, length, empty_handler) pp_start_e(buf, length, 0, empty_handler)
/** Start the parser in little-endian mode (default) */
#define pp_start(buf, length, empty_handler) pp_start_le(buf, length, empty_handler)
// --- utilities ---
/** Get remaining length */
#define pp_length(pp) ((pp)->end - (pp)->current)
/** Reset the current pointer to start */
#define pp_rewind(pp) do { pp->current = pp->start; } while (0)
/**
* @brief Get the remainder of the buffer.
*
* Returns NULL and sets 'length' to 0 if there are no bytes left.
*
* @param pp
* @param length : here the buffer length will be stored. NULL to do not store.
* @return the remaining portion of the input buffer
*/
const uint8_t *pp_tail(PayloadParser *pp, uint32_t *length);
/** Read uint8_t from the payload. */
uint8_t pp_u8(PayloadParser *pp);
/** Read bool from the payload. */
static inline int8_t pp_bool(PayloadParser *pp)
{
return pp_u8(pp) != 0;
}
/** Skip bytes */
void pp_skip(PayloadParser *pp, uint32_t num);
/** Read uint16_t from the payload. */
uint16_t pp_u16(PayloadParser *pp);
/** Read uint32_t from the payload. */
uint32_t pp_u32(PayloadParser *pp);
/** Read int8_t from the payload. */
int8_t pp_i8(PayloadParser *pp);
/** Read char (int8_t) from the payload. */
static inline int8_t pp_char(PayloadParser *pp)
{
return pp_i8(pp);
}
/** Read int16_t from the payload. */
int16_t pp_i16(PayloadParser *pp);
/** Read int32_t from the payload. */
int32_t pp_i32(PayloadParser *pp);
/** Read 4-byte float from the payload. */
float pp_float(PayloadParser *pp);
/**
* Parse a zero-terminated string
*
* @param pp - parser
* @param buffer - target buffer
* @param maxlen - buffer size
* @return actual number of bytes, excluding terminator
*/
uint32_t pp_string(PayloadParser *pp, char *buffer, uint32_t maxlen);
/**
* Parse a buffer
*
* @param pp - parser
* @param buffer - target buffer
* @param maxlen - buffer size
* @return actual number of bytes, excluding terminator
*/
uint32_t pp_buf(PayloadParser *pp, uint8_t *buffer, uint32_t maxlen);
#endif // PAYLOAD_PARSER_H
+1013
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
//
// Created by MightyPork on 2017/11/09.
//
#ifndef GEX_SNPRINTF_H
#define GEX_SNPRINTF_H
#include <stdarg.h>
#include <limits.h>
#include "macro.h"
size_t fixup_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
size_t fixup_snprintf(char *str, size_t count,const char *fmt,...);
size_t fixup_vasprintf(char **ptr, const char *format, va_list ap);
size_t fixup_asprintf(char **ptr, const char *format, ...);
size_t fixup_sprintf(char *ptr, const char *format, ...);
// Trap for using newlib functions
//#define vsnprintf fuck1
//#define snprintf fuck2
//#define vasprintf fuck3
//#define asprintf fuck4
//#define sprintf fuck5
#define VSNPRINTF(...) fixup_vsnprintf(__VA_ARGS__)
#define SNPRINTF(...) fixup_snprintf(__VA_ARGS__)
#define VASPRINTF(...) fixup_vasprintf(__VA_ARGS__)
#define ASPRINTF(...) fixup_asprintf(__VA_ARGS__)
#define SPRINTF(...) fixup_sprintf(__VA_ARGS__)
#endif //GEX_SNPRINTF_H
+87
View File
@@ -0,0 +1,87 @@
//
// Created by MightyPork on 2017/12/04.
//
#include <task_sched.h>
#include "platform.h"
#include "stacksmon.h"
#if USE_STACK_MONITOR
struct stackhandle {
const char *description;
uint8_t *buffer;
uint32_t len;
};
#define STACK_NUM 16
static uint32_t nextidx = 0;
static struct stackhandle stacks[STACK_NUM];
void stackmon_register(const char *description, void *buffer, uint32_t len)
{
assert_param(nextidx < STACK_NUM);
uint8_t *bv = buffer;
// This is probably redundant, FreeRTOS does it too.
for (uint32_t i = 0; i < len; i++) bv[i] = 0xA5;
stacks[nextidx].description = description;
stacks[nextidx].buffer = bv;
stacks[nextidx].len = len;
nextidx++;
}
void stackmon_dump(void)
{
PUTS("\r\n\033[1m---- STACK USAGE REPORT ---\033[m\r\n");
for (uint32_t i = 0; i < nextidx; i++) {
PRINTF("\033[36m>> %s\033[m @ %p\r\n", stacks[i].description, (void *) stacks[i].buffer);
struct stackhandle *stack = &stacks[i];
uint32_t free = 0;
if (stack->buffer[0] != 0xA5) {
PUTS(" \033[31m!!! OVERRUN !!!\033[m\r\n");
} else {
for (uint32_t j = 0; j < stack->len; j++) {
if (stack->buffer[j] == 0xA5) {
free++;
} else {
break;
}
}
}
uint32_t words = ((stack->len-free)>>2)+1;
if (words>stack->len>>2) words=stack->len>>2;
PRINTF(" Used: \033[33m%"PRIu32" / %"PRIu32" bytes\033[m (\033[33m%"PRIu32" / %"PRIu32" words\033[m) ~ \033[33m%"PRIu32" %%\033[m\r\n",
(stack->len-free),
stack->len,
words,
stack->len>>2,
(stack->len-free)*100/stack->len
);
}
PUTS("\033[36m>> QUEUES\033[m\r\n");
PRINTF(" Used slots: \033[33mHP %"PRIu32", LP %"PRIu32"\033[m\r\n",
jobQueHighWaterMarkHP, jobQueHighWaterMarkLP);
PRINTF("\033[1m---------------------------\033[m\r\n\r\n");
}
void stackmon_check_canaries(void)
{
for (uint32_t i = 0; i < nextidx; i++) {
struct stackhandle *stack = &stacks[i];
if (stack->buffer[0] != 0xA5) {
dbg("\r\n\033[31;1m!!!! STACK \"%s\" OVERRUN - CANARY IS DEAD !!!!\033[m\r\n", stack->description);
stackmon_dump();
trap("ABORT");
}
}
}
#endif
+20
View File
@@ -0,0 +1,20 @@
//
// Created by MightyPork on 2017/12/04.
//
#ifndef GEX_STACKSMON_H
#define GEX_STACKSMON_H
#include "platform.h"
#if USE_STACK_MONITOR
void stackmon_check_canaries(void);
void stackmon_dump(void);
void stackmon_register(const char *description, void *buffer, uint32_t len);
#else
#define stackmon_check_canaries() do {} while(0)
#define stackmon_dump() do {} while(0)
#define stackmon_register(description, buffer, len) do {} while(0)
#endif
#endif //GEX_STACKSMON_H
+57
View File
@@ -0,0 +1,57 @@
//
// Created by MightyPork on 2017/11/26.
//
#include "str_utils.h"
#include "avrlibc.h"
bool str_parse_yn(const char *str, bool *suc)
{
if (streq(str, "Y")) return true;
if (streq(str, "1")) return true;
if (streq(str, "YES")) return true;
if (streq(str, "N")) return false;
if (streq(str, "0")) return false;
if (streq(str, "NO")) return false;
*suc = false;
return false;
}
uint8_t str_parse_01(const char *str, const char *a, const char *b, bool *suc)
{
if (streq(str, a)) return 0;
if (streq(str, b)) return 1;
*suc = false;
return 0;
}
uint8_t str_parse_012(const char *str, const char *a, const char *b, const char *c, bool *suc)
{
if (streq(str, a)) return 0;
if (streq(str, b)) return 1;
if (streq(str, c)) return 2;
*suc = false;
return 0;
}
bool str_parse_pin(const char *value, char *targetName, uint8_t *targetNumber)
{
// discard leading 'P'
if (value[0] == 'P') {
value++;
}
size_t len = strlen(value);
if (len<2||len>3) return false;
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
// lets just hope it's OK
*targetNumber = (uint8_t) avr_atoi(value + 1);
return true;
}
+59
View File
@@ -0,0 +1,59 @@
#ifndef PLATFORSTR_UTILS_H
#define PLATFORSTR_UTILS_H
#include <stdbool.h>
#include <string.h>
#include "stringbuilder.h"
static inline bool __attribute__((const))
streq(const char *restrict str1, const char *restrict str2)
{
return strcmp(str1, str2) == 0;
}
static inline bool __attribute__((const))
strcaseq(const char *restrict str1, const char *restrict str2)
{
return strcasecmp(str1, str2) == 0;
}
static inline bool __attribute__((const))
strneq(const char *restrict str1, const char *restrict str2, uint32_t limit)
{
return strncmp(str1, str2, limit) == 0;
}
static inline bool __attribute__((const))
strncaseq(const char *restrict str1, const char *restrict str2, uint32_t limit)
{
return strncasecmp(str1, str2, limit) == 0;
}
static inline bool __attribute__((const))
strstarts(const char *restrict str, const char *restrict prefix)
{
return strncmp(str, prefix, strlen(prefix)) == 0;
}
static inline char __attribute__((const))
last_char_n(const char *str, uint32_t nth)
{
return str[strlen(str) - nth];
}
static inline char __attribute__((const))
last_char(const char *str)
{
return str[strlen(str) - 1];
}
bool str_parse_yn(const char *str, bool *suc);
uint8_t str_parse_01(const char *str, const char *a, const char *b, bool *suc);
uint8_t str_parse_012(const char *str, const char *a, const char *b, const char *c, bool *suc);
#define str_01(cond, a, b) ((cond) ? (b) : (a))
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
bool str_parse_pin(const char *str, char *targetName, uint8_t *targetNumber);
#endif
+114
View File
@@ -0,0 +1,114 @@
/**
* @file stringbuilder.c
*
* ADAPTED FROM:
*
* DAPLink Interface Firmware
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stringbuilder.h"
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
uint32_t strb_write_hex8(char *str, uint8_t value)
{
static const char nybble_chars[] = "0123456789abcdef";
*(str + 0) = nybble_chars[(value >> 4) & 0x0F ];
*(str + 1) = nybble_chars[(value >> 0) & 0x0F ];
return 2;
}
uint32_t strb_write_hex16(char *str, uint16_t value)
{
uint32_t pos = 0;
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 8) & 0xFF));
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0) & 0xFF));
return pos;
}
uint32_t strb_write_hex32(char *str, uint32_t value)
{
uint32_t pos = 0;
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x18) & 0xFF));
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x10) & 0xFF));
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x08) & 0xFF));
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x00) & 0xFF));
return pos;
}
uint32_t strb_write_uint32(char *str, uint32_t value)
{
uint32_t temp_val;
uint32_t digits;
uint32_t i;
// Count the number of digits
digits = 0;
temp_val = value;
while (temp_val > 0) {
temp_val /= 10;
digits += 1;
}
if (digits <= 0) {
digits = 1;
}
// Write the number
for (i = 0; i < digits; i++) {
str[digits - i - 1] = (char) ('0' + (value % 10));
value /= 10;
}
return digits;
}
uint32_t strb_write_uint32_zp(char *str, uint32_t value, uint16_t total_size)
{
uint32_t size;
// Get the size of value
size = strb_write_uint32(str, value);
if (size >= total_size) {
return size;
}
// Zero fill
memset(str, '0', total_size);
// Write value
strb_write_uint32(str + (total_size - size), value);
return total_size;
}
uint32_t strb_write_string(char *str, const char *data)
{
uint32_t pos = 0;
while (0 != data[pos]) {
str[pos] = data[pos];
pos++;
}
return pos;
}
#ifdef __cplusplus
}
#endif
+36
View File
@@ -0,0 +1,36 @@
/**
* @file stringbuilder.h
*
* ADAPTED FROM:
*
* DAPLink Interface Firmware
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef STRINGBUILDER_H
#define STRINGBUILDER_H
#include <stdint.h>
// Write the value to the address specified and return the size
uint32_t strb_write_hex8(char *str, uint8_t value);
uint32_t strb_write_hex16(char *str, uint16_t value);
uint32_t strb_write_hex32(char *str, uint32_t value);
uint32_t strb_write_uint32(char *str, uint32_t value);
uint32_t strb_write_uint32_zp(char *str, uint32_t value, uint16_t total_size);
uint32_t strb_write_string(char *str, const char *data);
#endif //STRINGBUILDER_H
+32
View File
@@ -0,0 +1,32 @@
#ifndef TYPE_COERCE_H
#define TYPE_COERCE_H
/**
* Structs for conversion between types,
* part of the TinyFrame utilities collection
*
* (c) Ondřej Hruška, 2016-2017. MIT license.
*
* This is a support header file for PayloadParser and PayloadBuilder.
*/
#include <stdint.h>
#include <stddef.h>
union conv8 {
uint8_t u8;
int8_t i8;
};
union conv16 {
uint16_t u16;
int16_t i16;
};
union conv32 {
uint32_t u32;
int32_t i32;
float f32;
};
#endif // TYPE_COERCE_H