printf_.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /** \file printf.c
  2. * Simplified printf() and sprintf() implementation - prints formatted string to
  3. * USART (or whereever). Most common % specifiers are supported. It costs you about
  4. * 3k FLASH memory - without floating point support it uses only 1k ROM!
  5. * \author Freddie Chopin, Martin Thomas, Marten Petschke and many others
  6. * \date 16.2.2012
  7. * reduced scanf() added by Andrzej Dworzynski on the base of reduced sscanf() written by
  8. * some nice gay from this post: http://www.fpgarelated.com/usenet/fpga/show/61760-1.php
  9. * thanks to everybody:)
  10. * \date 12.2.2013
  11. * http://www.skybeeper.com/index.php/en/english-en/25-tighten-scanf
  12. */
  13. /******************************************************************************
  14. * chip: STM32F10x
  15. * compiler: arm-none-eabi-gcc 4.6.0
  16. *
  17. * global functions:
  18. * int printf_(const char *format, ...)
  19. * int sprintf_(char *buffer, const char *format, ...)
  20. * int rscanf(const char* format, ...)
  21. *
  22. * STM32 specific functions:
  23. * Usart1Init(void)
  24. * void Usart1Put(char); // blocking put char, used by printf()
  25. * char Usart1Get(void); //used by rscanf()
  26. * set up scanf buffer by changing scanf_buff_size variable
  27. * local functions:
  28. * int putc_strg(int character, printf_file_t *stream)
  29. * int vfprintf_(printf_file_t *stream, const char *format, va_list arg)
  30. * void long_itoa (long val, int radix, int len, vfprintf_stream *stream)
  31. * static int rsscanf(const char* str, const char* format, va_list ap)
  32. ******************************************************************************/
  33. /*
  34. +=============================================================================+
  35. | includes
  36. +=============================================================================+
  37. */
  38. #include <stdarg.h> // (...) parameter handling
  39. #include <stdlib.h> //NULL pointer definition
  40. #include "stm32f10x.h" // only this headerfile is used
  41. #include "printf.h"
  42. #include "usart1.h"
  43. #define assert_param(expr) ((void)0) /*dummy to make the stm32 header work*/
  44. /*
  45. +=============================================================================+
  46. | global declarations
  47. +=============================================================================+
  48. */
  49. //in file printf.h
  50. /*
  51. +=============================================================================+
  52. | local declarations
  53. +=============================================================================+
  54. */
  55. static void putc_strg(char); // the put() function for sprintf()
  56. char *SPRINTF_buffer;
  57. int scanf_buff_size = 12; //chang this if needed
  58. static int vfprintf_(void (*) (char), const char *format, va_list arg); //generic print
  59. static void long_itoa (long, int, int, void (*) (char)); //heavily used by printf
  60. static int rsscanf(const char* str, const char* format, va_list ap);//used by rscanf
  61. /*
  62. +=============================================================================+
  63. | sample main() file
  64. +=============================================================================+
  65. */
  66. /*
  67. int main(void)
  68. {
  69. char my_buff[12];
  70. int i;
  71. Usart1Init();
  72. printf_(" USART1 Test\r\n");
  73. printf_("Enter your family name: ");
  74. rscanf ("%s",my_buff);
  75. printf_("%s\r\n",my_buff);
  76. printf_("Enter your age: ");
  77. rscanf ("%d",&i);
  78. printf_("%d\r\n",i);
  79. printf_("Mr. %s, %d years old.\r\n",my_buff,i);
  80. printf_ ("Enter a hexadecimal number:\r\n");
  81. rscanf("%x",&i);
  82. printf_("You have entered %x (%d).\r\n",i,i);
  83. while(1);
  84. return 0;
  85. }
  86. */
  87. /*
  88. +=============================================================================+
  89. | global functions
  90. +=============================================================================+
  91. */
  92. int printf_(const char *format, ...)
  93. {
  94. va_list arg;
  95. va_start(arg, format);
  96. vfprintf_((&Usart1Put), format, arg);
  97. va_end(arg);
  98. return 0;
  99. }
  100. int sprintf_(char *buffer, const char *format, ...)
  101. {
  102. va_list arg;
  103. SPRINTF_buffer=buffer; //Pointer auf einen String in Speicherzelle abspeichern
  104. va_start(arg, format);
  105. vfprintf_((&putc_strg), format, arg);
  106. va_end(arg);
  107. *SPRINTF_buffer ='\0'; // append end of string
  108. return 0;
  109. }
  110. //Reads data from usart1 and stores them according to parameter format
  111. //into the locations given by the additional arguments, as if
  112. // scanf was used
  113. // Reduced version of scanf (%d, %x, %c, %n are supported)
  114. // %d dec integer (E.g.: 12)
  115. // %x hex integer (E.g.: 0xa0)
  116. // %b bin integer (E.g.: b1010100010)
  117. // %n hex, de or bin integer (e.g: 12, 0xa0, b1010100010)
  118. // %c any character
  119. //buffer support 12 bytes
  120. int rscanf(const char* format, ...){
  121. va_list args;
  122. va_start( args, format );
  123. int count = 0;
  124. char ch = 0;
  125. char buffer[scanf_buff_size];
  126. SPRINTF_buffer = buffer;
  127. while(count =< scanf_buff_size )//get string
  128. {
  129. count++;
  130. ch = Usart1Get();
  131. if(ch != '\n' && ch != '\r') *SPRINTF_buffer++ = ch;
  132. else
  133. break;
  134. }
  135. *SPRINTF_buffer = '\0';//end of string
  136. SPRINTF_buffer = buffer;
  137. count = rsscanf(SPRINTF_buffer, format, args);
  138. va_end(args);
  139. return count;
  140. }
  141. /**
  142. * @def debug(format...)
  143. * @brief prints the timestamp, file name, line number, printf-formated @a format string and the
  144. * optional parameters to stdout
  145. *
  146. * The output looks like this:<br>
  147. * <pre>
  148. * 12345 filename.c[123]: format string
  149. * ^ ^ ^ ^
  150. * | | | line number
  151. * | | +--------- file name
  152. * | +-------------- tab character
  153. * +------------------- timestamp (ms since reset)
  154. * </pre>
  155. *
  156. * */
  157. //#define USE_DEBUG
  158. #ifdef USE_DEBUG
  159. #define debug(format,...) {\
  160. printf_("%ul\t%s[%i]: ", millisec, __FILE__, __LINE__); /* print file name and line number */\
  161. printf_(format, ## __VA_ARGS__); /* print format string and args */\
  162. printf_("\n"); \
  163. }
  164. #else
  165. #define debug(format,...) ((void)0)
  166. #endif /* USE_DEBUG */
  167. /*
  168. +=============================================================================+
  169. | local functions
  170. +=============================================================================+
  171. */
  172. // putc_strg() is the putc()function for sprintf_()
  173. static void putc_strg(char character)
  174. {
  175. *SPRINTF_buffer = (char)character; // just add the character to buffer
  176. SPRINTF_buffer++;
  177. }
  178. /*--------------------------------------------------------------------------------+
  179. * vfprintf_()
  180. * Prints a string to stream. Supports %s, %c, %d, %ld %ul %02d %i %x %lud and %%
  181. * - partly supported: long long, float (%l %f, %F, %2.2f)
  182. * - not supported: double float and exponent (%e %g %p %o \t)
  183. *--------------------------------------------------------------------------------+
  184. */
  185. static int vfprintf_(void (*putc)(char), const char* str, va_list arp)
  186. {
  187. int d, r, w, s, l; //d=char, r = radix, w = width, s=zeros, l=long
  188. char *c; // for the while loop only
  189. //const char* p;
  190. #ifdef INCLUDE_FLOAT
  191. float f;
  192. long int m, w2;
  193. #endif
  194. while ((d = *str++) != 0) {
  195. if (d != '%') {//if it is not format qualifier
  196. (*putc)(d);
  197. continue;//get out of while loop
  198. }
  199. d = *str++;//if it is '%'get next char
  200. w = r = s = l = 0;
  201. if (d == '%') {//if it is % print silmpy %
  202. (*putc)(d);
  203. d = *str++;
  204. }
  205. if (d == '0') {
  206. d = *str++; s = 1; //padd with zeros
  207. }
  208. while ((d >= '0')&&(d <= '9')) {
  209. w += w * 10 + (d - '0');
  210. d = *str++;
  211. }
  212. if (s) w = -w; //padd with zeros if negative
  213. #ifdef INCLUDE_FLOAT
  214. w2 = 0;
  215. if (d == '.')
  216. d = *str++;
  217. while ((d >= '0')&&(d <= '9')) {
  218. w2 += w2 * 10 + (d - '0');
  219. d = *str++;
  220. }
  221. #endif
  222. if (d == 's') {// if string
  223. c = va_arg(arp, char*); //get buffer addres
  224. //p = c;//debug
  225. while (*c)
  226. (*putc)(*(c++));//write the buffer out
  227. continue;
  228. }
  229. //debug
  230. //while(*p) Usart1Put(*p++);
  231. if (d == 'c') {
  232. (*putc)((char)va_arg(arp, int));
  233. continue;
  234. }
  235. if (d == 'u') { // %ul
  236. r = 10;
  237. d = *str++;
  238. }
  239. if (d == 'l') { // long =32bit
  240. l = 1;
  241. if (r==0) r = -10;
  242. d = *str++;
  243. }
  244. // if (!d) break;
  245. if (d == 'u') r = 10;// %lu, %llu
  246. else if (d == 'd' || d == 'i') {if (r==0) r = -10;} //can be 16 or 32bit int
  247. else if (d == 'X' || d == 'x') r = 16; // 'x' added by mthomas
  248. else if (d == 'b') r = 2;
  249. else str--; // normal character
  250. #ifdef INCLUDE_FLOAT
  251. if (d == 'f' || d == 'F') {
  252. f=va_arg(arp, double);
  253. if (f>0) {
  254. r=10;
  255. m=(int)f;
  256. }
  257. else {
  258. r=-10;
  259. f=-f;
  260. m=(int)(f);
  261. }
  262. long_itoa(m, r, w, (putc));
  263. f=f-m; m=f*(10^w2); w2=-w2;
  264. long_itoa(m, r, w2, (putc));
  265. l=3; //do not continue with long
  266. }
  267. #endif
  268. if (!r) continue; //
  269. if (l==0) {
  270. if (r > 0){ //unsigned
  271. long_itoa((unsigned long)va_arg(arp, int), r, w, (putc)); //needed for 16bit int, no harm to 32bit int
  272. }
  273. else //signed
  274. long_itoa((long)va_arg(arp, int), r, w, (putc));
  275. } else if (l==1){ // long =32bit
  276. long_itoa((long)va_arg(arp, long), r, w, (putc)); //no matter if signed or unsigned
  277. }
  278. }
  279. return 0;
  280. }
  281. static void long_itoa (long val, int radix, int len, void (*putc) (char))
  282. {
  283. char c, sgn = 0, pad = ' ';
  284. char s[20];
  285. int i = 0;
  286. if (radix < 0) {
  287. radix = -radix;
  288. if (val < 0) {
  289. val = -val;
  290. sgn = '-';
  291. }
  292. }
  293. if (len < 0) {
  294. len = -len;
  295. pad = '0';
  296. }
  297. if (len > 20) return;
  298. do {
  299. c = (char)((unsigned long)val % radix); //cast!
  300. if (c >= 10) c += ('A'-10); //ABCDEF
  301. else c += '0'; //0123456789
  302. s[i++] = c;
  303. val = (unsigned long)val /radix; //cast!
  304. } while (val);
  305. if (sgn) s[i++] = sgn;
  306. while (i < len)
  307. s[i++] = pad;
  308. do
  309. (*putc)(s[--i]);
  310. while (i);
  311. }
  312. //
  313. // Reduced version of sscanf (%d, %x, %c, %n are supported)
  314. // %d dec integer (E.g.: 12)
  315. // %x hex integer (E.g.: 0xa0)
  316. // %b bin integer (E.g.: b1010100010)
  317. // %n hex, de or bin integer (e.g: 12, 0xa0, b1010100010)
  318. // %c any character
  319. //
  320. static int rsscanf(const char* str, const char* format, va_list ap)
  321. {
  322. //va_list ap;
  323. int value, tmp;
  324. int count;
  325. int pos;
  326. char neg, fmt_code;
  327. const char* pf;
  328. char* sval;
  329. //va_start(ap, format);
  330. for (pf = format, count = 0; *format != 0 && *str != 0; format++, str++)
  331. {
  332. while (*format == ' ' && *format != 0) format++;//
  333. if (*format == 0) break;
  334. while (*str == ' ' && *str != 0) str++;//increment pointer of input string
  335. if (*str == 0) break;
  336. if (*format == '%')//recognize how to format
  337. {
  338. format++;
  339. if (*format == 'n')
  340. {
  341. if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))//if in str sth like 0xff
  342. {
  343. fmt_code = 'x';
  344. str += 2;
  345. }
  346. else
  347. if (str[0] == 'b')
  348. {
  349. fmt_code = 'b';
  350. str++;
  351. }
  352. else
  353. fmt_code = 'd';
  354. }
  355. else
  356. fmt_code = *format; //it is format letter
  357. switch (fmt_code)
  358. {
  359. case 'x':
  360. case 'X':
  361. for (value = 0, pos = 0; *str != 0; str++, pos++)
  362. {
  363. if ('0' <= *str && *str <= '9')
  364. tmp = *str - '0';
  365. else
  366. if ('a' <= *str && *str <= 'f')
  367. tmp = *str - 'a' + 10;
  368. else
  369. if ('A' <= *str && *str <= 'F')
  370. tmp = *str - 'A' + 10;
  371. else
  372. break;
  373. value *= 16;
  374. value += tmp;
  375. }
  376. if (pos == 0)
  377. return count;
  378. *(va_arg(ap, int*)) = value;
  379. count++;
  380. break;
  381. case 'b':
  382. for (value = 0, pos = 0; *str != 0; str++, pos++)
  383. {
  384. if (*str != '0' && *str != '1')
  385. break;
  386. value *= 2;
  387. value += *str - '0';
  388. }
  389. if (pos == 0)
  390. return count;
  391. *(va_arg(ap, int*)) = value;
  392. count++;
  393. break;
  394. case 'd':
  395. if (*str == '-')
  396. {
  397. neg = 1;
  398. str++;
  399. }
  400. else
  401. neg = 0;
  402. for (value = 0, pos = 0; *str != 0; str++, pos++)
  403. {
  404. if ('0' <= *str && *str <= '9')
  405. value = value*10 + (int)(*str - '0');
  406. else
  407. break;
  408. }
  409. if (pos == 0)
  410. return count;
  411. *(va_arg(ap, int*)) = neg ? -value : value;
  412. count++;
  413. break;
  414. case 'c':
  415. *(va_arg(ap, char*)) = *str;
  416. count++;
  417. break;
  418. case 's':
  419. sval = va_arg(ap, char*);
  420. while(*str){
  421. *sval++ = *str++;
  422. count++;
  423. }
  424. *sval = NULL;
  425. break;
  426. default:
  427. return count;
  428. }
  429. }
  430. else
  431. {
  432. if (*format != *str)//
  433. break;
  434. }
  435. }
  436. return count;
  437. }
  438. /******************************************************************************
  439. * END OF FILE
  440. ******************************************************************************/