log.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*
  2. * Copyright STREAMIT BV, 2010.
  3. *
  4. * Project : SIR
  5. * Module : Log
  6. * File name $Workfile: Log.c $
  7. * Last Save $Date: 2003/08/16 15:01:19 $
  8. * $Revision: 0.1 $
  9. * Creation Date : 2003/08/16 15:01:19
  10. *
  11. * Description : Keeps track of log messages
  12. * As an initial implementation this module
  13. * outputs messages to the serial port and uses
  14. * no buffering. (As a result logging delays execution
  15. * as long as the serial write takes)
  16. * At a later stage this module will have a logging
  17. * queue. This will not have much impact on execution
  18. * time. It will output messages to either a serial port
  19. * or telnet client.
  20. *
  21. */
  22. /*--------------------------------------------------------------------------*/
  23. /* Include files */
  24. /*--------------------------------------------------------------------------*/
  25. #define LOG_MODULE LOG_LOG_MODULE
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <sys/thread.h>
  29. #include <sys/heap.h>
  30. #include <sys/device.h>
  31. #include <sys/osdebug.h>
  32. //#pragma text:appcode
  33. #include "uart0driver.h"
  34. //#include "settings.h"
  35. #include "log.h"
  36. /*--------------------------------------------------------------------------*/
  37. /* Constant definitions */
  38. /*--------------------------------------------------------------------------*/
  39. /*!\brief Max length of address */
  40. #define MAX_OFFSET_LEN 8
  41. /*!\brief Max byte values printed on a line */
  42. #define BYTES_PER_LINE 16
  43. /*!\brief Max number of characters hex dump takes: 2 digits plus trailing blank */
  44. #define HEX_DUMP_LEN (BYTES_PER_LINE*3)
  45. /*!\brief Number of characters hex dump + ascii take: 3 chars, 2 blanks, 1 char */
  46. #define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
  47. /*!\brief Number of characters per line: address, 2 blanks, data dump */
  48. #define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
  49. #define LEVEL_MASK 0x07 // b0...b2
  50. #define NAME_MASK 0xF8 // b3..b7
  51. /*--------------------------------------------------------------------------*/
  52. /* Type declarations */
  53. /*--------------------------------------------------------------------------*/
  54. /*--------------------------------------------------------------------------*/
  55. /* Local variables */
  56. /*--------------------------------------------------------------------------*/
  57. /*!\brief The current log level */
  58. static TLogLevel g_tLevel;
  59. /*!\brief Stream to output the log data to */
  60. static FILE *g_tStream;
  61. /*--------------------------------------------------------------------------*/
  62. /* Global variables */
  63. /*--------------------------------------------------------------------------*/
  64. /*--------------------------------------------------------------------------*/
  65. /* Local functions */
  66. /*--------------------------------------------------------------------------*/
  67. /*!
  68. * \brief Return the prefix-level for the given log level.
  69. *
  70. * \param tLevel [in] The log level.
  71. *
  72. * \return Pointer to a string in program space.
  73. */
  74. static PGM_P LogPrefixLevel_P(TLogLevel tLevel)
  75. {
  76. switch (tLevel)
  77. {
  78. case LOG_EMERG_LEV :return(PSTR("\n#Emerg "));
  79. case LOG_ALERT_LEV :return(PSTR("\n#Alert "));
  80. case LOG_CRIT_LEV :return(PSTR("\n#Crit "));
  81. case LOG_ERR_LEV :return(PSTR("\n#Err "));
  82. case LOG_WARNING_LEV :return(PSTR("\n#Warn "));
  83. case LOG_NOTICE_LEV :return(PSTR("\n#Notic "));
  84. case LOG_INFO_LEV :return(PSTR("\n#Info "));
  85. case LOG_DEBUG_LEV :return(PSTR("\n#Debug "));
  86. default :return(PSTR("\n"));
  87. }
  88. }
  89. /*!
  90. * \brief Return the prefix-name for the given log module.
  91. *
  92. * \param tLevel [in] The log module.
  93. *
  94. * \return Pointer to a string in program space.
  95. */
  96. static PGM_P LogPrefixName_P(TLogLevel tLevel)
  97. {
  98. switch (tLevel)
  99. {
  100. case LOG_AUDIO_MODULE :return(PSTR("AU: "));
  101. case LOG_CHANNEL_MODULE :return(PSTR("CH: "));
  102. case LOG_COMAND_MODULE :return(PSTR("CM: "));
  103. case LOG_DISPLAY_MODULE :return(PSTR("DP: "));
  104. case LOG_FAT_MODULE :return(PSTR("FA: "));
  105. case LOG_FLASH_MODULE :return(PSTR("FL: "));
  106. case LOG_HTTP_MODULE :return(PSTR("HT: "));
  107. case LOG_INET_MODULE :return(PSTR("IN: "));
  108. case LOG_KEYBOARD_MODULE :return(PSTR("KB: "));
  109. case LOG_LED_MODULE :return(PSTR("LE: "));
  110. case LOG_LOG_MODULE :return(PSTR("LG: "));
  111. case LOG_MAIN_MODULE :return(PSTR("SY: "));
  112. case LOG_MENU_MODULE :return(PSTR("ME: "));
  113. case LOG_MMC_MODULE :return(PSTR("MM: "));
  114. case LOG_MMCDRV_MODULE :return(PSTR("MD: "));
  115. case LOG_PARSE_MODULE :return(PSTR("PA: "));
  116. case LOG_PLAYER_MODULE :return(PSTR("PL: "));
  117. case LOG_REMCON_MODULE :return(PSTR("RC: "));
  118. case LOG_RTC_MODULE :return(PSTR("RT: "));
  119. case LOG_SELFTEST_MODULE :return(PSTR("ST: "));
  120. case LOG_SESSION_MODULE :return(PSTR("SE: "));
  121. case LOG_SETTINGS_MODULE :return(PSTR("SG: "));
  122. case LOG_SPIDRV_MODULE :return(PSTR("SP: "));
  123. case LOG_STREAMER_MODULE :return(PSTR("SR: "));
  124. case LOG_UART0DRIVER_MODULE :return(PSTR("UA: "));
  125. case LOG_UPDATE_MODULE :return(PSTR("UD: "));
  126. case LOG_UTIL_MODULE :return(PSTR("UT: "));
  127. case LOG_VERSION_MODULE :return(PSTR("VE: "));
  128. case LOG_VS10XX_MODULE :return(PSTR("VS: "));
  129. case LOG_WATCHDOG_MODULE :return(PSTR("WD: "));
  130. default :return(PSTR("?? <DMK> "));
  131. }
  132. }
  133. /*--------------------------------------------------------------------------*/
  134. /* Global functions */
  135. /*--------------------------------------------------------------------------*/
  136. /*!
  137. * \brief Initialises this module
  138. *
  139. * \param -
  140. *
  141. * \return -
  142. */
  143. void LogInit(void)
  144. {
  145. /* Set default level */
  146. g_tLevel = LOG_DEBUG_LEV;
  147. LogOpen();
  148. }
  149. /*!
  150. * \brief Opens the module for use.
  151. *
  152. * \param -
  153. *
  154. * \return -
  155. */
  156. void LogOpen(void)
  157. {
  158. /* Associate our stream with a device */
  159. g_tStream = Uart0DriverGetStream();
  160. }
  161. /*!
  162. * \brief Closes the module.
  163. *
  164. * All interface functions from this module will result in void
  165. * operations.
  166. *
  167. * \param -
  168. *
  169. * \return -
  170. */
  171. void LogClose(void)
  172. {
  173. FILE *tPrevStream = g_tStream;
  174. /* Don't allow adding of new output. */
  175. g_tStream = NULL;
  176. /* Finish all current output. */
  177. fflush(tPrevStream);
  178. }
  179. /*!
  180. * \brief Log a message to the log medium using a fixed string.
  181. *
  182. * The fixed string must reside in program space. It is parsed
  183. * using the rules of (s)printf.
  184. *
  185. * \param tLevel priority level of the message.
  186. * \param szMsg format string of the message.
  187. * \param ... arguments to the format string.
  188. */
  189. void LogMsg_P(TLogLevel tLevel, PGM_P szMsg, ...)
  190. {
  191. va_list ap;
  192. if (g_tStream)
  193. {
  194. /* Log the string if the message is more important than the current level */
  195. if ((tLevel&LEVEL_MASK) <= g_tLevel)
  196. {
  197. fputs_P(LogPrefixLevel_P(tLevel&LEVEL_MASK), g_tStream);
  198. fputs_P(LogPrefixName_P(tLevel&NAME_MASK), g_tStream);
  199. va_start(ap, szMsg);
  200. vfprintf_P(g_tStream, szMsg, ap);
  201. va_end(ap);
  202. }
  203. }
  204. }
  205. void LogChar_P(const char bChar)
  206. {
  207. if (g_tStream)
  208. {
  209. fputc(bChar, g_tStream);
  210. }
  211. }
  212. /*!
  213. * \brief Set the priority level
  214. *
  215. * \param tNewLevel New priority level
  216. *
  217. * \return The previous priority level
  218. */
  219. TLogLevel LogSetLevel(TLogLevel tNewLevel)
  220. {
  221. TLogLevel tPrevLevel = g_tLevel;
  222. if (tNewLevel <= LOG_DEBUG_LEV)
  223. {
  224. g_tLevel = tNewLevel;
  225. }
  226. return(tPrevLevel);
  227. }
  228. /*!
  229. * \brief Print a block of memory
  230. *
  231. * Prints out 16 bytes of data per line
  232. * Every line starts with the address (offset),
  233. * the data in hex and that same data in ascii.
  234. *
  235. * \param tStream The stream to print to
  236. * \param cp The data
  237. * \param length The length of the data
  238. *
  239. * \return none
  240. */
  241. void HexDump(FILE *tStream, CONST u_char *cp, size_t length)
  242. {
  243. register unsigned int address, i, hex_pos, ascii_pos, l;
  244. unsigned int address_len;
  245. unsigned char c;
  246. char line[MAX_LINE_LEN + 1];
  247. static CONST char binhex[16] =
  248. {
  249. '0', '1', '2', '3', '4', '5', '6', '7',
  250. '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
  251. };
  252. if (tStream != NULL)
  253. {
  254. /*
  255. * How many digits do we need for the address?
  256. * We use at least 4 digits or more as needed
  257. */
  258. if (((length - 1) & 0xF0000000) != 0)
  259. {
  260. address_len = 8;
  261. }
  262. else if (((length - 1) & 0x0F000000) != 0)
  263. {
  264. address_len = 7;
  265. }
  266. else if (((length - 1) & 0x00F00000) != 0)
  267. {
  268. address_len = 6;
  269. }
  270. else if (((length - 1) & 0x000F0000) != 0)
  271. {
  272. address_len = 5;
  273. }
  274. else
  275. {
  276. address_len = 4;
  277. }
  278. address = 0;
  279. i = 0;
  280. hex_pos = 0;
  281. ascii_pos = 0;
  282. while (i < length)
  283. {
  284. if ((i & 15) == 0)
  285. {
  286. /*
  287. * Start of a new line.
  288. */
  289. memset(line, ' ', sizeof(line));
  290. hex_pos = 0;
  291. ascii_pos = 0;
  292. l = address_len;
  293. do
  294. {
  295. l--;
  296. c = (address >> (l*4)) & 0xF;
  297. line[hex_pos++] = binhex[c];
  298. } while (l != 0);
  299. /* 2 spaces */
  300. hex_pos += 2;
  301. /*
  302. * Offset in line of ASCII dump.
  303. */
  304. ascii_pos = hex_pos + HEX_DUMP_LEN + 2;
  305. }
  306. c = *cp++;
  307. /* Dump the hex value */
  308. line[hex_pos++] = binhex[c >> 4];
  309. line[hex_pos++] = binhex[c & 0xF];
  310. hex_pos++;
  311. /* Print the ascii value */
  312. line[ascii_pos++] = (c >= ' ' && c < 127) ? c : '.';
  313. i++;
  314. if ((i & 15) == 0 || i == length)
  315. {
  316. /*
  317. * We'll be starting a new line, or
  318. * we're finished printing this buffer;
  319. * dump out the line we've constructed,
  320. * and advance the offset.
  321. */
  322. line[ascii_pos] = '\0';
  323. fputs(line, tStream);
  324. fputc('\n', tStream);
  325. address += BYTES_PER_LINE;
  326. }
  327. }
  328. }
  329. }