/** \file printf.c * Simplified printf() and sprintf() implementation - prints formatted string to * USART (or whereever). Most common % specifiers are supported. It costs you about * 3k FLASH memory - without floating point support it uses only 1k ROM! * \author Freddie Chopin, Martin Thomas, Marten Petschke and many others * \date 16.2.2012 * reduced scanf() added by Andrzej Dworzynski on the base of reduced sscanf() written by * some nice gay from this post: http://www.fpgarelated.com/usenet/fpga/show/61760-1.php * thanks to everybody:) * \date 12.2.2013 * http://www.skybeeper.com/index.php/en/english-en/25-tighten-scanf */ /****************************************************************************** * chip: STM32F10x * compiler: arm-none-eabi-gcc 4.6.0 * * global functions: * int printf_(const char *format, ...) * int sprintf_(char *buffer, const char *format, ...) * int rscanf(const char* format, ...) * * STM32 specific functions: * Usart1Init(void) * void Usart1Put(char); // blocking put char, used by printf() * char Usart1Get(void); //used by rscanf() * set up scanf buffer by changing scanf_buff_size variable * local functions: * int putc_strg(int character, printf_file_t *stream) * int vfprintf_(printf_file_t *stream, const char *format, va_list arg) * void long_itoa (long val, int radix, int len, vfprintf_stream *stream) * static int rsscanf(const char* str, const char* format, va_list ap) ******************************************************************************/ /* +=============================================================================+ | includes +=============================================================================+ */ #include // (...) parameter handling #include //NULL pointer definition #include "stm32f10x.h" // only this headerfile is used #include "printf.h" #include "usart1.h" #define assert_param(expr) ((void)0) /*dummy to make the stm32 header work*/ /* +=============================================================================+ | global declarations +=============================================================================+ */ //in file printf.h /* +=============================================================================+ | local declarations +=============================================================================+ */ static void putc_strg(char); // the put() function for sprintf() char *SPRINTF_buffer; int scanf_buff_size = 12; //chang this if needed static int vfprintf_(void (*) (char), const char *format, va_list arg); //generic print static void long_itoa (long, int, int, void (*) (char)); //heavily used by printf static int rsscanf(const char* str, const char* format, va_list ap);//used by rscanf /* +=============================================================================+ | sample main() file +=============================================================================+ */ /* int main(void) { char my_buff[12]; int i; Usart1Init(); printf_(" USART1 Test\r\n"); printf_("Enter your family name: "); rscanf ("%s",my_buff); printf_("%s\r\n",my_buff); printf_("Enter your age: "); rscanf ("%d",&i); printf_("%d\r\n",i); printf_("Mr. %s, %d years old.\r\n",my_buff,i); printf_ ("Enter a hexadecimal number:\r\n"); rscanf("%x",&i); printf_("You have entered %x (%d).\r\n",i,i); while(1); return 0; } */ /* +=============================================================================+ | global functions +=============================================================================+ */ int printf_(const char *format, ...) { va_list arg; va_start(arg, format); vfprintf_((&Usart1Put), format, arg); va_end(arg); return 0; } int sprintf_(char *buffer, const char *format, ...) { va_list arg; SPRINTF_buffer=buffer; //Pointer auf einen String in Speicherzelle abspeichern va_start(arg, format); vfprintf_((&putc_strg), format, arg); va_end(arg); *SPRINTF_buffer ='\0'; // append end of string return 0; } //Reads data from usart1 and stores them according to parameter format //into the locations given by the additional arguments, as if // scanf was used // Reduced version of scanf (%d, %x, %c, %n are supported) // %d dec integer (E.g.: 12) // %x hex integer (E.g.: 0xa0) // %b bin integer (E.g.: b1010100010) // %n hex, de or bin integer (e.g: 12, 0xa0, b1010100010) // %c any character //buffer support 12 bytes int rscanf(const char* format, ...){ va_list args; va_start( args, format ); int count = 0; char ch = 0; char buffer[scanf_buff_size]; SPRINTF_buffer = buffer; while(count =< scanf_buff_size )//get string { count++; ch = Usart1Get(); if(ch != '\n' && ch != '\r') *SPRINTF_buffer++ = ch; else break; } *SPRINTF_buffer = '\0';//end of string SPRINTF_buffer = buffer; count = rsscanf(SPRINTF_buffer, format, args); va_end(args); return count; } /** * @def debug(format...) * @brief prints the timestamp, file name, line number, printf-formated @a format string and the * optional parameters to stdout * * The output looks like this:
*
 * 12345     filename.c[123]: format string
 * ^    ^    ^          ^
 * |    |    |          line number
 * |    |    +--------- file name
 * |    +-------------- tab character
 * +------------------- timestamp (ms since reset)
 * 
* * */ //#define USE_DEBUG #ifdef USE_DEBUG #define debug(format,...) {\ printf_("%ul\t%s[%i]: ", millisec, __FILE__, __LINE__); /* print file name and line number */\ printf_(format, ## __VA_ARGS__); /* print format string and args */\ printf_("\n"); \ } #else #define debug(format,...) ((void)0) #endif /* USE_DEBUG */ /* +=============================================================================+ | local functions +=============================================================================+ */ // putc_strg() is the putc()function for sprintf_() static void putc_strg(char character) { *SPRINTF_buffer = (char)character; // just add the character to buffer SPRINTF_buffer++; } /*--------------------------------------------------------------------------------+ * vfprintf_() * Prints a string to stream. Supports %s, %c, %d, %ld %ul %02d %i %x %lud and %% * - partly supported: long long, float (%l %f, %F, %2.2f) * - not supported: double float and exponent (%e %g %p %o \t) *--------------------------------------------------------------------------------+ */ static int vfprintf_(void (*putc)(char), const char* str, va_list arp) { int d, r, w, s, l; //d=char, r = radix, w = width, s=zeros, l=long char *c; // for the while loop only //const char* p; #ifdef INCLUDE_FLOAT float f; long int m, w2; #endif while ((d = *str++) != 0) { if (d != '%') {//if it is not format qualifier (*putc)(d); continue;//get out of while loop } d = *str++;//if it is '%'get next char w = r = s = l = 0; if (d == '%') {//if it is % print silmpy % (*putc)(d); d = *str++; } if (d == '0') { d = *str++; s = 1; //padd with zeros } while ((d >= '0')&&(d <= '9')) { w += w * 10 + (d - '0'); d = *str++; } if (s) w = -w; //padd with zeros if negative #ifdef INCLUDE_FLOAT w2 = 0; if (d == '.') d = *str++; while ((d >= '0')&&(d <= '9')) { w2 += w2 * 10 + (d - '0'); d = *str++; } #endif if (d == 's') {// if string c = va_arg(arp, char*); //get buffer addres //p = c;//debug while (*c) (*putc)(*(c++));//write the buffer out continue; } //debug //while(*p) Usart1Put(*p++); if (d == 'c') { (*putc)((char)va_arg(arp, int)); continue; } if (d == 'u') { // %ul r = 10; d = *str++; } if (d == 'l') { // long =32bit l = 1; if (r==0) r = -10; d = *str++; } // if (!d) break; if (d == 'u') r = 10;// %lu, %llu else if (d == 'd' || d == 'i') {if (r==0) r = -10;} //can be 16 or 32bit int else if (d == 'X' || d == 'x') r = 16; // 'x' added by mthomas else if (d == 'b') r = 2; else str--; // normal character #ifdef INCLUDE_FLOAT if (d == 'f' || d == 'F') { f=va_arg(arp, double); if (f>0) { r=10; m=(int)f; } else { r=-10; f=-f; m=(int)(f); } long_itoa(m, r, w, (putc)); f=f-m; m=f*(10^w2); w2=-w2; long_itoa(m, r, w2, (putc)); l=3; //do not continue with long } #endif if (!r) continue; // if (l==0) { if (r > 0){ //unsigned long_itoa((unsigned long)va_arg(arp, int), r, w, (putc)); //needed for 16bit int, no harm to 32bit int } else //signed long_itoa((long)va_arg(arp, int), r, w, (putc)); } else if (l==1){ // long =32bit long_itoa((long)va_arg(arp, long), r, w, (putc)); //no matter if signed or unsigned } } return 0; } static void long_itoa (long val, int radix, int len, void (*putc) (char)) { char c, sgn = 0, pad = ' '; char s[20]; int i = 0; if (radix < 0) { radix = -radix; if (val < 0) { val = -val; sgn = '-'; } } if (len < 0) { len = -len; pad = '0'; } if (len > 20) return; do { c = (char)((unsigned long)val % radix); //cast! if (c >= 10) c += ('A'-10); //ABCDEF else c += '0'; //0123456789 s[i++] = c; val = (unsigned long)val /radix; //cast! } while (val); if (sgn) s[i++] = sgn; while (i < len) s[i++] = pad; do (*putc)(s[--i]); while (i); } // // Reduced version of sscanf (%d, %x, %c, %n are supported) // %d dec integer (E.g.: 12) // %x hex integer (E.g.: 0xa0) // %b bin integer (E.g.: b1010100010) // %n hex, de or bin integer (e.g: 12, 0xa0, b1010100010) // %c any character // static int rsscanf(const char* str, const char* format, va_list ap) { //va_list ap; int value, tmp; int count; int pos; char neg, fmt_code; const char* pf; char* sval; //va_start(ap, format); for (pf = format, count = 0; *format != 0 && *str != 0; format++, str++) { while (*format == ' ' && *format != 0) format++;// if (*format == 0) break; while (*str == ' ' && *str != 0) str++;//increment pointer of input string if (*str == 0) break; if (*format == '%')//recognize how to format { format++; if (*format == 'n') { if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))//if in str sth like 0xff { fmt_code = 'x'; str += 2; } else if (str[0] == 'b') { fmt_code = 'b'; str++; } else fmt_code = 'd'; } else fmt_code = *format; //it is format letter switch (fmt_code) { case 'x': case 'X': for (value = 0, pos = 0; *str != 0; str++, pos++) { if ('0' <= *str && *str <= '9') tmp = *str - '0'; else if ('a' <= *str && *str <= 'f') tmp = *str - 'a' + 10; else if ('A' <= *str && *str <= 'F') tmp = *str - 'A' + 10; else break; value *= 16; value += tmp; } if (pos == 0) return count; *(va_arg(ap, int*)) = value; count++; break; case 'b': for (value = 0, pos = 0; *str != 0; str++, pos++) { if (*str != '0' && *str != '1') break; value *= 2; value += *str - '0'; } if (pos == 0) return count; *(va_arg(ap, int*)) = value; count++; break; case 'd': if (*str == '-') { neg = 1; str++; } else neg = 0; for (value = 0, pos = 0; *str != 0; str++, pos++) { if ('0' <= *str && *str <= '9') value = value*10 + (int)(*str - '0'); else break; } if (pos == 0) return count; *(va_arg(ap, int*)) = neg ? -value : value; count++; break; case 'c': *(va_arg(ap, char*)) = *str; count++; break; case 's': sval = va_arg(ap, char*); while(*str){ *sval++ = *str++; count++; } *sval = NULL; break; default: return count; } } else { if (*format != *str)// break; } } return count; } /****************************************************************************** * END OF FILE ******************************************************************************/