There are many instances when it would be nice to be able to send large amounts of data to an Arduino-based device. A very obvious example is any kind of media player, where you’d like to upload files from your computer, but there’s also sending configuration, whitelists, sets of instructions… there are many cases where this could be very useful.
I don’t know what the easiest way is, but a very simple way is using SerialUI‘s new “stream input” prompt (available as of the 1.7 release). If you use it in conjunction with Druid4Arduino, all the transfer-related work is done for you and you only need to focus on dealing with the incoming data.
Here’s a little introduction and demonstration of the functionality, used here to upload wave audio files to my “poor man’s programmable wave player“–a very simple media player.
If getting access to similar functionality would be of interest in your projects, read on to go over everything you need to know!
SerialUI prompts
When you create a system of menus and commands using SerialUI, it is recommended that you issue the various prompts just prior to fetching the data. So far, these have been showEnterDataPrompt() and showEnterNumericDataPrompt(). The real benefit of using these before you parseInt() (or otherwise request data), is that Druid knows about them and it will prompt the GUI’s user to enter something appropriate in the input box whenever you call showEnter*Prompt() in your command callbacks.
With release 1.7, a new type of prompt has been included that requests larger amounts of arbitrary data be sent to the device: the “data stream prompt“: showEnterStreamPromptAndReceive(). Unlike the other prompt methods, this one actually takes some parameters because it needs to know what to do with the incoming data.
The simplest way to call this method is:
mySerialUI.showEnterStreamPromptAndReceive(char * bufferToUse, uint8_t bufferSize, streamInputCallback callback);
The first two parameters are to inform the system of the temporary container to use for moving chunks of data around. That container’s size is up to you–a smaller container will take up less RAM but mean more trips to the data processing callback.
The streamInputCallback param is a function you define that takes four parameters (and returns void), something like so:
void myFunctionToProcessTheData(char* buffer, uint8_t buflen, size_t previous_position, size_t total_len) { // what you do here is up to you... // there are buflen bytes of data in buffer, starting at buffer[0]. // previous_position is the count of bytes processed so far, // total_len is the total size of all the data being sent. // if this was a media player, you might store these bytes in // external flash memory : for (uint8_t i=0; i< buflen; i++) { // stick buffer[i] in memory } }
Once that function is ready, you can create your command callback in which you actually request the upload data:
void myUploadClicked() { // some command callback that allows uploads // declare the swap space char buffer[32]; // show the prompt and receive the data. myFunctionToProcessTheData() // will be called repeatedly with a buffer filled with between 1 and 32 bytes, // until the entire upload has been processed. mySerialUI.showEnterStreamPromptAndReceive(buffer, 32, myFunctionToProcessTheData); }
And that’s all there is to it for the simplest cases. There are optional parameters to showEnterStreamPromptAndReceive() that include start and completed callbacks. You can learn more about these, the actual upload process from the client side, and more on the SerialUI project page (shortly).