318 lines
9.8 KiB
C
318 lines
9.8 KiB
C
/* *********************************************************************************************
|
|
* @Title: TRACE32 Remote API that use T32_NotifyStateEnable() and T32_CheckStateNotify()
|
|
* @Description:
|
|
* TRACE32 Remote API sample program illustrating the use of T32_NotifyStateEnable() and
|
|
* T32_CheckStateNotify() for receiving notifications from TRACE32 PowerView.
|
|
*
|
|
* Syntax: t32apinotify [node=<name_or_IP>] [port=<num>]
|
|
* Example: t32apinotify node=localhost port=20000
|
|
*
|
|
* For remote access TRACE32's configuration file "config.t32" has to contain these lines:
|
|
*
|
|
* RCL=NETASSIST
|
|
* PORT=20000
|
|
*
|
|
* This default port value may be changed but has to match the specified command line value.
|
|
*
|
|
* ENABLE_NOTIFICATION has to be defined manually if this sample program is compiled without
|
|
* the provided makefile.
|
|
*
|
|
*
|
|
* $Id: t32apinotify.c 146693 2022-04-07 16:08:37Z hlohn $
|
|
* $LastChangedRevision: 146693 $
|
|
* $LastChangedBy: hlohn $
|
|
*
|
|
* @Copyright: (C) 1989-2020 Lauterbach GmbH, licensed for use with TRACE32(R) only
|
|
* *********************************************************************************************
|
|
* $Id: t32apinotify.c 146693 2022-04-07 16:08:37Z hlohn $
|
|
*/
|
|
|
|
#include "t32.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef _WIN32
|
|
# include <Windows.h>
|
|
# include <conio.h>
|
|
#else
|
|
# include <sys/ioctl.h>
|
|
# include <termios.h>
|
|
# include <unistd.h>
|
|
# define Sleep(t) usleep((t)*1000)
|
|
# define __cdecl
|
|
#endif
|
|
#include "t32.h"
|
|
|
|
#ifndef _WIN32
|
|
static int kbhit(void)
|
|
{
|
|
int byteswaiting;
|
|
struct termios term, term2;
|
|
|
|
tcgetattr(0, &term);
|
|
term2 = term;
|
|
term2.c_lflag &= ~ICANON;
|
|
tcsetattr(0, TCSANOW, &term2);
|
|
ioctl(0, FIONREAD, &byteswaiting);
|
|
tcsetattr(0, TCSANOW, &term);
|
|
return byteswaiting > 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
static void T32_callbackEditExtern(int dummy, int lineNr, char *fileName);
|
|
static void T32_callbackBreakpointConfig(int dummy);
|
|
static void T32_callbackBreak(int dummy);
|
|
|
|
|
|
int indexOf_shift (char* base, char* str, size_t startIndex) {
|
|
int result;
|
|
size_t baselen = strlen(base);
|
|
char* pos = NULL;
|
|
|
|
// str should not longer than base
|
|
if (strlen(str) > baselen || startIndex > baselen) {
|
|
result = -1;
|
|
} else {
|
|
pos = strstr(base + startIndex, str);
|
|
if (pos == NULL) {
|
|
result = -1;
|
|
} else {
|
|
result = (int)(pos - base);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
size_t lastIndexOf (char* base, char* str) {
|
|
size_t result;
|
|
// str should not longer than base
|
|
if (strlen(str) > strlen(base)) {
|
|
result = -1;
|
|
} else {
|
|
unsigned int start = 0;
|
|
unsigned int endinit = (unsigned int)(strlen(base) - strlen(str));
|
|
unsigned int end = endinit;
|
|
int endtmp = endinit;
|
|
|
|
while(start != end) {
|
|
start = indexOf_shift(base, str, start);
|
|
end = indexOf_shift(base, str, end);
|
|
|
|
// not found from start
|
|
if (start == -1) {
|
|
end = -1; // then break;
|
|
} else if (end == -1) {
|
|
// found from start
|
|
// but not found from end
|
|
// move end to middle
|
|
if (endtmp == (start+1)) {
|
|
end = start; // then break;
|
|
} else {
|
|
end = endtmp - (endtmp - start) / 2;
|
|
if (end <= start) {
|
|
end = start+1;
|
|
}
|
|
endtmp = end;
|
|
}
|
|
} else {
|
|
// found from both start and end
|
|
// move start to end and
|
|
// move end to base - strlen(str)
|
|
start = end;
|
|
end = endinit;
|
|
}
|
|
}
|
|
result = start;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char string[32], cursor[4] = {'/','-','\\','|'};
|
|
int i, argn = 1, retval = EXIT_SUCCESS;
|
|
uint32_t result;
|
|
|
|
/*** get command line parameters and establish connection ************************************/
|
|
|
|
if ((argc > argn) && (!strncmp(argv[argn], "node=", 5) || !strncmp(argv[argn], "NODE=", 5))) {
|
|
T32_Config("NODE=", argv[argn] + 5);
|
|
argn++;
|
|
}
|
|
|
|
if ((argc > argn) && (!strncmp(argv[argn], "port=", 5) || !strncmp(argv[argn], "PORT=", 5))) {
|
|
if (T32_Config("PORT=", argv[argn] + 5) != T32_OK) {
|
|
printf("\n\n Invalid port number '%s' specified.\n", argv[argn] + 5);
|
|
retval = EXIT_FAILURE;
|
|
}
|
|
argn++;
|
|
}
|
|
|
|
if ((argc != argn) || (retval == EXIT_FAILURE) || (argc == 1)) {
|
|
printf("\n\n Syntax: %s.exe [node=<name_or_IP>] [port=<num>]", argv[0]);
|
|
printf( "\n Example: %s.exe node=localhost port=20000\n\n", argv[0]);
|
|
if (argc != 1)
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
printf("\n Connecting...");
|
|
|
|
for (i = 0; i < 2; i++) { /* try twice */
|
|
if (T32_Init() == T32_OK) {
|
|
if (T32_Attach(T32_DEV_ICD) == T32_OK)
|
|
break;
|
|
else
|
|
printf("%s to establish a remote connection with TRACE32 PowerView.%s\n",
|
|
i==0?"\n\n Failed once":"\n Failed twice", i==0?"\n":" Terminating ...\n");
|
|
}
|
|
else
|
|
printf("%s to initialize the remote connection.%s\n",
|
|
i==0?"\n\n Failed once":"\n Failed twice", i==0?" ":" Terminating ...\n");
|
|
|
|
T32_Exit(); /* reset/close a potentially existing connection */
|
|
if (i == 1)
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
printf("\r Successfully established a remote connection with TRACE32 PowerView.\n");
|
|
printf("\n See AREA window of TRACE32 PowerView for instructions on how to use the demo.\n");
|
|
printf("\n Press any key to quit this shell application.\n\n");
|
|
|
|
|
|
/*** enable notifications in TRACE32 PowerView and display all important information *********/
|
|
|
|
T32_Cmd("AREA.Clear");
|
|
T32_Cmd("WinCLEAR APIWin1"); T32_Cmd("WinCLEAR APIWin2");
|
|
T32_Cmd("WinCLEAR APIWin3"); T32_Cmd("WinCLEAR APIWin4");
|
|
T32_Cmd("PRINT");
|
|
T32_Cmd("PRINT");
|
|
T32_Cmd("SETUP.BREAKTRANSFER OFF"); /* disable former settings */
|
|
T32_Cmd("WinPOS 0 55%,,,,,APIWin2");
|
|
T32_Cmd("SYStem");
|
|
T32_Cmd("EVAL SIMULATOR()");
|
|
if ((T32_EvalGet(&result) == T32_OK) && (result != 0)) { /* assemble loop in case of simulator */
|
|
char SystemCpu[32];
|
|
T32_ExecuteFunction("SYStem.CPU()", SystemCpu, sizeof(SystemCpu), NULL);
|
|
if (!strcmp(SystemCpu,"NONE"))
|
|
T32_Cmd("SYStem.NEXTCPU");
|
|
T32_Cmd("SYStem.Up");
|
|
T32_Cmd("Data.Assemble P:0x0++0x50 nop");
|
|
T32_Cmd("EVAL CPU()");
|
|
T32_EvalGetString(string); /* for EVAL CPU() size of */
|
|
if (!strncmp(string, "TC", 2)) /* string is sufficient */
|
|
T32_Cmd("Data.Assemble P:0x50 j 0x0");
|
|
else
|
|
T32_Cmd("Data.Assemble P:0x50 b 0x0");
|
|
T32_Cmd("Register.Set PC P:0x0");
|
|
}
|
|
T32_Cmd("Break.Set REGISTER(PC)+0x10 REGISTER(PC)+0x20 REGISTER(PC)+0x30 REGISTER(PC)+0x40 /SOFT");
|
|
T32_Cmd("WinPOS 50% 0 50% 60%,,,APIWin3");
|
|
T32_Cmd("List");
|
|
T32_Cmd("WinPOS 50% 70% 50% 40%,,,APIWin4");
|
|
T32_Cmd("Break.List");
|
|
T32_Cmd("SETUP.BREAKTRANSFER ON"); /* enable 'target break' and 'breakpoint change' notification */
|
|
T32_Cmd("SETUP.EDITEXT ON"); /* enable 'edit source' notification, superfluous if only ASM code */
|
|
|
|
T32_Cmd("WinPOS 0 0 48% 50%,,,APIWin1");
|
|
T32_Cmd("AREA");
|
|
T32_Cmd("PRINT \"______________________________________________________\"");
|
|
T32_Cmd("PRINT %COLOR.GREEN \" Remote API Notification Demo\"");
|
|
T32_Cmd("PRINT");
|
|
T32_Cmd("PRINT \" Remote application executed 'SETUP.BREAKTRANSFER ON'\"");
|
|
T32_Cmd("PRINT \" in order to enable target-break-notification and\"");
|
|
T32_Cmd("PRINT \" breakpoint-change-notification.\"");
|
|
T32_Cmd("PRINT");
|
|
T32_Cmd("PRINT \" Press GO button to start execution, the remote\"");
|
|
T32_Cmd("PRINT \" application will be notified when a breakpoint\"");
|
|
T32_Cmd("PRINT \" is hit.\"");
|
|
T32_Cmd("PRINT");
|
|
T32_Cmd("PRINT \" Change breakpoint settings in the List or\"");
|
|
T32_Cmd("PRINT \" Break.List window, the remote application will\"");
|
|
T32_Cmd("PRINT \" be notified of any changes.\"");
|
|
T32_Cmd("PRINT \"______________________________________________________\"");
|
|
T32_Cmd("PRINT");
|
|
|
|
|
|
/* tell TRACE32 to report user request for editing source via EDIT.EXTernal command */
|
|
T32_NotifyStateEnable(T32_E_EDIT, (void (__cdecl *)(void)) T32_callbackEditExtern);
|
|
|
|
/* tell TRACE32 to report changes in breakpoint configuration */
|
|
T32_NotifyStateEnable(T32_E_BREAKPOINTCONFIG, (void (__cdecl *)(void)) T32_callbackBreakpointConfig);
|
|
|
|
/* tell TRACE32 to report when target program stops execution */
|
|
T32_NotifyStateEnable(T32_E_BREAK, (void (__cdecl *)(void)) T32_callbackBreak);
|
|
|
|
|
|
i = 0;
|
|
while (1) {
|
|
printf("\r %c", cursor[i]);
|
|
fflush(stdout);
|
|
i = ++i % 4;
|
|
|
|
/* poll for notification and invoke previously */
|
|
/* registered callback handler if appropriate */
|
|
T32_CheckStateNotify(0x0 /*dummy*/);
|
|
|
|
if (kbhit()) {
|
|
printf("\r\nYou've pressed a key to end this application.\n");
|
|
break;
|
|
}
|
|
|
|
Sleep(200);
|
|
}
|
|
|
|
|
|
if (T32_Exit() == T32_OK) {
|
|
printf("\nSucceeded to close the remote connection with TRACE32 PowerView.\n\n");
|
|
return EXIT_SUCCESS;
|
|
}
|
|
else {
|
|
printf("\nFailed to close the remote connection with TRACE32 PowerView.\n\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
/* Callback handler invoked when TRACE32 reports EDIT.EXTernal command.
|
|
* @param dummy: unused in this sample, is taken from T32_Check StateNotify() call
|
|
* @param lineNr: line number for placing the cursor
|
|
* @param fileName: name of file to edit
|
|
*/
|
|
static void T32_callbackEditExtern(int dummy, int lineNr, char *fileName)
|
|
{
|
|
static int i = 0;
|
|
|
|
/* application may open 3rd party editor */
|
|
printf("\r TRACE32: EDIT.EXTern request with filename %s and line number %d. (#%d)\n\n", fileName, lineNr, i++);
|
|
|
|
}
|
|
|
|
|
|
/* Callback handler invoked when the breakpoint configuration changes, e.g. after Break.Set command.
|
|
* @param dummy: unused in this sample, is taken from T32_Check StateNotify() call
|
|
*/
|
|
static void T32_callbackBreakpointConfig(int dummy)
|
|
{
|
|
static int i = 0;
|
|
|
|
/* application may request latest breakpoint information */
|
|
printf("\r TRACE32: breakpoint configuration has been changed. (#%d)\n\n", i++);
|
|
|
|
}
|
|
|
|
|
|
/* Callback handler invoked when the target program stops execution, e.g. after Break command.
|
|
* @param dummy: unused in this sample, is taken from T32_Check StateNotify() call
|
|
*/
|
|
static void T32_callbackBreak(int dummy)
|
|
{
|
|
static int i = 0;
|
|
|
|
/* application may trigger further actions */
|
|
printf("\r TRACE32: execution of target program has been stopped. (#%d)\n\n", i++);
|
|
|
|
}
|
|
|