/* ********************************************************************************************* * @Title: TRACE32 Remote API that use T32_Cmd() and T32_GetMessage() * @Description: * TRACE32 Remote API sample program illustrating the use of T32_Cmd() and T32_GetMessage() * This demo send a command to TRACE32 PowerView and request any AREA message. * Syntax: t32apicmd [node=] [port=] * Example: t32apicmd node=localhost port=20000 PRINT VERSION.BUILD() * * 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. * * This sample program also shows how to establish and close a remote connection with TRACE32. * * $Id: t32apicmd.c 168148 2024-03-28 16:57:07Z irohloff $ * $LastChangedRevision: 168148 $ * $LastChangedBy: irohloff $ * * @Copyright: (C) 1989-2020 Lauterbach GmbH, licensed for use with TRACE32(R) only * ********************************************************************************************* * $Id: t32apicmd.c 168148 2024-03-28 16:57:07Z irohloff $ */ #define WIN_MESSAGEMODENONE 0x00 #define WIN_MESSAGEMODEINFO 0x01 #define WIN_MESSAGEMODEERROR 0x02 #define WIN_MESSAGEMODESTATE 0x04 #define WIN_MESSAGEMODEWARNINFO 0x08 #define WIN_MESSAGEMODEERRORINFO 0x10 #define WIN_MESSAGEMODETEMP 0x20 #define WIN_MESSAGEMODETEMPINFO 0x40 #include "t32.h" #include #include #include uintptr_t indexOf_shift(char* base, char* str, size_t startIndex) { size_t baselen = strlen(base); char* pos = NULL; // str should not longer than base if ((strlen(str) > baselen) || (startIndex > baselen)) return -1; if (startIndex < 0 ) { startIndex = 0; } pos = strstr(base+startIndex, str); if (pos == NULL) return -1; return pos - base; } uintptr_t lastIndexOf(char* base, char* str) { uintptr_t start; uintptr_t endinit; uintptr_t end; uintptr_t endtmp; // str should not longer than base if (strlen(str) > strlen(base)) return -1; start = 0; endinit = strlen(base) - strlen(str); end = endinit; 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; } } return start; } static int executeCommand(const char *cmdstring) { uint16_t msgtype; char msgstring[4095]; /* bugfix: calling T32_Cmd("PRINT") first ensures */ /* that T32_GetMessage() will return no old message */ if (T32_Cmd("PRINT") != T32_OK) { printf(" Failed to execute 'T32_Cmd(""PRINT"")'\n\n" ); return EXIT_FAILURE; } if (T32_Cmd(cmdstring) != T32_OK) { printf(" Failed to execute erroneous user command '%s'\n\n", cmdstring); return EXIT_FAILURE; } if (T32_GetMessage(msgstring, &msgtype) != T32_OK) { printf(" Failed to query return message.\n\n"); return EXIT_FAILURE; } if (msgtype >= (WIN_MESSAGEMODETEMPINFO << 1)) { printf(" Failed to determine the type of the return message.\n\n"); return EXIT_FAILURE; } if ( msgtype == WIN_MESSAGEMODENONE || /* bugfix: for empty message the message type may be temp => DO NOT DISPLAY */ (msgstring[0] == 0 && (msgtype & (WIN_MESSAGEMODETEMPINFO|WIN_MESSAGEMODETEMP)) != 0) ) { printf(" successfully executed user command '%s'\n\n", cmdstring); return EXIT_SUCCESS; } if (msgtype & WIN_MESSAGEMODEINFO) printf(" info"); if (msgtype & WIN_MESSAGEMODESTATE) printf(" status"); if (msgtype & WIN_MESSAGEMODEWARNINFO) printf(" warning"); if ((msgtype & WIN_MESSAGEMODEERRORINFO) || (msgtype & WIN_MESSAGEMODEERROR)) printf(" error"); if ((msgtype & WIN_MESSAGEMODETEMPINFO) || (msgtype & WIN_MESSAGEMODETEMP)) printf(" miscellaneous"); printf(" message: %s\n\n", msgstring); return EXIT_SUCCESS; } int main(int argc, char **argv) { size_t i = 0; size_t j = 0; int argn = 1; int retval = EXIT_SUCCESS; char cmdstring[2041]; size_t index = lastIndexOf(__FILE__, "."); char filename [100]; if (index == -1 ) { strcpy(filename,__FILE__); } else { strncpy(filename, __FILE__, index); } /*** 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)) { printf("\n\n Syntax: %s.exe [node=] [port=] ", filename); printf( "\n Example: %s.exe node=localhost port=20000 PRINT VERSION.BUILD()\n\n\n", filename); printf(" Messages printed to TRACE32 AREA window are also printed to this\n"); printf(" shell. Most PRACTICE commands like Go only generate a message in\n"); printf(" case of an error. Escaping is important if the PRINT command is\n"); printf( " used (try PRINT \042\042\042hi\042\042\042 and" " PRINT \042\042\042\042\042\042\042hi\042\042\042\042\042\042\042).\n\n" ); return EXIT_FAILURE; } /* PRINT """hi""" and PRINT """""""hi""""""" work this way: */ /* If a command line argument/string is enclosed by quotes, it loses one opening and one closing */ /* quote when the string is stored in argv, so ""hi"" and """"""hi"""""" will be left. For the */ /* input-data of T32_Cmd() the C-language's standard quote-sign-escaping is applied, so "hi" and */ /* """hi""" are transfered to TRACE32 PowerView. TRACE32 expects strings to be enclosed by quotes */ /* and standard quote-sign-escaping is expected for further quotes, so hi and "hi" are printed. */ printf("\n\n Connecting... "); fflush(stdout); i = 0; for(;;) { i++; if (i >= 3) return EXIT_FAILURE; if (i > 1) { printf(" "); fflush(stdout); } if (T32_Init() != T32_OK) { T32_Exit(); if (i==1) printf("Failed once "); else printf("Failed twice"); printf(" to initialize the remote connection."); if (i >= 2) printf(" Terminating..."); printf("\n"); continue; } if (T32_Attach(T32_DEV_ICD) == T32_OK) break; T32_Exit(); if (i==1) printf("Failed once "); else printf("Failed twice"); printf(" to establish a remote connection with TRACE32 PowerView."); if (i >= 2) printf(" Terminating ..."); printf("\n"); } printf("\r Successfully established a remote connection with TRACE32 PowerView.\n"); /*** send input command to TRACE32 PowerView for execution and return any message ************/ for (i = argn; i < argc; i++) j += strlen(argv[i]); /* see T32_Cmd(),MaxPacketSize in hremote.c */ if ((j + argc - argn - 1 > 2048 - 8) || (sizeof(cmdstring) != 2041)) { printf(" Failed to send remote command, command exceeds 2040 characters.\n"); return EXIT_FAILURE; } strcpy(cmdstring, argv[argn]); while (++argn < argc) { strcat(cmdstring, " "); strcat(cmdstring, argv[argn]); } retval = executeCommand(cmdstring); if (T32_Exit() != T32_OK) { printf(" Failed to close the remote connection port on the dos shell application's side.\n\n"); return EXIT_FAILURE; } return retval; }