mirror of
https://github.com/thelsing/knx.git
synced 2025-11-07 01:20:20 +01:00
git-subtree-dir: examples/knx-cc1310/coresdk_cc13xx_cc26xx git-subtree-split: 0d78d3280357416a5c0388148cda13717c9ffaa5
417 lines
12 KiB
C
417 lines
12 KiB
C
/*
|
|
* Copyright (c) 2016-2017, Texas Instruments Incorporated
|
|
* 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 Texas Instruments Incorporated 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 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.
|
|
*/
|
|
/*
|
|
* ======== SystemP_nortos.c ========
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <ti/drivers/dpl/SystemP.h>
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Constants and macros
|
|
* -----------------------------------------------------------------------------
|
|
*/
|
|
#ifndef MIN
|
|
# define MIN(n, m) (((n) > (m)) ? (m) : (n))
|
|
#endif
|
|
|
|
/*
|
|
* ======== OUTMAX ========
|
|
* The maximum length of the output of a base 8 number produced by formatNum
|
|
* plus 5 to accomodate the decimal point and 4 digits after the decimal
|
|
* point.
|
|
*/
|
|
#define OUTMAX ((32 + 2) / 3 + 5)
|
|
#define PTRZPAD 8
|
|
#define MAXARGS 5
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
* Type definitions
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
/* ParseData */
|
|
typedef struct ParseData {
|
|
int width;
|
|
bool lFlag;
|
|
bool lJust;
|
|
int precis;
|
|
int len;
|
|
int zpad;
|
|
char *end;
|
|
char *ptr;
|
|
} ParseData;
|
|
|
|
/*
|
|
* Maximum sized (un)signed integer that we'll format.
|
|
*/
|
|
typedef uint32_t UIntMax;
|
|
typedef int32_t IntMax;
|
|
|
|
static int doPrint(char *buf, size_t n, const char *fmt, va_list va);
|
|
static char *formatNum(char *ptr, UIntMax un, int zpad, int base);
|
|
static void putChar(char **bufp, char c, size_t *n);
|
|
|
|
/*
|
|
* ======== SystemP_snprintf ========
|
|
*/
|
|
int SystemP_snprintf(char *buf, size_t n, const char *format,...)
|
|
{
|
|
va_list args;
|
|
int ret;
|
|
|
|
va_start(args, format);
|
|
ret = doPrint(buf, n, format, args);
|
|
va_end(args);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* ======== SystemP_snprintf_va ========
|
|
*/
|
|
int SystemP_vsnprintf(char *buf, size_t n, const char *format,
|
|
va_list va)
|
|
{
|
|
int ret;
|
|
|
|
ret = doPrint(buf, n, format, va);
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* ======== doPrint ========
|
|
*/
|
|
static int doPrint(char *buf, size_t n, const char *fmt, va_list va)
|
|
{
|
|
ParseData parse;
|
|
int base;
|
|
char c;
|
|
int res = 0;
|
|
char outbuf[OUTMAX];
|
|
|
|
if (fmt == (char *)NULL) {
|
|
return (res);
|
|
}
|
|
|
|
while ((c = *fmt++) != '\0') {
|
|
if (c != '%') {
|
|
putChar(&buf, c, &n);
|
|
res++;
|
|
}
|
|
else {
|
|
c = *fmt++;
|
|
/* check for - flag (pad on right) */
|
|
if (c == '-') {
|
|
parse.lJust = true;
|
|
c = *fmt++;
|
|
}
|
|
else {
|
|
parse.lJust = false;
|
|
}
|
|
/* check for leading 0 pad */
|
|
if (c == '0') {
|
|
parse.zpad = 1;
|
|
c = *fmt++;
|
|
}
|
|
else {
|
|
parse.zpad = 0;
|
|
}
|
|
|
|
/* allow optional field width/precision specification */
|
|
parse.width = 0;
|
|
parse.precis = -1;
|
|
|
|
/* note: dont use isdigit (very large for C30) */
|
|
if (c == '*') {
|
|
/* Width is specified in argument, not in format string */
|
|
parse.width = (int)va_arg(va, int);
|
|
|
|
c = *fmt++;
|
|
if (parse.width < 0) {
|
|
parse.lJust = true;
|
|
parse.width = -parse.width;
|
|
}
|
|
}
|
|
else {
|
|
while (c >= '0' && c <= '9') {
|
|
parse.width = parse.width * 10 + c - '0';
|
|
c = *fmt++;
|
|
}
|
|
}
|
|
|
|
/* allow optional field precision specification */
|
|
if (c == '.') {
|
|
parse.precis = 0;
|
|
c = *fmt++;
|
|
if (c == '*') {
|
|
/* Width specified in argument, not in format string */
|
|
parse.precis = (int)va_arg(va, int);
|
|
|
|
if (parse.precis < 0) {
|
|
parse.precis = 0;
|
|
}
|
|
c = *fmt++;
|
|
}
|
|
else {
|
|
while (c >= '0' && c <= '9') {
|
|
parse.precis = parse.precis * 10 + c - '0';
|
|
c = *fmt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* setup for leading zero padding */
|
|
if (parse.zpad) {
|
|
parse.zpad = parse.width;
|
|
}
|
|
|
|
/* check for presence of l flag (e.g., %ld) */
|
|
if (c == 'l' || c == 'L') {
|
|
parse.lFlag = true;
|
|
c = *fmt++;
|
|
}
|
|
else {
|
|
parse.lFlag = false;
|
|
}
|
|
|
|
parse.ptr = outbuf;
|
|
parse.end = outbuf + OUTMAX;
|
|
parse.len = 0;
|
|
|
|
if (c == 'd' || c == 'i') {
|
|
/* signed decimal */
|
|
IntMax val = (IntMax)va_arg(va, int32_t);
|
|
|
|
if (parse.precis > parse.zpad) {
|
|
parse.zpad = parse.precis;
|
|
}
|
|
parse.ptr = formatNum(parse.end, val, parse.zpad, -10);
|
|
parse.len = parse.end - parse.ptr;
|
|
}
|
|
/* use comma operator to optimize code generation! */
|
|
else if (((base = 10), (c == 'u')) || /* unsigned decimal */
|
|
((base = 16), (c == 'x')) || /* unsigned hex */
|
|
((base = 8), (c == 'o'))) { /* unsigned octal */
|
|
|
|
UIntMax val = (UIntMax)va_arg(va, uint32_t);
|
|
|
|
if (parse.precis > parse.zpad) {
|
|
parse.zpad = parse.precis;
|
|
}
|
|
parse.ptr = formatNum(parse.end, val, parse.zpad, base);
|
|
parse.len = parse.end - parse.ptr;
|
|
}
|
|
else if ((base = 16), (c == 'p')) {
|
|
parse.zpad = PTRZPAD; /* ptrs are 0 padded */
|
|
parse.ptr = formatNum(
|
|
parse.end,
|
|
(UIntMax)va_arg(va, uint32_t),
|
|
parse.zpad, base);
|
|
*(--parse.ptr) = '@';
|
|
parse.len = parse.end - parse.ptr;
|
|
}
|
|
else if (c == 'c') {
|
|
/* character */
|
|
*parse.ptr = (char)va_arg(va, int);
|
|
parse.len = 1;
|
|
}
|
|
else if (c == 's') {
|
|
/* string */
|
|
parse.ptr = (char *)va_arg(va, void *);
|
|
|
|
/* substitute (null) for NULL pointer */
|
|
if (parse.ptr == (char *)NULL) {
|
|
parse.ptr = "(null)";
|
|
}
|
|
parse.len = strlen(parse.ptr);
|
|
if (parse.precis != -1 && parse.precis < parse.len) {
|
|
parse.len = parse.precis;
|
|
}
|
|
}
|
|
else if (c == 'f') {
|
|
double d, tmp;
|
|
bool negative = false;
|
|
uint32_t fract;
|
|
|
|
d = va_arg(va, double);
|
|
|
|
if (d < 0.0) {
|
|
d = -d;
|
|
negative = true;
|
|
parse.zpad--;
|
|
}
|
|
|
|
/*
|
|
* Assumes four digits after decimal point. We are using a
|
|
* temporary double variable to force double-precision
|
|
* computations without using --fp_mode=strict flag.
|
|
* See the description of that flag in the compiler's doc
|
|
* for a further explanation.
|
|
*/
|
|
tmp = (d - (int32_t)d) * 1e4;
|
|
fract = (uint32_t)tmp;
|
|
|
|
parse.ptr = formatNum(parse.end, fract, 4, 10);
|
|
*(--parse.ptr) = '.';
|
|
|
|
parse.len = parse.end - parse.ptr;
|
|
/* format integer part (right to left!) */
|
|
parse.ptr = formatNum(parse.ptr, (int32_t)d,
|
|
parse.zpad - parse.len, 10);
|
|
if (negative) {
|
|
*(--parse.ptr) = '-';
|
|
}
|
|
|
|
parse.len = parse.end - parse.ptr;
|
|
}
|
|
else {
|
|
putChar(&buf, c, &n);
|
|
res++;
|
|
continue;
|
|
}
|
|
|
|
/* compute number of characters left in field */
|
|
parse.width -= parse.len;
|
|
|
|
if (!parse.lJust) {
|
|
/* pad with blanks on left */
|
|
while (--parse.width >= 0) {
|
|
putChar(&buf, ' ', &n);
|
|
res++;
|
|
}
|
|
}
|
|
|
|
/* output number, character or string */
|
|
while (parse.len--) {
|
|
putChar(&buf, *parse.ptr++, &n);
|
|
res++;
|
|
}
|
|
/* pad with blanks on right */
|
|
if (parse.lJust) {
|
|
while (--parse.width >= 0) {
|
|
putChar(&buf, ' ', &n);
|
|
res++;
|
|
}
|
|
}
|
|
} /* if */
|
|
} /* while */
|
|
|
|
if (buf) {
|
|
*buf = '\0';
|
|
}
|
|
|
|
return (res);
|
|
}
|
|
|
|
|
|
/*
|
|
* ======== formatNum ========
|
|
* Internal function
|
|
*
|
|
* Format unsigned long number in specified base, returning pointer to
|
|
* converted output.
|
|
*
|
|
* Note: ptr points PAST end of the buffer, and is decremented as digits
|
|
* are converted from right to left!
|
|
*
|
|
* Note: base is negative if n is signed else n unsigned!
|
|
*
|
|
* ptr - Pointer to the end of the working buffer where the string version
|
|
* of the number will be placed.
|
|
* un - The unsigned number to be formated
|
|
* base - The base to format the number into. TODO - signed?
|
|
*/
|
|
static char *formatNum(char *ptr, UIntMax un, int zpad, int base)
|
|
{
|
|
int i = 0;
|
|
char sign = 0;
|
|
|
|
UIntMax n;
|
|
n = un;
|
|
|
|
if (base < 0) {
|
|
/* handle signed long case */
|
|
base = -base;
|
|
if ((IntMax)n < 0) {
|
|
n = -(IntMax)n;
|
|
|
|
/* account for sign '-': ok since zpad is signed */
|
|
--zpad;
|
|
sign = '-';
|
|
}
|
|
}
|
|
|
|
/* compute digits in number from right to left */
|
|
do {
|
|
*(--ptr) = "0123456789abcdef"[(int)(n % base)];
|
|
n = n / base;
|
|
++i;
|
|
} while (n);
|
|
|
|
/* pad with leading 0s on left */
|
|
while (i < zpad) {
|
|
*(--ptr) = '0';
|
|
++i;
|
|
}
|
|
|
|
/* add sign indicator */
|
|
if (sign) {
|
|
*(--ptr) = sign;
|
|
}
|
|
return (ptr);
|
|
}
|
|
|
|
/*
|
|
* ======== putChar ========
|
|
* Write character `c` to the buffer and the buffer pointer.
|
|
*
|
|
* Keeps track of the number of characters written into the buffer by
|
|
* modifying bufsize `n`. Atmost, `n` - 1 characters are written.
|
|
*/
|
|
static void putChar(char **bufp, char c, size_t *n)
|
|
{
|
|
/* if the size == 1, don't write so we can '\0' terminate buffer */
|
|
if ((*n) <= 1) {
|
|
return;
|
|
}
|
|
|
|
/* decrement n to keep track of the number of chars written */
|
|
(*n)--;
|
|
*((*bufp)++) = c;
|
|
}
|