Protocol Example

Let’s say that we have a protocol where we want to save the number of frames of type 100. If the frame is type 100, we will display the number of type 100 frames previously received in the decoder. If it isn’t type 100, we don’t display the number.

Our static has just one variable int m_count.

Our static has just two methods. One is a PROCESSING method that increments our counter. It is only executed during the compile phase. The other is a RETRIEVE method that we will use to get the counter from the static. It would be executed during both phases. Yes, these operations could be done in one method, but bear with me.

There are just four frames:

Frame 1: 100

Frame 2: 150

Frame 3: 100

Frame 4: 100

Compilation:

  • Create the Static. m_count is 0 because @RESET made it 0.

  • We get Frame 1.

    • We call PD to store the state of the Static

    • We call the RETRIEVE method. m_count = 0. We don’t do much with it.

    • We call the PROCESSING method to increment m_count to equal 1

  • We get Frame 2

    • We call PD to store the state of the Static (m_count = 1)

    • This frame is not type 100 so we don’t care about m_count. We don’t call either method.

  • We get Frame 3

    • We call PD to store the state of the Static (m_count = 1)

    • We call the RETRIEVE method. m_count = 1. We don’t do much with it.

    • We call the PROCESSING method to increment m_count to equal 2

  • We get Frame 4

    • We call PD to store the state of the Static (m_count = 2)

    • We call the RETRIEVE method. m_count = 2. We don’t do much with it.

    • We call the PROCESSING method to increment m_count to equal 3

Reconstruction:

Here, the Static is more of a snapshot viewer. In the FRM file, we have a snapshot of the data in the static for each frame.

  • Create the Static. m_count is 0.

  • We load Frame 1.

    • We call GD to get the state of the Static (m_count = 0)

    • This frame is type 100. We call the RETRIEVE method and display a value of 0.

    • When DecoderScript encounters the PROCESSING method call it knows we are reconstructing and ignores it.

  • We load Frame 2

    • We call GD to get the state of the Static (m_count = 1)

    • This frame is not type 100 so we don’t care about m_count and we don’t call either method.

  • We load Frame 3

    • We call GD to get the state of the Static (m_count = 1)

    • This frame is type 100. We call the RETRIEVE method and display a value of 1.

    • When DecoderScript encounters the PROCESSING method call it knows we are reconstructing and ignores it.

  • We load Frame 4

    • We call GD to get the state of the Static (m_count = 2)

    • This frame is type 100. We call the RETRIEVE method and display a value of 2.

    • When DecoderScript encounters the PROCESSING method call it knows we are reconstructing and ignores it.

Notice that nothing changed in our static during reconstruction. It’s ok to execute code that might change the static during reconstruction but it would be overwritten by GD. It is wasteful to do anything that would modify the contents of the static. All calculations should be done during the compile phase. During reconstruction, we should just be extracting results from the static. We might ask, what if we did nothing in PD, GD or OD? Good question. Many things could happen. First of all, our PROCESSING method would not be executed at all during reconstruction which means that m_count would stay 0. In our test case, we would notice that and fix it right away. The more eccentric effect has to do with the order in which frames are reconstructed. Because of the FRM file, frames have no context. We get a snapshot of the static for each and every frame and any frame can be reconstructed in any order and that’s just what the Frontline products will do. Leaving out communication with the FRM file is asking for the worst kind of trouble.

Optimization:

Remember, PD is called before each frame. After processing the frame, we might realize that what we stored with PD was overkill. OD is called after the frame is processed and it’s our chance to remove data that we won’t need to reconstruct this frame.

Notice in Frame 2, the data stored by PD was not needed during reconstruction. The static was never used for reconstructing that frame. Since we only are storing two bytes, it doesn’t matter much. If we are writing a static that keeps lots of data, it could matter a lot.

The thing is that PD is called before the frame is processed during the compile phase so we didn’t know that it was a waste of time.

So here’s what we do. Set up a Boolean variable that gets set to true only if we would need our data. In OD, simply call:

if(I don’t need my data)

abStatic.RemoveAll();

Nothing gets stored. In our example, we would do this for Frame 2 which calls no methods and doesn’t access the static. GD will try to restore the data but since there is nothing there, the data will be set to 0. This is a good opportunity to re-enforce a basic concept.

When you are saving data with PD, you are not wiping out your static. All you are doing is setting up your static data for use during the reconstruction of the current frame. Not saving something during PD is entirely appropriate if it was not used to decode the frame. The static persists from frame to frame during compile. During reconstruction, it is constantly overwritten by GD.

Let’s look at our new chronology for Frame 2 more closely:

Compile:

  • PD is called to save the contents of the static (waste of time but unavoidable)

  • The frame is processed. The type is not 100 so no methods are called. We cleverly put a flag in the static to tell us if it was accessed or not. It was set to false during PD and would be set to true if either of our methods were called.

  • In OD, we check the flag and see that nothing was used. We know that during reconstruction, we won’t need any data. We clear out abStatic so that nothing is written to the FRM file.

Reconstruction:

  • GD is called and yields no data

  • The frame is processed. The type is not 100 so no methods are called. We are unaware that the static is empty.

Some more considerations:

  • We own abStatic. We can and should use the helper class to get and store our data but we don’t necessarily have to. abStatic is the output of PD, the input to GD and the target of OD. It’s not written until after OD which is why we get the second chance.

  • We might ask, what does GD do if there’s nothing there? Good question. If we use the helper class, it will get data for us until we quit asking. If there is nothing left, numeric variables will be 0 and CStrings will be empty. For example, if PD saves 2 ints and GD wants 4, the last two ints returned by GD will be 0s. Conversely, if PD saves 4 ints and GD only asks for 2, there is no penalty other than wasted space in the file.

  • Data is saved by PD without any identifying marks. That is, if we have three variables to save, they are serialized in the order we save them. We must get them in the same order to avoid a data misalignment and a subsequent need for headache medication. If we save variable A, then B, and then C, we must retrieve them in that order.

  • The helper class can save and get only basic types. If we have a structure, class or other aggregate construct, we must save the component variables individually. In the case of an array, we must traverse the array and save each element. In the case of a class, it is wise to write get() and store() methods that save the class data. If it’s a structure, we will need code to save the members.

  • Some programmers omit PD altogether. They just use OD and save what they know they would have needed for that frame.

  • The GD, PD and OD sections must be present or they may not execute.

In OD, we can create our own copy of the static so we can make changes. In the code below, we create a new copy of the static, call GD to get the data from abStatic into old and then put it back. Of course, in between, we can do whatever we like. We could, for instance, selectively remove elements that we know we didn’t need from a list. We could empty out strings that we didn’t need.

CDecoderStaticusb_setup old("");

old._ReadDataFromAByteArray(abStatic); // move from abStatic to old

// throw away stuff I don’t want

old._PutDataInAByteArray(abStatic); // move from old to abStatic