Merge commit '14ff147a610d775c157ffc48b4e4521d0a6493f0'

* commit '14ff147a610d775c157ffc48b4e4521d0a6493f0':
  Squashed 'features/frameworks/mbed-trace/' changes from 7a1bd34..0a4f6be
pull/9838/head
Arto Kinnunen 2019-02-25 13:01:32 +02:00
commit ab1cfc5c7e
13 changed files with 459 additions and 7 deletions

View File

@ -0,0 +1 @@
BUILD

View File

@ -0,0 +1,37 @@
# Mbed OS code style definition file for astyle
# Don't create backup files, let git handle it
suffix=none
# K&R style
style=kr
# 1 TBS addition to k&r, add braces to one liners
# Use -j as it was changed in astyle from brackets to braces, this way it is compatible with older astyle versions
-j
# 4 spaces, convert tabs to spaces
indent=spaces=4
convert-tabs
# Indent switches and cases
indent-switches
# Remove spaces in and around parentheses
unpad-paren
# Insert a space after if, while, for, and around operators
pad-header
pad-oper
# Pointer/reference operators go next to the name (on the right)
align-pointer=name
align-reference=name
# Attach { for classes and namespaces
attach-namespaces
attach-classes
# Extend longer lines, define maximum 120 value. This results in aligned code,
# otherwise the lines are broken and not consistent
max-continuation-indent=120

View File

@ -2,3 +2,4 @@ build/*
yotta_modules/*
yotta_targets/*
test/*
example/*

View File

@ -0,0 +1,281 @@
echo "Start to build"
properties ([
buildDiscarder(
logRotator(
artifactNumToKeepStr: '10',
numToKeepStr: '100'
)
)
])
// List of targets to compile
def morpheusTargets = [
//"LPC1768",
//"NUCLEO_F401RE",
//"NRF51DK",
"K64F"
]
// Map morpheus toolchains to compiler labels on Jenkins
def toolchains = [
ARM: "armcc",
IAR: "iar_arm",
GCC_ARM: "arm-none-eabi-gcc"
]
// yotta target includes toolchain
def yottaTargets = [
"frdm-k64f-gcc": "gcc",
"frdm-k64f-armcc": "armcc",
"nrf51dk-gcc": "gcc",
"stm32f429i-disco-gcc": "gcc",
"x86-linux-native": "linux && astyle"
]
// Initial maps for parallel build steps
def stepsForParallel = [:]
// Jenkins pipeline does not support map.each, we need to use oldschool for loop
for (int i = 0; i < morpheusTargets.size(); i++) {
for(int j = 0; j < toolchains.size(); j++) {
def target = morpheusTargets.get(i)
def toolchain = toolchains.keySet().asList().get(j)
def compilerLabel = toolchains.get(toolchain)
def stepName = "mbed-os5-${target} ${toolchain}"
stepsForParallel[stepName] = morpheusBuildStep(target, compilerLabel, toolchain)
}
}
// map yotta steps
for (int i = 0; i < yottaTargets.size(); i++) {
def target = yottaTargets.keySet().asList().get(i)
def compilerLabel = yottaTargets.get(target)
def stepName = "mbed-os3-${target}"
stepsForParallel[stepName] = yottaBuildStep(target, compilerLabel)
}
/* Jenkins does not allow stages inside parallel execution,
* https://issues.jenkins-ci.org/browse/JENKINS-26107 will solve this by adding labeled blocks
*/
// Actually run the steps in parallel - parallel takes a map as an argument, hence the above.
timestamps {
timeout(time: 30, unit: "MINUTES") {
parallel stepsForParallel
}
}
def execute(cmd) {
if(isUnix()) {
sh "${cmd}"
} else {
bat "${cmd}"
}
}
//Create morpheus build steps for parallel execution
def morpheusBuildStep(target, compilerLabel, toolchain) {
return {
node ("${compilerLabel}") {
deleteDir()
dir("mbed-trace") {
String buildName = "mbed-os5-${target}-${toolchain}"
def scmVars = checkout scm
env.GIT_COMMIT_HASH = scmVars.GIT_COMMIT
setBuildStatus('PENDING', "build ${buildName}", 'build starts')
stage ("build:${buildName}") {
try{
execute("mbed --version")
execute("echo https://github.com/armmbed/mbed-os/#6a0a86538c0b9b2bfcc4583b1e2b7fea8f4e71e9 > mbed-os.lib")
execute("mbed deploy")
execute("rm -rf ./mbed-os/features/frameworks/mbed-trace")
execute("mbed compile -m ${target} -t ${toolchain} --library")
setBuildStatus('SUCCESS', "build ${buildName}", "build done")
} catch (err) {
echo "Caught exception: ${err}"
setBuildStatus('FAILURE', "build ${buildName}", "build failed")
throw err
}
}
stage("build:example:${buildName}") {
execute("mkdir ../example-mbed-os-5 || true")
execute("cp -R example/mbed-os-5 ../example-mbed-os-5")
dir("../example-mbed-os-5") {
def exampleName = "example-${buildName}"
setBuildStatus('PENDING', "build ${exampleName}", 'build starts')
try {
execute("echo \"https://github.com/ARMmbed/mbed-os/#6a0a86538c0b9b2bfcc4583b1e2b7fea8f4e71e9\" > mbed-os.lib")
execute("echo \"https://github.com/ARMmbed/mbed-trace#${env.GIT_COMMIT_HASH}\" > mbed-trace.lib")
execute("mbed new .")
execute("mbed deploy")
execute("rm -rf ./mbed-os/features/frameworks/mbed-trace")
execute("rm -rf ./mbed-trace/example")
execute("rm -rf ./mbed-trace/test")
execute("mbed compile -t ${toolchain} -m ${target}")
setBuildStatus('SUCCESS', "build ${exampleName}", "build done")
} catch(err) {
echo "Caught exception: ${err}"
setBuildStatus('FAILURE', "build ${exampleName}", "build failed")
currentBuild.result = 'FAILURE'
} finally {
// clean up
postBuild(buildName, false)
step([$class: 'WsCleanup'])
}
}
}
}
}
}
}
//Create yotta build steps for parallel execution
def yottaBuildStep(target, compilerLabel) {
return {
String buildName = "mbed-os3-${target}"
node ("${compilerLabel}") {
deleteDir()
dir("mbed-trace") {
def scmVars = checkout scm
env.GIT_COMMIT_HASH = scmVars.GIT_COMMIT
def isTest = target == "x86-linux-native" // tests are valid only in linux target
stage ("build:${buildName}") {
setBuildStatus('PENDING', "build ${buildName}", 'build starts')
try{
execute("yotta --version")
execute("yotta target $target")
execute("yotta --plain build mbed-trace")
setBuildStatus('SUCCESS', "build ${buildName}", "build done")
} catch (err) {
echo "Caught exception: ${err}"
setBuildStatus('FAILURE', "build ${buildName}", "build failed")
currentBuild.result = 'FAILURE'
}
} // stage
if (isTest) {
stage("test:${buildName}") {
setBuildStatus('PENDING', "test ${buildName}", 'test starts')
try {
execute("yotta test mbed_trace_test")
execute("lcov --base-directory . --directory . --capture --output-file coverage.info")
execute("genhtml -o ./test_coverage coverage.info")
execute("gcovr -x -o junit.xml")
execute("cppcheck --enable=all --std=c99 --inline-suppr --template=\"{file},{line},{severity},{id},{message}\" source 2> cppcheck.txt")
// check if astyle is correct
execute("astyle --options=.astylerc source/*.c mbed-trace/*.h")
// check differency
execute("git diff-index -p --exit-code HEAD")
setBuildStatus('SUCCESS', "test ${buildName}", "test done")
} catch(err) {
echo "Caught exception: ${err}"
setBuildStatus('FAILURE', "test ${buildName}", "test failed")
currentBuild.result = 'FAILURE'
}
} // stage
stage("example:${buildName}") {
dir("example/linux") {
def exampleName = "example-linux"
setBuildStatus('PENDING', "build ${exampleName}", 'build starts')
try {
execute("make")
setBuildStatus('SUCCESS', "build ${exampleName}", "build done")
} catch(err) {
echo "Caught exception: ${err}"
setBuildStatus('FAILURE', "build ${exampleName}", "build failed")
currentBuild.result = 'FAILURE'
}
}
} // stage
stage("leak-check:${buildName}") {
dir("example/linux") {
def stageName = "leak-check"
setBuildStatus('PENDING', "test ${stageName}", 'test starts')
try {
execute("./memtest.sh")
setBuildStatus('SUCCESS', "test ${stageName}", "test done")
} catch(err) {
echo "Caught exception: ${err}"
setBuildStatus('FAILURE', "test ${stageName}", "test failed")
currentBuild.result = 'FAILURE'
}
}
} // stage
} // if linux
postBuild(buildName, isTest)
step([$class: 'WsCleanup'])
} // dir
}
}
}
def postBuild(buildName, isTest) {
// move files to target+toolchain specific folder
execute("mkdir -p output/${buildName}")
execute("find . -name 'libmbed-trace.a' -exec mv {} 'output/${buildName}' \\;")
execute("find . -name 'mbed-trace.ar' -exec mv {} 'output/${buildName}' \\;")
execute("find ../example-mbed-os-5 -name 'example-mbed-os-5.bin' -exec mv {} 'output/${buildName}/example-mbed-os-5.bin' \\; || true")
// Archive artifacts
step([
$class: 'ArtifactArchiver',
artifacts: "cppcheck.txt,output/**",
fingerprint: true,
allowEmptyArchive: true
])
if (isTest) {
// Publish cobertura
step([
$class: 'CoberturaPublisher',
coberturaReportFile: 'junit.xml'
])
// Publish compiler warnings
step([
$class: 'WarningsPublisher',
parserConfigurations: [[
parserName: 'GNU Make + GNU C Compiler (gcc)',
pattern: 'mbed-trace/*.h,source/*.c,test/*.cpp'
]],
unstableTotalAll: '0',
useDeltaValues: true,
usePreviousBuildAsReference: true
])
// Publish HTML reports
publishHTML(target: [
alwayLinkToLastBuild: false,
keepAll: true,
reportDir: "test_coverage",
reportFiles: "index.html",
reportName: "Build HTML Report"
])
}
}
// helper function to set build status to github PR
def setBuildStatus(String state, String context, String message) {
step([
$class: "GitHubCommitStatusSetter",
reposSource: [
$class: "ManuallyEnteredRepositorySource",
url: "https://github.com/ARMmbed/mbed-trace.git"
],
contextSource: [
$class: "ManuallyEnteredCommitContextSource",
context: context
],
errorHandlers: [[
$class: "ChangingBuildStatusErrorHandler",
result: "UNSTABLE"
]],
commitShaSource: [
$class: "ManuallyEnteredShaSource",
sha: env.GIT_COMMIT_HASH
],
statusResultSource: [
$class: 'ConditionalStatusResultSource',
results: [
[
$class: 'AnyBuildResult',
message: message,
state: state
]
]
]
])
}

View File

@ -23,11 +23,11 @@ The purpose of the library is to provide a light, simple and general tracing sol
* 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 uses `stdout` as the default output target because it goes directly to serial port in mbed-os.
* 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.
* 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
@ -43,7 +43,7 @@ The purpose of the library is to provide a light, simple and general tracing sol
### 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).
* 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#L245).
* 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)
@ -76,9 +76,16 @@ Don't forget to fulfill the other [prerequisites](#prerequisites)!
([Click here for more information on the configuration system](https://docs.mbed.com/docs/mbed-os-api/en/latest/config_system/))
## Examples
* [mbed-os-5](example/mbed-os-5)
* [linux](example/linux)
### 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>`.
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:
@ -146,7 +153,9 @@ In Mbed OS, the build time maximum tracing level can be set through `mbed_app.js
### 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:
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));

View File

@ -0,0 +1,2 @@
all:
gcc main.c -g -I ../.. ../../source/mbed_trace.c -DYOTTA_CFG -DMBED_CONF_MBED_TRACE_FEA_IPV6=0 -o app

View File

@ -0,0 +1,13 @@
# linux example application using mbed-trace library
## build
```
make
```
## run
```
./app
```

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 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 "mbed-trace/mbed_trace.h"
#define TRACE_GROUP "main"
int main(void)
{
mbed_trace_init();
tr_debug("debug print");
tr_info("info print");
tr_warn("warning print");
tr_error("error print");
mbed_trace_free();
return 0;
}

View File

@ -0,0 +1 @@
valgrind --leak-check=yes --error-exitcode=1 ./app

View File

@ -0,0 +1,27 @@
# mbed-os 5 example application using mbed-trace library
## define mbed-os.lib
```
echo https://github.com/armmbed/mbed-os/#6a0a86538c0b9b2bfcc4583b1e2b7fea8f4e71e9 > mbed-os.lib
```
## build
```
mbed deploy
mbed compile -t GCC_ARM -m K64F
```
## Usage
When you flash a target with this application and open a terminal you should see the following traces:
```
[INFO][main] Hello tracers
[DBG ][main] Infinite loop..
[DBG ][main] Infinite loop..
[DBG ][main] Infinite loop..
...
```

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 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 "mbed.h"
#include "mbed_trace.h"
#define TRACE_GROUP "main"
int main(void)
{
// Initialize trace library
mbed_trace_init();
// trace Something
tr_info("Hello tracers");
while(1) {
tr_debug("Infinite loop..");
}
}

View File

@ -0,0 +1,15 @@
{
"macros": [
"MEM_ALLOC=malloc",
"MEM_FREE=free"
],
"target_overrides": {
"*": {
"platform.stdio-baud-rate": 115200,
"platform.stdio-convert-newlines": true,
"platform.stdio-buffered-serial": true,
"target.features_add": ["COMMON_PAL"],
"mbed-trace.enable": 1
}
}
}

View File

@ -142,6 +142,7 @@ static trace_t m_trace = {
.line_length = DEFAULT_TRACE_LINE_LENGTH,
.tmp_data = 0,
.tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN,
.tmp_data_ptr = 0,
.prefix_f = 0,
.suffix_f = 0,
.printf = mbed_trace_default_print,