printf.c
来自「MANTIS是由科罗拉多大学开发的传感器网络嵌入式操作系统。 这是mantis」· C语言 代码 · 共 501 行
C
501 行
// This file is part of MANTIS OS, Operating System// See http://mantis.cs.colorado.edu///// Copyright (C) 2003,2004,2005 University of Colorado, Boulder//// This program is free software; you can redistribute it and/or// modify it under the terms of the mos license (see file LICENSE)/**************************************************************************//* File: printf.c *//* Author Adam Torgerson *//* Date: 01/25/04 *//* Edited: Jeff Rose : rosejn@colorado.edu *//* Date: 03/10/04 *//* *//* String printing over the uart. (Now using the com layer.) *//**************************************************************************//** @file printf.c * @brief String printing over the uart. (Now using the com layer) * @author Adam Torgerson * @author Modified: Jeff Rose * @author Modified: Charles Gruenwald * @date Created: 01/25/2004 * @date Modified: 03/10/2004 */#include "mos.h"#ifndef PLATFORM_LINUX#include <string.h>#include "printf.h"#include "com.h"#include "mutex.h"#ifdef ARCH_AVR#include <avr/pgmspace.h>#endif#include "led.h"static comBuf printf_packet;static mos_mutex_t printf_lock;static uint8_t charbuff[16]; //buffer for reversing itoa converisionsstatic uint8_t buffsize;static uint8_t fieldwidth;static char padchar;static void send_string(const char *s);static void norecurse_32(uint32_t input, uint8_t radix);static void norecurse_16(uint16_t input, uint8_t radix);static void check_size(void);#ifdef ARCH_AVRstatic void send_prog_string(PGM_P s);#endif#ifdef PLATFORM_TELOSB#define com_send_packet(packet_ptr) com_send(IFACE_SERIAL2, packet_ptr)#else#define com_send_packet(packet_ptr) com_send(IFACE_SERIAL, packet_ptr)#endif/* check the size of the packet, send it off if it's too big... */inline static void check_size(void){ if(printf_packet.size == COM_DATA_SIZE - 2) { printf_packet.data[printf_packet.size++] = '\0'; //com_send(IFACE_SERIAL, &printf_packet); com_send_packet(&printf_packet); printf_packet.size = 0; }}/* initialize the mutex */void printf_init(void){ mos_mutex_init(&printf_lock);}/* HACK to let us optimize, define our own version of puts() the assembler "optimizes" calls to printf() with no args by converting it to a puts () */int puts(const char *msg){ //printf("%s\n\0", msg); mos_mutex_lock(&printf_lock); send_string(msg); printf_packet.data[printf_packet.size++] = '\n'; printf_packet.data[printf_packet.size++] = '\0'; //com_send(IFACE_SERIAL, &printf_packet); com_send_packet(&printf_packet); printf_packet.size = 0; mos_mutex_unlock(&printf_lock); return 0;}/* HACK to let us optimize, define our own version of putchar() the assembler "optimizes" calls to printf() with a single char argument by converting it to a putchar() */int putchar(int character){ mos_mutex_lock(&printf_lock); printf_packet.size = 2; printf_packet.data[0] = character; printf_packet.data[1] = '\0'; //com_send(IFACE_SERIAL, &printf_packet); com_send_packet(&printf_packet); printf_packet.size = 0; mos_mutex_unlock(&printf_lock); return 0;}/** @brief printf Prints the formatted string over the serial line * after which a shell must display the text to the screen. Note that * %C is for 8 bit numbers, %d for 16-bit and %l for 32 bit. * @param format Format to print */int16_t printf(const char *format, ...){ va_list arg; const char *p = format; if(format == NULL) return -1; mos_mutex_lock(&printf_lock); va_start(arg, format); printf_packet.size = 0; memset(printf_packet.data, 0, COM_DATA_SIZE); while(*p) { // If its not a conversion specifier we just send it if(*p != '%') { printf_packet.data[printf_packet.size++] = *p++; check_size(); } else { // Otherwise we need to substitute in a variable *p++; // TODO the padding options are not implemented for non-numeric stuff // Pad with zeros or spaces? if (*p == '0') { padchar = '0'; p++; } else padchar = ' '; // Width of field fieldwidth = 0; while(*p >= '0' && *p <= '9') { fieldwidth = fieldwidth * 10 + *p - '0'; p++; } switch(*p++) { case 's': { char *s; s = va_arg(arg, char *); send_string(s); break; }#ifdef ARCH_AVR case 'P': { PGM_P s; s = va_arg(arg, PGM_P); send_prog_string(s); }#endif case 'd': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16, 10); break; } case 'l': { uint32_t num32; num32 = va_arg(arg, uint32_t); norecurse_32(num32, 10); break; } case 'c': { uint16_t num8 = 0; num8 = (uint8_t)va_arg(arg, uint16_t); printf_packet.data[printf_packet.size++] = num8; check_size(); break; } case 'C': { uint16_t num8 = 0; num8 = (uint8_t) va_arg(arg, uint16_t); norecurse_16((uint16_t)num8, 10); break; } case 'x': printf_packet.data[printf_packet.size++] = '0'; check_size(); printf_packet.data[printf_packet.size++] = 'x'; check_size(); case 'h': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16, 16); break; } case 'o': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16, 8); break; } case '%': printf_packet.data[printf_packet.size++] = '%'; check_size(); break; case 'b': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16, 2); break; } default: printf_packet.data[printf_packet.size++] = '?'; check_size(); printf_packet.data[printf_packet.size++] = '?'; check_size(); printf_packet.data[printf_packet.size++] = '?'; check_size(); break; } } } va_end(arg); printf_packet.data[printf_packet.size++] = '\0'; //com_send(IFACE_SERIAL, &printf_packet); com_send_packet(&printf_packet); printf_packet.size = 0; mos_mutex_unlock(&printf_lock); return 0;}#ifdef ARCH_AVR/** @brief printf_P Same as printf, except that the format string must be stored * int program memory. * @param format Format to print */int16_t printf_P(const prog_char *format, ...){ va_list arg; const prog_char *p = format; if(format == NULL) return -1; mos_mutex_lock(&printf_lock); va_start(arg, format); printf_packet.size = 0; char c = pgm_read_byte(p); while(c) { // If its not a conversion specifier we just send it if(c != '%') { printf_packet.data[printf_packet.size++] = c; c = pgm_read_byte(++p); check_size(); } else { // Otherwise we need to substitute in a variable c = pgm_read_byte(++p); // TODO the padding options are not implemented for non-numeric stuff // Pad with zeros or spaces? if (c == '0') { padchar = '0'; c = pgm_read_byte(++p); } else padchar = ' '; // Width of field fieldwidth = 0; while(c >= '0' && c <= '9') { fieldwidth = fieldwidth * 10 + c - '0'; c = pgm_read_byte(++p); } switch(c) { case 's': { char *s; s = va_arg(arg, char *); send_string(s); break; } case 'P': { PGM_P s; s = va_arg(arg, PGM_P); send_prog_string(s); } case 'd': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16,10); break; } case 'l': { uint32_t num32; num32 = va_arg(arg, uint32_t); norecurse_32(num32, 10); break; } case 'c': { uint16_t num8 = 0; num8 = (uint8_t)va_arg(arg, uint16_t); printf_packet.data[printf_packet.size++] = num8; check_size(); break; } case 'C': { uint16_t num8 = 0; num8 = (uint8_t) va_arg(arg, uint16_t); norecurse_16((uint16_t)num8, 10); break; } case 'x': printf_packet.data[printf_packet.size++] = '0'; check_size(); printf_packet.data[printf_packet.size++] = 'x'; check_size(); case 'h': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16, 16); break; } case 'o': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16, 8); break; } case '%': printf_packet.data[printf_packet.size++] = '%'; check_size(); break; case 'b': { uint16_t num16; num16 = va_arg(arg, uint16_t); norecurse_16(num16, 2); break; } default: printf_packet.data[printf_packet.size++] = '?'; check_size(); printf_packet.data[printf_packet.size++] = '?'; check_size(); printf_packet.data[printf_packet.size++] = '?'; check_size(); break; } c = pgm_read_byte(++p); } } va_end(arg); printf_packet.data[printf_packet.size++] = '\0'; com_send(IFACE_SERIAL, &printf_packet); printf_packet.size = 0; mos_mutex_unlock(&printf_lock); return 0;}#endif/* Send a NULL terminated string. */static void send_string(const char *s){ /*while(fieldwidth--) { printf_packet.data[printf_packet.size++] = padchar; check_size(); }*/ while(*s) { printf_packet.data[printf_packet.size++] = *s++; check_size(); }}#ifdef ARCH_AVR/* Send a NULL terminated string from flash. */static void send_prog_string(PGM_P s){ /*while(fieldwidth--) { printf_packet.data[printf_packet.size++] = padchar; check_size(); }*/ uint8_t byte; while((byte = pgm_read_byte(s++))) { printf_packet.data[printf_packet.size++] = byte; check_size(); }}#endif/* Convert a number to a certain radix and send over uart. * 16-bit version */static void norecurse_16(uint16_t input, uint8_t radix){ uint8_t remainder = input % radix; buffsize = 0; if(input == 0) charbuff[buffsize++] = '0'; while(input >= radix) { if(remainder <= 9) charbuff[buffsize++] = remainder + '0'; else charbuff[buffsize++] = remainder - 10 + 'A'; input /= radix; remainder = input % radix; } //last place if(remainder > 0) { if(remainder <= 9) charbuff[buffsize++] = remainder + '0'; else charbuff[buffsize++] = remainder - 10 + 'A'; } // Calculate amount we still need to pad. We never truncate a result. if(fieldwidth > buffsize) fieldwidth -= buffsize; else fieldwidth = 0; while(fieldwidth--) { printf_packet.data[printf_packet.size++] = padchar; check_size(); } while(buffsize > 0) { printf_packet.data[printf_packet.size++] = charbuff[--buffsize]; check_size(); }}/* Convert a number to a certain radix and send over uart. * 16-bit version */static void norecurse_32(uint32_t input, uint8_t radix){ uint8_t remainder = input % radix; buffsize = 0; if(input == 0) charbuff[buffsize++] = '0'; while(input >= radix) { if(remainder <= 9) charbuff[buffsize++] = remainder + '0'; else charbuff[buffsize++] = remainder - 10 + 'A'; input /= radix; remainder = input % radix; } if(remainder > 0) { if(remainder <= 9) charbuff[buffsize++] = remainder + '0'; else charbuff[buffsize++] = remainder - 10 + 'A'; } // Calculate amount we still need to pad. We never truncate a result. if(fieldwidth > buffsize) fieldwidth -= buffsize; else fieldwidth = 0; while(fieldwidth--) { printf_packet.data[printf_packet.size++] = padchar; check_size(); } while(buffsize > 0) { printf_packet.data[printf_packet.size++] = charbuff[--buffsize]; check_size(); }}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?