Swadge 2024 2.0.0
APIs to develop games for the Magfest Swadge
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
swadge2024.h File Reference

Detailed Description

Design Philosophy

A Swadge mode is struct of configuration variables and function pointers, which is the closest thing in C to an object. These provide a common interface so that the system firmware can run each mode. The Swadge's system firmware will initialize peripherals required by the mode and call the mode's function pointers when appropriate.

If a mode does not need a particular function, for example it doesn't do audio handling, it is safe to set the function pointer to NULL. The function won't be called. All fields must be initialized to something, since an uninitialized field may lead to undefined behavior.

Note
The details of all configuration variables and function pointers can be found in swadgeMode_t.

The top level menu will maintain a list of all available modes and the user can pick the mode to run. This approach is similar to apps. Only one mode may run at a single time, and when it runs it will have full system resources.

Usage

Each mode must have a single swadgeMode_t. How the Swadge mode works is flexible and left up to the mode's author to determine. Maybe it uses a menu.h, maybe it has a custom UI. All Swadge mode source code should be in the /main/modes folder. Each mode should have it's own folder to keep source organized.

To build the firmware, the mode's source files must be added to /main/CMakeLists.txt. The emulator's makefile automatically finds files to compile recursively, so they do not need to be explicitly listed.

It's best practice not to use 'generic' names for functions and variables, because they may collide with another mode's functions or variables. When possible, functions and variables should be prefixed with something unique, like demo in the example below.

Example

Adding a mode to the CMakeFile requires adding two separate lines in the idf_component_register section.

"modes/pong/pong.c"

under the SRCS section and

"modes/pong"

under the INCLUDES section.

Function prototypes must be declared before using them to initialize function pointers:

// It's good practice to declare immutable strings as const so they get placed in ROM, not RAM
static const char demoName[] = "Demo";
static void demoEnterMode(void);
static void demoExitMode(void);
static void demoMainLoop(int64_t elapsedUs);
static void demoAudioCallback(uint16_t* samples, uint32_t sampleCnt);
static void demoBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int16_t h, int16_t up, int16_t upNum);
static void demoEspNowRecvCb(const esp_now_recv_info_t* esp_now_info, const uint8_t* data, uint8_t len, int8_t rssi);
static void demoEspNowSendCb(const uint8_t* mac_addr, esp_now_send_status_t status);
static int16_t demoAdvancedUSB(uint8_t* buffer, uint16_t length, uint8_t isGet);
static void demoDacCb(uint8_t *samples, int16_t len);

Then functions can be used to initialize a swadgeMode_t:

swadgeMode_t demoMode = {
.modeName = demoName,
.wifiMode = ESP_NOW,
.overrideUsb = false,
.usesAccelerometer = true,
.usesThermometer = true,
.overrideSelectBtn = false,
.fnEnterMode = demoEnterMode,
.fnExitMode = demoExitMode,
.fnMainLoop = demoMainLoop,
.fnAudioCallback = demoAudioCallback,
.fnBackgroundDrawCallback = demoBackgroundDrawCallback,
.fnEspNowRecvCb = demoEspNowRecvCb,
.fnEspNowSendCb = demoEspNowSendCb,
.fnAdvancedUSB = demoAdvancedUSB,
.fnDacCb = demoDacCb,
};
@ ESP_NOW
ESP-NOW packets are delivered to Swadge modes from the main loop.
Definition hdw-esp-now.h:101
struct swadgeMode swadgeMode_t

The declared functions must actually exist somewhere:

static void demoEnterMode(void)
{
// Fill this in
}
static void demoExitMode(void)
{
// Fill this in
}
static void demoMainLoop(int64_t elapsedUs)
{
// Fill this in
}
static void demoAudioCallback(uint16_t* samples, uint32_t sampleCnt)
{
// Fill this in
}
static void demoBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int16_t h, int16_t up, int16_t upNum)
{
// Fill this in
}
static void demoEspNowRecvCb(const esp_now_recv_info_t* esp_now_info, const uint8_t* data, uint8_t len, int8_t rssi)
{
// Fill this in
}
static void demoEspNowSendCb(const uint8_t* mac_addr, esp_now_send_status_t status)
{
// Fill this in
}
static int16_t demoAdvancedUSB(uint8_t* buffer, uint16_t length, uint8_t isGet)
{
// Fill this in
return 0;
}
static void demoDacCb(uint8_t *samples, int16_t len)
{
// Fill this in
}

The swadgeMode_t should be declared as extern in a header file so that it can be referenced in other modes.

#ifndef _DEMO_MODE_H_
#define _DEMO_MODE_H_
#include "swadge2024.h"
extern swadgeMode_t demoMode;
#endif

Add the modeIncludeList.h:

#include "demoMode.h"

Add the mode to the menu initializer and mode list in modeIncludeList.c:

// add the following to the allSwadgeModes array, make sure to seperate by a comma
&demoMode
// In modeListSetMenu(). Add to the appropriate section.
addSingleItemToMenu(mainMenu->menu, demoMode.modeName);
menuItem_t * addSingleItemToMenu(menu_t *menu, const char *label)
Add a single item entry to the menu. When this item is selected, the menuCb callback is called with t...
Definition menu.c:193

Go to the source code of this file.

Data Structures

struct  swadgeMode
 

Macros

#define EXIT_TIME_US   1000000
 
#define DEFAULT_FRAME_RATE_US   (1000000 / 40)
 the default time between drawn frames, in microseconds (40FPS)
 

Typedefs

typedef struct swadgeMode swadgeMode_t
 

Functions

bool checkButtonQueueWrapper (buttonEvt_t *evt)
 Service the queue of button events that caused interrupts This only returns a single event, even if there are multiple in the queue This function may be called multiple times in a row to completely empty the queue.
 
void switchToSwadgeMode (const swadgeMode_t *mode)
 
void softSwitchToPendingSwadge (void)
 Switch to the pending Swadge mode without restarting the system.
 
void deinitSystem (void)
 Deinitialize all components in the system.
 
void openQuickSettings (void)
 
void setFrameRateUs (uint32_t newFrameRateUs)
 Set the framerate, in microseconds.
 
uint32_t getFrameRateUs (void)
 Get the current framerate, in microseconds.
 
void switchToSpeaker (void)
 Enable the speaker (and battery monitor) and disable the microphone.
 
void switchToMicrophone (void)
 Enable the microphone and disable the speaker (and battery monitor)
 
void powerDownPeripherals (void)
 Power down all hardware peripherals.
 
void powerUpPeripherals (void)
 Power up all hardware peripherals.
 
font_tgetSysFont (void)
 Get the Sys Ibm Font. Font is pre-loaded fto ensure a font is always available for devs to use.
 
midiFile_tgetSysSound (void)
 

Data Structure Documentation

◆ swadgeMode

struct swadgeMode
Data Fields
const char * modeName This swadge mode's name, used in menus. This is not a function pointer.
wifiMode_t wifiMode This is a setting, not a function pointer. Set it to NO_WIFI to save power by not using WiFi at all. Set it to ESP_NOW to send and receive packets to and from all Swadges in range. ESP_NOW_IMMEDIATE is the same as ESP_NOW but does not use a queue for incoming packets.
bool overrideUsb If this is false, then the default TinyUSB driver will be installed (HID gamepad). If this is true, then the swadge mode can do whatever it wants with USB.
bool usesAccelerometer If this is false, the accelerometer will not be initialized and accelGetAccelVec() will not work. If this is true, then the swadge will be initialized.
bool usesThermometer If this is false, the thermometer will not be initialized and readTemperatureSensor() will not work. If this is true, then the swadge will be initialized.
bool overrideSelectBtn If this is false, then PB_SELECT events will only be used to return to the main menu or open the quick settings menu. If this is true then PB_SELECT events will be passed to the Swadge mode and PB_SELECT will not return to the main menu or open the quick settings menu.
void(*)(void) fnEnterMode This function is called when this mode is started. It should initialize variables and start the mode.
void(*)(void) fnExitMode This function is called when the mode is exited. It should free any allocated memory.
void(*)(int64_t elapsedUs) fnMainLoop This function is called from the main loop. It's pretty quick, but the timing may be inconsistent.
Parameters
elapsedUsThe time elapsed since the last time this function was called. Use this value to determine when it's time to do things
void(*)(uint16_t *samples, uint32_t sampleCnt) fnAudioCallback This function is called whenever audio samples are read from the microphone (ADC) and are ready for processing. Samples are read at 8KHz. If this function is not NULL, then readBattmon() will not work.
Parameters
samplesA pointer to 12 bit audio samples
sampleCntThe number of samples read
void(*)(int16_t x, int16_t y, int16_t w, int16_t h, int16_t up, int16_t upNum) fnBackgroundDrawCallback This function is called when the display driver wishes to update a section of the display.
Parameters
xthe x coordinate that should be updated
ythe x coordinate that should be updated
wthe width of the rectangle to be updated
hthe height of the rectangle to be updated
upupdate number
upNumupdate number denominator
void(*)(const esp_now_recv_info_t *esp_now_info, const uint8_t *data, uint8_t len, int8_t rssi) fnEspNowRecvCb This function is called whenever an ESP-NOW packet is received.
Parameters
esp_now_infoInformation about the transmission, including The MAC addresses
dataA pointer to the data received
lenThe length of the data received
rssiThe RSSI for this packet, from 1 (weak) to ~90 (touching)
void(*)(const uint8_t *mac_addr, esp_now_send_status_t status) fnEspNowSendCb This function is called whenever an ESP-NOW packet is sent. It is just a status callback whether or not the packet was actually sent. This will be called after calling espNowSend().
Parameters
mac_addrThe MAC address which the data was sent to
statusThe status of the transmission
int16_t(*)(uint8_t *buffer, uint16_t length, uint8_t isGet) fnAdvancedUSB Advanced USB Functionality, for hooking existing advanced_usb interface.
  • if isGet == 1, that is a "get" or an "IN" endpoint, where the Swadge sends data to the Host.
  • if isGet == 0, that is a "set" or an "OUT" endpoint, where the Host sends data to the Swadge.
Parameters
bufferPointer to full command
lengthTotal length of the buffer (command ID included)
isGet0 if this is a SET_REPORT, 1 if this is a GET_REPORT
Returns
The number of bytes returned to the host
fnDacCallback_t fnDacCb This function is called to fill sample buffers for the DAC. If this is NULL, then globalMidiPlayerFillBuffer() will be used instead to fill sample buffers.
void(*)(struct swadgePassPacket *packet) fnAddToSwadgePassPacket This function is called to fill in a SwadgePass packet with mode-specific data. The Swadge mode should only fill in it's relevant data and not touch other mode's data.
Warning
This function will be called when the mode is not initialized or running, so it MUST NOT rely on memory allocated or data loaded in the mode's initializer.
Parameters
packetThe packet to fill in
trophyDataList_t * trophyData A struct with the settings and data required for trophy behavior. Set to NULL for no trophies.

Macro Definition Documentation

◆ EXIT_TIME_US

#define EXIT_TIME_US   1000000

◆ DEFAULT_FRAME_RATE_US

#define DEFAULT_FRAME_RATE_US   (1000000 / 40)

the default time between drawn frames, in microseconds (40FPS)

Typedef Documentation

◆ swadgeMode_t

typedef struct swadgeMode swadgeMode_t

Function Documentation

◆ checkButtonQueueWrapper()

bool checkButtonQueueWrapper ( buttonEvt_t * evt)

Service the queue of button events that caused interrupts This only returns a single event, even if there are multiple in the queue This function may be called multiple times in a row to completely empty the queue.

This is a wrapper for checkButtonQueue() which also monitors the button to return to the main menu

Parameters
evtIf an event occurred, return it through this argument
Returns
true if an event occurred, false if nothing happened

◆ switchToSwadgeMode()

void switchToSwadgeMode ( const swadgeMode_t * mode)

Set up variables to synchronously switch the swadge mode in the main loop

Parameters
modeA pointer to the mode to switch to

◆ softSwitchToPendingSwadge()

void softSwitchToPendingSwadge ( void )

Switch to the pending Swadge mode without restarting the system.

◆ deinitSystem()

void deinitSystem ( void )

Deinitialize all components in the system.

◆ openQuickSettings()

void openQuickSettings ( void )

◆ setFrameRateUs()

void setFrameRateUs ( uint32_t newFrameRateUs)

Set the framerate, in microseconds.

Parameters
newFrameRateUsThe time between frame draws, in microseconds

◆ getFrameRateUs()

uint32_t getFrameRateUs ( void )

Get the current framerate, in microseconds.

Returns
uint32_t The time between frame draws, in microseconds

◆ switchToSpeaker()

void switchToSpeaker ( void )

Enable the speaker (and battery monitor) and disable the microphone.

◆ switchToMicrophone()

void switchToMicrophone ( void )

Enable the microphone and disable the speaker (and battery monitor)

◆ powerDownPeripherals()

void powerDownPeripherals ( void )

Power down all hardware peripherals.

◆ powerUpPeripherals()

void powerUpPeripherals ( void )

Power up all hardware peripherals.

◆ getSysFont()

font_t * getSysFont ( void )

Get the Sys Ibm Font. Font is pre-loaded fto ensure a font is always available for devs to use.

◆ getSysSound()

midiFile_t * getSysSound ( void )