Design Philosophy
SwadgePass is a feature where Swadges can transmit and receive small packets of data while idle. This feature was inspired by Nintendo's StreetPass. SwadgePass data may include things like avatar data or high scores from all Swadge Modes.
SwadgePass uses ESP-NOW, not WiFi or Bluetooth. See hdw-esp-now.h.
Transmission and Reception
Packets are transmitted with sendSwadgePass(). To preserve battery life, this should only be called when the Swadge is idling in it's LED animation mode (dance.c). In this state, the Swadge will transmit every 7.5s, +/- 1.875s. Randomness ensures two Swadges don't get locked out-of-sync while transmitting and receiving. After transmitting, the Swadge stays awake and listening for 700ms. While not transmitting or listening, the Swadge light sleeps for 100ms increments, updating the LEDs ten times per second.
The receiver is initialized with initSwadgePassReceiver() and packets are received with receiveSwadgePass(). Any incoming packet may be passed to this function, including from modes which are using ESP-NOW for other purposes, as long as the receiver was initialized. deinitSwadgePassReceiver() frees memory allocated for the receiver.
During normal operation, if not explicitly used the WiFi radio is turned off and SwadgePass data is neither transmitted nor received.
Usage
Transmission and reception of SwadgePass data is automatic in dance.c and does not need to be managed by each SwadgeMode (see Transmission and Reception). Other modes may transmit and receive SwadgePass data, but it is discouraged for battery reasons.
Building a Packet for Transmission
A swadgePassPacket_t is built with the function fillSwadgePassPacket(), which calls each mode's swadgeMode_t.fnAddToSwadgePassPacket function. Each mode may add data to swadgePassPacket_t, and modes must not modify data which is not their own. The total packet size must be less than 250 bytes, which is the largest possible ESP-NOW packet.
- Warning
- swadgeMode_t.fnAddToSwadgePassPacket is called when the Swadge Mode is not initialized, so it must not rely on memory allocated or data loaded in swadgeMode_t.fnEnterMode
Using Received SwadgePass Data
Swadge Modes may check received SwadgePass data by giving an empty list_t to getSwadgePasses() to fill. getSwadgePasses() may fill the list with all received SwadgePass data, or only SwadgePass data which has not been used by the given mode yet. After being filled, the list contain pointers to swadgePassData_t and may be iterated through. swadgePassData_t.key is the string representation of the source MAC address. SwadgePass data will not change during Swadge Modes (aside from dance.c), so the data should be loaded once and saved for the mode's lifetime. getSwadgePasses() should not be called repeatedly.
If the Swadge Mode wants to use each SwadgePass data from a source only once, it can be checked with isPacketUsedByMode(). This may be useful for an RPG game where each received SwadgePass gets to make one action. Once the data is used, it can be marked as such with setPacketUsedByMode(). This will save the used state to non-volatile storage, which persists reboots.
- Warning
- setPacketUsedByMode() writes to NVS and we have seen freezes while writing to NVS many times in a row while the microphone and speaker peripherals are active. It is strongly advised to turn off those peripherals during NVS writes. Example:
void dacStop(void)
Stop the DAC.
Definition hdw-dac.c:172
void dacStart(void)
Start the DAC. This will cause samples to be requested from the application.
Definition hdw-dac.c:158
void switchToSpeaker(void)
Enable the speaker (and battery monitor) and disable the microphone.
Definition swadge2024.c:938
When the Swadge Mode is finished with the SwadgePass data, it must be freed with freeSwadgePasses().
SwadgePass Size Limitations
- Warning
- Read this section carefully! It caused some pretty visible bugs across the entire firmware release. Turns out all Swadge modes need RAM and most write to NVS too.
Version 3.1.0 was released with MAX_NUM_SWADGE_PASSES set to 100. This seemed like a good idea at the time, but in practice the Swadge could only store 80 to 90 SwadgePasses in NVS and would often crash while trying to load them to RAM. Version 3.1.1 added pruneSwadgePasses(), which is called on startup and erases SwadgePasses to the new limit of MAX_NUM_SWADGE_PASSES (50). This function does not need to be called manually.
It must also be noted that getSwadgePasses() is a memory-intensive function because it has to load all relevant NVS keys to RAM and then load the SwadgePass data to RAM as well. This function should be called early in a Swadge mode's lifecycle, ideally before other audio or visual assets are loaded or memory is otherwise allocated for menus, gameplay logic, or other reasons. After SwadgePass data is extracted, freeSwadgePasses() should be called to make space for loading assets, allocating gameplay RAM, etc.
Example
Building a Packet for Transmission Example
swadgeMode_t.fnAddToSwadgePassPacket would be set to this example function.
{
packet->myHighScore = 9001;
}
A SwadgePass packet which is transmitted over ESP NOW.
Definition swadgePass.h:160
Using Received SwadgePass Data Example
while (spNode)
{
{
ESP_LOGI("SP", "Receive from %s. Preamble is %d", spd->key, spd->data.packet.preamble);
}
}
struct node * next
The next node in the list.
Definition linked_list.h:79
struct node node_t
A node in a doubly linked list with pointers to the previous and next values (which may be NULL),...
void * val
A pointer to the data for this node.
Definition linked_list.h:78
node_t * first
The first node in the list.
Definition linked_list.h:88
A doubly linked list with pointers to the first and last nodes.
Definition linked_list.h:87
void getSwadgePasses(list_t *swadgePasses, const struct swadgeMode *mode, bool getUsed)
Fill a list with SwadgePass data. The list should be empty before calling this function.
Definition swadgePass.c:240
bool isPacketUsedByMode(swadgePassData_t *data, const struct swadgeMode *mode)
Return if a given mode has used this SwadgePass data yet.
Definition swadgePass.c:311
void setPacketUsedByMode(swadgePassData_t *data, const struct swadgeMode *mode, bool isUsed)
Set if a given mode has used this SwadgePass data yet.
Definition swadgePass.c:328
SwadgePass data that is received from another Swadge.
Definition swadgePass.h:206