doc: renamed project
This commit is contained in:
committed by
Sylvan Arnold
parent
244e516bd8
commit
32618389d1
236
pico-sensor/McuLib/src/McuCoverage.c
Normal file
236
pico-sensor/McuLib/src/McuCoverage.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*!
|
||||
* Copyright (c) 2024, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* \brief Implementation of the McuCoverage module.
|
||||
*/
|
||||
|
||||
#include "McuCoverage.h"
|
||||
|
||||
#if McuCoverage_CONFIG_IS_ENABLED
|
||||
#include "McuLib.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "McuLog.h"
|
||||
#if McuLib_CONFIG_SDK_USE_FREERTOS
|
||||
#include "McuRTOS.h"
|
||||
#endif
|
||||
#include <gcov.h>
|
||||
|
||||
int McuCoverage_Check(void) {
|
||||
FILE *file = NULL;
|
||||
|
||||
/*
|
||||
* Creating a file without absolute path.
|
||||
* With J-Link and MCUXpresso IDE 11.4.1, this file gets created in the IDE installation directory (C:\NXP\MCUXpressoIDE_11.4.1_6260\ide).
|
||||
* Where the file gets created (current directory of the semihosting process on the host) really depends on the probe firmware and is non-standard.
|
||||
* See as well:
|
||||
* https://developer.arm.com/documentation/dui0058/d/semihosting/semihosting-swis/sys-open--0x01-?lang=en
|
||||
*/
|
||||
file = fopen ("gcov_text.txt", "w"); /* on RP2040, file is present in project root folder. If using external gdb server: in the current directory of the GDB server */
|
||||
if (file!=NULL) {
|
||||
fputs("hello world with file I/O\r\n", file);
|
||||
fclose(file);
|
||||
} else {
|
||||
return 0; /* failed */
|
||||
}
|
||||
|
||||
file = fopen ("c:\\tmp\\test.txt", "w");
|
||||
if (file!=NULL) {
|
||||
fputs("hello world with file I/O\r\n", file);
|
||||
(void)fwrite("hello\r\n", sizeof("hello\r\n")-1, 1, file);
|
||||
fclose(file);
|
||||
return 1; /* ok */
|
||||
}
|
||||
return 0; /* failed */
|
||||
}
|
||||
|
||||
void McuCoverage_Deinit(void) {
|
||||
/* nothing needed */
|
||||
}
|
||||
|
||||
/* call the coverage initializers if not done by startup code */
|
||||
void McuCoverage_Init(void) {
|
||||
#if McuCoverage_CONFIG_USE_FREESTANDING
|
||||
/* In a freestanding environment, we use custom hooks to write data. The constructors/destructors are *not* used,
|
||||
* instead we rely on the .gcov_info in the binary.
|
||||
*/
|
||||
#else
|
||||
#if McuLib_CONFIG_CPU_IS_RPxxxx
|
||||
/* constructor calls for coverage already done in C:\Raspy\pico\pico-sdk\src\rp2_common\pico_runtime/runtime.c */
|
||||
#else
|
||||
void (**p)(void);
|
||||
extern uint32_t __init_array_start, __init_array_end; /* linker defined symbols, array of function pointers */
|
||||
uint32_t beg = (uint32_t)&__init_array_start;
|
||||
uint32_t end = (uint32_t)&__init_array_end;
|
||||
|
||||
while(beg<end) {
|
||||
p = (void(**)(void))beg; /* get function pointer */
|
||||
(*p)(); /* call constructor */
|
||||
beg += sizeof(p); /* next pointer */
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* custom exit function */
|
||||
void exit_(int i) {
|
||||
for(;;) {}
|
||||
}
|
||||
|
||||
/* see https://gcc.gnu.org/onlinedocs/gcc/Freestanding-Environments.html#Tutorial */
|
||||
#if McuCoverage_CONFIG_USE_FREESTANDING
|
||||
|
||||
static McuCoverage_OutputCharFct_t OutputCharFct = NULL;
|
||||
|
||||
void McuCoverage_OutputString(const unsigned char *str) {
|
||||
if (OutputCharFct==NULL) {
|
||||
return;
|
||||
}
|
||||
while(*str!='\0') {
|
||||
OutputCharFct(*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
void McuCoverage_SetOuputCharCallback(McuCoverage_OutputCharFct_t callback) {
|
||||
OutputCharFct = callback;
|
||||
}
|
||||
|
||||
/* The start and end symbols are provided by the linker script. We use the
|
||||
array notation to avoid issues with a potential small-data area. */
|
||||
|
||||
/* Use the following in the linker file:
|
||||
.gcov_info:
|
||||
{
|
||||
PROVIDE (__gcov_info_start = .);
|
||||
KEEP (*(.gcov_info))
|
||||
PROVIDE (__gcov_info_end = .);
|
||||
} > FLASH
|
||||
|
||||
Additionally, set the following compiler option:
|
||||
-fprofile-info-section
|
||||
|
||||
See https://github.com/gcc-mirror/gcc/blob/master/libgcc/gcov.h
|
||||
*/
|
||||
|
||||
extern const struct gcov_info *const __gcov_info_start[];
|
||||
extern const struct gcov_info *const __gcov_info_end[];
|
||||
|
||||
static const unsigned char a = 'a';
|
||||
|
||||
/* each 8bit binary data value c gets encoded into two characters, each in rang 'a'-'p' (p is 'a'+16):
|
||||
buf[0]: 'a' + LowNibble(c)
|
||||
buf[1]: 'a' + HighNibble(c)
|
||||
*/
|
||||
static inline unsigned char *encode(unsigned char c, unsigned char buf[2]) {
|
||||
buf[0] = a + c % 16;
|
||||
buf[1] = a + (c / 16) % 16;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* The application reads a character stream encoded by encode() from stdin,
|
||||
decodes it, and writes the decoded characters to stdout. Characters other
|
||||
than the 16 characters 'a' to 'p' are ignored. */
|
||||
static int can_decode(unsigned char c) {
|
||||
return (unsigned char)(c - a) < 16;
|
||||
}
|
||||
|
||||
/* application which reads from stdin a previously encoded data stream and decodes it to stdout. */
|
||||
void application_decode(void) {
|
||||
int first = 1;
|
||||
int i;
|
||||
unsigned char c;
|
||||
|
||||
while ((i = fgetc(stdin)) != EOF) {
|
||||
unsigned char x = (unsigned char)i;
|
||||
|
||||
if (can_decode (x)) {
|
||||
if (first) {
|
||||
c = x - a;
|
||||
} else {
|
||||
fputc (c + 16 * (x - a), stdout);
|
||||
}
|
||||
first = !first;
|
||||
} else {
|
||||
first = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function shall produce a reliable in order byte stream to transfer the
|
||||
gcov information from the target to the host system. */
|
||||
static void dump(const void *d, unsigned n, void *arg) {
|
||||
(void)arg;
|
||||
const unsigned char *c = d;
|
||||
unsigned char buf[2];
|
||||
|
||||
for(unsigned int i = 0; i<n; i++) {
|
||||
if (OutputCharFct!=NULL) {
|
||||
encode(c[i], buf);
|
||||
OutputCharFct(buf[0]);
|
||||
OutputCharFct(buf[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The filename is serialized to a gcfn data stream by the
|
||||
__gcov_filename_to_gcfn() function. The gcfn data is used by the
|
||||
"merge-stream" subcommand of the "gcov-tool" to figure out the filename
|
||||
associated with the gcov information. */
|
||||
static void filename(const char *f, void *arg) {
|
||||
__gcov_filename_to_gcfn(f, dump, arg);
|
||||
}
|
||||
|
||||
/* The __gcov_info_to_gcda() function may have to allocate memory under
|
||||
certain conditions. Simply try it out if it is needed for your application
|
||||
or not. */
|
||||
static void *allocate(unsigned length, void *arg) {
|
||||
(void)arg;
|
||||
void *p;
|
||||
#if McuLib_CONFIG_SDK_USE_FREERTOS
|
||||
p = pvPortMalloc(length);
|
||||
#else
|
||||
p = malloc (length);
|
||||
#endif
|
||||
if (p==NULL) {
|
||||
McuLog_fatal("malloc failed");
|
||||
for(;;) {} /* error */
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the gcov information of all translation units. */
|
||||
static void dump_gcov_info (void) {
|
||||
const struct gcov_info *const *info = __gcov_info_start;
|
||||
const struct gcov_info *const *end = __gcov_info_end;
|
||||
|
||||
__asm__ ("" : "+r" (info)); /* Obfuscate variable to prevent compiler optimizations. */
|
||||
while (info != end) { /* iterate through all infos (or modules instrumented) */
|
||||
void *arg = NULL;
|
||||
__gcov_info_to_gcda(*info, filename, dump, allocate, arg); /* write record*/
|
||||
if (OutputCharFct!=NULL) { /* each record is terminated with a newline character */
|
||||
OutputCharFct('\n');
|
||||
}
|
||||
info++;
|
||||
}
|
||||
}
|
||||
#endif /* McuCoverage_CONFIG_USE_FREESTANDING */
|
||||
|
||||
void McuCoverage_WriteFiles(void) {
|
||||
#if McuCoverage_CONFIG_USE_FREESTANDING
|
||||
dump_gcov_info();
|
||||
#else
|
||||
#if __GNUC__ < 11
|
||||
// void __gcov_flush(void); /* internal gcov function to write data */
|
||||
__gcov_flush(); /* __gcov_flush() has been removed in the libraries for GCC11 */
|
||||
#else
|
||||
// void __gcov_dump(void); /* from GCC11 on, __gcov_flush() has been replaced by __gcov_dump() */
|
||||
__gcov_dump(); /* from GCC11 on, use __gcov_dump() */
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* #if McuCoverage_CONFIG_IS_ENABLED */
|
||||
Reference in New Issue
Block a user