Closed maosuyun2009 closed 6 years ago
good to hear you find it useful!
Ack is not built-in on purpose, I decided it's better to leave that to higher protocol layers for more flexibility.
You can implement acked upload with something like this (it's not tested, just off the top of my head). Don't copy-paste this code, just look at the general idea how it could be done:
it's not re-entrant because of using a global variable, there's certainly some room for improvement (in the library and also in the uploader code)
An alternative way if you dont want to do it asynchronously is using a "synchronous query", see the readme for an example.
message_types.h
- a file shared by both peers, defines your message IDs
#define MSG_UPLOAD_BEGIN 100
#define MSG_UPLOAD_ACK 101
#define MSG_UPLOAD_CHUNK 102
#define MSG_UPLOAD_COMPLETE 103
this is the uploader code
#include "message_types.h"
#define UPLOAD_CHUNK_LEN 1024
#define UPLOAD_TIMEOUT_MS 5000
struct {
uint8_t *data;
size_t len;
size_t last_index;
TF_ID listener_id;
} uploadProgress;
static bool myUploadHandler(TF_ID frame_id, TF_TYPE type, const uint8_t *data, TF_LEN len)
{
if (type == MSG_UPLOAD_ACK) {
// advance to account for the last chunk
// this can overflow, that's ok - we use that to test if we're done
uploadProgress.last_index += UPLOAD_CHUNK_LEN;
if (uploadProgress.last_index < uploadProgress.len) {
// more to send
size_t chunk_siz = min(uploadProgress.len - uploadProgress.last_index, UPLOAD_CHUNK_LEN);
TF_Respond(MSG_UPLOAD_CHUNK,
data+uploadProgress.last_index,
chunk_siz,
frame_id);
// todo clear the old timeout,set a new one:
startTimeout(myUploadTimeoutCallback, UPLOAD_TIMEOUT_MS);
}
else {
// tell client we're done
TF_Respond(MSG_UPLOAD_COMPLETE,
NULL, 0, // message is empty
frame_id);
// ignore further responses
TF_RemoveIdListener(frame_id);
// todo clear the old timeout
}
return true;
} else {
// unexpected type - not MSG_UPLOAD_ACK
// maybe signalizing an error?
// true if we handled the message, false to let some other handler deal with it
return true;
}
}
static void myUploadTimeoutCallback(void)
{
// TODO try to resend last chunk, or abort:
// do this only if upload is in progress
TF_RemoveIdListener(uploadProgress.listener_id);
}
void upload_start(uint8_t *data, size_t len)
{
uploadProgress.data = data;
uploadProgress.len = len;
uploadProgress.last_index = 0;
size_t chunk_siz = min(uploadProgress.len, UPLOAD_CHUNK_LEN);
TF_Send(MSG_UPLOAD_BEGIN,
data,
chunk_siz,
myUploadHandler,
&uploadProgress.listener_id);
// Start a timeout to cancel the operation
// Use some system mechanism for this (or just don't do it)
startTimeout(myUploadTimeoutCallback, UPLOAD_TIMEOUT_MS);
}
Now, the client (which receives our upload)
#include "message_types.h"
size_t upl_pos = 0;
bool upload_handler(TF_ID frame_id, TF_TYPE type, const uint8_t *data, TF_LEN len)
{
if (type == MSG_UPLOAD_BEGIN) {
// start of upload
// (normally you'd also send the data length in the first frame etc,
// so the client knows that length to expect)
// do something with *data
(void)data;
upl_pos = len;
TF_Respond(MSG_UPLOAD_ACK,
NULL, 0, // response message is empty
frame_id);
return true;
}
if (type == MSG_UPLOAD_CHUNK) {
// some more data...
// TODO discard this if an upload has not begun
// do something with *data
// it goes at offset {upl_pos}
(void)data;
upl_pos += len;
TF_Respond(MSG_UPLOAD_ACK,
NULL, 0, // response message is empty
frame_id);
return true;
}
if (type == MSG_UPLOAD_COMPLETE) {
// do something
return true;
}
}
void setup_listeners(void)
{
// we use one handler for all three for simplicity
TF_AddTypeListener(MSG_UPLOAD_BEGIN, upload_handler);
TF_AddTypeListener(MSG_UPLOAD_CHUNK, upload_handler);
TF_AddTypeListener(MSG_UPLOAD_COMPLETE, upload_handler);
}
you could also send the last chunk already with message type MSG_UPLOAD_COMPLETE, but then the client would have to ack that too, or you don't have the resend with timeout functionality for the last chunk.
Hi, thank you share this libray, I want use this libray to my OTA funcation, Maybe,receiver should response to sender the complete and correct of data