HEX Reader
I am trying to fault find a device attached to an NI-3000 and the device uses HEX strings to communicate. I have been logging all communications to a file and notepad will not read the hex codes in the file (?? Q).
Do any of you use any HEX readers that you could recomend ?
Do any of you use any HEX readers that you could recomend ?
Comments
http://www.hhdsoftware.com/Products/home/hex-editor-free.html
The device I am logging has no fixed end of line or beginning of line characters and occasionally it varies in length. When writing to the log file I add a time to the start of the line to allow me to easily see when the command was sent and it also helps divides the log file up a bit so I can quickly find the information and see patterns.
When I use the HEX viewer it has no structure to how it is viewed and justs wraps it in fixed widths presenting a window full of HEX. It would help if I could identify a set of characters as EOL markers or split it out into blocks, which I would match up to my date stamps to help break the view up, but I?m not sure if that?s possible.
I then thought it may be easier to decode the HEX and write the logs files in ASCII, then I could present them how I wanted and view then in notepad.
e.g.
<date>: $01,$02,$05
<date>: $03,$02,$05,$02,$05
DEFINE_DEVICE dvTP = 10001:1:0 DEFINE_VARIABLE CHAR cTestData[] = {1,2,5,10,255} DEFINE_FUNCTION fnMakeThisFriendly(char instring[]) { CHAR outstring[128] INTEGER x FOR (x=1; x<=LENGTH_ARRAY(instring); x++) { outstring = "outstring,'$',FORMAT('%02X',instring[x]),$20" } outstring = "DATE,':',$20,outstring" //replace this with file write routine SEND_STRING 0, outstring } DEFINE_EVENT BUTTON_EVENT[dvTP,1] { PUSH: { fnMakeThisFriendly(cTestData) } }Here is the output when button 1 is pushed:Line 1 :: 09/28/07: $01 $02 $05 $0A $FF - 02:18:50
Cheers
Glad to help. FORMAT() is the super-duper big brother/cousin of ITOA() and is extremely useful indeed.
Cheers.
This line works fine:
outstring = "outstring,'$',FORMAT('%02X',instring[x]),$20"
But I should have wrote it this way instead:
outstring = "outstring,FORMAT('$%02X',instring[x]),$20"
Alot of people don't know, but there is actually a debug.axi include file that is installed with studio.
see the include file below. It contains alot of x to string conversation for sending to terminal.
C:\Program Files\Common Files\AMXShare\AXIs\debug.axi
PROGRAM_NAME='debug' (***********************************************************) (* FILE CREATED ON: 12/28/2001 AT: 00:00:00 *) (***********************************************************) (* FILE_LAST_MODIFIED_ON: 06/30/2006 AT: 16:06:33 *) (***********************************************************) (* FILE REVISION: Rev 2.04 GLM *) (* REVISION DATE: 06/30/2006 AT: 16:06:33 *) (* - 'SEND DEVICE_INFO TO DEBUG' now trims garbage *) (* from SN's less than 16 characters long. *) (***********************************************************) (* FILE REVISION: Rev 2.03 GLM *) (* REVISION DATE: 07/08/2005 AT: 15:12:54 *) (* - All "DEV..." functions now return the actual *) (* system number, never 0... *) (***********************************************************) (*!!FILE REVISION: 2.02 GLM *) (* REVISION DATE: 05/31/2005 *) (* - In the 'SEND...' calls, replace STR1 with an *) (* equal number of spaces if a single reply takes *) (* more than one line, after the first line. *) (* So it's easier to distiguish between multiple *) (* responses. *) (***********************************************************) (*!!FILE REVISION: 2.01 GLM *) (* REVISION DATE: 02/01/2005 *) (* - added DPS_TO_STRING, similar to DEV_TO_STRING *) (* but always returns actual system number. *) (* - added 'STRING TO DEV' call. A call because *) (* functions cannot return complex data types such *) (* as DEVs. *) (* - fixed problem where sometimes an extra ' would *) (* sneak into 'SEND 7BIT ASCII TO DEBUG' responses. *) (* - 'SEND ASCII TO DEBUG' and 'SEND ASCII TO MASTER' *) (* now format DEL as $7F. *) (* - changed the 'SEND...' calls so they no longer *) (* add a space between the header and data. *) (* - added 'SEND DEVICE_INFO TO DEBUG'. *) (* - rearranged calls alphabetically. *) (***********************************************************) (*!!FILE REVISION: 2.00 GLM *) (* REVISION DATE: 11/22/2004 *) (* - use STACK_VAR instead of LOCAL_VAR. *) (* - no longer has virtual device for control, it was *) (* never used in practice. *) (***********************************************************) (*!!FILE REVISION: 1.07 GLM *) (* REVISION DATE: 04/22/2004 *) (* - added DEV_CHAN_TO_STRING, DEV_LEV_TO_STRING *) (* these functions take a seperate dev,chan or *) (* dev,lev as parameters. *) (***********************************************************) (*!!FILE REVISION: 1.06 GLM *) (* REVISION DATE: 09/15/2003 *) (* - modified 'SEND INTEGER TO DEBUG' to only format *) (* line length. It had been a misnamed version of *) (* 'SEND DECIMAL TO DEBUG'. *) (***********************************************************) (*!!FILE REVISION: 1.05 GLM *) (* REVISION DATE: 05/29/2003 *) (* - added 'SEND 7BIT ASCII TO DEBUG' *) (* characters >= $7F are formated as hex *) (* - remove ; from #DEFINE __DEBUG_LIB__ *) (* - added explicit parameter types where missing *) (* - added 'SEND DECIMAL TO DEBUG'. This is actually *) (* what 'SEND INTEGER TO DEBUG' should have been *) (* named. *) (***********************************************************) (*!!FILE REVISION: 1.04 GLM *) (* REVISION DATE: 01/21/2003 *) (* - added 'SEND INTEGER TO DEBUG' *) (***********************************************************) (*!!FILE REVISION: 1.03 GLM *) (* REVISION DATE: 08/28/2002 *) (* Code cleanup: *) (* - added line ends ";" for Studio debug mode. *) (* - changed remaining LENGTH_STRING's to *) (* LENGTH_ARRAY's. *) (* - explicitly declare all variable types. *) (***********************************************************) (*!!FILE REVISION: 1.02 GLM *) (* REVISION DATE: 04/27/2002 *) (* - Added 'SEND ASCII TO DEBUG' and 'SEND ITOHEX TO *) (* DEBUG'. *) (* These calls have: *) (* - Device parameter to allow sending info to *) (* devices other than 0:0:0, for example to virtual *) (* device for multi master debugging. *) (* - Line length parameter to allow different line *) (* lengths. If this is 0, line length defaults to *) (* 80 for mode 2, 67 for all other modes *) (* - Mode parameter, if set to 2 appends <cr>,<lf> *) (* to each line for master 'MSG ON 2' *) (*!!FILE REVISION: 1.01 GLM *) (* REVISION DATE: 04/27/2002 *) (* - First line returned by the 'SEND ASCII...' and *) (* 'SEND ITOHEX...' calls is one less character *) (* than subsequent lines to account for Netlinx '>' *) (* prompt. Removed in version 1.02. *) (***********************************************************) (*!!FILE REVISION: 1.00 GLM *) (* REVISION DATE: 03/26/2002 *) (* *) (* COMMENTS: *) (* DEBUG FUNCTIONS AND CALLS *) /* 1 FUNCTION CHAR[17] DEV_TO_STRING (DEV dvDEV) */ /* 2 FUNCTION CHAR[25] DEVCHAN_TO_STRING (DEVCHAN dcDC) */ /* 3 FUNCTION CHAR[25] DEV_CHAN_TO_STRING (DEV dvDEV, INTEGER nCH) */ /* 4 FUNCTION CHAR[25] DEVLEV_TO_STRING (DEVLEV dlDL) */ /* 5 FUNCTION CHAR[25] DEV_LEV_TO_STRING (DEV dvDEV, INTEGER nLV) */ /* 6 FUNCTION CHAR[17] DPS_TO_STRING (DEV dvDEV) */ /* 7 CALL 'SEND 131 BYTE PACKETS TO MASTER' (sSTRING[]) */ /* 8 CALL 'SEND 7BIT ASCII TO DEBUG' (DEV dvDEBUG,STR1[],STR2[],nLine,nMode)*/ /* 9 CALL 'SEND ASCII TO DEBUG' (DEV dvDEBUG,STR1[],STR2[],nLine,nMode) */ /* 10 CALL 'SEND ASCII TO MASTER' (STR1[],STR2[]) */ /* 11 CALL 'SEND DECIMAL TO DEBUG' (DEV dvDEBUG,STR1[],STR2[],nLine,nMode) */ /* 12 CALL 'SEND DEVICE_INFO TO DEBUG' (DEV dvDEBUG, DEV dvDEV) */ /* 13 CALL 'SEND INTEGER TO DEBUG' (DEV dvDEBUG,STR1[],STR2[],nLine,nMode) */ /* 14 CALL 'SEND ITOHEX TO DEBUG' (DEV dvDEBUG,STR1[],STR2[],nLine,nMode) */ /* 15 CALL 'SEND ITOHEX TO MASTER' (STR1[],STR2[]) */ /* 16 CALL 'STRING TO DEV' (sDEV[],dvDEV) */ (***********************************************************) #IF_NOT_DEFINED __DEBUG_LIB__ #DEFINE __DEBUG_LIB__ (***********************************************************) (* DEVICE NUMBER DEFINITIONS GO BELOW *) (***********************************************************) DEFINE_DEVICE (***********************************************************) (* CONSTANT DEFINITIONS GO BELOW *) (***********************************************************) DEFINE_CONSTANT // VERSION FOR CODE CHAR __DEBUG_LIB_NAME__[12] = ' debug.axi'; CHAR __DEBUG_LIB_VERSION__[] = '2.04'; CHAR __SPACES__[128] = { $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20, $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20, $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20, $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20, $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20, $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20, $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20, $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20 } (***********************************************************) (* SUBROUTINE DEFINITIONS GO BELOW *) (***********************************************************) (* EXAMPLE: DEFINE_FUNCTION <RETURN_TYPE> <NAME> (<PARAMETERS>) *) (* EXAMPLE: DEFINE_CALL '<NAME>' (<PARAMETERS>) *) /////////////////////////// // DEBUG FUNCTIONS/CALLS // /////////////////////////// // DEFINE_FUNCTION DEV_TO_STRING // PARAMETER: // dvDEV - DEVICE USED // RETURNS: // dvDEV AS A STRING DEFINE_FUNCTION CHAR[17] DEV_TO_STRING (DEV dvDEV) { IF (dvDEV.SYSTEM = 0) // if device is defined as local, i.e. system is 0 RETURN "FORMAT('%d',dvDEV.NUMBER),':',FORMAT('%d',dvDEV.PORT),':',FORMAT('%d',SYSTEM_NUMBER)"; ELSE RETURN "FORMAT('%d',dvDEV.NUMBER),':',FORMAT('%d',dvDEV.PORT),':',FORMAT('%d',dvDEV.SYSTEM)"; } // DEFINE_FUNCTION DEVCHAN_TO_STRING // PARAMETER: // dcDC - DEVCHAN USED // RETURNS: // DEVCHAN AS A STRING, IN BRACKETS DEFINE_FUNCTION CHAR[25] DEVCHAN_TO_STRING (DEVCHAN dcDC) { IF (dcDC.DEVICE.SYSTEM = 0) // if device is defined as local, i.e. system is 0 { RETURN "'[', FORMAT('%d',dcDC.DEVICE.NUMBER),':', FORMAT('%d',dcDC.DEVICE.PORT),':', FORMAT('%d',SYSTEM_NUMBER), ',', FORMAT('%d',dcDC.CHANNEL), ']'"; } ELSE { RETURN "'[', FORMAT('%d',dcDC.DEVICE.NUMBER),':', FORMAT('%d',dcDC.DEVICE.PORT),':', FORMAT('%d',dcDC.DEVICE.SYSTEM), ',', FORMAT('%d',dcDC.CHANNEL), ']'"; } } // DEFINE_FUNCTION DEV_CHAN_TO_STRING // PARAMETER: // dvDEV - DEV USED // nCH - CHAN USED // RETURNS: // DEVCHAN AS A STRING, IN BRACKETS DEFINE_FUNCTION CHAR[25] DEV_CHAN_TO_STRING (DEV dvDEV, INTEGER nCH) { IF (dvDEV.SYSTEM = 0) // if device is defined as local, i.e. system is 0 { RETURN "'[', FORMAT('%d',dvDEV.NUMBER),':', FORMAT('%d',dvDEV.PORT),':', FORMAT('%d',SYSTEM_NUMBER), ',', FORMAT('%d',nCH), ']'"; } ELSE { RETURN "'[', FORMAT('%d',dvDEV.NUMBER),':', FORMAT('%d',dvDEV.PORT),':', FORMAT('%d',dvDEV.SYSTEM), ',', FORMAT('%d',nCH), ']'"; } } // DEFINE_FUNCTION DEVLEV_TO_STRING // PARAMETER: // dlDL - DEVLEV USED // RETURNS: // DEVLEV AS A STRING DEFINE_FUNCTION CHAR[25] DEVLEV_TO_STRING (DEVLEV dlDL) { IF (dlDL.DEVICE.SYSTEM = 0) // if device is defined as local, i.e. system is 0 { RETURN "FORMAT('%d',dlDL.DEVICE.NUMBER),':', FORMAT('%d',dlDL.DEVICE.PORT),':', FORMAT('%d',SYSTEM_NUMBER), ',', FORMAT('%d',dlDL.LEVEL)"; } ELSE { RETURN "FORMAT('%d',dlDL.DEVICE.NUMBER),':', FORMAT('%d',dlDL.DEVICE.PORT),':', FORMAT('%d',dlDL.DEVICE.SYSTEM), ',', FORMAT('%d',dlDL.LEVEL)"; } } // DEFINE_FUNCTION DEV_LEV_TO_STRING // PARAMETER: // dvDEV - DEV USED // nLV - LEV USED // RETURNS: // DEVLEV AS A STRING DEFINE_FUNCTION CHAR[25] DEV_LEV_TO_STRING (DEV dvDEV, INTEGER nLV) { IF (dvDEV.SYSTEM = 0) // if device is defined as local, i.e. system is 0 { RETURN "FORMAT('%d',dvDEV.NUMBER),':', FORMAT('%d',dvDEV.PORT),':', FORMAT('%d',SYSTEM_NUMBER), ',', FORMAT('%d',nLV)"; } ELSE { RETURN "FORMAT('%d',dvDEV.NUMBER),':', FORMAT('%d',dvDEV.PORT),':', FORMAT('%d',dvDEV.SYSTEM), ',', FORMAT('%d',nLV)"; } } // DEFINE_FUNCTION DPS_TO_STRING // PARAMETER: // dvDEV - DEVICE USED // RETURNS: // dvDEV AS A STRING // this function differs from the original DEV_TO_STRING in that it always // returns the actual system number, never system 0 DEFINE_FUNCTION CHAR[17] DPS_TO_STRING (DEV dvDEV) { IF (dvDEV.SYSTEM = 0) // if device is defined as local, i.e. system is 0 RETURN "FORMAT('%d',dvDEV.NUMBER),':',FORMAT('%d',dvDEV.PORT),':',FORMAT('%d',SYSTEM_NUMBER)"; ELSE RETURN "FORMAT('%d',dvDEV.NUMBER),':',FORMAT('%d',dvDEV.PORT),':',FORMAT('%d',dvDEV.SYSTEM)"; } // DEFINE_CALL 'SEND 131 BYTE PACKETS TO MASTER' // BREAKS STRINGS UP INTO THE MAXIMUM SIZE // THAT CAN BE SENT TO THE MASTER, SENDS // THEM TO THE MASTER. // PARAMETER: // sTRING - STRING TO BE SENT TO MASTER DEFINE_CALL 'SEND 131 BYTE PACKETS TO MASTER' (CHAR sSTRING[]) STACK_VAR CHAR s131_BYTES[131]; { WHILE (LENGTH_STRING(sSTRING) > 131) { s131_BYTES = LEFT_STRING(sSTRING,131); sSTRING = RIGHT_STRING(sSTRING,LENGTH_STRING(sSTRING)-131); SEND_STRING 0:0:0,"s131_BYTES"; } IF (LENGTH_STRING(sSTRING)) { SEND_STRING 0:0:0,"sSTRING"; } } // CALL 'SEND 7BIT ASCII TO DEBUG' // PASSES ASCII CHARACTERS UNFORMATTED, ASCII STRINGS INSIDE SINGLE-QUOTES // FORMATS CHARS >= $7F (del) AS 2 DIGIT HEX, SEPERATED BY COMMAS // FORMATS CONTROL CHARACTERS AS 2 DIGIT HEX, SEPERATED BY COMMAS // ASCII STRINGS SEPERATED FROM HEX BY COMMAS // PARAMETERS: // dvDEBUG IS DESTINATION // STR1 IS HEADER // STR2 IS DATA TO BE FORMATTED // nLine IS LINE LENGTH. 0 = default = 80 for nMode 2, 67 for all others. // nMode is MSG ON mode. 2 = append <cr>,<lf> to lines. DEFINE_CALL 'SEND 7BIT ASCII TO DEBUG' (DEV dvDEBUG,CHAR STR1[],CHAR STR2[],INTEGER nLINE,INTEGER nMODE) STACK_VAR integer X; integer STR1_LEN; integer STR2_LEN; integer ASCII_PACKET_LEN; STACK_VAR char ASCII[16000]; STACK_VAR INTEGER FIRST_STRING_SENT; { STR1_LEN = LENGTH_ARRAY(STR1); STR2_LEN = LENGTH_ARRAY(STR2); FOR (X = 1; X <= STR2_LEN; X++) { // IF IT'S A CONTROL CHARACTER // OR DEL OR EXTENDED ASCII IF (STR2[X] < $20 || STR2[X] >= $7F) { IF (X = STR2_LEN) // IF IT'S THE LAST BYTE { // JUST PRINT $XX ASCII = "ASCII,FORMAT('$%0 2X',STR2[X])"; } // IF THE NEXT BYTE IS A CONTROL CHARACTER // OR DEL OR EXTENDED ASCII ELSE IF (STR2[X+1] < $20 || STR2[X+1] > $7F) { // END WITH COMMA ASCII = "ASCII,FORMAT('$%0 2X,',STR2[X])"; } ELSE { // END WITH COMMA/SINGLE QUOTE ASCII = "ASCII,FORMAT('$%0 2X,''',STR2[X])"; } } ELSE // IF IT'S PRINTABLE { SELECT { ACTIVE (X = 1): // IF IT'S THE FIRST BYTE { IF (X = STR2_LEN || // IF IT'S THE ONLY BYTE OR STR2[X+1] < $20 || // THE NEXT BYTE IS A CONTROL CHARACTER OR STR2[X+1] >= $7F) // THE NEXT BYTE IS DEL OR EXTENDED ASCII { // PUT IT IN SINGLE QUOTES ASCII = "'''',STR2[X],''''"; } ELSE { ASCII = "'''',STR2[X]"; // LEADING SINGLE QUOTE ONLY } } ACTIVE (X = STR2_LEN): // IF IT'S THE LAST BYTE { // TRAILING SINGLE QUOTE ONLY ASCII = "ASCII,STR2[X],''''"; } ACTIVE (STR2[X+1] < $20): // IF THE NEXT BYTE IS A CONTROL CHARACTER { // TRAILING SINGLE QUOTE/COMMA ASCII = "ASCII,STR2[X],''','"; } ACTIVE (STR2[X+1] >= $7F): // IF THE NEXT BYTE IS DEL OR EXTENDED ASCII { // TRAILING SINGLE QUOTE/COMMA ASCII = "ASCII,STR2[X],''','"; } ACTIVE (1): { ASCII = "ASCII,STR2[X]"; // JUST PRINT THE CHARACTER } } } } SELECT // SET THE ASCII PACKET LENGTH { ACTIVE (nLINE > 131): // MAX IS 131 CHARACTER LINE { ASCII_PACKET_LEN = 131 - STR1_LEN; } ACTIVE (nLINE > STR1_LEN && nLINE <= 131): { ASCII_PACKET_LEN = nLINE - STR1_LEN; } ACTIVE (nMODE = 2): // MODE 2 DEFAULT TO 80 CHARACTER LINE { ASCII_PACKET_LEN = 80 - STR1_LEN; } ACTIVE (1): // DEFAULT TO 67 CHARACTER LINE { ASCII_PACKET_LEN = 67 - STR1_LEN; } } // SEND THE DATA // WHILE THERE'S MORE THAN ONE LINE ... WHILE (LENGTH_ARRAY(ASCII) > ASCII_PACKET_LEN) { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN),13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN)"; } ASCII = RIGHT_STRING(ASCII,LENGTH_STRING(ASCII)-ASCII_PACKET_LEN) IF (!FIRST_STRING_SENT) // replace STR1 with spaces after first pass { ON[FIRST_STRING_SENT] STR1 = LEFT_STRING(__SPACES__,LENGTH_STRING(STR1)) } } IF (LENGTH_ARRAY(ASCII)) // IF THERE'S ANYTHING LEFT SEND IT { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,ASCII,13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,ASCII"; } } } // CALL 'SEND ASCII TO DEBUG' // PASSES ASCII CHARACTERS UNFORMATTED, ASCII STRINGS INSIDE SINGLE-QUOTES // FORMATS CONTROL CHARACTERS AS 2 DIGIT HEX, SEPERATED BY COMMAS // ASCII STRINGS SEPERATED FROM HEX BY COMMAS // PARAMETERS: // dvDEBUG IS DESTINATION // STR1 IS HEADER // STR2 IS DATA TO BE FORMATTED // nLine IS LINE LENGTH. 0 = default = 80 for nMode 2, 67 for all others. // nMode is MSG ON mode. 2 = append <cr>,<lf> to lines. DEFINE_CALL 'SEND ASCII TO DEBUG' (DEV dvDEBUG,CHAR STR1[],CHAR STR2[],INTEGER nLINE,INTEGER nMODE) STACK_VAR integer X; integer STR1_LEN; integer STR2_LEN; integer ASCII_PACKET_LEN; STACK_VAR char ASCII[16000]; STACK_VAR INTEGER FIRST_STRING_SENT; { STR1_LEN = LENGTH_ARRAY(STR1); STR2_LEN = LENGTH_ARRAY(STR2); FOR (X = 1; X <= STR2_LEN; X++) { // IF IT'S A CONTROL CHARACTER IF (STR2[X] < $20 || STR2[X] = $7F) { IF (X = STR2_LEN) // IF IT'S THE LAST BYTE { // JUST PRINT $XX ASCII = "ASCII,FORMAT('$%0 2X',STR2[X])"; } // IF THE NEXT BYTE IS A CONTROL CHARACTER ELSE IF (STR2[X+1] < $20 || STR2[X+1] = $7F) { // END WITH COMMA ASCII = "ASCII,FORMAT('$%0 2X,',STR2[X])"; } ELSE { // END WITH COMMA/SINGLE QUOTE ASCII = "ASCII,FORMAT('$%0 2X,''',STR2[X])"; } } ELSE // IF IT'S PRINTABLE { SELECT { ACTIVE (X = 1): // IF IT'S THE FIRST BYTE { IF (X = STR2_LEN || // IF IT'S THE ONLY BYTE OR // THE NEXT BYTE IS A CONTROL CHARACTER STR2[X+1] < $20 || STR2[X+1] = $7F) { // PUT IT IN SINGLE QUOTES ASCII = "'''',STR2[X],''''"; } ELSE { ASCII = "'''',STR2[X]"; // LEADING SINGLE QUOTE ONLY } } ACTIVE (X = STR2_LEN): // IF IT'S THE LAST BYTE { // TRAILING SINGLE QUOTE ONLY ASCII = "ASCII,STR2[X],''''"; } // IF THE NEXT BYTE IS A CONTROL CHARACTER ACTIVE (STR2[X+1] < $20 || STR2[X+1] = $7F): { // TRAILING SINGLE QUOTE/COMMA ASCII = "ASCII,STR2[X],''','"; } ACTIVE (1): { ASCII = "ASCII,STR2[X]"; // JUST PRINT THE CHARACTER } } } } SELECT // SET THE ASCII PACKET LENGTH { ACTIVE (nLINE > 131): // MAX IS 131 CHARACTER LINE { ASCII_PACKET_LEN = 131 - STR1_LEN; } ACTIVE (nLINE > STR1_LEN && nLINE <= 131): { ASCII_PACKET_LEN = nLINE - STR1_LEN; } ACTIVE (nMODE = 2): // MODE 2 DEFAULT TO 80 CHARACTER LINE { ASCII_PACKET_LEN = 80 - STR1_LEN; } ACTIVE (1): // DEFAULT TO 67 CHARACTER LINE { ASCII_PACKET_LEN = 67 - STR1_LEN; } } // SEND THE DATA // WHILE THERE'S MORE THAN ONE LINE ... WHILE (LENGTH_ARRAY(ASCII) > ASCII_PACKET_LEN) { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN),13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN)"; } ASCII = RIGHT_STRING(ASCII,LENGTH_STRING(ASCII)-ASCII_PACKET_LEN) IF (!FIRST_STRING_SENT) // replace STR1 with spaces after first pass { ON[FIRST_STRING_SENT] STR1 = LEFT_STRING(__SPACES__,LENGTH_STRING(STR1)) } } IF (LENGTH_ARRAY(ASCII)) // IF THERE'S ANYTHING LEFT SEND IT { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,ASCII,13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,ASCII"; } } } // CALL 'SEND ASCII TO MASTER' // PASSES ASCII CHARACTERS UNFORMATTED, ASCII STRINGS INSIDE SINGLE-QUOTES // FORMATS CONTROL CHARACTERS AS 2 DIGIT HEX, SEPERATED BY COMMAS // ASCII STRINGS SEPERATED FROM HEX BY COMMAS // PARAMETERS: // STR1 IS HEADER // STR2 IS DATA TO BE FORMATTED DEFINE_CALL 'SEND ASCII TO MASTER' (STR1[],STR2[]) STACK_VAR integer X; integer STR1_LEN; integer STR2_LEN; integer ASCII_PACKET_LEN; STACK_VAR char ASCII[16000]; STACK_VAR INTEGER FIRST_STRING_SENT; { STR1_LEN = LENGTH_ARRAY(STR1); STR2_LEN = LENGTH_ARRAY(STR2); FOR (X = 1; X <= STR2_LEN; X++) { // IF IT'S A CONTROL CHARACTER IF (STR2[X] < $20 || STR2[X] = $7F) { IF (X = STR2_LEN) // IF IT'S THE LAST BYTE { // JUST PRINT $XX ASCII = "ASCII,FORMAT('$%0 2X',STR2[X])"; } // IF THE NEXT BYTE IS A CONTROL CHARACTER ELSE IF (STR2[X+1] < $20 || STR2[X+1] = $7F) { // END WITH COMMA ASCII = "ASCII,FORMAT('$%0 2X,',STR2[X])"; } ELSE { // END WITH COMMA/SINGLE QUOTE ASCII = "ASCII,FORMAT('$%0 2X,''',STR2[X])"; } } ELSE // IF IT'S PRINTABLE { SELECT { ACTIVE (X = 1): // IF IT'S THE FIRST BYTE { IF (X = STR2_LEN || // IF IT'S THE ONLY BYTE OR // THE NEXT BYTE IS A CONTROL CHARACTER STR2[X+1] < $20 || STR2[X+1] = $7F) { // PUT IT IN SINGLE QUOTES ASCII = "'''',STR2[X],''''"; } ELSE { ASCII = "'''',STR2[X]"; // LEADING SINGLE QUOTE ONLY } } ACTIVE (X = STR2_LEN): // IF IT'S THE LAST BYTE { // TRAILING SINGLE QUOTE ONLY ASCII = "ASCII,STR2[X],''''"; } // IF THE NEXT BYTE IS A CONTROL CHARACTER ACTIVE (STR2[X+1] < $20 || STR2[X+1] = $7F): { // TRAILING SINGLE QUOTE/COMMA ASCII = "ASCII,STR2[X],''','"; } ACTIVE (1): { ASCII = "ASCII,STR2[X]"; // JUST PRINT THE CHARACTER } } } } ASCII_PACKET_LEN = 67 - STR1_LEN; // 80 CHARACTER LINE // 67 IS THE STRING LENGTH (MAX IS 131) // 13 CHARACTERS FOR TIMESTAMP WHILE (LENGTH_ARRAY(ASCII) > ASCII_PACKET_LEN) { SEND_STRING 0:0:0,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN)"; ASCII = RIGHT_STRING(ASCII,LENGTH_STRING(ASCII)-ASCII_PACKET_LEN); IF (!FIRST_STRING_SENT) // replace STR1 with spaces after first pass { ON[FIRST_STRING_SENT] STR1 = LEFT_STRING(__SPACES__,LENGTH_STRING(STR1)) } } IF (LENGTH_ARRAY(ASCII)) { SEND_STRING 0:0:0,"STR1,ASCII"; } } // 'SEND DECIMAL TO DEBUG' // FORMATS ALL CHARACTERS AS 3 DIGIT DECIMAL, SEPERATED BY COMMAS // PARAMETERS: // dvDEBUG IS DESTINATION // STR1 IS HEADER // STR2 IS DATA TO BE FORMATTED // nLine IS LINE LENGTH. 0 = default = 80 for nMode 2, 67 for all others. // nMode is MSG ON mode. 2 = append <cr>,<lf> to lines. DEFINE_CALL 'SEND DECIMAL TO DEBUG' (DEV dvDEBUG,CHAR STR1[],CHAR STR2[],INTEGER nLine,INTEGER nMode) STACK_VAR integer X; integer STR1_LEN; integer STR2_LEN; integer ASCII_PACKET_LEN; STACK_VAR char ASCII[16000]; STACK_VAR INTEGER FIRST_STRING_SENT; { STR1_LEN = LENGTH_ARRAY(STR1); STR2_LEN = LENGTH_ARRAY(STR2); FOR (X = 1; X <= STR2_LEN; X++) // BUILD UP ASCII STRING FROM STR2 { IF (X = STR2_LEN) // IF IT'S THE LAST BYTE { ASCII = "ASCII,FORMAT('%03d',STR2[X])"; } ELSE { ASCII = "ASCII,FORMAT('%03d,',STR2[X])"; } } SELECT // SET THE ASCII PACKET LENGTH { ACTIVE (nLINE > 131): // MAX IS 131 CHARACTER LINE { ASCII_PACKET_LEN = 131 - STR1_LEN; } ACTIVE (nLINE > STR1_LEN && nLINE <= 131): { ASCII_PACKET_LEN = nLINE - STR1_LEN; } ACTIVE (nMODE = 2): // MODE 2 DEFAULT TO 80 CHARACTER LINE { ASCII_PACKET_LEN = 80 - STR1_LEN; } ACTIVE (1): // DEFAULT TO 67 CHARACTER LINE { ASCII_PACKET_LEN = 67 - STR1_LEN; } } // SEND DATA // WHILE THERE'S MORE THAN ONE LINE... WHILE (LENGTH_ARRAY(ASCII) > ASCII_PACKET_LEN) { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN),13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN)"; } ASCII = RIGHT_STRING(ASCII,LENGTH_STRING(ASCII)-ASCII_PACKET_LEN); IF (!FIRST_STRING_SENT) // replace STR1 with spaces after first pass { ON[FIRST_STRING_SENT] STR1 = LEFT_STRING(__SPACES__,LENGTH_STRING(STR1)) } } IF (LENGTH_ARRAY(ASCII)) // IF THERE'S ANYTHING LEFT SEND IT { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,ASCII,13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,ASCII"; } } } /* CALL 'SEND DEVICE_INFO TO DEBUG' */ /* FUNCTION: Get device info structure for a device, */ /* then send the info to a debug device such */ /* as the master's debug port. */ /* PARAMETERS: dvDEBUG - device to receive device info */ /* dvDEV - device from which to get info */ DEFINE_CALL 'SEND DEVICE_INFO TO DEBUG' (DEV dvDEBUG, DEV dvDEV) STACK_VAR DEV_INFO_STRUCT devinfo STACK_VAR CHAR sSTR[100] { IF (DEVICE_ID(dvDEV)) // if device is online { DEVICE_INFO(dvDEV,devinfo) send_string dvDebug,"'D:P:S ',DPS_TO_STRING(dvDEV)" if (length_array(devinfo.MANUFACTURER_STRING)) send_string dvDebug,"'Manufacturer ',devinfo.MANUFACTURER_STRING" else send_string dvDebug,"'Manufacturer not available'" if (devinfo.MANUFACTURER) send_string dvDebug,"'Manufacturer ID ',ITOA(devinfo.MANUFACTURER)" else send_string dvDebug,"'Manufacturer ID not available'" if (length_array(devinfo.DEVICE_ID_STRING)) send_string dvDebug,"'Device ',devinfo.DEVICE_ID_STRING" else send_string dvDebug,"'Device not available'" send_string dvDebug,"'Device ID $',ITOHEX(devinfo.DEVICE_ID)" if (length_array(devinfo.VERSION)) send_string dvDebug,"'Version ',devinfo.VERSION" else send_string dvDebug,"'Version not available'" if (devinfo.FIRMWARE_ID) send_string dvDebug,"'Firmware ID $',ITOHEX(devinfo.FIRMWARE_ID)" else send_string dvDebug,"'Firmware ID not available'" if (length_array(devinfo.SERIAL_NUMBER)) { // if serial_number is blank for Netlinx device, // first byte is $00 if (find_string(devinfo.SERIAL_NUMBER,"$00",1) = 1) // 16 0's send_string dvDebug,"'Serial Number 0000000000000000'" // trim excess bytes if SN is not 16 chars long else if (find_string(devinfo.SERIAL_NUMBER,"$00",1) > 1) send_string dvDebug,"'Serial Number ', LEFT_STRING(devinfo.SERIAL_NUMBER, LENGTH_ARRAY(devinfo.SERIAL_NUMBER) - (17 - FIND_STRING(devinfo.serial_number,"$00",1)) )" else // if no $00, just send the whole string send_string dvDebug,"'Serial Number ',devinfo.SERIAL_NUMBER" } else // this should never happen send_string dvDebug,"'Serial Number not available'" SWITCH (devinfo.SOURCE_TYPE) { CASE SOURCE_TYPE_NO_ADDRESS: send_string dvDebug,"'Source Type $00: not available'" CASE SOURCE_TYPE_NEURON_ID: send_string dvDebug,"'Source Type $01: connected via ICSNet'" CASE SOURCE_TYPE_IP_ADDRESS: send_string dvDebug,"'Source Type $02: connected via ethernet'" CASE SOURCE_TYPE_AXLINK: send_string dvDebug,"'Source Type $03: connected via AXLink'" CASE SOURCE_TYPE_NEURON_SUBNODE_ICSP: send_string dvDebug,"'Source Type $10: connected via ICSNet'" CASE SOURCE_TYPE_NEURON_SUBNODE_PL: send_string dvDebug,"'Source Type $11: connected via ICSNet'" CASE SOURCE_TYPE_IP_SOCKET_ADDRESS: send_string dvDebug,"'Source Type $12: connected via ethernet'" CASE SOURCE_TYPE_RS232: send_string dvDebug,"'Source Type $13: connected via RS232'" CASE $20: send_string dvDebug,"'Source Type $20: internal to the NetLinx controller'" DEFAULT: send_string dvDebug,FORMAT('Source Type $%02X: unknown',devinfo.SOURCE_TYPE) } if (length_array(devinfo.SOURCE_STRING)) send_string dvDebug,"'Source String ',devinfo.SOURCE_STRING" else send_string dvDebug,"'Source String not available'" } else send_string dvDebug,"'D:P:S ',DPS_TO_STRING(dvDEV),' not online'" } // 'SEND INTEGER TO DEBUG' // DOES NOT FORMAT CHARACTERS, FORMATS LINE LENGTH ONLY // PARAMETERS: // dvDEBUG IS DESTINATION // STR1 IS HEADER // STR2 IS DATA TO BE FORMATTED // nLine IS LINE LENGTH. 0 = default = 80 for nMode 2, 67 for all others. // nMode is MSG ON mode. 2 = append <cr>,<lf> to lines. DEFINE_CALL 'SEND INTEGER TO DEBUG' (DEV dvDEBUG,CHAR STR1[],CHAR STR2[],INTEGER nLine,INTEGER nMode) STACK_VAR integer STR1_LEN; integer STR2_LEN; integer PACKET_LEN; STACK_VAR char sTEMP[16000]; STACK_VAR INTEGER FIRST_STRING_SENT; { STR1_LEN = LENGTH_ARRAY(STR1); STR2_LEN = LENGTH_ARRAY(STR2); sTEMP = STR2; // BUILD UP TEMP STRING FROM STR2 SELECT // SET THE PACKET LENGTH { ACTIVE (nLINE > 131): // MAX IS 131 CHARACTER LINE { PACKET_LEN = 131 - STR1_LEN; } ACTIVE (nLINE > STR1_LEN && nLINE <= 131): { PACKET_LEN = nLINE - STR1_LEN; } ACTIVE (nMODE = 2): // MODE 2 DEFAULT TO 80 CHARACTER LINE { PACKET_LEN = 80 - STR1_LEN; } ACTIVE (1): // DEFAULT TO 67 CHARACTER LINE { PACKET_LEN = 67 - STR1_LEN; } } // SEND DATA // WHILE THERE'S MORE THAN ONE LINE... WHILE (LENGTH_ARRAY(sTEMP) > PACKET_LEN) { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(sTEMP,PACKET_LEN),13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(sTEMP,PACKET_LEN)"; } sTEMP = RIGHT_STRING(sTEMP,LENGTH_STRING(sTEMP)-PACKET_LEN); IF (!FIRST_STRING_SENT) // replace STR1 with spaces after first pass { ON[FIRST_STRING_SENT] STR1 = LEFT_STRING(__SPACES__,LENGTH_STRING(STR1)) } } IF (LENGTH_ARRAY(sTEMP)) // IF THERE'S ANYTHING LEFT SEND IT { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,sTEMP,13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,sTEMP"; } } } // 'SEND ITOHEX TO DEBUG' // FORMATS ALL CHARACTERS AS 2 DIGIT HEX, SEPERATED BY COMMAS // PARAMETERS: // dvDEBUG IS DESTINATION // STR1 IS HEADER // STR2 IS DATA TO BE FORMATTED // nLine IS LINE LENGTH. 0 = default = 80 for nMode 2, 67 for all others. // nMode is MSG ON mode. 2 = append <cr>,<lf> to lines. DEFINE_CALL 'SEND ITOHEX TO DEBUG' (DEV dvDEBUG,CHAR STR1[],CHAR STR2[],INTEGER nLine,INTEGER nMode) STACK_VAR integer X; integer STR1_LEN; integer STR2_LEN; integer ASCII_PACKET_LEN; STACK_VAR char ASCII[16000]; STACK_VAR INTEGER FIRST_STRING_SENT; { STR1_LEN = LENGTH_ARRAY(STR1); STR2_LEN = LENGTH_ARRAY(STR2); FOR (X = 1; X <= STR2_LEN; X++) // BUILD UP ASCII STRING FROM STR2 { IF (X = STR2_LEN) // IF IT'S THE LAST BYTE { ASCII = "ASCII,FORMAT('$%0 2X',STR2[X])"; } ELSE { ASCII = "ASCII,FORMAT('$%0 2X,',STR2[X])"; } } SELECT // SET THE ASCII PACKET LENGTH { ACTIVE (nLINE > 131): // MAX IS 131 CHARACTER LINE { ASCII_PACKET_LEN = 131 - STR1_LEN; } ACTIVE (nLINE > STR1_LEN && nLINE <= 131): { ASCII_PACKET_LEN = nLINE - STR1_LEN; } ACTIVE (nMODE = 2): // MODE 2 DEFAULT TO 80 CHARACTER LINE { ASCII_PACKET_LEN = 80 - STR1_LEN; } ACTIVE (1): // DEFAULT TO 67 CHARACTER LINE { ASCII_PACKET_LEN = 67 - STR1_LEN; } } // SEND DATA // WHILE THERE'S MORE THAN ONE LINE... WHILE (LENGTH_ARRAY(ASCII) > ASCII_PACKET_LEN) { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN),13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN)"; } ASCII = RIGHT_STRING(ASCII,LENGTH_STRING(ASCII)-ASCII_PACKET_LEN); IF (!FIRST_STRING_SENT) // replace STR1 with spaces after first pass { ON[FIRST_STRING_SENT] STR1 = LEFT_STRING(__SPACES__,LENGTH_STRING(STR1)) } } IF (LENGTH_ARRAY(ASCII)) // IF THERE'S ANYTHING LEFT SEND IT { IF (nMODE = 2) { SEND_STRING dvDEBUG,"STR1,ASCII,13,10"; } ELSE { SEND_STRING dvDEBUG,"STR1,ASCII"; } } } // SEND_ITOHEX_TO_MASTER // FORMATS ALL CHARACTERS AS 2 DIGIT HEX, SEPERATED BY COMMAS // PARAMETERS: STR1 IS HEADER; STR2 IS DATA TO BE FORMATTED; DEFINE_CALL 'SEND ITOHEX TO MASTER' (STR1[],STR2[]) STACK_VAR integer X; integer STR1_LEN; integer STR2_LEN; integer ASCII_PACKET_LEN; STACK_VAR char ASCII[16000]; STACK_VAR INTEGER FIRST_STRING_SENT; { STR1_LEN = LENGTH_ARRAY(STR1); STR2_LEN = LENGTH_ARRAY(STR2); FOR (X = 1; X <= STR2_LEN; X++) { IF (X = STR2_LEN) // IF IT'S THE LAST BYTE { ASCII = "ASCII,FORMAT('$%0 2X',STR2[X])"; } ELSE { ASCII = "ASCII,FORMAT('$%0 2X,',STR2[X])"; } } ASCII_PACKET_LEN = 67 - STR1_LEN; // 80 CHARACTER LINE // 67 IS THE STRING LENGTH (MAX IS 131) // 13 CHARACTERS FOR TIMESTAMP WHILE (LENGTH_ARRAY(ASCII) > ASCII_PACKET_LEN) { SEND_STRING 0:0:0,"STR1,LEFT_STRING(ASCII,ASCII_PACKET_LEN)"; ASCII = RIGHT_STRING(ASCII,LENGTH_STRING(ASCII)-ASCII_PACKET_LEN); IF (!FIRST_STRING_SENT) // replace STR1 with spaces after first pass { ON[FIRST_STRING_SENT] STR1 = LEFT_STRING(__SPACES__,LENGTH_STRING(STR1)) } } IF (LENGTH_ARRAY(ASCII)) { SEND_STRING 0:0:0,"STR1,ASCII"; } } /* CALL 'STRING TO DEV' */ /* FUNCTION: Takes ASCII string of the form '...<dev>' or */ /* '...<dev>:<prt>:<sys>' and puts those values */ /* into dvDEV. */ /* PARAMETERS: Txt - String that contains the dv:prt:sys */ /* as ASCII text. */ /* dvDEV - storage for the returned value */ DEFINE_CALL 'STRING TO DEV' (char Txt[],dev dvDEV) STACK_VAR INTEGER DV STACK_VAR INTEGER PRT STACK_VAR INTEGER SYS STACK_VAR INTEGER WherePrt STACK_VAR INTEGER WhereSys { /*********************/ /* get device number */ /*********************/ DV = ATOI(Txt) // if Txt does not contain a number, // DV will be 0 (the master) /*******************/ /* get port number */ /*******************/ IF (FIND_STRING(Txt,':',2)) // if Txt is of form '...<dv>:<prt>...' { WherePrt = FIND_STRING(Txt,':',1) IF (WherePrt) // if there might be a port number { // if port 0 was entered and // Txt if of form '...<dv>:<prt>:<sys>' IF (FIND_STRING(Txt,':0:',1) = WherePrt) PRT = 0 ELSE { PRT = ATOI(RIGHT_STRING(Txt,LENGTH_ARRAY(Txt)-WherePrt)) IF (PRT = 0) // if Txt does not contain a number past the PRT = 1 // first ':', PRT will be 1 } } } ELSE // if Txt does not contain a number past the PRT = 1 // first ':', PRT will be 1 /*********************/ /* get system number */ /*********************/ // if Txt is of form '...<dv>:<prt>:<sys>' // note: SYS 0 means local system IF (FIND_STRING(Txt,':',WherePrt + 1)) { WhereSys = FIND_STRING(Txt,':',WherePrt + 1) SYS = ATOI(RIGHT_STRING(Txt,LENGTH_ARRAY(Txt)-WhereSys)) } dvDEV = DV:PRT:SYS } (***********************************************************) (* THE EVENTS GOES BELOW *) (***********************************************************) DEFINE_EVENT DATA_EVENT[0:1:0] { ONLINE: { wait 50 // WAIT FOR DEVICE HOLDOFF { // WHAT VERSION? SEND_STRING 0:0:0,"'Using lib ',__DEBUG_LIB_NAME__, ', v',__DEBUG_LIB_VERSION__"; } } } #END_IF (***********************************************************) (* END OF PROGRAM *) (* DO NOT PUT ANY CODE BELOW THIS COMMENT *) (***********************************************************)