-
Notifications
You must be signed in to change notification settings - Fork 34
1) How UNFLoader works
UNFLoader starts by detecting the connected flashcart and then assigns function pointers to functions related to said cart. These function pointers provide a way to abstract which flashcart the tool is connected to, and makes it easier for developers to extend the tool's functionality without needing to know how each cart works.
UNFLoader provides the following functions (located in device.h) to abstract different processes of flashcart USB communication:
// Finds what cart is connected via USB and initializes the function pointers
void device_find(int automode);
// Opens the USB pipeline
void device_open();
// Sends a ROM via USB given a filepath
void device_sendrom(char* rompath);
// Uploads arbitrary data to the connected flashcart (More on this later)
void device_senddata(int datatype, char* data, u32 size);
// Checks if the USB pipeline is open
bool device_isopen();
// Closes the USB pipeline
void device_close();If the -d argument is provided to UNFLoader during intialization, once a ROM is uploaded to a flashcart, UNFLoader enters debug mode. In this state, the tool enters an loop where it periodically calls the FT_GetQueueStatus function to detect incoming data. This is handled by the debug_main function in debug.cpp.
How does the tool know what to do with the incoming data? How can it differentiate between prints and binary data? How does it know if the incoming data is part of a larger block? The answer is that UNFLoader uses a specific communication protocol to deal with these problems.
When uploading or receiving arbitrary data, UNFLoader expects the data to be formatted like so:
- 4 Bytes with
'D' 'M' 'A' '@'to signalize data start. - 4 Bytes with the data header (more on this in a bit).
- N bytes with the data, where N is the size value provided in the data header.
- Finally, 4 bytes with
'C' 'M' 'P' 'H'to signalize data end[1].
The data header provides two important chunks of information. The first byte of the data header contains the type of data which is being sent/received, and the next 3 bytes state how large the incoming data is (Which can range between 1 byte to a maximum of 8MB). The data type mentioned in the first byte is up to the developer to implement, however the following data types are already provided by default:
// Incoming data is text for printf
#define DATATYPE_TEXT 0x01
// Incoming data is raw binary
#define DATATYPE_RAWBINARY 0x02
// Incoming data describes contents of next incoming data
// Use to help you process the data that comes after it (see screenshot implmentation)
#define DATATYPE_HEADER 0x03
// Incoming data is a framebuffer
#define DATATYPE_SCREENSHOT 0x04There is no checksum in place to detect the authenticity of the data. This might be implemented at a later date, but for now it is unused to speed up USB operations. A very simple method for a checksum would be to add every single byte of the received data together.
[1] The CMP signal is currently not used when uploading arbitrary data to the 64Drive on the N64 side (but it is used on the PC side). The reason for this is explained in the 64Drive chapter.