|
Swadge ESP32-S2
2.0.0
APIs to develop for the Magfest Swadge
|
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.
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.
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.
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.
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.
When the Swadge Mode is finished with the SwadgePass data, it must be freed with freeSwadgePasses().
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.
swadgeMode_t.fnAddToSwadgePassPacket would be set to this example function.
Go to the source code of this file.
Data Structures | |
| struct | swadgePassPacket |
| A SwadgePass packet which is transmitted over ESP NOW. More... | |
| struct | swadgePassNvs_t |
| SwadgePass data that is saved to NVS. More... | |
| struct | swadgePassData_t |
| SwadgePass data that is received from another Swadge. More... | |
| struct | swadgePassPacket.cosCrunch |
| struct | swadgePassPacket.swadgeIt |
| struct | swadgePassPacket.roboRunner |
| struct | swadgePassPacket.swadgesona |
| struct | swadgePassPacket.atrium |
| struct | swadgePassPacket.megaPulseEx |
Macros | |
| #define | MAX_NUM_SWADGE_PASSES 50 |
Typedefs | |
| typedef struct swadgePassPacket | swadgePassPacket_t |
| A SwadgePass packet which is transmitted over ESP NOW. | |
Functions | |
| void | initSwadgePassReceiver (void) |
| Initialize the SwadgePass receiver. This reads SwadgePass data from NVS to SPIRAM so that each reception doesn't require a bunch of NVS reads. | |
| void | deinitSwadgePassReceiver (void) |
| Deinitialize the SwadgePass receiver. This frees memory. | |
| void | fillSwadgePassPacket (swadgePassPacket_t *packet) |
| Fill a SwadgePass packet with data from all modes before transmission. | |
| void | sendSwadgePass (swadgePassPacket_t *packet) |
| Transmit a SwadgePass packet. | |
| void | receiveSwadgePass (const esp_now_recv_info_t *esp_now_info, const uint8_t *data, uint8_t len, int8_t rssi) |
| Receive an ESP NOW packet and save it if it is a SwadgePass packet. | |
| 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. | |
| void | freeSwadgePasses (list_t *swadgePasses) |
| Free SwadgePass data loaded with getSwadgePasses(). | |
| bool | isPacketUsedByMode (swadgePassData_t *data, const struct swadgeMode *mode) |
| Return if a given mode has used this SwadgePass data yet. | |
| void | setPacketUsedByMode (swadgePassData_t *data, const struct swadgeMode *mode, bool isUsed) |
| Set if a given mode has used this SwadgePass data yet. | |
| void | pruneSwadgePasses (void) |
| Prune received SwadgePasses down to MAX_NUM_SWADGE_PASSES (50). | |
| struct swadgePassNvs_t |
| Data Fields | ||
|---|---|---|
| uint32_t | usedModeMask | A bitmask indicating if a mode has used this data. |
| swadgePassPacket_t | packet | The received SwadgePass packet. |
| struct swadgePassData_t |
| Data Fields | ||
|---|---|---|
| char | key[NVS_KEY_NAME_MAX_SIZE] | A string representation of the other Swadge's MAC address. |
| swadgePassNvs_t | data | The SwadgePass data stored in this Swadge's NVS. |
| struct swadgePassPacket.swadgesona |
| Data Fields | ||
|---|---|---|
| swadgesonaCore_t | core | |
| #define MAX_NUM_SWADGE_PASSES 50 |
| typedef struct swadgePassPacket swadgePassPacket_t |
A SwadgePass packet which is transmitted over ESP NOW.
| void initSwadgePassReceiver | ( | void | ) |
Initialize the SwadgePass receiver. This reads SwadgePass data from NVS to SPIRAM so that each reception doesn't require a bunch of NVS reads.
| void deinitSwadgePassReceiver | ( | void | ) |
Deinitialize the SwadgePass receiver. This frees memory.
| void fillSwadgePassPacket | ( | swadgePassPacket_t * | packet | ) |
Fill a SwadgePass packet with data from all modes before transmission.
| packet | The packet to fill |
|
inline |
Transmit a SwadgePass packet.
| packet | The packet to transmit |
| void receiveSwadgePass | ( | const esp_now_recv_info_t * | esp_now_info, |
| const uint8_t * | data, | ||
| uint8_t | len, | ||
| int8_t | rssi ) |
Receive an ESP NOW packet and save it if it is a SwadgePass packet.
This limits the number of received SwadgePasses to MAX_NUM_SWADGE_PASSES. If a SwadgePass is received while at capacity, the most used SwadgePass will be deleted first, as determined by the most number of bits set in swadgePassNvs_t.usedModeMask.
If a SwadgePass is received from a Swadge for which there already is data, the old data will be overwritten if it's different and the swadgePassNvs_t.usedModeMask will always be cleared.
| esp_now_info | Metadata for the packet, including src and dst MAC addresses |
| data | The received data |
| len | The length of the received data |
| rssi | unused |
| 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.
| swadgePasses | A list to fill with type swadgePassData_t |
| mode | The Swadge Mode getting SwadgePass data (may be NULL) |
| getUsed | true to return all SwadgePass data, false to return only unused SwadgePass data |
| void freeSwadgePasses | ( | list_t * | swadgePasses | ) |
Free SwadgePass data loaded with getSwadgePasses().
| swadgePasses | A list of SwadgePasses to free. The list should contain swadgePassData_t |
| bool isPacketUsedByMode | ( | swadgePassData_t * | data, |
| const struct swadgeMode * | mode ) |
Return if a given mode has used this SwadgePass data yet.
| data | The SwadgePass data |
| mode | The mode using the SwadgePass data |
| void setPacketUsedByMode | ( | swadgePassData_t * | data, |
| const struct swadgeMode * | mode, | ||
| bool | isUsed ) |
Set if a given mode has used this SwadgePass data yet.
This will write changes to NVS. Note that if this is called many times in a row, like when processing a batch of SwadgePasses, the microphone and speaker should be disabled. We have seen freezes doing many NVS writes while those peripherals are active
| data | The SwadgePass data |
| mode | The mode using the SwadgePass data |
| isUsed | true if the data should be set as used, false if it should be set as unused |
| void pruneSwadgePasses | ( | void | ) |
Prune received SwadgePasses down to MAX_NUM_SWADGE_PASSES (50).
The 3.1.0 release had a maximum of 100 SwadgePasses, but that was too many.
This function must be called once on startup to ensure memory doesn't run out.