Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How an Ember+ client knows that the GetDirectory information received is complete #81

Open
sgruenfelder opened this issue Jul 4, 2018 · 2 comments

Comments

@sgruenfelder
Copy link

I wonder if other Ember+ developers have the same opinion on how an Ember+ client knows that it has received all the requested information after issuing a GetDirectory command.

In the last months all Ember+ servers I played with have send a single packet as reply to a GetDirectory command. The packet containes all the items found in the directory of interest.

Now I have seen an Ember+ server implementation that sends several replies after the receipt of a single GetDirectory command. Each reply contains one item of the directory the client wants to explore. The author claims that this is in line with Ember+. (1) I have my doubts, is that true? If that is truly in line: (2) how can the client ever know that the information received is complete? This is something needed when implementing clients that automatically change a large number of parameters. The clients would traverse the directories. (3) Does anyone know how this is handled by VSM?

Best regards
sgruenfelder

@mywave82
Copy link
Contributor

It might be split up into multiple packets, since you might have more nodes than can fit into a single packet.

In libember_slim, when a new packet is allocated, we tell the glowOutput generator if is the last packet (and keeps a track in the buffer space if it the first package or not)

void glowOutput_beginPackage(GlowOutput *pThis, bool isLastPackage)
{
   bool isFirstPackage = pThis->packageCount == 0;

   writeFramingHeader(pThis, isFirstPackage, isLastPackage);

   if(isFirstPackage)
      ember_writeContainerBegin(&pThis->base.base.base, &glowTags.root, GlowType_RootElementCollection);

   pThis->packageCount++;
}
static void writeFramingHeader(GlowOutput *pThis, bool isFirstPackage, bool isLastPackage)
{
   byte flags = 0;

   if(isFirstPackage)
      flags |= EmberFramingFlag_FirstPackage;
   if(isLastPackage)
      flags |= EmberFramingFlag_LastPackage;

   berFramingOutput_writeHeader(&pThis->base, (EmberFramingFlags)flags);
   pThis->hasLastPackage = isLastPackage;
}
void berFramingOutput_writeHeader(BerFramingOutput *pThis, EmberFramingFlags flags)
{
   BerOutput *pBase = &pThis->base.base;
   unsigned short index;

   ASSERT(pThis != NULL);
   ASSERT(pThis->base.position == 0);

   if (pThis->useNonEscapingFrames)
   {
       berMemoryOutput_writeByte(pBase, S101_Invalid);
       berMemoryOutput_writeByte(pBase, 0x04);                  // Length Length
       berMemoryOutput_writeByte(pBase, 0x00);                  // Payload Length 0
       berMemoryOutput_writeByte(pBase, 0x00);                  // Payload Length 1
       berMemoryOutput_writeByte(pBase, 0x00);                  // Payload Length 2
       berMemoryOutput_writeByte(pBase, 0x00);                  // Payload Length 3
       berMemoryOutput_writeByte(pBase, 0x00);                  // slotid
       berMemoryOutput_writeByte(pBase, EMBER_MESSAGE_ID);      // message
       berMemoryOutput_writeByte(pBase, EMBER_COMMAND_PAYLOAD); // command
       berMemoryOutput_writeByte(pBase, 0x01);                  // framing version
       berMemoryOutput_writeByte(pBase, (byte)(flags & 0xFF));  // flags: first_package | last_package;
       berMemoryOutput_writeByte(pBase, pThis->dtd);

       if (pThis->pAppBytes != NULL)
       {
           berMemoryOutput_writeByte(pBase, pThis->appBytesCount);

           for (index = 0; index < pThis->appBytesCount; index++)
               berMemoryOutput_writeByte(pBase, pThis->pAppBytes[index]);
       }
       else
       {
           berMemoryOutput_writeByte(pBase, 0x00);
       }
   }
   else
   {
       pThis->crc = 0xFFFF;

       berMemoryOutput_writeByte(pBase, S101_BOF);
       writeEscapedByteWithCrc(pThis, 0x00);                  // slotid
       writeEscapedByteWithCrc(pThis, EMBER_MESSAGE_ID);      // message
       writeEscapedByteWithCrc(pThis, EMBER_COMMAND_PAYLOAD); // command
       writeEscapedByteWithCrc(pThis, 0x01);                  // framing version
       writeEscapedByteWithCrc(pThis, (byte)(flags & 0xFF));  // flags: first_package | last_package
       writeEscapedByteWithCrc(pThis, pThis->dtd);            // dtd

       if (pThis->pAppBytes != NULL)
       {
           writeEscapedByteWithCrc(pThis, pThis->appBytesCount);

           for (index = 0; index < pThis->appBytesCount; index++)
               writeEscapedByteWithCrc(pThis, pThis->pAppBytes[index]);
       }
       else
       {
           writeEscapedByteWithCrc(pThis, 0x00);            // appbytes count
       }
   }
}

@MrJones4u
Copy link

MrJones4u commented Oct 22, 2019

Actually, the correct way for a getDirectory response is to return a node with all parameters. While all sub nodes might be contained within the node all parameters [descriptions] must be contained. The actual parameter value can be part of the node, yet may also be sent separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants