#include "SFBTypes.h"
#include "SFBAssert.h"
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) |
bool | packetEqual (const u8 *packet1, const u8 *packet2) |
Check if two packets have the same content. | |
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) |
Set the value of the 'read cursor' within packet to be newIndex, or to packetLength(const u8 *), whichever is smaller. | |
bool | packetRead (u8 *packet, int &result, int code=DEC, u32 maxLen=MAX_PACKET_LENGTH) |
Starting from packetCursor() of packet, consume no more than maxLen bytes to read an integer, in one of a variety of formats specified by code, and store the read value into result. | |
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 | packetRead (u8 *packet, u64 &result) |
Starting from the packetCursor() position of packet, read a big-endian network order u64 into result. | |
bool | packetRead (u8 *packet, u8 *result, u32 length) |
Starting from packetCursor() of packet, read exactly length bytes into buffer, advancing packetCursor() by length, and return true . | |
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. | |
u8 * | makePacket (u8 *buffer, u32 bufferLength, u8 face, const char *packetData) |
u8 * | makePacket (u8 *buffer, u32 bufferLength, u8 face, const u8 *packetData, u32 packetDataLength) |
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.
packet | The packet to examine for possessing a valid check byte. |
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); }
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 and packetReadEOF() will be true.
Note that packetReread() can be used to modify the cursor value of a packet.
packet | The packet whose cursor position is needed |
Check if two packets have the same content.
Considers only the lengths and content of the packets; any possible differences in their packetSource(), packetFlags(), and/or packetCursor() are ignored.
true
if the packet1 and packet2 are the same length and all packetLength() bytes match; false
otherwiseAccess 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.
packet | The packet whose flags are to be read. |
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
Access the length of packet.
packet | The packet whose length is needed |
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 }
Starting from packetCursor() of packet, read exactly length bytes into buffer, advancing packetCursor() by length, and return true
.
If packetReadLength() of packet is less than length return false
and leave packet and buffer unchanged.
packet | The packet to read. | |
buffer | A non-null pointer to at least length bytes of writable space. | |
length | How many bytes to read. |
true
if length bytes were read and stored in buffer; 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.true
is returned, the packetCursor() of packet is advanced by length bytes, and length bytes are written to buffer.Starting from the packetCursor() position of packet, read a big-endian network order u64 into result.
Reads values output by facePrintBinary(u8 face,u64 value).
packet | The packet to read from. | |
result | A reference to where the read number will be stored, if the return value is true. |
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.
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) |
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. } ...
Starting from packetCursor() of packet, consume no more than maxLen bytes to read an integer, in one of a variety of formats specified by code, and store the read value into result.
packet | The packet to read. | |
result | Where to store the read integer value | |
code | What format number to read; one of: BYTE, BESHORT, or BELONG, or BIN, OCT, DEC, or HEX, or another number in the range 2..36 to read a number in that base. | |
maxLen | Maximum number of bytes to read. |
true
if number in the specified format was successfully read and stored in result; false
otherwise.true
is returned, the packetCursor() of packet is advanced by the number of bytes read, and result is overwritten with the read value. Note that if false
is returned, the packetCursor() of packet may or may not have been advanced, depending on the reason for the failure. bool packetReadCheckByte | ( | u8 * | packet | ) |
Attempt to read a valid chack byte from the current position of packet.
packet | The packet to read the check byte from. |
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.false
is returned, otherwise the packetReadLength() of packet is decreased from 1 to 0, if true
is returned.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?
packet | The packet whose packetCursor() position to check |
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.. } ...
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.
packet | The packet whose read length is needed |
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 } }
Set the value of the 'read cursor' within packet to be newIndex, or to packetLength(const u8 *), whichever is smaller.
packet | The packet whose read cursor to alter | |
newIndex | The new position of packet's read cursor (default value: 0) |
void myHandler(u8 * packet) { u32 serialNumber; if (packetScanf(packet,"x%d:",&serialNumber) != 3) return; // Bail unless good start.. u32 index = packetCursor(packet); // Now remember where we are u32 val; if (packetScanf(packet,"0x%x\n", &val) != 4) { // Try for "0x" plus a hexadecimal.. packetReread(packet,index); // But if that fails, back up.. if (packetScanf(packet,"%d\n",&val) != 2) // and try for a decimal instead return; // And if that fails, punt } .. }
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.
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.
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. |
void myHandler(u8 * packet) { if (zpacketPrefix(packet,"foo")) { println("could be 'foo', 'foo bar', or 'food', but not 'fo', 'Foo', or ' foo'"); } }