Эх сурвалжийг харах

Light printf() and scanf()

Vladimir N. Shilov 9 жил өмнө
parent
commit
c8cb99abf2

+ 514 - 0
rprintf/printf_.c

@@ -0,0 +1,514 @@
+/** \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 <stdarg.h>     // (...) parameter handling
+#include <stdlib.h>     //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:<br>
+ * <pre>
+ * 12345     filename.c[123]: format string
+ * ^    ^    ^          ^
+ * |    |    |          line number
+ * |    |    +--------- file name
+ * |    +-------------- tab character
+ * +------------------- timestamp (ms since reset)
+ * </pre>
+ *
+ * */
+//#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
+******************************************************************************/

+ 27 - 0
rprintf/printf_.h

@@ -0,0 +1,27 @@
+/*
+ * printf.h
+ *
+ *  Created on: 08-02-2013
+ *      Author: andy
+ * http://www.skybeeper.com/index.php/en/english-en/25-tighten-scanf
+ */
+
+#ifndef PRINTF_H_
+#define PRINTF_H_
+//public function
+int printf_(const char *format, ...);
+int sprintf_(char *buffer, const char *format, ...);
+int rscanf(const char* format, ...);
+#endif /* PRINTF_H_ */
+
+/*
++=============================================================================+
+| options
++=============================================================================+
+*/
+//#define INCLUDE_FLOAT  // this enables float in printf() and costs you about 2kByte ROM
+//#define USE_DEBUG      // this enables a Macro based on printf()
+#define PLL_FREQUENCY			24000000ul	///< desired target frequency of the core
+#define UART1_BAUDRATE  		9600
+
+

+ 1 - 0
rprintf/urls.txt

@@ -0,0 +1 @@
+http://www.skybeeper.com/index.php/en/english-en/25-tighten-scanf

+ 50 - 0
rprintf/usart1.c

@@ -0,0 +1,50 @@
+/*
+ * usart.c
+ * http://www.skybeeper.com/index.php/en/english-en/25-tighten-scanf
+ */
+#include "usart1.h"
+
+/*
++=============================================================================+
+/file usart1.c
++=============================================================================+
+*/
+/*
+ * how to count BRR
+ * BRR = P_frequency /(16*baudrate)
+ * for example:
+ * 24 000 000/(16*9600)= 156,25
+ * 156 dec = 0x9C
+ * 0,25*16 = 4dec = 0x4 hex
+ * BRR = 0x009C+0x0004 = 0x09C4
+ *
+ * this way of counting BRR is equal and gives results directly in hex
+ * BRR  = (PLL_FREQUENCY+UART1_BAUDRATE/2)/UART1_BAUDRATE;
+ */
+
+void Usart1Init(void){
+
+	RCC->APB2ENR |= (RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN);  //Clock
+	AFIO->MAPR &= ~(AFIO_MAPR_USART1_REMAP);		//UART1 at the original pins
+	GPIOA->CRH  = 0x0090;  							//GPIO_CRH_BIT9 = Alternate function, 10MHz
+    USART1->BRR  = (PLL_FREQUENCY+UART1_BAUDRATE/2)/UART1_BAUDRATE;
+	             //0x008B;  Baud=FREQUENCY/(16*8,69)=115107;	// BRR simplified thanks to Uwe Hermann
+    USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);  // RX, TX enable
+}
+
+
+
+void Usart1Put(char ch)
+{
+	USART_SendData(USART1, (char) ch);
+
+  	while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
+	{
+	}
+}
+
+char Usart1Get(void){
+
+	while ( USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
+	return (char)USART_ReceiveData(USART1);
+}

+ 19 - 0
rprintf/usart1.h

@@ -0,0 +1,19 @@
+/*
+ * usart.h
+ * http://www.skybeeper.com/index.php/en/english-en/25-tighten-scanf
+ */
+
+#ifndef USART1_H_
+#define USART1_H_
+#include "STM32f10x.h"
+
+//device and usart parameters
+#define PLL_FREQUENCY			24000000ul	///< desired target frequency of the core
+#define UART1_BAUDRATE  		9600
+
+void Usart1Init(void);
+void Usart1Put(char ch);
+char Usart1Get(void);
+
+
+#endif /* USART1_H_ */