| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- /*
- * Copyright (C) 2000-2004 by ETH Zurich
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ETH ZURICH AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ETH ZURICH
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.btnode.ethz.ch
- *
- */
- /*
- * os/tracer.c
- *
- * 22.12.2004 Philipp Blum <blum@tik.ee.ethz.ch>
- *
- * \brief Routines to capture traces of nutOS programs
- * \note Only supported on AVR-GCC platform
- *
- */
- #if defined(__GNUC__) && defined(__AVR__)
- /************************************************/
- /* includes */
- /************************************************/
- #include <sys/tracer.h> // t_traceitem, t_trace
- #include <sys/heap.h> // NutHeapAlloc
- #include <sys/timer.h> // NutGetMillis
- #include <sys/thread.h> // NUTTHREADINFO
- #include <sys/atom.h> // NutEnterCritical_notrace
- #include <dev/irqreg.h> // sig_OVERFLOW1
- #include <stdio.h> // printf, sscanf
- #include <string.h> // strcmp
- /************************************************/
- /* global variables */
- /************************************************/
- unsigned int micros_high = 0;
- t_traceitem *trace_items = 0;
- t_traceitem *trace_current = 0;
- int trace_head = 0;
- int trace_size = 0;
- char trace_isfull = 0;
- char trace_isinit = 0;
- char trace_mode = TRACE_MODE_OFF;
- char trace_mask[TRACE_TAG_LAST+1] = {
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 0,
- 0,
- 1,
- 1,
- 1
- };
- char* tag_string[TRACE_TAG_LAST+1] = {
- "Critical Enter",
- "Critical Exit",
- "Thread Yield",
- "Thread SetPrio",
- "Thread Wait",
- "Thread Sleep",
- "Interrupt Enter",
- "Interrupt Exit",
- "Trace Start",
- "Trace Stop",
- "User *"
- };
- char* int_string[TRACE_INT_LAST+1] = {
- "UART0_CTS",
- "UART0_RXCOMPL",
- "UART0_TXEMPTY",
- "UART1_CTS",
- "UART1_RXCOMPL",
- "UART1_TXEMPTY",
- "TIMER0_OVERFL",
- "TIMER1_OVERFL",
- "SUART_TIMER",
- "SUART_RX"
- };
- char* mode_string[TRACE_MODE_LAST+1] = {
- "OFF",
- "CIRCULAR",
- "ONESHOT"
- };
- char* user_string[TRACE_MAX_USER];
- /************************************************/
- /* function definitions */
- /************************************************/
- static void NutTraceTimer1IRQ(void *arg)
- {
- // TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_ENTER,TRACE_INT_TIMER1_OVERFL);
- micros_high++;
- // TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_TIMER1_OVERFL);
- }
- int NutTraceInit(int size, char mode)
- {
- if (!trace_isinit) {
- // start timer1 at CPU frequency/8 and register interrupt service routine
- outb(TCCR1B, 2);
- NutRegisterIrqHandler(&sig_OVERFLOW1, NutTraceTimer1IRQ, 0);
- sbi(TIMSK, TOIE1);
- trace_isinit = 1;
- }
- if (size==0) {
- size = TRACE_SIZE_DEFAULT;
- }
- if (size != trace_size) {
- // current buffer is not of size that is wanted
- if (trace_items != 0) {
- // but memory is already allocated -> free old buffer
- NutHeapFree(trace_items);
- }
- // allocate buffer
- trace_items = (t_traceitem *)NutHeapAlloc(size * sizeof(t_traceitem));
- if (trace_items == 0) {
- // failed
- return trace_size = 0;
- }
- else {
- trace_size = size;
- }
- }
- // if (mode == TRACE_MODE_OFF) {
- // // if terminal-cmd "trace size <val>" is called trace is started in
- // // default mode
- // mode = TRACE_MODE_DEFAULT;
- // }
- trace_mode = mode;
- NutTraceClear();
- return trace_size;
- }
- void NutTraceClear()
- {
- trace_head = trace_isfull = 0;
- TRACE_ADD_ITEM(TRACE_TAG_START,0);
- }
- void NutTraceStop()
- {
- TRACE_ADD_ITEM(TRACE_TAG_STOP,0);
- trace_mode = TRACE_MODE_OFF;
- }
- void NutTraceTerminal(char* arg)
- {
- int val;
- if (sscanf(arg,"print%d",&val)==1) {
- NutTracePrint(val);
- return;
- }
- if (!strncmp(arg,"print",5)) {
- NutTracePrint(0);
- return;
- }
- if (!strncmp(arg,"oneshot",7)) {
- NutTraceInit(trace_size,TRACE_MODE_ONESHOT);
- printf("TRACE mode %s, restarted\n",mode_string[(int)trace_mode]);
- return;
- }
- if (!strncmp(arg,"circular",8)) {
- NutTraceInit(trace_size,TRACE_MODE_CIRCULAR);
- printf("TRACE mode %s, restarted\n",mode_string[(int)trace_mode]);
- return;
- }
- if (sscanf(arg,"size%d",&val)==1) {
- printf("TRACE new size: %d\n",NutTraceInit(val,trace_mode));
- return;
- }
- if (!strncmp(arg,"stop",4)) {
- NutTraceStop();
- printf("TRACE stopped\n");
- return;
- }
- if (sscanf(arg,"mask%d",&val)==1) {
- if (val<=TRACE_TAG_LAST) {
- trace_mask[val]=trace_mask[val] ? 0 : 1;
- NutTraceClear();
- }
- NutTraceMaskPrint();
- return;
- }
- if (!strncmp(arg,"mask",4)) {
- NutTraceMaskPrint();
- return;
- }
- NutTraceStatusPrint();
- printf("SYNTAX: trace [print [<size>]|oneshot|circular|size <size>|stop|mask [<tag>]]\n");
- }
- void NutTraceStatusPrint(void)
- {
- printf("TRACE STATUS\n");
- printf(" Mode is %s\n",mode_string[(int)trace_mode]);
- printf(" Size is %d\n",trace_size);
- if (trace_isfull)
- printf(" is full\n");
- else
- printf(" contains %d elements\n",trace_head);
- }
- void NutTracePrint(int size)
- {
- int i,index;
- uint32_t time;
- char mode;
- unsigned int micros, millis, secs;
- mode = trace_mode;
- trace_mode = TRACE_MODE_OFF;
- printf("\nTRACE");
- if (trace_size == 0) {
- printf(" not initialized!\n\n");
- return;
- }
- printf(" contains %d items, ",(trace_isfull ? trace_size : trace_head));
- if (size == 0) {
- size = trace_size;
- }
- if (trace_isfull) {
- if (size > trace_size) {
- size = trace_size;
- }
- }
- else {
- if (size > trace_head) {
- size = trace_head;
- }
- }
- printf(" printing %d items.\n",size);
- printf("%-20s%-12s%-12s\n","TAG","PC/Info","Time [s:ms:us]");
- printf("-----------------------------------------------\n");
- for (i=size-1;i>=0;i--) {
- index = trace_head - i - 1;
- if (index<0) {
- index += trace_size;
- }
- time = ((uint32_t)trace_items[index].time_h)<<16 | trace_items[index].time_l;
- micros = (int)(time%1000);
- millis = (int)((time/1000)%1000);
- secs = (int)(time/1000000);
- switch (trace_items[index].tag) {
- case TRACE_TAG_THREAD_YIELD:
- case TRACE_TAG_THREAD_SETPRIO:
- case TRACE_TAG_THREAD_WAIT:
- case TRACE_TAG_THREAD_SLEEP:
- printf("%-20s%-15s%7u:%03u:%03u\n",
- tag_string[(int)trace_items[index].tag],
- ((NUTTHREADINFO*)(trace_items[index].pc))->td_name,
- secs,millis,micros);
- break;
- case TRACE_TAG_INTERRUPT_ENTER:
- case TRACE_TAG_INTERRUPT_EXIT:
- printf("%-20s%-15s%7u:%03u:%03u\n",
- tag_string[(int)trace_items[index].tag],
- int_string[(int)trace_items[index].pc],
- secs,millis,micros);
- break;
- case TRACE_TAG_USER:
- printf("%-20s%-15s%7u:%03u:%03u\n",
- tag_string[(int)trace_items[index].tag],
- user_string[(int)trace_items[index].pc],
- secs,millis,micros);
- break;
- default:
- printf("%-20s%-#15x%7u:%03u:%03u\n",
- tag_string[(int)trace_items[index].tag],
- trace_items[index].pc,
- secs,millis,micros);
- }
- }
- trace_mode = mode;
- }
- int NutTraceGetPC(void)
- {
- int pc = ((int)(*((char*)SP+1)));
- pc = (pc<<8)|(0x00ff&(int)(*((char*)SP+2)));
- return pc<<1;
- }
- void NutTraceMaskSet(int tag)
- {
- if (tag<=TRACE_TAG_LAST) {
- trace_mask[tag] = 1;
- }
- }
- void NutTraceMaskClear(int tag)
- {
- if (tag<=TRACE_TAG_LAST) {
- trace_mask[tag] = 0;
- }
- }
- void NutTraceMaskPrint(void)
- {
- int tag;
- printf("TRACEMASK\n");
- for (tag=0;tag<=TRACE_TAG_LAST;tag++) {
- printf(" %d %s ",tag,tag_string[tag]);
- if (trace_mask[tag])
- printf("ON\n");
- else
- printf("OFF\n");
- }
- }
- int NutTraceRegisterUserTag(int tag, char* tag_string)
- {
- if (tag >= TRACE_MAX_USER)
- return -1;
- user_string[tag] = tag_string;
- return tag;
- }
- #endif
|