single byte char array with text "icsbin"used to identify file type.
File Version
4
single byte char array indicate version.
Version Section
Variable (see below)
This data structure is determinant the File Version
Version Specification
Version 0x101
This format is no longer created. Click to see Network ID's
Description
Length in Bytes
Notes
Length of Vs3 File
4
int value indicating the length of the next section (the vs3 file). A zero indicates no vs3 file is present.
Vs3 file
variable (see above)
vs3 file used to save this binary file. This vs3 file is later used to decode the binary data into usable information.
Length of text comment
4
int indicating the length of the text header comment of the saved file. SINCE THE COMMENT IS UNICODE THEREFORE HIS IS THE LENGTH IN CHARACTERS - NOT BYTES.
Text comment
2 bytes per character (see above for number of characters)
Unicode text comment.
Size of Buffer of Messages
4
sizeof(VSBSpyMessage) multiplied by Number of messages saved to the file
Current Buffer Pointer
4
int value which is the pointer to the most recent buffer item +1. (only needed if Number of All time messages > Original buffer size)
Original Buffer Size
4
int value which is the size of the buffer memory originally allocated by this buffer
Number of All time messages
4
this indicates how many messages were received by this buffer (this number will indicate overflows)
Buffer of Messages
variable (see Size of Buffer of Messages)
VSBSpyMessage structures
Start Time of Collection
struct icsspyMsgTime
this is a comparison value between the system time stamp and the neoVI time stamp.
Version 0x102
This format is created by the extractor. Click to see Network ID's
Description
Length in Bytes
Notes
Length of EDP Section
4
int value indicating the length of the next section (the EDP). A zero indicates no EDP section file is present.
variable (see above)
used to save the extra data bytes for networks such as Ethernet, Flexray, and CANFD
Buffer of Messages
variable (see Size of Buffer of Messages)
VSBSpyMessage structures
Start Time of Collection
struct icsspyMsgTime
this is a comparison value between the system time stamp and the neoVI time stamp.
Version 0x103
This format is created using VSpy. Click to see Network ID's
Description
Length in Bytes
Notes
Length of EDP Section
4
int value indicating the length of the next section (the EDP). A zero indicates no EDP section is present.
variable (see above)
used to save the extra data bytes for networks such as Ethernet, Flexray, and CANFD
Length of text comment
4
int indicating the length of the text header comment of the saved file. SINCE THE COMMENT IS UNICODE THEREFORE HIS IS THE LENGTH IN CHARACTERS - NOT BYTES.
Text comment
2 bytes per character (see above for number of characters)
Unicode text comment.
Size of Buffer of Messages
4
sizeof(VSBSpyMessage) multiplied by Number of messages saved to the file
Current Buffer Pointer
4
int value which is the pointer to the most recent buffer item +1. (only needed if Number of All time messages > Original buffer size)
Original Buffer Size
4
int value which is the size of the buffer memory originally allocated by this buffer
Number of All time messages
4
this indicates how many messages were received by this buffer (this number will indicate overflows)
Buffer of Messages
variable (see Size of Buffer of Messages)
VSBSpyMessage structures
Start Time of Collection
struct icsspyMsgTime
this is a comparison value between the system time stamp and the neoVI time stamp.
EDP section
Used by version 0x102 and 0x103. The ExtraDataPtr -1 of each message is a index to the EDP in EDP section. Click to see Network ID's
Version 0x104
This format is created by the Loggers and VSpy Stream to Disk.
Description
Length in Bytes
Notes
Buffer of Messages
VSBSpyMessage structures
VSBSpyMessage structures
EDP
variable (see previous message's ExtraDataPtr)
used to save the extra data bytes for networks such as Ethernet, Flexray, and CANFD
......
variable
Buffer of Message and EDP continue to repeat until Start Time of Collection. If you are reading the VSB file, simple continue to read until Buffer of Message size read not equal sizeof(VSBSpyMessage)
Start Time of Collection
struct icsspyMsgTime
this is a comparison value between the system time stamp and the neoVI time stamp.
NetWork ID
version 0x101
Description
Value
HSCAN
0
MSCAN
1
SWCAN
2
LSFTCAN
5
DEVICE
8
HSCAN2
9
HSCAN3
10
LIN2
11
LIN3
12
LIN4
13
version 0x102 , 0x103, 0x104
Description
Value
DEVICE
0
HSCAN
1
MSCAN
2
SWCAN
3
LSFTCAN
4
J1708
6
JVPW
8
ISO
9
ISO2
14
LIN
16
ISO3
41
HSCAN2
42
HSCAN3
44
ISO4
47
LIN2
48
LIN3
49
LIN4
50
LIN5
84
MOST
51
CGI
53
HSCAN4
61
HSCAN5
62
SWCAN2
68
ETHERNET_DAQ
69
FLEXRAY1A
80
FLEXRAY1B
81
FLEXRAY2A
82
FLEXRAY2B
83
FLEXRAY
85
MOST25
90
MOST50
91
ETHERNET
93
GMFSA
94
TCP
95
HSCAN6
96
HSCAN7
97
LIN6
98
LSFTCAN2
99
OP_ETHERNET1
17
OP_ETHERNET2
18
OP_ETHERNET3
19
OP_ETHERNET4
45
OP_ETHERNET5
46
OP_ETHERNET6
73
OP_ETHERNET7
75
OP_ETHERNET8
76
OP_ETHERNET9
77
OP_ETHERNET10
78
OP_ETHERNET11
79
OP_ETHERNET12
87
Example
Below is a C++ example of how to open a .vsb file (v102 & v103 & 104) and display the network messages (Ethernet, CANFD, and CAN) with some other useful information You can view the full C++ code or Download the full project from the links provided.
Reading File Specification
bool Messages::Read(char* sFileName){unsignedlong numEDP =0; m_pFile =fopen(sFileName,"rb");if (m_pFile) {fSead( 0, SEEK_END);int length =ftell(m_pFile); //identify length of File fSead( 0, SEEK_SET);charid[6]; if (!fRead((char * )&id, 6) || memcmp(id, "icsbin", 6) != 0) //check for icsbin in the first 6 bytes to identify if it a VSB file
{printf("Invalid VSB file\n");returnfalse; }unsignedint fileversion;if (!fRead((char*)&fileversion,4)){ //VSB has 4 versions 101 is no longer used printf("Read Error\n");returnfalse; }elseif (fileversion ==0x102)//this is created by the extractor { int EDPSize = ReadEDPSelction(); //the extra data section contains extra data which is different for each message type
if (EDPSize ==0)fSead( VSB_HEADERSIZE, SEEK_SET); unsigned long numofmessages = ((length - (EDPSize + SIZEOFEDPSIZE)) - VSB_HEADERSIZE) / sizeof(icsSpyMessage); //calculate number of messages in file; the plus 4
m_nMessages = numofmessages; // set number of messages in fileif (numofmessages){if(!ReadMessage(numofmessages, fileversion)){ //read messagesprintf("file was not read correctly \n");returnfalse; } }elseif (fileversion ==0x103)//this is created by VSPY {ReadEDPSelction(); //read EDPunsignedlong numofmessages =Read103Header(); //read 103 header m_nMessages = numofmessages; //set number of messages in fileif (numofmessages){if(!ReadMessage(numofmessages, fileversion)){ //read messagesprintf("file was not read correctly \n");returnfalse; } } }elseif (fileversion ==0x104){//this is created by various hardware and VSPY for logging if(!Read104()){ // 104 has a very different structure compared to the other file typesprintf("file was not read correctly \n");returnfalse; } }else{printf("%s is an unsupported VSB version!\n", sFileName);returnfalse; }fclose(m_pFile); }else {printf("Could not open %s to read!\n", sFileName);returnfalse; }returntrue;}
Reading EDP Section
int Messages::ReadEDPSelction(){unsignedlong edpsize; bool bFixTimeStamp =false;if (fRead((char*)&edpsize, SIZEOFEDPSIZE) && edpsize >0)//read size of edp section {unsignedlong tempEDPSize = edpsize;staticconstchar* EDP_SECTION ="EDP_SECTION"; char obItem [EDPSECTIONSTRINGSIZE]; // check if there's an EDP_SECTION in here if (fRead(obItem, EDPSECTIONSTRINGSIZE) && tempEDPSize >= EDPSECTIONSTRINGSIZE && strcmp(obItem, EDP_SECTION) == 0)//verify edp section
{ // the following lines of code is a bad idea for large files. but since it is an simple example I wanted to simplify the code normality you would want to use some sort of file stream.
tempEDPSize -= EDPSECTIONSTRINGSIZE; m_pEDPSection =newchar[tempEDPSize]; if (!fRead(m_pEDPSection, tempEDPSize)){ //load edp section into memoryprintf("invalid file read\n");return0; }char* edpPtr = m_pEDPSection; while (tempEDPSize >0)//parse edp section {int edpLen =*(int*)edpPtr; m_edps.push_back(std::pair<char*, int>(edpPtr + sizeof(int), edpLen));//each node in this vector pertains to a different message (this will make more sense when you look at Read Message )
tempEDPSize -=sizeof(int); edpPtr += edpLen +sizeof(edpLen); tempEDPSize -= edpLen; }return edpsize; } }return0;}
Reading 0x103 File Info
unsignedlong Messages::Read103Header(){unsignedlong theNumOfMsgs;size_t msgslength, currbuffptr, numalltime, commentlength, origbuffsize;fRead((char*)&commentlength,4); //check if there is a commentif (commentlength >0)fSead( (long)commentlength *2, SEEK_CUR); // skip comment (comment written in wchar_t)fRead((char*)&msgslength,4);//size of message section fRead((char*)&origbuffsize,4); //original size of bufferfRead((char*)&currbuffptr,4); // current buffer postion fRead((char*)&numalltime,4); // number of message all time theNumOfMsgs = msgslength /sizeof(VSBSpyMessage); // number of messagesreturn theNumOfMsgs;}
Reading 0x102 and 0x103 Messages
bool Messages::ReadMessage(unsignedlong theNumOfMsgs,unsignedint fileversion){ VSBSpyMessage * pMessageRead =newVSBSpyMessage(); m_pMessages =newicsSpyMessage[theNumOfMsgs];bool firstMsg =true; SpyMsgTime timeStampRead; SpyMsgTime FirstMsgTime;for(unsignedint i =0; i < theNumOfMsgs; i++){//read one message at a timeif(!fRead((char*)pMessageRead,sizeof(VSBSpyMessage))){//read messagedelete pMessageRead;delete m_pMessages; m_pMessages =NULL; theNumOfMsgs =0;returnfalse; }if (firstMsg) {//record the start time of the first messageFirstMsgTime.HardwareTimeStampID =m_pMessages[0].TimeStampHardwareID;FirstMsgTime.HardwareTime1 =m_pMessages[0].TimeHardware;FirstMsgTime.HardwareTime2 =m_pMessages[0].TimeHardware2;FirstMsgTime.SystemTimeStampID =m_pMessages[0].TimeStampSystemID;FirstMsgTime.SystemTime1 =m_pMessages[0].TimeSystem;FirstMsgTime.SystemTime2 =m_pMessages[0].TimeSystem2; firstMsg =false; }VSBMessageToNormal(&m_pMessages[i], pMessageRead);// convert structure bool clear =true;if (pMessageRead->ExtraDataPtrEnabled &&pMessageRead->iExtraDataPtr) // check for edp section {if (pMessageRead->iExtraDataPtr >=1&&pMessageRead->iExtraDataPtr <=m_edps.size()) { int iEDPIndex = pMessageRead->iExtraDataPtr - 1;// identify index in the m_edps vector we made in the ReadEDPSelction function
int payloadLength =m_edps[iEDPIndex].second; m_pMessages[i].pExtraDataPtr = new pExtraDataPtrHandler(); //using pExtraDataPtrHandler to simply make to identify length of edp section
((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->pExtraDataPtr =m_edps[iEDPIndex].first; ((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->length = payloadLength; clear =false; } }if (clear) {m_pMessages[i].ColorID =0; //reset valuesm_pMessages[i].pExtraDataPtr =0; //reset values }if (fileversion ==0x102)//all 102s implicitly have bit 7 high. since we're converting to 103 we need to force itm_pMessages[i].TimeStampHardwareID |=0x80; }if (!fRead((char*)&timeStampRead,sizeof(timeStampRead))) //check if start logging time was recorded timeStampRead = FirstMsgTime; // if start logging time was not record simply set it to first message time m_startTimeStamp = timeStampRead;delete pMessageRead;returntrue;}
Reading 0x104
bool Messages::Read104() // 104 don't have a edp section they instead put the extra data after that message {unsignedlong EDPLength =0, Edpsize =0, numOfMessages =0;bool firstMsg =true; SpyMsgTime timeStampRead; SpyMsgTime FirstMsgTime; VSBSpyMessage *pMessage =newVSBSpyMessage();while (fRead((char*)pMessage,sizeof(VSBSpyMessage))) // read messages to identify number of message and edp size { numOfMessages++; if (pMessage->ExtraDataPtrEnabled && pMessage->iExtraDataPtr > 0)// as you can see we are using extraDataptr to identify the size of the edp section for that message
{ Edpsize +=pMessage->iExtraDataPtr; // The EDP is the length of the extra data following the message, skip itfSead((unsignedint)pMessage->iExtraDataPtr, SEEK_CUR); } } fSead( VSB_HEADERSIZE, SEEK_SET); //go back to the start //from here on out it is very similar to 103 and 102 but the location of the edp section is different m_pMessages =newicsSpyMessage[numOfMessages];for (unsignedint i =0; i < numOfMessages; i++) {if (!fRead((char*)pMessage,sizeof(VSBSpyMessage)))break; //errorif (firstMsg) {FirstMsgTime.HardwareTimeStampID =pMessage[0].TimeStampHardwareID;FirstMsgTime.HardwareTime1 =pMessage[0].TimeHardware;FirstMsgTime.HardwareTime2 =pMessage[0].TimeHardware2;FirstMsgTime.SystemTimeStampID =pMessage[0].TimeStampSystemID;FirstMsgTime.SystemTime1 =pMessage[0].TimeSystem;FirstMsgTime.SystemTime2 =pMessage[0].TimeSystem2; firstMsg =false; }bool clear =true;VSBMessageToNormal(&m_pMessages[i], pMessage);if (pMessage->ExtraDataPtrEnabled &&pMessage->iExtraDataPtr >=1 ) { EDPLength =pMessage->iExtraDataPtr;char* pEDP =newchar[EDPLength];if(!fRead(pEDP, EDPLength))returnfalse; //errorm_pMessages[i].pExtraDataPtr =newpExtraDataPtrHandler(); ((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->pExtraDataPtr = (void*)pEDP; ((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->length = EDPLength; clear =false; }if (clear) { EDPLength =0;m_pMessages[i].ColorID =0;m_pMessages[i].pExtraDataPtr =0; } }if (!fRead((char*)&timeStampRead,sizeof(timeStampRead))) timeStampRead = FirstMsgTime; m_startTimeStamp = timeStampRead; m_nMessages = numOfMessages;returntrue;}