log.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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_NTP_MODULE :return(PSTR("NT: "));
  116. case LOG_PARSE_MODULE :return(PSTR("PA: "));
  117. case LOG_PLAYER_MODULE :return(PSTR("PL: "));
  118. case LOG_REMCON_MODULE :return(PSTR("RC: "));
  119. case LOG_RTC_MODULE :return(PSTR("RT: "));
  120. case LOG_SELFTEST_MODULE :return(PSTR("ST: "));
  121. case LOG_SESSION_MODULE :return(PSTR("SE: "));
  122. case LOG_SETTINGS_MODULE :return(PSTR("SG: "));
  123. case LOG_SPIDRV_MODULE :return(PSTR("SP: "));
  124. case LOG_STREAMER_MODULE :return(PSTR("SR: "));
  125. case LOG_UART0DRIVER_MODULE :return(PSTR("UA: "));
  126. case LOG_UPDATE_MODULE :return(PSTR("UD: "));
  127. case LOG_UTIL_MODULE :return(PSTR("UT: "));
  128. case LOG_VERSION_MODULE :return(PSTR("VE: "));
  129. case LOG_VS10XX_MODULE :return(PSTR("VS: "));
  130. case LOG_WATCHDOG_MODULE :return(PSTR("WD: "));
  131. default :return(PSTR("?? <DMK> "));
  132. }
  133. }
  134. /*--------------------------------------------------------------------------*/
  135. /* Global functions */
  136. /*--------------------------------------------------------------------------*/
  137. /*!
  138. * \brief Initialises this module
  139. *
  140. * \param -
  141. *
  142. * \return -
  143. */
  144. void LogInit(void)
  145. {
  146. /* Set default level */
  147. g_tLevel = LOG_DEBUG_LEV;
  148. LogOpen();
  149. }
  150. /*!
  151. * \brief Opens the module for use.
  152. *
  153. * \param -
  154. *
  155. * \return -
  156. */
  157. void LogOpen(void)
  158. {
  159. /* Associate our stream with a device */
  160. g_tStream = Uart0DriverGetStream();
  161. }
  162. /*!
  163. * \brief Closes the module.
  164. *
  165. * All interface functions from this module will result in void
  166. * operations.
  167. *
  168. * \param -
  169. *
  170. * \return -
  171. */
  172. void LogClose(void)
  173. {
  174. FILE *tPrevStream = g_tStream;
  175. /* Don't allow adding of new output. */
  176. g_tStream = NULL;
  177. /* Finish all current output. */
  178. fflush(tPrevStream);
  179. }
  180. /*!
  181. * \brief Log a message to the log medium using a fixed string.
  182. *
  183. * The fixed string must reside in program space. It is parsed
  184. * using the rules of (s)printf.
  185. *
  186. * \param tLevel priority level of the message.
  187. * \param szMsg format string of the message.
  188. * \param ... arguments to the format string.
  189. */
  190. void LogMsg_P(TLogLevel tLevel, PGM_P szMsg, ...)
  191. {
  192. va_list ap;
  193. if (g_tStream)
  194. {
  195. /* Log the string if the message is more important than the current level */
  196. if ((tLevel&LEVEL_MASK) <= g_tLevel)
  197. {
  198. fputs_P(LogPrefixLevel_P(tLevel&LEVEL_MASK), g_tStream);
  199. fputs_P(LogPrefixName_P(tLevel&NAME_MASK), g_tStream);
  200. va_start(ap, szMsg);
  201. vfprintf_P(g_tStream, szMsg, ap);
  202. va_end(ap);
  203. }
  204. }
  205. }
  206. void LogChar_P(const char bChar)
  207. {
  208. if (g_tStream)
  209. {
  210. fputc(bChar, g_tStream);
  211. }
  212. }
  213. /*!
  214. * \brief Set the priority level
  215. *
  216. * \param tNewLevel New priority level
  217. *
  218. * \return The previous priority level
  219. */
  220. TLogLevel LogSetLevel(TLogLevel tNewLevel)
  221. {
  222. TLogLevel tPrevLevel = g_tLevel;
  223. if (tNewLevel <= LOG_DEBUG_LEV)
  224. {
  225. g_tLevel = tNewLevel;
  226. }
  227. return(tPrevLevel);
  228. }
  229. /*!
  230. * \brief Print a block of memory
  231. *
  232. * Prints out 16 bytes of data per line
  233. * Every line starts with the address (offset),
  234. * the data in hex and that same data in ascii.
  235. *
  236. * \param tStream The stream to print to
  237. * \param cp The data
  238. * \param length The length of the data
  239. *
  240. * \return none
  241. */
  242. void HexDump(FILE *tStream, CONST u_char *cp, size_t length)
  243. {
  244. register unsigned int address, i, hex_pos, ascii_pos, l;
  245. unsigned int address_len;
  246. unsigned char c;
  247. char line[MAX_LINE_LEN + 1];
  248. static CONST char binhex[16] =
  249. {
  250. '0', '1', '2', '3', '4', '5', '6', '7',
  251. '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
  252. };
  253. if (tStream != NULL)
  254. {
  255. /*
  256. * How many digits do we need for the address?
  257. * We use at least 4 digits or more as needed
  258. */
  259. if (((length - 1) & 0xF0000000) != 0)
  260. {
  261. address_len = 8;
  262. }
  263. else if (((length - 1) & 0x0F000000) != 0)
  264. {
  265. address_len = 7;
  266. }
  267. else if (((length - 1) & 0x00F00000) != 0)
  268. {
  269. address_len = 6;
  270. }
  271. else if (((length - 1) & 0x000F0000) != 0)
  272. {
  273. address_len = 5;
  274. }
  275. else
  276. {
  277. address_len = 4;
  278. }
  279. address = 0;
  280. i = 0;
  281. hex_pos = 0;
  282. ascii_pos = 0;
  283. while (i < length)
  284. {
  285. if ((i & 15) == 0)
  286. {
  287. /*
  288. * Start of a new line.
  289. */
  290. memset(line, ' ', sizeof(line));
  291. hex_pos = 0;
  292. ascii_pos = 0;
  293. l = address_len;
  294. do
  295. {
  296. l--;
  297. c = (address >> (l*4)) & 0xF;
  298. line[hex_pos++] = binhex[c];
  299. } while (l != 0);
  300. /* 2 spaces */
  301. hex_pos += 2;
  302. /*
  303. * Offset in line of ASCII dump.
  304. */
  305. ascii_pos = hex_pos + HEX_DUMP_LEN + 2;
  306. }
  307. c = *cp++;
  308. /* Dump the hex value */
  309. line[hex_pos++] = binhex[c >> 4];
  310. line[hex_pos++] = binhex[c & 0xF];
  311. hex_pos++;
  312. /* Print the ascii value */
  313. line[ascii_pos++] = (c >= ' ' && c < 127) ? c : '.';
  314. i++;
  315. if ((i & 15) == 0 || i == length)
  316. {
  317. /*
  318. * We'll be starting a new line, or
  319. * we're finished printing this buffer;
  320. * dump out the line we've constructed,
  321. * and advance the offset.
  322. */
  323. line[ascii_pos] = '\0';
  324. fputs(line, tStream);
  325. fputc('\n', tStream);
  326. address += BYTES_PER_LINE;
  327. }
  328. }
  329. }
  330. }