Projektarbeit Line Following Robot bei Prof. Chowanetz im WS22/23
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vcos_logcat.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. /*
  2. Copyright (c) 2012, Broadcom Europe Ltd
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. * Redistributions of source code must retain the above copyright
  7. notice, this list of conditions and the following disclaimer.
  8. * Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. * Neither the name of the copyright holder nor the
  12. names of its contributors may be used to endorse or promote products
  13. derived from this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  18. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. /*=============================================================================
  26. Categorized logging for VCOS - a generic implementation.
  27. =============================================================================*/
  28. #include "interface/vcos/vcos.h"
  29. #include "interface/vcos/vcos_ctype.h"
  30. #include "interface/vcos/vcos_string.h"
  31. #include "interface/vcos/vcos_inttypes.h"
  32. static VCOS_MUTEX_T lock;
  33. static int warned_loglevel; /* only warn about invalid log level once */
  34. static VCOS_VLOG_IMPL_FUNC_T vcos_vlog_impl_func = vcos_vlog_default_impl;
  35. #define VCOS_LOG_CATEGORY (&dflt_log_category)
  36. static VCOS_LOG_CAT_T dflt_log_category;
  37. VCOS_LOG_CAT_T *vcos_logging_categories = NULL;
  38. static int inited;
  39. #if VCOS_HAVE_CMD
  40. /*
  41. * For kernel or videocore purposes, we generally want the log command. For
  42. * user-space apps, they might want to provide their own log command, so we
  43. * don't include the built in on.
  44. *
  45. * So pthreads/vcos_platform.h defines VCOS_WANT_LOG_CMD to be 0. It is
  46. * undefined elsewhere.
  47. */
  48. # if !defined( VCOS_WANT_LOG_CMD )
  49. # define VCOS_WANT_LOG_CMD 1
  50. # endif
  51. #else
  52. # define VCOS_WANT_LOG_CMD 0
  53. #endif
  54. /* For now, do not link logging categories into linked lists
  55. * as it breaks when people unload shared libraries without
  56. * getting the counts right.
  57. */
  58. #ifdef __VIDEOCORE__
  59. #define REGISTER_CATEGORIES 1
  60. #else
  61. #define REGISTER_CATEGORIES 0
  62. #endif
  63. #if VCOS_WANT_LOG_CMD
  64. /*****************************************************************************
  65. *
  66. * Does a vcos_assert(0), which is useful to test logging.
  67. *
  68. *****************************************************************************/
  69. VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param )
  70. {
  71. (void)param;
  72. #if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS )
  73. vcos_log_error( "vcos_asserts have been compiled out" );
  74. vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" );
  75. #else
  76. vcos_assert(0);
  77. vcos_cmd_printf( param, "Executed vcos_assert(0)\n" );
  78. #endif
  79. return VCOS_SUCCESS;
  80. }
  81. /*****************************************************************************
  82. *
  83. * Sets a vcos logging level
  84. *
  85. *****************************************************************************/
  86. VCOS_STATUS_T vcos_log_set_cmd( VCOS_CMD_PARAM_T *param )
  87. {
  88. VCOS_LOG_CAT_T *cat;
  89. char *name;
  90. char *levelStr;
  91. VCOS_LOG_LEVEL_T level;
  92. VCOS_STATUS_T status;
  93. if ( param->argc != 3 )
  94. {
  95. vcos_cmd_usage( param );
  96. return VCOS_EINVAL;
  97. }
  98. name = param->argv[1];
  99. levelStr = param->argv[2];
  100. if ( vcos_string_to_log_level( levelStr, &level ) != VCOS_SUCCESS )
  101. {
  102. vcos_cmd_printf( param, "Unrecognized logging level: '%s'\n", levelStr );
  103. return VCOS_EINVAL;
  104. }
  105. vcos_mutex_lock(&lock);
  106. status = VCOS_SUCCESS;
  107. for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
  108. {
  109. if ( vcos_strcmp( name, cat->name ) == 0 )
  110. {
  111. cat->level = level;
  112. vcos_cmd_printf( param, "Category %s level set to %s\n", name, levelStr );
  113. break;
  114. }
  115. }
  116. if ( cat == NULL )
  117. {
  118. vcos_cmd_printf( param, "Unrecognized category: '%s'\n", name );
  119. status = VCOS_ENOENT;
  120. }
  121. vcos_mutex_unlock(&lock);
  122. return status;
  123. }
  124. /*****************************************************************************
  125. *
  126. * Prints out the current settings for a given category (or all cvategories)
  127. *
  128. *****************************************************************************/
  129. VCOS_STATUS_T vcos_log_status_cmd( VCOS_CMD_PARAM_T *param )
  130. {
  131. VCOS_LOG_CAT_T *cat;
  132. VCOS_STATUS_T status;
  133. vcos_mutex_lock(&lock);
  134. if ( param->argc == 1)
  135. {
  136. int nw;
  137. int nameWidth = 0;
  138. /* Print information about all of the categories. */
  139. for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
  140. {
  141. nw = (int)strlen( cat->name );
  142. if ( nw > nameWidth )
  143. {
  144. nameWidth = nw;
  145. }
  146. }
  147. for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
  148. {
  149. vcos_cmd_printf( param, "%-*s - %s\n", nameWidth, cat->name, vcos_log_level_to_string( cat->level ));
  150. }
  151. }
  152. else
  153. {
  154. /* Print information about a particular category */
  155. for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
  156. {
  157. if ( vcos_strcmp( cat->name, param->argv[1] ) == 0 )
  158. {
  159. vcos_cmd_printf( param, "%s - %s\n", cat->name, vcos_log_level_to_string( cat->level ));
  160. break;
  161. }
  162. }
  163. if ( cat == NULL )
  164. {
  165. vcos_cmd_printf( param, "Unrecognized logging category: '%s'\n", param->argv[1] );
  166. status = VCOS_ENOENT;
  167. goto out;
  168. }
  169. }
  170. status = VCOS_SUCCESS;
  171. out:
  172. vcos_mutex_unlock(&lock);
  173. return status;
  174. }
  175. /*****************************************************************************
  176. *
  177. * Prints out the current settings for a given category (or all cvategories)
  178. *
  179. *****************************************************************************/
  180. VCOS_STATUS_T vcos_log_test_cmd( VCOS_CMD_PARAM_T *param )
  181. {
  182. if ( param->argc == 1 )
  183. {
  184. static int seq_num = 100;
  185. /* No additional arguments - generate a message with an incrementing number */
  186. vcos_log_error( "Test message %d", seq_num );
  187. seq_num++;
  188. vcos_cmd_printf( param, "Logged 'Test message %d'\n", seq_num );
  189. }
  190. else
  191. {
  192. int arg_idx;
  193. /* Arguments supplied - log these */
  194. for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
  195. {
  196. vcos_log_error( "argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
  197. }
  198. vcos_cmd_printf( param, "Logged %d line(s) of test data\n", param->argc );
  199. }
  200. return VCOS_SUCCESS;
  201. }
  202. /*****************************************************************************
  203. *
  204. * Internal commands
  205. *
  206. *****************************************************************************/
  207. static VCOS_CMD_T log_cmd_entry[] =
  208. {
  209. { "assert", "", vcos_log_assert_cmd, NULL, "Does a vcos_assert(0) to test logging" },
  210. { "set", "category level", vcos_log_set_cmd, NULL, "Sets the vcos logging level for a category" },
  211. { "status", "[category]", vcos_log_status_cmd, NULL, "Prints the vcos log status for a (or all) categories" },
  212. { "test", "[arbitrary text]", vcos_log_test_cmd, NULL, "Does a vcos_log to test logging" },
  213. { NULL, NULL, NULL, NULL, NULL }
  214. };
  215. static VCOS_CMD_T cmd_log =
  216. { "log", "command [args]", NULL, log_cmd_entry, "Commands related to vcos logging" };
  217. #endif
  218. void vcos_logging_init(void)
  219. {
  220. if (inited)
  221. {
  222. /* FIXME: should print a warning or something here */
  223. return;
  224. }
  225. vcos_mutex_create(&lock, "vcos_log");
  226. vcos_log_platform_init();
  227. vcos_log_register("default", &dflt_log_category);
  228. #if VCOS_WANT_LOG_CMD
  229. vcos_cmd_register( &cmd_log );
  230. #endif
  231. vcos_assert(!inited);
  232. inited = 1;
  233. }
  234. /** Read an alphanumeric token, returning True if we succeeded.
  235. */
  236. static int read_tok(char *tok, size_t toklen, const char **pstr, char sep)
  237. {
  238. const char *str = *pstr;
  239. size_t n = 0;
  240. char ch;
  241. /* skip past any whitespace */
  242. while (str[0] && isspace((int)(str[0])))
  243. str++;
  244. while ((ch = *str) != '\0' &&
  245. ch != sep &&
  246. (isalnum((int)ch) || (ch == '_')) &&
  247. n != toklen-1)
  248. {
  249. tok[n++] = ch;
  250. str++;
  251. }
  252. /* did it work out? */
  253. if (ch == '\0' || ch == sep)
  254. {
  255. if (ch) str++; /* move to next token if not at end */
  256. /* yes */
  257. tok[n] = '\0';
  258. *pstr = str;
  259. return 1;
  260. }
  261. else
  262. {
  263. /* no */
  264. return 0;
  265. }
  266. }
  267. const char *vcos_log_level_to_string( VCOS_LOG_LEVEL_T level )
  268. {
  269. switch (level)
  270. {
  271. case VCOS_LOG_UNINITIALIZED: return "uninit";
  272. case VCOS_LOG_NEVER: return "never";
  273. case VCOS_LOG_ERROR: return "error";
  274. case VCOS_LOG_WARN: return "warn";
  275. case VCOS_LOG_INFO: return "info";
  276. case VCOS_LOG_TRACE: return "trace";
  277. }
  278. return "???";
  279. }
  280. VCOS_STATUS_T vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level )
  281. {
  282. if (strcmp(str,"error") == 0)
  283. *level = VCOS_LOG_ERROR;
  284. else if (strcmp(str,"never") == 0)
  285. *level = VCOS_LOG_NEVER;
  286. else if (strcmp(str,"warn") == 0)
  287. *level = VCOS_LOG_WARN;
  288. else if (strcmp(str,"warning") == 0)
  289. *level = VCOS_LOG_WARN;
  290. else if (strcmp(str,"info") == 0)
  291. *level = VCOS_LOG_INFO;
  292. else if (strcmp(str,"trace") == 0)
  293. *level = VCOS_LOG_TRACE;
  294. else
  295. return VCOS_EINVAL;
  296. return VCOS_SUCCESS;
  297. }
  298. static int read_level(VCOS_LOG_LEVEL_T *level, const char **pstr, char sep)
  299. {
  300. char buf[16];
  301. int ret = 1;
  302. if (read_tok(buf,sizeof(buf),pstr,sep))
  303. {
  304. if (vcos_string_to_log_level(buf,level) != VCOS_SUCCESS)
  305. {
  306. vcos_log("Invalid trace level '%s'\n", buf);
  307. ret = 0;
  308. }
  309. }
  310. else
  311. {
  312. ret = 0;
  313. }
  314. return ret;
  315. }
  316. void vcos_log_register(const char *name, VCOS_LOG_CAT_T *category)
  317. {
  318. const char *env;
  319. VCOS_LOG_CAT_T *i;
  320. category->name = name;
  321. if ( category->level == VCOS_LOG_UNINITIALIZED )
  322. {
  323. category->level = VCOS_LOG_ERROR;
  324. }
  325. category->flags.want_prefix = (category != &dflt_log_category );
  326. if (!REGISTER_CATEGORIES)
  327. return;
  328. vcos_mutex_lock(&lock);
  329. /* is it already registered? */
  330. for (i = vcos_logging_categories; i ; i = i->next )
  331. {
  332. if (i == category)
  333. {
  334. i->refcount++;
  335. break;
  336. }
  337. }
  338. if (!i)
  339. {
  340. /* not yet registered */
  341. category->next = vcos_logging_categories;
  342. vcos_logging_categories = category;
  343. category->refcount++;
  344. vcos_log_platform_register(category);
  345. }
  346. vcos_mutex_unlock(&lock);
  347. /* Check to see if this log level has been enabled. Look for
  348. * (<category:level>,)*
  349. *
  350. * VC_LOGLEVEL=ilcs:info,vchiq:warn
  351. */
  352. env = _VCOS_LOG_LEVEL();
  353. if (env)
  354. {
  355. do
  356. {
  357. char env_name[64];
  358. VCOS_LOG_LEVEL_T level;
  359. if (read_tok(env_name, sizeof(env_name), &env, ':') &&
  360. read_level(&level, &env, ','))
  361. {
  362. if (strcmp(env_name, name) == 0)
  363. {
  364. category->level = level;
  365. break;
  366. }
  367. }
  368. else
  369. {
  370. if (!warned_loglevel)
  371. {
  372. vcos_log("VC_LOGLEVEL format invalid at %s\n", env);
  373. warned_loglevel = 1;
  374. }
  375. return;
  376. }
  377. } while (env[0] != '\0');
  378. }
  379. vcos_log_info( "Registered log category '%s' with level %s",
  380. category->name,
  381. vcos_log_level_to_string( category->level ));
  382. }
  383. void vcos_log_unregister(VCOS_LOG_CAT_T *category)
  384. {
  385. VCOS_LOG_CAT_T **pcat;
  386. if (!REGISTER_CATEGORIES)
  387. return;
  388. vcos_mutex_lock(&lock);
  389. category->refcount--;
  390. if (category->refcount == 0)
  391. {
  392. pcat = &vcos_logging_categories;
  393. while (*pcat != category)
  394. {
  395. if (!*pcat)
  396. break; /* possibly deregistered twice? */
  397. if ((*pcat)->next == NULL)
  398. {
  399. vcos_assert(0); /* already removed! */
  400. vcos_mutex_unlock(&lock);
  401. return;
  402. }
  403. pcat = &(*pcat)->next;
  404. }
  405. if (*pcat)
  406. *pcat = category->next;
  407. vcos_log_platform_unregister(category);
  408. }
  409. vcos_mutex_unlock(&lock);
  410. }
  411. VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void)
  412. {
  413. return &dflt_log_category;
  414. }
  415. void vcos_set_log_options(const char *opt)
  416. {
  417. (void)opt;
  418. }
  419. void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
  420. const char *label,
  421. uint32_t addr,
  422. const void *voidMem,
  423. size_t numBytes )
  424. {
  425. const uint8_t *mem = (const uint8_t *)voidMem;
  426. size_t offset;
  427. char lineBuf[ 100 ];
  428. char *s;
  429. while ( numBytes > 0 )
  430. {
  431. s = lineBuf;
  432. for ( offset = 0; offset < 16; offset++ )
  433. {
  434. if ( offset < numBytes )
  435. {
  436. s += vcos_snprintf( s, 4, "%02x ", mem[ offset ]);
  437. }
  438. else
  439. {
  440. s += vcos_snprintf( s, 4, " " );
  441. }
  442. }
  443. for ( offset = 0; offset < 16; offset++ )
  444. {
  445. if ( offset < numBytes )
  446. {
  447. uint8_t ch = mem[ offset ];
  448. if (( ch < ' ' ) || ( ch > '~' ))
  449. {
  450. ch = '.';
  451. }
  452. *s++ = (char)ch;
  453. }
  454. }
  455. *s++ = '\0';
  456. if (( label != NULL ) && ( *label != '\0' ))
  457. {
  458. vcos_log_impl( cat, VCOS_LOG_INFO, "%s: %08" PRIx32 ": %s", label, addr, lineBuf );
  459. }
  460. else
  461. {
  462. vcos_log_impl( cat, VCOS_LOG_INFO, "%08" PRIx32 ": %s", addr, lineBuf );
  463. }
  464. addr += 16;
  465. mem += 16;
  466. if ( numBytes > 16 )
  467. {
  468. numBytes -= 16;
  469. }
  470. else
  471. {
  472. numBytes = 0;
  473. }
  474. }
  475. }
  476. void vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...)
  477. {
  478. va_list ap;
  479. va_start(ap,fmt);
  480. vcos_vlog_impl( cat, _level, fmt, ap );
  481. va_end(ap);
  482. }
  483. void vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
  484. {
  485. vcos_vlog_impl_func( cat, _level, fmt, args );
  486. }
  487. void vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func )
  488. {
  489. if ( vlog_impl_func == NULL )
  490. {
  491. vcos_vlog_impl_func = vcos_vlog_default_impl;
  492. }
  493. else
  494. {
  495. vcos_vlog_impl_func = vlog_impl_func;
  496. }
  497. }