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