Add mbed-trace subtree

Next time, updating of mbed-trace is just:
```
git subtree pull --squash -m "Update mbed-trace" \
     -P features/FEATURE_COMMON_PAL/mbed-trace \
     git@github.com:ARMmbed/mbed-trace.git master
```
pull/2887/head
Seppo Takalo 2016-10-03 14:40:33 +03:00
commit 11f8ccc871
16 changed files with 1957 additions and 0 deletions

View File

@ -0,0 +1,38 @@
# Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
yotta_modules/
yotta_targets/
build/
test_coverage/
**/*.info
**/*~

View File

@ -0,0 +1,4 @@
build/*
yotta_modules/*
yotta_targets/*
test/*

View File

@ -0,0 +1,9 @@
# Hello!
We are an open source project of [ARM mbed](www.mbed.com). Contributions via [pull request](https://github.com/armmbed/mbed-client-trace/pulls), and [bug reports](https://github.com/armmbed/mbed-client-trace/issues) are welcome!
For more details please see our general [CONTRIBUTING.md](https://github.com/ARMmbed/greentea/blob/master/docs/CONTRIBUTING.md) document.
# Contributor agreement
For your pull request to be accepted, we will need you to agree to our [contributor agreement](http://developer.mbed.org/contributor_agreement/) to give us the necessary rights to use and distribute your contributions. (To click through the agreement create an account on mbed.com and log in.)
<3

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,5 @@
SRCS := $(wildcard source/*.c)
LIB := libmbed-trace.a
EXPORT_HEADERS := mbed-trace
include ../exported_rules.mk

View File

@ -0,0 +1,176 @@
# mbed-trace
A general purpose tracing abstraction library for mbed devices.
## Description
The purpose of the library is to provide a light, simple and general tracing solution for mbed devices. By default, it prints traces to `stdout` (usually, a serial port), but the output can also be redirected to other targets. The library was developed using ANSI C language, but it can be used with C++ as well. Currently, there is no C++ wrapper available, but it can be created easily on top of this library.
## Philosophy
* The library needs to be light, fast, simple and abstract.
* Dependencies must be minimal.
* The memory space required by the library is allocated at the initialization only once during the application lifetime.
* No new malloc/free are needed when running the library.
* The trace methods must be as fast as possible.
* After a trace method call, the trace function needs to release the required resources.
* A trace method call produces a single line containing `<level>`, `<group>` and `<message>`
* It must be possible to filter messages on the fly. Compile time filtering is not fully supported yet.
## Compromises
* The traces are stored as ASCII arrays in the flash memory (pretty high memory consumption). Therefore, it is not necessary to:
* encode/decode the trace messages on the fly (this may take too much CPU time) or
* have external dev-env dependencies to encode the traces compile time and an external application to decode the traces.
* The group name length is limited to four characters. This makes the lines cleaner and it is enough for most use cases for separating the module names. The group name length may not be suitable for a clean human readable format, but still four characters is enough for unique module names.
* The trace function uses `stdout` as the default output target because it goes directly to serial port when initialized.
* The trace function produces traces like: `[<levl>][grp ]: msg`. This provides an easy way to detect trace prints and separate traces from normal prints (for example with _regex_).
* This approach requires a `sprintf` implementation (`stdio.h`). The memory consumption is pretty high, but it allows an efficient way to format traces.
* The solution is not Interrupt safe. (PRs are more than welcome.)
* The solution is not Thread safe by default. Thread safety for the actual trace calls can be enabled by providing wait and release callback functions that use mutexes defined by the application.
## Examples of traces
```
[DBG ][abc ]: This is a debug message from module abc<cr><lf>
[ERR ][abc ]: Something goes wrong in module abc<cr><lf>
[WARN][br ]: Oh no, br warning occurs!<cr><lf>
[INFO][br ]: Hi there.<cr><lf>
```
## Usage
### Prerequisites
* Initialize the serial port so that `stdout` works. You can verify that the serial port works using the `printf()` function.
* if you want to redirect the traces somewhere else, see the [trace API](https://github.com/ARMmbed/mbed-trace/blob/master/mbed-trace/mbed_trace.h#L170).
* To enable the tracing API:
* With yotta: set `YOTTA_CFG_MBED_TRACE` to 1 or true. Setting the flag to 0 or false disables tracing.
* [With mbed OS 5](#enabling-the-tracing-api-in-mbed-os-5)
* By default, trace uses 1024 bytes buffer for trace lines, but you can change it by yotta with: `YOTTA_CFG_MBED_TRACE_LINE_LENGTH`.
* To disable the IPv6 conversion, set `YOTTA_CFG_MBED_TRACE_FEA_IPV6 = 0`.
* If thread safety is needed, configure the wait and release callback functions before initialization to enable the protection. Usually, this needs to be done only once in the application's lifetime.
* Call the trace initialization (`mbed_trace_init`) once before using any other APIs. It allocates the trace buffer and initializes the internal variables.
* Define `TRACE_GROUP` in your source code (not in the header!) to use traces. It is a 1-4 characters long char-array (for example `#define TRACE_GROUP "APPL"`). This will be printed on every trace line.
### Enabling the tracing API in mbed OS 5
* Add the feature COMMON_PAL into the build
* Set `MBED_CONF_MBED_TRACE_ENABLE` to 1 or true
To do so, add the following to your mbed_app.json:
```json
{
"target_overrides": {
"*": {
"target.features_add": ["COMMON_PAL"],
"mbed-trace.enable": 1
}
}
}
```
Don't forget to fulfill the other [prerequisites](#prerequisites)!
([Click here for more information on the configuration system](https://github.com/ARMmbed/mbed-os/blob/master/docs/config_system.md))
### Traces
When you want to print traces, use the `tr_<level>` macros. The macros behave like `printf()`. For example, `tr_debug("hello %s", "trace")` produces the following trace line: `[DBG ][APPL] hello trace<cr><lf>`.
Available levels:
* debug
* warning
* error
* info
* cmdline (special behavior, should not be used)
For the thread safety, set the mutex wait and release functions. You need do this before the initialization to have the functions available right away:
```c
mbed_trace_mutex_wait_function_set(my_mutex_wait);
mbed_trace_mutex_release_function_set(my_mutex_release);
```
Initialization (once in application's lifetime):
```c
int mbed_trace_init(void);
```
Set the output function, `printf` by default:
```c
mbed_trace_print_function_set(printf)
```
### Helping functions
The purpose of the helping functions is to provide simple conversions, for example from an array to C string, so that you can print everything to single trace line. They must be called inside the actual trace calls, for example:
```
tr_debug("My IP6 address: %s", mbed_trace_ipv6(addr));
```
Available conversion functions:
```
char *mbed_trace_ipv6(const void *addr_ptr)
char *mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len)
char *mbed_trace_array(const uint8_t *buf, uint16_t len)
```
See more in [mbed_trace.h](https://github.com/ARMmbed/mbed-trace/blob/master/mbed-trace/mbed_trace.h).
## Usage example:
```c++
#define YOTTA_CFG_MBED_TRACE 1 //this can be defined also in the yotta configuration file config.json
#include "mbed-trace/mbed_trace.h"
#define TRACE_GROUP "main"
// These are necessary only if thread safety is needed
static Mutex MyMutex;
static void my_mutex_wait()
{
MyMutex.lock();
}
static void my_mutex_release()
{
MyMutex.unlock();
}
int main(void){
mbed_trace_mutex_wait_function_set( my_mutex_wait ); // only if thread safety is needed
mbed_trace_mutex_release_function_set( my_mutex_release ); // only if thread safety is needed
mbed_trace_init(); // initialize the trace library
tr_debug("this is debug msg"); //-> "[DBG ][main]: this is a debug msg"
tr_err("this is error msg"); //-> "[ERR ][main]: this is an error msg"
tr_warn("this is warning msg"); //-> "[WARN][main]: this is a warning msg"
tr_info("this is info msg"); //-> "[INFO][main]: this is an info msg"
char arr[] = {30, 31, 32};
tr_debug("printing array: %s", mbed_trace_array(arr, 3)); //-> "[DBG ][main]: printing array: 01:02:03"
return 0;
}
```
## Unit tests
To run unit tests:
* In Linux
```
yotta target x86-linux-native
yotta test mbed_trace_test
```
* In Windows
```
yotta target x86-windows-native
yotta test mbed_trace_test
```

View File

@ -0,0 +1,403 @@
/*
* Copyright (c) 2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file mbed_trace.h
* Trace interface for MbedOS applications.
* This file provide simple but flexible way to handle software traces.
* Trace library are abstract layer, which use stdout (printf) by default,
* but outputs can be easily redirect to custom function, for example to
* store traces to memory or other interfaces.
*
* usage example:
* \code(main.c:)
* #include "mbed_trace.h"
* #define TRACE_GROUP "main"
*
* int main(void){
* mbed_trace_init(); // initialize trace library
* tr_debug("this is debug msg"); //print debug message to stdout: "[DBG]
* tr_err("this is error msg");
* tr_warn("this is warning msg");
* tr_info("this is info msg");
* return 0;
* }
* \endcode
* Activate with compiler flag: YOTTA_CFG_MBED_TRACE
* Configure trace line buffer size with compiler flag: YOTTA_CFG_MBED_TRACE_LINE_LENGTH. Default length: 1024.
*
*/
#ifndef MBED_TRACE_H_
#define MBED_TRACE_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef YOTTA_CFG
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#else
#include "ns_types.h"
#endif
#include <stdarg.h>
#ifndef YOTTA_CFG_MBED_TRACE
#define YOTTA_CFG_MBED_TRACE 0
#endif
#ifndef YOTTA_CFG_MBED_TRACE_FEA_IPV6
#define YOTTA_CFG_MBED_TRACE_FEA_IPV6 1
#endif
#ifndef MBED_CONF_MBED_TRACE_ENABLE
#define MBED_CONF_MBED_TRACE_ENABLE 0
#endif
/** 3 upper bits are trace modes related,
and 5 lower bits are trace level configuration */
/** Config mask */
#define TRACE_MASK_CONFIG 0xE0
/** Trace level mask */
#define TRACE_MASK_LEVEL 0x1F
/** plain trace data instead of "headers" */
#define TRACE_MODE_PLAIN 0x80
/** color mode */
#define TRACE_MODE_COLOR 0x40
/** Use print CR before trace line */
#define TRACE_CARRIAGE_RETURN 0x20
/** used to activate all trace levels */
#define TRACE_ACTIVE_LEVEL_ALL 0x1F
/** print all traces same as above */
#define TRACE_ACTIVE_LEVEL_DEBUG 0x1f
/** print info,warn and error traces */
#define TRACE_ACTIVE_LEVEL_INFO 0x0f
/** print warn and error traces */
#define TRACE_ACTIVE_LEVEL_WARN 0x07
/** print only error trace */
#define TRACE_ACTIVE_LEVEL_ERROR 0x03
/** print only cmd line data */
#define TRACE_ACTIVE_LEVEL_CMD 0x01
/** trace nothing */
#define TRACE_ACTIVE_LEVEL_NONE 0x00
/** this print is some deep information for debug purpose */
#define TRACE_LEVEL_DEBUG 0x10
/** Info print, for general purpose prints */
#define TRACE_LEVEL_INFO 0x08
/** warning prints, which shouldn't causes any huge problems */
#define TRACE_LEVEL_WARN 0x04
/** Error prints, which causes probably problems, e.g. out of mem. */
#define TRACE_LEVEL_ERROR 0x02
/** special level for cmdline. Behaviours like "plain mode" */
#define TRACE_LEVEL_CMD 0x01
//usage macros:
#define tr_info(...) mbed_tracef(TRACE_LEVEL_INFO, TRACE_GROUP, __VA_ARGS__) //!< Print info message
#define tr_debug(...) mbed_tracef(TRACE_LEVEL_DEBUG, TRACE_GROUP, __VA_ARGS__) //!< Print debug message
#define tr_warning(...) mbed_tracef(TRACE_LEVEL_WARN, TRACE_GROUP, __VA_ARGS__) //!< Print warning message
#define tr_warn(...) mbed_tracef(TRACE_LEVEL_WARN, TRACE_GROUP, __VA_ARGS__) //!< Alternative warning message
#define tr_error(...) mbed_tracef(TRACE_LEVEL_ERROR, TRACE_GROUP, __VA_ARGS__) //!< Print Error Message
#define tr_err(...) mbed_tracef(TRACE_LEVEL_ERROR, TRACE_GROUP, __VA_ARGS__) //!< Alternative error message
#define tr_cmdline(...) mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, __VA_ARGS__) //!< Special print for cmdline. See more from TRACE_LEVEL_CMD -level
//aliases for the most commonly used functions and the helper functions
#define tracef(dlevel, grp, ...) mbed_tracef(dlevel, grp, __VA_ARGS__) //!< Alias for mbed_tracef()
#define vtracef(dlevel, grp, fmt, ap) mbed_vtracef(dlevel, grp, fmt, ap) //!< Alias for mbed_vtracef()
#define tr_array(buf, len) mbed_trace_array(buf, len) //!< Alias for mbed_trace_array()
#define tr_ipv6(addr_ptr) mbed_trace_ipv6(addr_ptr) //!< Alias for mbed_trace_ipv6()
#define tr_ipv6_prefix(prefix, prefix_len) mbed_trace_ipv6_prefix(prefix, prefix_len) //!< Alias for mbed_trace_ipv6_prefix()
#define trace_array(buf, len) mbed_trace_array(buf, len) //!< Alias for mbed_trace_array()
#define trace_ipv6(addr_ptr) mbed_trace_ipv6(addr_ptr) //!< Alias for mbed_trace_ipv6()
#define trace_ipv6_prefix(prefix, prefix_len) mbed_trace_ipv6_prefix(prefix, prefix_len) //!< Alias for mbed_trace_ipv6_prefix()
/**
* Allow specification of default TRACE_GROUP to be used if not specified by application
*/
#ifndef TRACE_GROUP
#ifdef YOTTA_CFG_MBED_TRACE_GROUP
#define TRACE_GROUP_STR_HELPER(x) #x
#define TRACE_GROUP_STR(x) TRACE_GROUP_STR_HELPER(x)
#define TRACE_GROUP TRACE_GROUP_STR(YOTTA_CFG_MBED_TRACE_GROUP)
#endif
#endif
/**
* Initialize trace functionality
* @return 0 when all success, otherwise non zero
*/
int mbed_trace_init( void );
/**
* Free trace memory
*/
void mbed_trace_free( void );
/**
* Resize buffers (line / tmp ) sizes
* @param lineLength new maximum length for trace line (0 = do no resize)
* @param tmpLength new maximum length for trace tmp buffer (used for trace_array, etc) (0 = do no resize)
*/
void mbed_trace_buffer_sizes(int lineLength, int tmpLength);
/**
* Set trace configurations
* Possible parameters:
*
* TRACE_MODE_COLOR
* TRACE_MODE_PLAIN (this exclude color mode)
* TRACE_CARRIAGE_RETURN (print CR before trace line)
*
* TRACE_ACTIVE_LEVEL_ALL - to activate all trace levels
* or TRACE_ACTIVE_LEVEL_DEBUG (alternative)
* TRACE_ACTIVE_LEVEL_INFO
* TRACE_ACTIVE_LEVEL_WARN
* TRACE_ACTIVE_LEVEL_ERROR
* TRACE_ACTIVE_LEVEL_CMD
* TRACE_LEVEL_NONE - to deactivate all traces
*
* @param config Byte size Bit-mask. Bits are descripted above.
* usage e.g.
* @code
* mbed_trace_config_set( TRACE_ACTIVE_LEVEL_ALL|TRACE_MODE_COLOR );
* @endcode
*/
void mbed_trace_config_set(uint8_t config);
/** get trace configurations
* @return trace configuration byte
*/
uint8_t mbed_trace_config_get(void);
/**
* Set trace prefix function
* pref_f -function return string with null terminated
* Can be used for e.g. time string
* e.g.
* char* trace_time(){ return "rtc-time-in-string"; }
* mbed_trace_prefix_function_set( &trace_time );
*/
void mbed_trace_prefix_function_set( char* (*pref_f)(size_t) );
/**
* Set trace suffix function
* suffix -function return string with null terminated
* Can be used for e.g. time string
* e.g.
* char* trace_suffix(){ return " END"; }
* mbed_trace_suffix_function_set( &trace_suffix );
*/
void mbed_trace_suffix_function_set(char* (*suffix_f)(void) );
/**
* Set trace print function
* By default, trace module print using printf() function,
* but with this you can write own print function,
* for e.g. to other IO device.
*/
void mbed_trace_print_function_set( void (*print_f)(const char*) );
/**
* Set trace print function for tr_cmdline()
*/
void mbed_trace_cmdprint_function_set( void (*printf)(const char*) );
/**
* Set trace mutex wait function
* By default, trace calls are not thread safe.
* If thread safety is required this can be used to set a callback function that will be called before each trace call.
* The specific implementation is up to the application developer, but the mutex must count so it can
* be acquired from a single thread repeatedly.
*/
void mbed_trace_mutex_wait_function_set(void (*mutex_wait_f)(void));
/**
* Set trace mutex release function
* By default, trace calls are not thread safe.
* If thread safety is required this can be used to set a callback function that will be called before returning from
* each trace call. The specific implementation is up to the application developer, but the mutex must count so it can
* be acquired from a single thread repeatedly.
*/
void mbed_trace_mutex_release_function_set(void (*mutex_release_f)(void));
/**
* When trace group contains text in filters,
* trace print will be ignored.
* e.g.:
* mbed_trace_exclude_filters_set("mygr");
* mbed_tracef(TRACE_ACTIVE_LEVEL_DEBUG, "ougr", "This is not printed");
*/
void mbed_trace_exclude_filters_set(char* filters);
/** get trace exclude filters
*/
const char* mbed_trace_exclude_filters_get(void);
/**
* When trace group contains text in filter,
* trace will be printed.
* e.g.:
* set_trace_include_filters("mygr");
* mbed_tracef(TRACE_ACTIVE_LEVEL_DEBUG, "mygr", "Hi There");
* mbed_tracef(TRACE_ACTIVE_LEVEL_DEBUG, "grp2", "This is not printed");
*/
void mbed_trace_include_filters_set(char* filters);
/** get trace include filters
*/
const char* mbed_trace_include_filters_get(void);
/**
* General trace function
* This should be used every time when user want to print out something important thing
* Usage e.g.
* mbed_tracef( TRACE_LEVEL_INFO, "mygr", "Hello world!");
*
* @param dlevel debug level
* @param grp trace group
* @param fmt trace format (like printf)
* @param ... variable arguments related to fmt
*/
#if defined(__GNUC__) || defined(__CC_ARM)
void mbed_tracef(uint8_t dlevel, const char* grp, const char *fmt, ...) __attribute__ ((__format__(__printf__, 3, 4)));
#else
void mbed_tracef(uint8_t dlevel, const char* grp, const char *fmt, ...);
#endif
/**
* General trace function
* This should be used every time when user want to print out something important thing
* and vprintf functionality is desired
* Usage e.g.
* va_list ap;
* va_start (ap, fmt);
* mbed_vtracef( TRACE_LEVEL_INFO, "mygr", fmt, ap );
* va_end (ap);
*
* @param dlevel debug level
* @param grp trace group
* @param fmt trace format (like vprintf)
* @param ap variable arguments list (like vprintf)
*/
#if defined(__GNUC__) || defined(__CC_ARM)
void mbed_vtracef(uint8_t dlevel, const char* grp, const char *fmt, va_list ap) __attribute__ ((__format__(__printf__, 3, 0)));
#else
void mbed_vtracef(uint8_t dlevel, const char* grp, const char *fmt, va_list ap);
#endif
/**
* Get last trace from buffer
*/
const char* mbed_trace_last(void);
#if YOTTA_CFG_MBED_TRACE_FEA_IPV6 == 1
/**
* mbed_tracef helping function for convert ipv6
* table to human readable string.
* usage e.g.
* char ipv6[16] = {...}; // ! array length is 16 bytes !
* mbed_tracef(TRACE_LEVEL_INFO, "mygr", "ipv6 addr: %s", mbed_trace_ipv6(ipv6));
*
* @param add_ptr IPv6 Address pointer
* @return temporary buffer where ipv6 is in string format
*/
char* mbed_trace_ipv6(const void *addr_ptr);
/**
* mbed_tracef helping function for print ipv6 prefix
* usage e.g.
* char ipv6[16] = {...}; // ! array length is 16 bytes !
* mbed_tracef(TRACE_LEVEL_INFO, "mygr", "ipv6 addr: %s", mbed_trace_ipv6_prefix(ipv6, 4));
*
* @param prefix IPv6 Address pointer
* @param prefix_len prefix length
* @return temporary buffer where ipv6 is in string format
*/
char* mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len);
#endif
/**
* mbed_tracef helping function for convert hex-array to string.
* usage e.g.
* char myarr[] = {0x10, 0x20};
* mbed_tracef(TRACE_LEVEL_INFO, "mygr", "arr: %s", mbed_trace_array(myarr, 2));
*
* @param buf hex array pointer
* @param len buffer length
* @return temporary buffer where string copied
* if array as string not fit to temp buffer, this function write '*' as last character,
* which indicate that buffer is too small for array.
*/
char* mbed_trace_array(const uint8_t* buf, uint16_t len);
#ifdef __cplusplus
}
#endif
#endif /* MBED_TRACE_H_ */
/* These macros are outside the inclusion guard so they will be re-evaluated for every inclusion of the header.
* If tracing is disabled, the dummies will hide the real functions. The real functions can still be reached by
* surrounding the name of the function with brackets, e.g. "(mbed_tracef)(dlevel, grp, "like so");"
* */
#if defined(FEA_TRACE_SUPPORT) || MBED_CONF_MBED_TRACE_ENABLE || YOTTA_CFG_MBED_TRACE || (defined(YOTTA_CFG) && !defined(NDEBUG))
// Make sure FEA_TRACE_SUPPORT is always set whenever traces are enabled.
#ifndef FEA_TRACE_SUPPORT
#define FEA_TRACE_SUPPORT
#endif
// undefine dummies, revealing the real functions
#undef MBED_TRACE_DUMMIES_DEFINED
#undef mbed_trace_init
#undef mbed_trace_free
#undef mbed_trace_buffer_sizes
#undef mbed_trace_config_set
#undef mbed_trace_config_get
#undef mbed_trace_prefix_function_set
#undef mbed_trace_suffix_function_set
#undef mbed_trace_print_function_set
#undef mbed_trace_cmdprint_function_set
#undef mbed_trace_mutex_wait_function_set
#undef mbed_trace_mutex_release_function_set
#undef mbed_trace_exclude_filters_set
#undef mbed_trace_exclude_filters_get
#undef mbed_trace_include_filters_set
#undef mbed_trace_include_filters_get
#undef mbed_tracef
#undef mbed_vtracef
#undef mbed_trace_last
#undef mbed_trace_ipv6
#undef mbed_trace_ipv6_prefix
#undef mbed_trace_array
#elif !defined(MBED_TRACE_DUMMIES_DEFINED)
// define dummies, hiding the real functions
#define MBED_TRACE_DUMMIES_DEFINED
#define mbed_trace_init(...) ((void) 0)
#define mbed_trace_free(...) ((void) 0)
#define mbed_trace_buffer_sizes(...) ((void) 0)
#define mbed_trace_config_set(...) ((void) 0)
#define mbed_trace_config_get(...) ((uint8_t) 0)
#define mbed_trace_prefix_function_set(...) ((void) 0)
#define mbed_trace_suffix_function_set(...) ((void) 0)
#define mbed_trace_print_function_set(...) ((void) 0)
#define mbed_trace_cmdprint_function_set(...) ((void) 0)
#define mbed_trace_mutex_wait_function_set(...) ((void) 0)
#define mbed_trace_mutex_release_function_set(...) ((void) 0)
#define mbed_trace_exclude_filters_set(...) ((void) 0)
#define mbed_trace_exclude_filters_get(...) ((const char *) 0)
#define mbed_trace_include_filters_set(...) ((void) 0)
#define mbed_trace_include_filters_get(...) ((const char *) 0)
#define mbed_trace_last(...) ((const char *) 0)
#define mbed_tracef(...) ((void) 0)
#define mbed_vtracef(...) ((void) 0)
/**
* These helper functions accumulate strings in a buffer that is only flushed by actual trace calls. Using these
* functions outside trace calls could cause the buffer to overflow.
*/
#define mbed_trace_ipv6(...) dont_use_trace_helpers_outside_trace_calls
#define mbed_trace_ipv6_prefix(...) dont_use_trace_helpers_outside_trace_calls
#define mbed_trace_array(...) dont_use_trace_helpers_outside_trace_calls
#endif /* FEA_TRACE_SUPPORT */

View File

@ -0,0 +1,9 @@
{
"name": "mbed-trace",
"config": {
"enable": {
"help": "Used to globally enable traces.",
"value": null
}
}
}

View File

@ -0,0 +1,38 @@
{
"name": "mbed-trace",
"version": "1.2.1",
"description": "Trace library for mbed devices",
"keywords": [
"trace",
"debug",
"library",
"client",
"mbedOS",
"mbed"
],
"author": "Jussi Vatjus-Anttila",
"repository": {
"url": "https://github.com/ARMmbed/mbed-trace.git",
"type": "git"
},
"homepage": "https://github.com/ARMmbed/mbed-trace",
"licenses": [
{
"url": "https://spdx.org/licenses/Apache-2.0",
"type": "Apache-2.0"
}
],
"testTargetDependencies": {
"x86-linux-native": {
"cpputest": "ARMmbed/cpputest",
"nanostack-libservice": "^3.6.0"
},
"x86-windows-native": {
"cpputest": "ARMmbed/cpputest",
"nanostack-libservice": "^3.6.0"
}
},
"dependencies": {
"nanostack-libservice": "^3.6.0"
}
}

View File

@ -0,0 +1,12 @@
if(DEFINED TARGET_LIKE_X86_LINUX_NATIVE)
add_library( mbed-trace
mbed_trace.c
)
add_definitions("-g -O0 -fprofile-arcs -ftest-coverage")
target_link_libraries(mbed-trace gcov nanostack-libservice)
else()
add_library( mbed-trace
mbed_trace.c
)
target_link_libraries(mbed-trace nanostack-libservice)
endif()

View File

@ -0,0 +1,562 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#ifndef YOTTA_CFG_MBED_TRACE
#define YOTTA_CFG_MBED_TRACE 1
#define YOTTA_CFG_MBED_TRACE_FEA_IPV6 1
#endif
#include "mbed-trace/mbed_trace.h"
#if YOTTA_CFG_MBED_TRACE_FEA_IPV6 == 1
#include "mbed-client-libservice/ip6string.h"
#include "mbed-client-libservice/common_functions.h"
#endif
#if defined(YOTTA_CFG_MBED_TRACE_MEM)
#define MBED_TRACE_MEM_INCLUDE YOTTA_CFG_MBED_TRACE_MEM_INCLUDE
#define MBED_TRACE_MEM_ALLOC YOTTA_CFG_MBED_TRACE_MEM_ALLOC
#define MBED_TRACE_MEM_FREE YOTTA_CFG_MBED_TRACE_MEM_FREE
#else /* YOTTA_CFG_MEMLIB */
// Default options
#ifndef MBED_TRACE_MEM_INCLUDE
#define MBED_TRACE_MEM_INCLUDE <stdlib.h>
#endif
#include MBED_TRACE_MEM_INCLUDE
#ifndef MBED_TRACE_MEM_ALLOC
#define MBED_TRACE_MEM_ALLOC malloc
#endif
#ifndef MBED_TRACE_MEM_FREE
#define MBED_TRACE_MEM_FREE free
#endif
#endif /* YOTTA_CFG_MEMLIB */
#define VT100_COLOR_ERROR "\x1b[31m"
#define VT100_COLOR_WARN "\x1b[33m"
#define VT100_COLOR_INFO "\x1b[39m"
#define VT100_COLOR_DEBUG "\x1b[90m"
/** default max trace line size in bytes */
#ifdef YOTTA_CFG_MBED_TRACE_LINE_LENGTH
#define DEFAULT_TRACE_LINE_LENGTH YOTTA_CFG_MBED_TRACE_LINE_LENGTH
#else
#define DEFAULT_TRACE_LINE_LENGTH 1024
#endif
/** default max temporary buffer size in bytes, used in
trace_ipv6, trace_ipv6_prefix and trace_array */
#ifdef YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN
#define DEFAULT_TRACE_TMP_LINE_LEN YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN
#elif defined YOTTA_CFG_MTRACE_TMP_LINE_LEN
#warning The YOTTA_CFG_MTRACE_TMP_LINE_LEN flag is deprecated! Use YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN instead.
#define DEFAULT_TRACE_TMP_LINE_LEN YOTTA_CFG_MTRACE_TMP_LINE_LEN
#else
#define DEFAULT_TRACE_TMP_LINE_LEN 128
#endif
/** default max filters (include/exclude) length in bytes */
#define DEFAULT_TRACE_FILTER_LENGTH 24
/** default print function, just redirect str to printf */
static void mbed_trace_realloc( char **buffer, int *length_ptr, int new_length);
static void mbed_trace_default_print(const char *str);
static void mbed_trace_reset_tmp(void);
typedef struct trace_s {
/** trace configuration bits */
uint8_t trace_config;
/** exclude filters list, related group name */
char *filters_exclude;
/** include filters list, related group name */
char *filters_include;
/** Filters length */
int filters_length;
/** trace line */
char *line;
/** trace line length */
int line_length;
/** temporary data */
char *tmp_data;
/** temporary data array length */
int tmp_data_length;
/** temporary data pointer */
char *tmp_data_ptr;
/** prefix function, which can be used to put time to the trace line */
char *(*prefix_f)(size_t);
/** suffix function, which can be used to some string to the end of trace line */
char *(*suffix_f)(void);
/** print out function. Can be redirect to flash for example. */
void (*printf)(const char *);
/** print out function for TRACE_LEVEL_CMD */
void (*cmd_printf)(const char *);
/** mutex wait function which can be called to lock against a mutex. */
void (*mutex_wait_f)(void);
/** mutex release function which must be used to release the mutex locked by mutex_wait_f. */
void (*mutex_release_f)(void);
/** number of times the mutex has been locked */
int mutex_lock_count;
} trace_t;
static trace_t m_trace = {
.filters_exclude = 0,
.filters_include = 0,
.line = 0,
.tmp_data = 0,
.prefix_f = 0,
.suffix_f = 0,
.printf = 0,
.cmd_printf = 0,
.mutex_wait_f = 0,
.mutex_release_f = 0,
.mutex_lock_count = 0
};
int mbed_trace_init(void)
{
m_trace.trace_config = TRACE_MODE_COLOR | TRACE_ACTIVE_LEVEL_ALL | TRACE_CARRIAGE_RETURN;
m_trace.line_length = DEFAULT_TRACE_LINE_LENGTH;
if (m_trace.line == NULL) {
m_trace.line = MBED_TRACE_MEM_ALLOC(m_trace.line_length);
}
m_trace.tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN;
if (m_trace.tmp_data == NULL) {
m_trace.tmp_data = MBED_TRACE_MEM_ALLOC(m_trace.tmp_data_length);
}
m_trace.tmp_data_ptr = m_trace.tmp_data;
m_trace.filters_length = DEFAULT_TRACE_FILTER_LENGTH;
if (m_trace.filters_exclude == NULL) {
m_trace.filters_exclude = MBED_TRACE_MEM_ALLOC(m_trace.filters_length);
}
if (m_trace.filters_include == NULL) {
m_trace.filters_include = MBED_TRACE_MEM_ALLOC(m_trace.filters_length);
}
if (m_trace.line == NULL ||
m_trace.tmp_data == NULL ||
m_trace.filters_exclude == NULL ||
m_trace.filters_include == NULL) {
//memory allocation fail
mbed_trace_free();
return -1;
}
memset(m_trace.tmp_data, 0, m_trace.tmp_data_length);
memset(m_trace.filters_exclude, 0, m_trace.filters_length);
memset(m_trace.filters_include, 0, m_trace.filters_length);
memset(m_trace.line, 0, m_trace.line_length);
m_trace.prefix_f = 0;
m_trace.suffix_f = 0;
m_trace.printf = mbed_trace_default_print;
m_trace.cmd_printf = 0;
return 0;
}
void mbed_trace_free(void)
{
MBED_TRACE_MEM_FREE(m_trace.line);
m_trace.line_length = 0;
m_trace.line = 0;
MBED_TRACE_MEM_FREE(m_trace.tmp_data);
m_trace.tmp_data = 0;
m_trace.tmp_data_ptr = 0;
MBED_TRACE_MEM_FREE(m_trace.filters_exclude);
m_trace.filters_exclude = 0;
MBED_TRACE_MEM_FREE(m_trace.filters_include);
m_trace.filters_include = 0;
m_trace.filters_length = 0;
m_trace.prefix_f = 0;
m_trace.suffix_f = 0;
m_trace.printf = mbed_trace_default_print;
m_trace.cmd_printf = 0;
m_trace.mutex_wait_f = 0;
m_trace.mutex_release_f = 0;
m_trace.mutex_lock_count = 0;
}
static void mbed_trace_realloc( char **buffer, int *length_ptr, int new_length)
{
MBED_TRACE_MEM_FREE(*buffer);
*buffer = MBED_TRACE_MEM_ALLOC(new_length);
*length_ptr = new_length;
}
void mbed_trace_buffer_sizes(int lineLength, int tmpLength)
{
if( lineLength > 0 ) {
mbed_trace_realloc( &(m_trace.line), &m_trace.line_length, lineLength );
}
if( tmpLength > 0 ) {
mbed_trace_realloc( &(m_trace.tmp_data), &m_trace.tmp_data_length, tmpLength);
mbed_trace_reset_tmp();
}
}
void mbed_trace_config_set(uint8_t config)
{
m_trace.trace_config = config;
}
uint8_t mbed_trace_config_get(void)
{
return m_trace.trace_config;
}
void mbed_trace_prefix_function_set(char *(*pref_f)(size_t))
{
m_trace.prefix_f = pref_f;
}
void mbed_trace_suffix_function_set(char *(*suffix_f)(void))
{
m_trace.suffix_f = suffix_f;
}
void mbed_trace_print_function_set(void (*printf)(const char *))
{
m_trace.printf = printf;
}
void mbed_trace_cmdprint_function_set(void (*printf)(const char *))
{
m_trace.cmd_printf = printf;
}
void mbed_trace_mutex_wait_function_set(void (*mutex_wait_f)(void))
{
m_trace.mutex_wait_f = mutex_wait_f;
}
void mbed_trace_mutex_release_function_set(void (*mutex_release_f)(void))
{
m_trace.mutex_release_f = mutex_release_f;
}
void mbed_trace_exclude_filters_set(char *filters)
{
if (filters) {
(void)strncpy(m_trace.filters_exclude, filters, m_trace.filters_length);
} else {
m_trace.filters_exclude[0] = 0;
}
}
const char *mbed_trace_exclude_filters_get(void)
{
return m_trace.filters_exclude;
}
const char *mbed_trace_include_filters_get(void)
{
return m_trace.filters_include;
}
void mbed_trace_include_filters_set(char *filters)
{
if (filters) {
(void)strncpy(m_trace.filters_include, filters, m_trace.filters_length);
} else {
m_trace.filters_include[0] = 0;
}
}
static int8_t mbed_trace_skip(int8_t dlevel, const char *grp)
{
if (dlevel >= 0 && grp != 0) {
// filter debug prints only when dlevel is >0 and grp is given
/// @TODO this could be much better..
if (m_trace.filters_exclude[0] != '\0' &&
strstr(m_trace.filters_exclude, grp) != 0) {
//grp was in exclude list
return 1;
}
if (m_trace.filters_include[0] != '\0' &&
strstr(m_trace.filters_include, grp) == 0) {
//grp was in include list
return 1;
}
}
return 0;
}
static void mbed_trace_default_print(const char *str)
{
puts(str);
}
void mbed_tracef(uint8_t dlevel, const char *grp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
mbed_vtracef(dlevel, grp, fmt, ap);
va_end(ap);
}
void mbed_vtracef(uint8_t dlevel, const char* grp, const char *fmt, va_list ap)
{
if ( m_trace.mutex_wait_f ) {
m_trace.mutex_wait_f();
m_trace.mutex_lock_count++;
}
if (NULL == m_trace.line) {
goto end;
}
m_trace.line[0] = 0; //by default trace is empty
if (mbed_trace_skip(dlevel, grp) || fmt == 0 || grp == 0 || !m_trace.printf) {
//return tmp data pointer back to the beginning
mbed_trace_reset_tmp();
goto end;
}
if ((m_trace.trace_config & TRACE_MASK_LEVEL) & dlevel) {
bool color = (m_trace.trace_config & TRACE_MODE_COLOR) != 0;
bool plain = (m_trace.trace_config & TRACE_MODE_PLAIN) != 0;
bool cr = (m_trace.trace_config & TRACE_CARRIAGE_RETURN) != 0;
int retval = 0, bLeft = m_trace.line_length;
char *ptr = m_trace.line;
if (plain == true || dlevel == TRACE_LEVEL_CMD) {
//add trace data
retval = vsnprintf(ptr, bLeft, fmt, ap);
if (dlevel == TRACE_LEVEL_CMD && m_trace.cmd_printf) {
m_trace.cmd_printf(m_trace.line);
m_trace.cmd_printf("\n");
} else {
//print out whole data
m_trace.printf(m_trace.line);
}
} else {
if (color) {
if (cr) {
retval = snprintf(ptr, bLeft, "\r\x1b[2K");
if (retval >= bLeft) {
retval = 0;
}
if (retval > 0) {
ptr += retval;
bLeft -= retval;
}
}
if (bLeft > 0) {
//include color in ANSI/VT100 escape code
switch (dlevel) {
case (TRACE_LEVEL_ERROR):
retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_ERROR);
break;
case (TRACE_LEVEL_WARN):
retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_WARN);
break;
case (TRACE_LEVEL_INFO):
retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_INFO);
break;
case (TRACE_LEVEL_DEBUG):
retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_DEBUG);
break;
default:
color = 0; //avoid unneeded color-terminate code
retval = 0;
break;
}
if (retval >= bLeft) {
retval = 0;
}
if (retval > 0 && color) {
ptr += retval;
bLeft -= retval;
}
}
}
if (bLeft > 0 && m_trace.prefix_f) {
//find out length of body
size_t sz = 0;
va_list ap2;
va_copy(ap2, ap);
sz = vsnprintf(NULL, 0, fmt, ap2) + retval + (retval ? 4 : 0);
va_end(ap2);
//add prefix string
retval = snprintf(ptr, bLeft, "%s", m_trace.prefix_f(sz));
if (retval >= bLeft) {
retval = 0;
}
if (retval > 0) {
ptr += retval;
bLeft -= retval;
}
}
if (bLeft > 0) {
//add group tag
switch (dlevel) {
case (TRACE_LEVEL_ERROR):
retval = snprintf(ptr, bLeft, "[ERR ][%-4s]: ", grp);
break;
case (TRACE_LEVEL_WARN):
retval = snprintf(ptr, bLeft, "[WARN][%-4s]: ", grp);
break;
case (TRACE_LEVEL_INFO):
retval = snprintf(ptr, bLeft, "[INFO][%-4s]: ", grp);
break;
case (TRACE_LEVEL_DEBUG):
retval = snprintf(ptr, bLeft, "[DBG ][%-4s]: ", grp);
break;
default:
retval = snprintf(ptr, bLeft, " ");
break;
}
if (retval >= bLeft) {
retval = 0;
}
if (retval > 0) {
ptr += retval;
bLeft -= retval;
}
}
if (retval > 0 && bLeft > 0) {
//add trace text
retval = vsnprintf(ptr, bLeft, fmt, ap);
if (retval >= bLeft) {
retval = 0;
}
if (retval > 0) {
ptr += retval;
bLeft -= retval;
}
}
if (retval > 0 && bLeft > 0 && m_trace.suffix_f) {
//add suffix string
retval = snprintf(ptr, bLeft, "%s", m_trace.suffix_f());
if (retval >= bLeft) {
retval = 0;
}
if (retval > 0) {
ptr += retval;
bLeft -= retval;
}
}
if (retval > 0 && bLeft > 0 && color) {
//add zero color VT100 when color mode
retval = snprintf(ptr, bLeft, "\x1b[0m");
if (retval >= bLeft) {
retval = 0;
}
if (retval > 0) {
// not used anymore
//ptr += retval;
//bLeft -= retval;
}
}
//print out whole data
m_trace.printf(m_trace.line);
}
//return tmp data pointer back to the beginning
mbed_trace_reset_tmp();
}
end:
if ( m_trace.mutex_release_f ) {
while (m_trace.mutex_lock_count > 0) {
m_trace.mutex_lock_count--;
m_trace.mutex_release_f();
}
}
}
static void mbed_trace_reset_tmp(void)
{
m_trace.tmp_data_ptr = m_trace.tmp_data;
}
const char *mbed_trace_last(void)
{
return m_trace.line;
}
/* Helping functions */
#define tmp_data_left() m_trace.tmp_data_length-(m_trace.tmp_data_ptr-m_trace.tmp_data)
#if YOTTA_CFG_MBED_TRACE_FEA_IPV6 == 1
char *mbed_trace_ipv6(const void *addr_ptr)
{
/** Acquire mutex. It is released before returning from mbed_vtracef. */
if ( m_trace.mutex_wait_f ) {
m_trace.mutex_wait_f();
m_trace.mutex_lock_count++;
}
char *str = m_trace.tmp_data_ptr;
if (str == NULL) {
return "";
}
if (tmp_data_left() < 41) {
return "";
}
if (addr_ptr == NULL) {
return "<null>";
}
str[0] = 0;
m_trace.tmp_data_ptr += ip6tos(addr_ptr, str) + 1;
return str;
}
char *mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len)
{
/** Acquire mutex. It is released before returning from mbed_vtracef. */
if ( m_trace.mutex_wait_f ) {
m_trace.mutex_wait_f();
m_trace.mutex_lock_count++;
}
char *str = m_trace.tmp_data_ptr;
if (str == NULL) {
return "";
}
if (tmp_data_left() < 45) {
return "";
}
if ((prefix_len != 0 && prefix == NULL) || prefix_len > 128) {
return "<err>";
}
m_trace.tmp_data_ptr += ip6_prefix_tos(prefix, prefix_len, str) + 1;
return str;
}
#endif //YOTTA_CFG_MBED_TRACE_FEA_IPV6
char *mbed_trace_array(const uint8_t *buf, uint16_t len)
{
/** Acquire mutex. It is released before returning from mbed_vtracef. */
if ( m_trace.mutex_wait_f ) {
m_trace.mutex_wait_f();
m_trace.mutex_lock_count++;
}
int i, bLeft = tmp_data_left();
char *str, *wptr;
str = m_trace.tmp_data_ptr;
if (str == NULL || bLeft == 0) {
return "";
}
if (buf == NULL) {
return "<null>";
}
wptr = str;
wptr[0] = 0;
const uint8_t *ptr = buf;
char overflow = 0;
for (i = 0; i < len; i++) {
if (bLeft <= 3) {
overflow = 1;
break;
}
int retval = snprintf(wptr, bLeft, "%02x:", *ptr++);
if (retval <= 0 || retval > bLeft) {
break;
}
bLeft -= retval;
wptr += retval;
}
if (wptr > str) {
if( overflow ) {
// replace last character as 'star',
// which indicate buffer len is not enough
*(wptr - 1) = '*';
} else {
//null to replace last ':' character
*(wptr - 1) = 0;
}
}
m_trace.tmp_data_ptr = wptr;
return str;
}

View File

@ -0,0 +1,22 @@
# only build tests on targets that declare they are like posix
if(DEFINED TARGET_LIKE_X86_WINDOWS_NATIVE OR DEFINED TARGET_LIKE_X86_LINUX_NATIVE)
# describe the test executable
add_executable(mbed_trace_test EXCLUDE_FROM_ALL Test.cpp stubs/ip6tos_stub.c)
include_directories("../yotta_modules/cpputest" "./stubs")
# describe what the test executable needs to link with
target_link_libraries(mbed_trace_test "mbed-trace" cpputest)
# describe what is actual test binary
if(DEFINED TARGET_LIKE_X86_WINDOWS_NATIVE)
add_test(mbed_trace_test "build/x86-windows-native/test/mbed_trace_test")
add_dependencies(all_tests mbed_trace_test)
endif()
if(DEFINED TARGET_LIKE_X86_LINUX_NATIVE)
SET(TEST_EXECUTABLE "../../../build/x86-linux-native/test/mbed_trace_test")
add_test(mbed_trace_test ${TEST_EXECUTABLE})
add_dependencies(all_tests mbed_trace_test)
endif()
endif()

View File

@ -0,0 +1,431 @@
/*
* Copyright (c) 2014 ARM. All rights reserved.
*/
/**
* \file \test_libTrace\Test.c
*
* \brief Unit tests for mbed_trace
*/
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "mbed-cpputest/CppUTest/TestHarness.h"
#include "mbed-cpputest/CppUTest/SimpleString.h"
#include "mbed-cpputest/CppUTest/CommandLineTestRunner.h"
#define YOTTA_CFG_MBED_TRACE 1
#define YOTTA_CFG_MBED_TRACE_FEA_IPV6 1
#include "mbed-trace/mbed_trace.h"
#include "ip6tos_stub.h"
int main(int ac, char **av)
{
return CommandLineTestRunner::RunAllTests(ac, av);
}
static int mutex_wait_count = 0;
static int mutex_release_count = 0;
static bool check_mutex_lock_status = true;
void my_mutex_wait()
{
mutex_wait_count++;
}
void my_mutex_release()
{
mutex_release_count++;
}
char buf[1024];
#include <stdio.h>
void myprint(const char* str)
{
if ( check_mutex_lock_status ) {
CHECK( (mutex_wait_count - mutex_release_count) > 0 );
}
strcpy(buf, str);
}
TEST_GROUP(trace)
{
void setup()
{
mbed_trace_init();
mbed_trace_config_set(TRACE_MODE_PLAIN|TRACE_ACTIVE_LEVEL_ALL);
mbed_trace_print_function_set( myprint );
mbed_trace_mutex_wait_function_set( my_mutex_wait );
mbed_trace_mutex_release_function_set( my_mutex_release );
}
void teardown()
{
CHECK(mutex_wait_count == mutex_release_count); // Check the mutex count with every test
mbed_trace_free();
}
};
/* Unity test code starts */
TEST(trace, MutexNotSet)
{
mbed_trace_mutex_wait_function_set( 0 );
mbed_trace_mutex_release_function_set( 0 );
int mutex_call_count_at_entry = mutex_wait_count;
check_mutex_lock_status = false;
char expectedStr[] = "Hello hello!";
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "Hello hello!");
STRCMP_EQUAL(expectedStr, buf);
CHECK( mutex_call_count_at_entry == mutex_wait_count );
CHECK( mutex_call_count_at_entry == mutex_release_count );
mbed_trace_mutex_wait_function_set( my_mutex_wait );
mbed_trace_mutex_release_function_set( my_mutex_release );
check_mutex_lock_status = true;
}
TEST(trace, Array)
{
unsigned char longStr[200] = {0x66};
for(int i=0;i<200;i++) {longStr[i] = 0x66; }
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "%s", mbed_trace_array(longStr, 200) );
}
TEST(trace, LongString)
{
char longStr[1000] = {0x36};
for(int i=0;i<999;i++) {longStr[i] = 0x36; }
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "%s", longStr );
}
TEST(trace, TooLong)
{
#define TOO_LONG_SIZE 9400
#define TRACE_LINE_SIZE 1024
char longStr[TOO_LONG_SIZE] = {0};
for(int i=0;i<TOO_LONG_SIZE;i++) { longStr[i] = 0x36; }
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "%s", longStr );
char shouldStr[TRACE_LINE_SIZE] = "[DBG ][mygr]: ";
for(int i=14;i<TRACE_LINE_SIZE;i++) { shouldStr[i] = 0x36; }
shouldStr[TRACE_LINE_SIZE-1] = 0;
STRCMP_EQUAL(shouldStr, buf);
}
TEST(trace, BufferResize)
{
uint8_t arr[20] = {0};
memset(arr, '0', 20);
mbed_trace_buffer_sizes(0, 10);
STRCMP_EQUAL("30:30:30*", mbed_trace_array(arr, 20));
mbed_trace_buffer_sizes(0, 15);
STRCMP_EQUAL("30:30:30:30*", mbed_trace_array(arr, 20));
mbed_trace_buffer_sizes(0, 15);
STRCMP_EQUAL("30:30:30:30", mbed_trace_array(arr, 4));
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "flush buffers and locks");
}
#if YOTTA_CFG_MBED_TRACE_FEA_IPV6 == 1
ip6tos_stub_def_t ip6tos_stub; // extern variable
TEST(trace, ipv6)
{
uint8_t prefix[] = { 0x14, 0x6e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 };
int prefix_len = 64;
char expected_str1[] = "146e:a00::/64";
ip6tos_stub.output_string = "146e:a00::/64";
char *str = mbed_trace_ipv6_prefix(prefix, prefix_len);
CHECK(memcmp(ip6tos_stub.input_array, prefix, 8) == 0);
STRCMP_EQUAL(expected_str1, str);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "flush buffers and locks");
char expected_str2[] = "::/0";
ip6tos_stub.output_string = "::/0";
str = mbed_trace_ipv6_prefix(NULL, 0);
STRCMP_EQUAL(expected_str2, str);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "flush buffers and locks");
char expected_str3[] = "<err>";
str = mbed_trace_ipv6_prefix(NULL, 1);
STRCMP_EQUAL(expected_str3, str);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "flush buffers and locks");
char expected_str4[] = "<err>";
str = mbed_trace_ipv6_prefix(prefix, 200);
STRCMP_EQUAL(expected_str4, str);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "flush buffers and locks");
char expected_str5[] = "";
ip6tos_stub.output_string = "0123456789012345678901234567890123456789";
str = mbed_trace_ipv6_prefix(prefix, 64); // Fill the tmp_data buffer
str = mbed_trace_ipv6_prefix(prefix, 64);
str = mbed_trace_ipv6_prefix(prefix, 64);
str = mbed_trace_ipv6_prefix(prefix, 64);
STRCMP_EQUAL(expected_str5, str);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "flush buffers and locks");
}
TEST(trace, active_level_all_ipv6)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
uint8_t arr[] = { 0x20, 0x01, 0xd, 0xb8, 0,0,0,0,0,1,0,0,0,0,0,1 };
ip6tos_stub.output_string = "2001:db8::1:0:0:1";
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "my addr: %s", mbed_trace_ipv6(arr));
CHECK(memcmp(ip6tos_stub.input_array, arr, 16) == 0);
STRCMP_EQUAL("[DBG ][mygr]: my addr: 2001:db8::1:0:0:1", buf);
}
#endif //YOTTA_CFG_MBED_TRACE_FEA_IPV6
TEST(trace, config_change)
{
mbed_trace_config_set(TRACE_MODE_COLOR|TRACE_ACTIVE_LEVEL_ALL);
CHECK(mbed_trace_config_get() == TRACE_MODE_COLOR|TRACE_ACTIVE_LEVEL_ALL);
mbed_trace_config_set(TRACE_MODE_PLAIN|TRACE_ACTIVE_LEVEL_NONE);
CHECK(mbed_trace_config_get() == TRACE_MODE_PLAIN|TRACE_ACTIVE_LEVEL_NONE);
mbed_trace_config_set(TRACE_MODE_PLAIN|TRACE_ACTIVE_LEVEL_ALL);
CHECK(mbed_trace_config_get() == TRACE_MODE_PLAIN|TRACE_ACTIVE_LEVEL_ALL);
}
TEST(trace, active_level_all_color)
{
mbed_trace_config_set(TRACE_MODE_COLOR|TRACE_ACTIVE_LEVEL_ALL);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hello");
STRCMP_EQUAL("\x1b[90m[DBG ][mygr]: hello\x1b[0m", buf);
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "to one");
STRCMP_EQUAL("\x1b[39m[INFO][mygr]: to one\x1b[0m", buf);
mbed_tracef(TRACE_LEVEL_WARN, "mygr", "and all");
STRCMP_EQUAL("\x1b[33m[WARN][mygr]: and all\x1b[0m", buf);
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "even you");
STRCMP_EQUAL("\x1b[31m[ERR ][mygr]: even you\x1b[0m", buf);
}
TEST(trace, change_levels)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_DEBUG);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hep");
STRCMP_EQUAL("[DBG ][mygr]: hep", buf);
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_DEBUG|TRACE_MODE_PLAIN);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hep");
STRCMP_EQUAL("hep", buf);
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_DEBUG|TRACE_MODE_COLOR);
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "hep");
STRCMP_EQUAL("\x1b[31m[ERR ][mygr]: hep\x1b[0m", buf);
}
TEST(trace, active_level_debug)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_DEBUG);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hep");
STRCMP_EQUAL("[DBG ][mygr]: hep", buf);
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("[INFO][mygr]: test", buf);
mbed_tracef(TRACE_LEVEL_WARN, "mygr", "hups");
STRCMP_EQUAL("[WARN][mygr]: hups", buf);
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "o'ou");
STRCMP_EQUAL("[ERR ][mygr]: o'ou", buf);
}
TEST(trace, active_level_info)
{
buf[0] = 0;
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_INFO);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hep");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("[INFO][mygr]: test", buf);
mbed_tracef(TRACE_LEVEL_WARN, "mygr", "hups");
STRCMP_EQUAL("[WARN][mygr]: hups", buf);
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "o'ou");
STRCMP_EQUAL("[ERR ][mygr]: o'ou", buf);
}
TEST(trace, active_level_warn)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_WARN);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hep");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_WARN, "mygr", "hups");
STRCMP_EQUAL("[WARN][mygr]: hups", buf);
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "o'ou");
STRCMP_EQUAL("[ERR ][mygr]: o'ou", buf);
}
TEST(trace, active_level_error)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ERROR);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hep");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_WARN, "mygr", "hups");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "o'ou");
STRCMP_EQUAL("[ERR ][mygr]: o'ou", buf);
}
TEST(trace, active_level_none)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_NONE);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hep");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_WARN, "mygr", "hups");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "o'ou");
STRCMP_EQUAL("", mbed_trace_last());
}
TEST(trace, active_level_all_1)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
mbed_trace_exclude_filters_set((char*)"mygr");
mbed_tracef(TRACE_LEVEL_DEBUG, "mygu", "hep");
STRCMP_EQUAL("[DBG ][mygu]: hep", buf);
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("", mbed_trace_last());
}
TEST(trace, active_level_all_2)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
mbed_trace_exclude_filters_set((char*)"mygr,mygu");
mbed_tracef(TRACE_LEVEL_DEBUG, "mygu", "hep");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("", mbed_trace_last());
}
TEST(trace, active_level_all_3)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
mbed_trace_include_filters_set((char*)"mygr");
mbed_tracef(TRACE_LEVEL_DEBUG, "mygu", "hep");
STRCMP_EQUAL("", mbed_trace_last());
mbed_tracef(TRACE_LEVEL_INFO, "mygr", "test");
STRCMP_EQUAL("[INFO][mygr]: test", buf);
}
TEST(trace, active_level_all_array)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
uint8_t arr[] = {0x01, 0x02, 0x03};
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "my addr: %s", mbed_trace_array(arr, 3));
STRCMP_EQUAL("[DBG ][mygr]: my addr: 01:02:03", buf);
}
size_t time_length;
char trace_prefix_str[] = "[<TIME>]";
char* trace_prefix(size_t length){
time_length = length;
return trace_prefix_str;
}
TEST(trace, prefix)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
mbed_trace_prefix_function_set( &trace_prefix );
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "test %d %d", 1, 2);
STRCMP_EQUAL("[<TIME>][DBG ][mygr]: test 1 2", buf);
//TEST_ASSERT_EQUAL_INT(4, time_length);
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL|TRACE_MODE_PLAIN);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "test");
STRCMP_EQUAL("test", buf);
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL|TRACE_MODE_COLOR);
mbed_tracef(TRACE_LEVEL_ERROR, "mygr", "test");
STRCMP_EQUAL("\x1b[31m[<TIME>][ERR ][mygr]: test\x1b[0m", buf);
}
char trace_suffix_str[] = "[END]";
char* trace_suffix()
{
return trace_suffix_str;
}
TEST(trace, suffix)
{
mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL);
mbed_trace_prefix_function_set( &trace_prefix );
mbed_trace_suffix_function_set( &trace_suffix );
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "test");
STRCMP_EQUAL("[<TIME>][DBG ][mygr]: test[END]", buf);
}
TEST(trace, formatting)
{
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hello %d %d %.1f", 12, 13, 5.5);
STRCMP_EQUAL("hello 12 13 5.5", buf);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hello %d %d %d %d %d %d", 12, 13, 5, 6, 8, 9);
STRCMP_EQUAL("hello 12 13 5 6 8 9", buf);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "HOH %d HAH %d %d %d %d %d", 12, 13, 5, 6, 8, 9);
STRCMP_EQUAL("HOH 12 HAH 13 5 6 8 9", buf);
}
TEST(trace, filters_control)
{
mbed_trace_include_filters_set((char*)"hello");
STRCMP_EQUAL("hello", mbed_trace_include_filters_get());
mbed_trace_include_filters_set(0);
STRCMP_EQUAL("", mbed_trace_include_filters_get());
mbed_trace_exclude_filters_set((char*)"hello");
STRCMP_EQUAL("hello", mbed_trace_exclude_filters_get());
mbed_trace_exclude_filters_set(0);
STRCMP_EQUAL("", mbed_trace_exclude_filters_get());
}
TEST(trace, no_printer)
{
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hello");
STRCMP_EQUAL("hello", buf);
mbed_trace_print_function_set(NULL);
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "this shoudnt be printed because printer is missing");
STRCMP_EQUAL("hello", buf);
}
TEST(trace, uninitialized)
{
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "hello");
STRCMP_EQUAL("hello", buf);
mbed_trace_free();
mbed_tracef(TRACE_LEVEL_DEBUG, "mygr", "this shoudnt be printed because mtrace is not initialized");
STRCMP_EQUAL("hello", buf);
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2016 ARM Limited. All rights reserved.
*/
#include "ip6string.h"
#include <string.h>
#include <stdio.h>
#include "common_functions.h"
#include "ip6tos_stub.h"
ip6tos_stub_def_t ip6tos_stub; // extern variable
uint8_t ip6tos(const void *ip6addr, char *p)
{
memcpy(ip6tos_stub.input_array, ip6addr, 16);
strcpy(p, ip6tos_stub.output_string);
return strlen(p);
}
uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p)
{
bitcopy(ip6tos_stub.input_array, prefix, prefix_len);
strcpy(p, ip6tos_stub.output_string);
return strlen(p);
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2016 ARM Limited. All rights reserved.
*/
#ifndef MBED_TRACE_TEST_STUBS_IP6STRING_H_
#define MBED_TRACE_TEST_STUBS_IP6STRING_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
typedef struct {
const char *output_string;
uint8_t input_array[16];
} ip6tos_stub_def_t;
extern ip6tos_stub_def_t ip6tos_stub;
#ifdef __cplusplus
}
#endif
#endif /* MBED_TRACE_TEST_STUBS_IP6STRING_H_ */