parent
772e6196b9
commit
737700a157
@ -0,0 +1,144 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <assert.h> |
||||||
|
#include "utils/payload_parser.h" |
||||||
|
#include "utils/payload_builder.h" |
||||||
|
|
||||||
|
#define GEX_H |
||||||
|
#include "gex_bulk.h" |
||||||
|
#include "gex_internal.h" |
||||||
|
#include "gex_message_types.h" |
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk read from a unit, synchronous |
||||||
|
* |
||||||
|
* @param unit - the unit to target |
||||||
|
* @param bulk - the bulk transport info struct |
||||||
|
* @return actual number of bytes received. |
||||||
|
*/ |
||||||
|
uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk) |
||||||
|
{ |
||||||
|
// fprintf(stderr, "Ask to read:\n");
|
||||||
|
// We ask for the transfer. This is unit specific and can contain information that determines the transferred data
|
||||||
|
GexMsg resp0 = GEX_Query(unit, bulk->req_cmd, bulk->req_data, bulk->req_len); |
||||||
|
|
||||||
|
if (resp0.type == MSG_ERROR) { |
||||||
|
fprintf(stderr, "Bulk read rejected! %.*s\n", resp0.len, (char*)resp0.payload); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
if (resp0.type != MSG_BULK_READ_OFFER) { |
||||||
|
fprintf(stderr, "Bulk read failed, response not BULK_READ_OFFER!\n"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// fprintf(stderr, "BR, got offer!\n");
|
||||||
|
|
||||||
|
// Check how much data is available
|
||||||
|
PayloadParser pp = pp_start(resp0.payload, resp0.len, NULL); |
||||||
|
uint32_t total = pp_u32(&pp); |
||||||
|
assert(pp.ok); |
||||||
|
|
||||||
|
total = MIN(total, bulk->capacity); // clamp...
|
||||||
|
// fprintf(stderr, "Total is %d\n", total);
|
||||||
|
|
||||||
|
uint32_t at = 0; |
||||||
|
while (at < total+1) { // +1 makes sure we read one past end and trigger the END OF DATA msg
|
||||||
|
uint8_t buf[10]; |
||||||
|
PayloadBuilder pb = pb_start(buf, 10, NULL); |
||||||
|
pb_u32(&pb, 120); // This selects the chunk size.
|
||||||
|
// FIXME Something is wrong in the poll function, or the transport in general,
|
||||||
|
// because chunks larger than e.g. 128 bytes seem to get stuck half-transferred.
|
||||||
|
// This isn't an issue for events and regular sending, only query responses like here.
|
||||||
|
// This may also cause problems when receiving events while reading a bulk.
|
||||||
|
// It may be best to get rid of the comport and use libusb, after all.
|
||||||
|
|
||||||
|
// fprintf(stderr, "Poll read:\n");
|
||||||
|
GexMsg resp = GEX_QueryEx(unit, MSG_BULK_READ_POLL, buf, |
||||||
|
(uint32_t) pb_length(&pb), resp0.session, true, true); |
||||||
|
|
||||||
|
if (resp.type == MSG_ERROR) { |
||||||
|
fprintf(stderr, "Bulk read failed! %.*s\n", resp.len, (char *) resp.payload); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
if (resp.type == MSG_BULK_END) { |
||||||
|
// No more data
|
||||||
|
fprintf(stderr, "Bulk read OK, closed.\n"); |
||||||
|
return at; |
||||||
|
} |
||||||
|
|
||||||
|
if (resp.type == MSG_BULK_DATA) { |
||||||
|
memcpy(bulk->buffer+at, resp.payload, resp.len); |
||||||
|
at += resp.len; |
||||||
|
} else { |
||||||
|
fprintf(stderr, "Bulk read failed! Bad response type.\n"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return at; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk write to a unit, synchronous |
||||||
|
* |
||||||
|
* @param unit - the unit to target |
||||||
|
* @param bulk - the bulk transport info struct |
||||||
|
* @return true on success |
||||||
|
*/ |
||||||
|
bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk) |
||||||
|
{ |
||||||
|
// We ask for the transfer. This is unit specific
|
||||||
|
GexMsg resp0 = GEX_Query(unit, bulk->req_cmd, bulk->req_data, bulk->req_len); |
||||||
|
|
||||||
|
if (resp0.type == MSG_ERROR) { |
||||||
|
fprintf(stderr, "Bulk write rejected! %.*s\n", resp0.len, (char*)resp0.payload); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (resp0.type != MSG_BULK_WRITE_OFFER) { |
||||||
|
fprintf(stderr, "Bulk write failed, response not MSG_BULK_WRITE_OFFER!\n"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
PayloadParser pp = pp_start(resp0.payload, resp0.len, NULL); |
||||||
|
uint32_t max_size = pp_u32(&pp); |
||||||
|
uint32_t max_chunk = pp_u32(&pp); |
||||||
|
assert(pp.ok); |
||||||
|
|
||||||
|
if (max_size < bulk->len) { |
||||||
|
fprintf(stderr, "Write not possible, not enough space.\n"); |
||||||
|
// Inform GEX we're not going to do it
|
||||||
|
GEX_SendEx(unit, MSG_BULK_ABORT, NULL, 0, resp0.session, true); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
uint32_t at = 0; |
||||||
|
while (at < bulk->len) { |
||||||
|
uint32_t chunk = MIN(max_chunk, bulk->len - at); |
||||||
|
// fprintf(stderr, "Query at %d, len %d\n", (int)at, (int)chunk);
|
||||||
|
GexMsg resp = GEX_QueryEx(unit, MSG_BULK_DATA, bulk->buffer + at, chunk, |
||||||
|
resp0.session, true, true); |
||||||
|
at += chunk; |
||||||
|
|
||||||
|
if (resp.type == MSG_ERROR) { |
||||||
|
fprintf(stderr, "Bulk write failed! %.*s\n", resp.len, (char *) resp.payload); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (resp.type != MSG_SUCCESS) { |
||||||
|
fprintf(stderr, "Bulk write failed! Bad response type.\n"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Conclude the transfer
|
||||||
|
GEX_SendEx(unit, MSG_BULK_END, NULL, 0, resp0.session, true); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CLIENT_GEX_BULK_H |
||||||
|
#define GEX_CLIENT_GEX_BULK_H |
||||||
|
|
||||||
|
#ifndef GEX_H |
||||||
|
#error "Include gex.h instead!" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "gex_defines.h" |
||||||
|
#include "gex_unit.h" |
||||||
|
#include <stdint.h> |
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk read from a unit, synchronous |
||||||
|
* |
||||||
|
* @param unit - the unit to target |
||||||
|
* @param bulk - the bulk transport info struct |
||||||
|
* @return actual number of bytes received. |
||||||
|
*/ |
||||||
|
uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk write to a unit, synchronous |
||||||
|
* |
||||||
|
* @param unit - the unit to target |
||||||
|
* @param bulk - the bulk transport info struct |
||||||
|
* @return true on success |
||||||
|
*/ |
||||||
|
bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk); |
||||||
|
|
||||||
|
#endif //GEX_CLIENT_GEX_BULK_H
|
Loading…
Reference in new issue