# SFBPacket.h File Reference

Packet structure and access methods. More...

`#include "SFBTypes.h"`
`#include "SFBAssert.h"`

Include dependency graph for SFBPacket.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

## Data Structures
struct | PacketHeader
| The information associated with a packet, when it is stored in memory only -- there is no preestablished packet header on the wire. More...
## Defines
#define | PFSC_END ((u8) '\012')
#define | PFSC_ESC ((u8) '\333')
#define | PFSC_EEND ((u8) '\334')
#define | PFSC_EESC ((u8) '\335')
#define | CHECK_BYTE_INIT_VALUE (0xF0)
#define | CHECK_BYTE_UPDATE(v, d) ((v) = ((v<<1)|((v>>7)&1))^d)
#define | API_ASSERT_VALID_PACKET(u8ptr) API_ASSERT(validPacket(u8ptr),E_API_INVALID_PACKET)
const PacketHeader & | packetHeaderInternalUnsafeConst (const u8 *packet)
| Low-level packet handling methods.
PacketHeader & | packetHeaderInternalUnsafe (u8 *packet)
u8 | packetLength (const u8 *packet)
| Access the length of packet.
u8 | packetReadLength (const u8 *packet)
| Access the 'read length' of packet.
u8 | packetFlags (const u8 *packet)
| Access the flags of packet.
u8 | packetSource (const u8 *packet)
| Access the source of packet.
u8 | packetCursor (const u8 *packet)
| Access the read cursor of packet.
bool | packetCheckByteValid (const u8 *packet)
| Determine if packet ends with a valid 'check byte'.
bool | validPacket (const u8 *packet)
void | packetReread (u8 *packet, u32 newIndex=0)
bool | packetRead (u8 *packet, int &result, int code=DEC, u32 maxLen=MAX_PACKET_LENGTH)
bool | packetRead (u8 *packet, u32 &result, int code=DEC, u32 maxLen=MAX_PACKET_LENGTH)
| Starting from the packetCursor() position, attempt to read a number into result, in the format specified by code, from packet.
bool | packetReadCheckByte (u8 *packet)
| Attempt to read a valid chack byte from the current position of packet.
bool | packetReadEOF (u8 *packet)
| Have we read to the end of packet?
bool | packetReadPacket (u8 *packet, u8 *&subpacket)
bool | zpacketPrefix (u8 *packet, const char *to)
| Determine if packet begins with the sequence of non-null bytes given by to.

## Detailed Description

Packet structure and access methods.

Author:
  David H. Ackley.

Date:
  (C) 2009 All rights reserved.

Code License:
  The GNU Lesser General Public License

License Note:
  All code samples shown in documentation are placed into the public domain.

## Function Documentation

bool packetCheckByteValid | ( | const u8 * | packet | ) |

Determine if packet ends with a valid 'check byte'.

A packet check byte is generated by calling facePrintlnCheckByte() or by using the `"%\n"` format code in facePrintf(); it is a single byte 'summary' or 'digest' of the all the rest of the packet content that precedes it.

A packet may or may not end with a check byte, depending on how it was generated. Although it is a mistake to call this method on a packet that does not contain a check byte, it is up to the programmer to avoid it and this mistake is not detected by the SFB library; the return value of such a call will usually be false, but might, simply by bad luck, be true.

Note that this method ignores the packetCursor(); it always checks the entire packet contents.

Parameters:

  | packet | The packet to examine for possessing a valid check byte.

Returns:
  true if packet has a valid check byte; false if the packetLength() is zero or the final byte is not a valid check byte for the rest of packet.

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

Example:

        void myHandler(u8 * packet) {
          if (!packetCheckByteValid(packet)) // Not doing API_ASSERT_TRUE(packetCheckByteValid(packet)) --
            return;                          // Who knows what the world might send us?  Just ignore bogons..
          println("valid packet");
          ...
        }
        void setup() {
          reflex('h',myHandler);
        }
        void loop() {
          pprintf("hello world%\n");     // The %\n adds the check byte!
          delay(1000);
        }

u8 packetCursor | ( | const u8 * | packet | ) |

Access the read cursor of packet.

Each packet has an internal cursor value indicating how much of the packet has been read (e.g., by packetRead() or packetScanf()); this method accesses that value. A cursor value of 0 means the cursor is before the first byte, and so the first byte will next be read, and a cursor value of packetLength() means the cursor is after the last byte, so no more bytes can be read packetReadEOF() will be true.

Note that packetReread() can be used to modify the cursor value of a packet.

Parameters:

  | packet | The packet whose cursor position is needed

Returns:
  from 0 to packetLength(u8 * packet).

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

u8 packetFlags | ( | const u8 * | packet | ) |

Access the flags of packet.

Non-zero packet flags generally, though not necessarily, correspond to various error conditions, and by default packets with errors will _not_ cause reflex triggering, so in the simplest packet handling circumstances, the return value from this function will typically be 0.

Parameters:

  | packet | The packet whose flags are to be read.

Returns:
  a bitwise-OR of these possible flag values: PK_DELETED, PK_OVERRUN, PK_PARITY, PK_BREAK, PK_BUFFER, PK_BAD_ESCAPE.

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

Example:

        void myAHandler(u8 * packet) {                     // 'Broken' packets not delivered to normal handlers..
          API_ASSERT_ZERO(packetFlags(packet)&PK_BROKEN);  // ..so none of those packet flags can be set.
          ...
        }
        void myBHandler(u8 * packet) {                     // But here we've specially requested broken packets.
          if (packetFlags(packet)&PK_BROKEN)               // ..so this 'if' condition might be true
            println("WARNING!  Packet with errors received");
          ...
        }
        ...
        void setup() {
          reflex('a', myAHandler);      // Define a normal reflex
          reflex('b', myBHandler, SFBReactor::TRIGGER_SPINE, true);  // Final 'true' arg says include broken packets

u8 packetLength | ( | const u8 * | packet | ) |

Access the length of packet.

Parameters:

  | packet | The packet whose length is needed

Returns:
  from 0 to MAX_PACKET_LENGTH

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

Example:

        void myHandler(u8 * packet) {
          print("I received a packet of length ");   // Start a packet with a fixed message
          println(packetLength(packet), DEC);        // End it with a number in decimal
        }

Examples:
  forward.cpp, and tee.cpp.

bool packetRead | ( | u8 * | packet,
|  | u32 & | result,
|  | int | code,
|  | u32 | maxLen |
| ) |  |  |

Starting from the packetCursor() position, attempt to read a number into result, in the format specified by code, from packet.

See packetRead(u8 * packet, int &result, int code, u32 maxLen) for other details including the possible values of code and the meaning of maxLen.

Parameters:

  | packet | The packet to read
  | result | A reference to where the read number will be stored, if the return value is true.
  | code | A code representing the format to read; see packetRead(u8 * packet, int &result, int code, u32 maxLen)
  | maxLen | How many bytes to read at most; see packetRead(u8 * packet, int &result, int code, u32 maxLen)

Returns:
  true if suitable number was read and stored in result; false if no such number can be read from the current position, either because an input unsuitable for code is seen first, or because the end of the packet is reached first.

Blinks:
  See packetRead(u8 * packet, int &result, int code, u32 maxLen) for possible errors.

The packetCursor() is advanced by however many bytes were successfully read, which will be a value between zero and the smaller of packetLength() and maxlen, inclusive. packetCursor() is left set equal to packetLength(), if the entire remainder of packet was read, or pointing at the first character of packet could not be interpreted as part of a number of type code, or at the next byte to be read after maxlen bytes have been read by this call.

Example:

        void myHandler(u8 * packet) {
          u32 num;
          if (!packetRead(packet,num,BIN))   // Can't really fail, the way it's set up..
            return false;                    // because there'll always be at least one legal byte to read..
          pprintf("received a packet beginning with %d in binary\n",num);
        }
        void setup() {
          reflex('0',myHandler);  // Put same handler on both type 0
          reflex('1',myHandler);  // and type 1 packets.
        }
        ...

bool packetReadCheckByte | ( | u8 * | packet | ) |

Attempt to read a valid chack byte from the current position of packet.

Parameters:

  | packet | The packet to read the check byte from.

Returns:
  `true` if and only if packetReadLength() had been 1 (meaning we had been looking at the last byte of packet) and that byte was a valid check byte for the rest of packet, and returns `false` otherwise.

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

Side Effects:
  None, if `false` is returned, otherwise the packetReadLength() of packet is decreased from 1 to 0, if `true` is returned.

Example:

        void myHandler(u8 * packet) {
          u32 val;
          if (!packetRead(packet,val,BYTE) || val != 'x') return; // Bail unless first byte is 'x'
          if (!packetRead(packet,val,DEC) || val >= 100) return;  // Bail unless then a decimal in 0..99
          if (!packetReadCheckByte(packet)) return;               // Bail unless then valid check byte
          pprintf("L received valid 'x%d' packet\n",val); // Announce success
        }
        void setup() {
          reflex('x',myHandler);         // Create an 'x' reflex
        }
        void loop() {
          pprint("x%d%\n",random(100));  // Broadcast x packets.  "%\n" appends the check byte!
          delay(1000);
        }

bool packetReadEOF | ( | u8 * | packet | ) |

Have we read to the end of packet?

Parameters:

  | packet | The packet whose packetCursor() position to check

Returns:
  true if and only if the packetReadLength() of packet is 0, meaning no more bytes can be read from packet.

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

Example:

        void myHandler(u8 * packet) {
          u32 ch;
          while (!packetReadEOF(packet)) {   // While there's still something in there..
            packetRead(packet,ch,BYTE);      // ..read another byte
            pprintf("got %c\n", ch);          // This can generate a lot of packets!
         }
        }
        void setup() {
          reflex('s',myHandler);  // 's' for 's'pam-generator..
        }
        ...

u8 packetReadLength | ( | const u8 * | packet | ) |

Access the 'read length' of packet.

The read length is the difference between the packetLength() and the packetCursor() of a given packet -- in other words, it is the number of further characters that may be read from packet.

Parameters:

  | packet | The packet whose read length is needed

Returns:
  from 0 to MAX_PACKET_LENGTH

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

Example:

        void pointlessDemo(u8 * packet) {
          if (packetReadLength(packet) > 0) {    // True if at least one byte can be read
            u8 ch;
            bool result = packetRead(packet,&ch,BYTE);   // So this must succeed
            API_ASSERT_TRUE(result);             // So the universe is insane if it doesn't
          }
        }

u8 packetSource | ( | const u8 * | packet | ) |

Access the source of packet.

The packet source is commonly, but not necessarily, the SFB face (NORTH, SOUTH, EAST, or WEST) that the packet arrived from.

Examples:
  forward.cpp, pingpong.cpp, pingpong2.cpp, and tee.cpp.

bool zpacketPrefix | ( | u8 * | packet,
|  | const char * | to |
| ) |  |  |

Determine if packet begins with the sequence of non-null bytes given by to.

Note that unlike 'packet reading' functions such as packetRead() or packetScanf, this function ignores the packetCursor() and always examines packet from the beginning.

Parameters:

  | packet | The packet whose initial bytes are to be checked for a match against to.
  | to | The zero-terminated string specifying a prefix to be sought in packet.

Returns:
  true if packetLength(u8 * packet) is >= strlen(to), and the first strlen(to) bytes of packet are identical to the corresponding bytes of to; and false otherwise.

Blinks:
  E_API_INVALID_PACKET if packet is null or pointing at something that is detectably corrupt or not a packet.

Blinks:
  E_API_NULL_POINTER if to is null.

Example:

        void myHandler(u8 * packet) {
          if (zpacketPrefix(packet,"foo")) {
            println("could be 'foo', 'foo bar', or 'food', but not 'fo', 'Foo', or ' foo'");
          }
        }