You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
6.1 KiB

/*
* printf.c
*
* Created on: Dec 7, 2017
* Author: maximilian
*/
//--------------Includes-----------------
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "stm32f10x.h"
#include "helpers.h"
#include "printf.h"
#include "../platform/usart.h"
#include "ossettings.h"
#include "error.h"
/** Increment index for a char buffer savely, preventing overflows.
*
* @param ioindex Index, that is supposed to be manipulated.
* @param ibuffsize Buffer size, which should not be exceeded.
* @retval 1 (SUCCESS) or 0 (FAILURE).
*/
static inline uint8_t osPreventBuffOv(uint* ioindex, size_t ibuffsize)
{
if(*ioindex < ibuffsize)
(*ioindex)++;
else
{
THROW_ERROR(E_BUFFER_OVERFLOW);
return 0;
}
return 1;
}
/** Parsing for floats within printf.
*
* @param iobuffer Buffer where the formated string ends up.
* @param ibuffsize Size of the iobuffer for security reasons.
* @param iformat Pointer to the format string from the user.
* @param i Pointer to the index where to write in the iobuffer.
* @param ifloat Float which shall be printed nicely.
* @param iflag Indicator if the user wants a certain amount of decimals.
* @retval Characters printed (SUCCESS) or -1 (FAILURE).
*/
static uint8_t osParseFloat(char* iobuffer, size_t ibuffsize, const char** iformat, uint* i, double ifloat, uint8_t iflag)
{
int temp_int;
size_t temp_buffsize;
char temp_string[16];
int float_decimals;
/* Get the pre-decimal positions through implicit casting. */
temp_int = ifloat;
if(!osItoa(temp_int, temp_string, sizeof(temp_string)/sizeof(char), &temp_buffsize))
return 0;
/* Concatenate. */
for(uint j=0; j < temp_buffsize; j++)
{
iobuffer[*i] = temp_string[j];
if(!osPreventBuffOv(i, ibuffsize))
return 0;
}
if(!iflag)
float_decimals = 4;
else
{
/* Determine how many decimals shall be printed. */
(*iformat)++;
float_decimals = **iformat;
/* Go from ASCII to int. */
float_decimals -= 48;
}
/* Print a comma. */
iobuffer[*i] = ',';
osPreventBuffOv(i, ibuffsize);
/* Amplify to prepare for int. data conv. */
ifloat *= (float)osPowInt(10, float_decimals);
temp_int = ifloat;
/* Get rid of everything before the comma. */
temp_int %= osPowInt(10, float_decimals);
if(!osItoa(temp_int, temp_string, sizeof(temp_string)/sizeof(char), &temp_buffsize))
return 0;
/* Concatenate. */
for(uint j=0; j < temp_buffsize; j++)
{
iobuffer[*i] = temp_string[j];
if(!osPreventBuffOv(i, ibuffsize))
return 0;
}
/* Get rid of the f. */
if(iflag)
(*iformat)++;
return 1;
}
/** printf implementation where the magic happens.
*
* @param iarguments Variable arguments list.
* @param iobuffer Buffer where the formated string ends up.
* @param ibuffsize Size of the iobuffer for security reasons.
* @param iformat Format string from the user.
* @retval Characters printed (SUCCESS) or -1 (FAILURE).
*/
static int osVPrintf(va_list iarguments, char* iobuffer, size_t ibuffsize, const char* iformat)
{
uint i = 0;
int temp_int;
char temp_char;
char* temp_charptr;
size_t temp_buffsize;
char temp_string[16];
/* Keep processing until the end of the C string. */
while(*iformat != '\0')
{
/* Do formating magic here. */
if(*iformat == '%')
{
iformat++;
switch(*iformat)
{
case 'd':
/* Get int and convert it.*/
temp_int = va_arg(iarguments, int);
if(!osItoa(temp_int, temp_string, sizeof(temp_string)/sizeof(char), &temp_buffsize))
return -1;
/* Concatenate. */
for(uint j=0; j < temp_buffsize; j++)
{
iobuffer[i] = temp_string[j];
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
}
break;
case 's':
temp_charptr = va_arg(iarguments, char*);
while(*temp_charptr != '\0')
{
/* If you are too lazy to always type \r\n */
#ifdef CONVERT_NEWLINE
if( (*temp_charptr) == '\n' )
{
/* Copy \n */
iobuffer[i] = *temp_charptr;
temp_charptr++;
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
/* Add \r */
iobuffer[i] = '\r';
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
}
else
{
iobuffer[i] = *temp_charptr;
temp_charptr++;
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
}
#else
iobuffer[i] = *temp_charptr;
temp_charptr++;
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
#endif
}
break;
case 'c':
/* Get char and convert it.*/
temp_char = va_arg(iarguments, int);
iobuffer[i] = temp_char;
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
break;
case '%':
/* Enable possibility to write %% to write a single %.*/
iobuffer[i] = '%';
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
break;
case '.':
if(!osParseFloat(iobuffer, ibuffsize, &iformat, &i, va_arg(iarguments, double), 1))
return -1;
break;
case 'f':
if(!osParseFloat(iobuffer, ibuffsize, &iformat, &i, va_arg(iarguments, double), 0))
return -1;
break;
default:
THROW_ERROR(E_WRONG_USAGE_OF_PRINTF);
return 0;
}
/* Skip control specifier. */
iformat++;
}
else
{
/* If you are too lazy to always type \r\n */
#ifdef CONVERT_NEWLINE
if( (*iformat) == '\n' )
{
/* Copy \n */
iobuffer[i] = *iformat;
iformat++;
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
/* Add \r */
iobuffer[i] = '\r';
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
}
#endif
/* Copy characters into buffer. */
iobuffer[i] = *iformat;
iformat++;
if(!osPreventBuffOv(&i, ibuffsize))
return -1;
}
}
iobuffer[i] = '\0';
/* Return number of elements in the buffer. */
return (i+1);
}
int osPrintf(const char* iformat, ...)
{
va_list arguments;
char buffer[STD_STRING_BUFFER_SIZE];
int return_val;
va_start(arguments, iformat);
return_val = osVPrintf(arguments, buffer, sizeof(buffer), iformat);
if(return_val)
{
/* Return value is the size of the created string in the buffer. */
usart2PutString((uint8_t*)buffer, return_val);
}
else
{
THROW_ERROR(E_PRINTF_WENT_WRONG);
return -1;
}
va_end(arguments);
return return_val;
}