|
|
|
|
|
|
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
#include "usb_dev.h" |
|
|
#include "usb_dev.h" |
|
|
#include "usb_desc.h" |
|
|
|
|
|
#include "usb_flightsim.h" |
|
|
#include "usb_flightsim.h" |
|
|
#include "core_pins.h" // for yield(), millis() |
|
|
#include "core_pins.h" // for yield(), millis() |
|
|
#include <string.h> // for memcpy() |
|
|
#include <string.h> // for memcpy() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FlightSimClass::xmit(const void *p1, uint8_t n1, const void *p2, uint8_t n2) |
|
|
void FlightSimClass::xmit(const void *p1, uint8_t n1, const void *p2, uint8_t n2) |
|
|
{ |
|
|
{ |
|
|
uint8_t total; |
|
|
|
|
|
|
|
|
uint16_t total; |
|
|
|
|
|
|
|
|
total = n1 + n2; |
|
|
total = n1 + n2; |
|
|
if (total > FLIGHTSIM_TX_SIZE) { |
|
|
if (total > FLIGHTSIM_TX_SIZE) { |
|
|
|
|
|
|
|
|
tx_noautoflush = 0; |
|
|
tx_noautoflush = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void FlightSimClass::xmit_big_packet(const void *p1, uint16_t n1, const void *p2, uint16_t n2) |
|
|
|
|
|
|
|
|
void FlightSimClass::xmit_big_packet(const void *p1, uint8_t n1, const void *p2, uint8_t n2) |
|
|
{ |
|
|
{ |
|
|
if (!enabled || !usb_configuration) return; |
|
|
if (!enabled || !usb_configuration) return; |
|
|
|
|
|
|
|
|
|
|
|
uint16_t remaining = n1 + n2; |
|
|
|
|
|
if (remaining > 255) return; |
|
|
|
|
|
|
|
|
bool part2 = false; |
|
|
bool part2 = false; |
|
|
uint16_t remainingPart1 = n1; |
|
|
|
|
|
uint16_t remaining; |
|
|
|
|
|
const void *dataPtr = p1; |
|
|
|
|
|
bool needAdditionalFragment = false; |
|
|
|
|
|
|
|
|
uint8_t remainingPart1 = n1; |
|
|
|
|
|
const uint8_t *dataPtr = (const uint8_t*)p1; |
|
|
|
|
|
bool writeFragmentHeader = false; |
|
|
uint8_t fragmentCounter = 1; |
|
|
uint8_t fragmentCounter = 1; |
|
|
|
|
|
|
|
|
tx_noautoflush =1; // don't mess with my data, I'm working on it! |
|
|
tx_noautoflush =1; // don't mess with my data, I'm working on it! |
|
|
|
|
|
|
|
|
// If we have a current packet, fill it with whatever fits |
|
|
// If we have a current packet, fill it with whatever fits |
|
|
uint8_t partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; |
|
|
uint8_t partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; |
|
|
if (partLen > n1) partLen=n1; |
|
|
if (partLen > n1) partLen=n1; |
|
|
// copy first part |
|
|
|
|
|
|
|
|
// copy first part, containing total packet length |
|
|
memcpy(tx_packet->buf + tx_packet->index, dataPtr, partLen); |
|
|
memcpy(tx_packet->buf + tx_packet->index, dataPtr, partLen); |
|
|
remainingPart1 -= partLen; |
|
|
remainingPart1 -= partLen; |
|
|
tx_packet->index += partLen; |
|
|
tx_packet->index += partLen; |
|
|
if (remainingPart1) { |
|
|
if (remainingPart1) { |
|
|
|
|
|
// there still is data from the first part that |
|
|
|
|
|
// will go to the next packet. The boolean variable |
|
|
|
|
|
// part2 remains false |
|
|
remaining = remainingPart1+n2; |
|
|
remaining = remainingPart1+n2; |
|
|
dataPtr += partLen; |
|
|
dataPtr += partLen; |
|
|
} else { |
|
|
} else { |
|
|
// maybe we have space for more |
|
|
|
|
|
|
|
|
// maybe we have space for some data from the second part |
|
|
part2=true; |
|
|
part2=true; |
|
|
partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; |
|
|
partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; |
|
|
|
|
|
// there is no need here to check whether partLen is |
|
|
|
|
|
// bigger than n2. It's not. If it were, all the data |
|
|
|
|
|
// would have fit in a single packet and xmit_big_packet |
|
|
|
|
|
// would never have been called... |
|
|
remaining = n2; |
|
|
remaining = n2; |
|
|
if (partLen) { |
|
|
if (partLen) { |
|
|
memcpy(tx_packet->buf + tx_packet->index, p2, partLen); |
|
|
memcpy(tx_packet->buf + tx_packet->index, p2, partLen); |
|
|
remaining -= partLen; |
|
|
remaining -= partLen; |
|
|
tx_packet->index += partLen; |
|
|
tx_packet->index += partLen; |
|
|
dataPtr = p2 + partLen; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
dataPtr = (const uint8_t*)p2 + partLen; |
|
|
} |
|
|
} |
|
|
// Packet padding should not be necessary, as xmit_big_packet |
|
|
// Packet padding should not be necessary, as xmit_big_packet |
|
|
// will only be called for data that doesn't fit in a single |
|
|
// will only be called for data that doesn't fit in a single |
|
|
|
|
|
|
|
|
for (int i = tx_packet->index; i < FLIGHTSIM_TX_SIZE; i++) { |
|
|
for (int i = tx_packet->index; i < FLIGHTSIM_TX_SIZE; i++) { |
|
|
tx_packet->buf[i] = 0; |
|
|
tx_packet->buf[i] = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// queue first packet for sending |
|
|
tx_packet->len = FLIGHTSIM_TX_SIZE; |
|
|
tx_packet->len = FLIGHTSIM_TX_SIZE; |
|
|
usb_tx(FLIGHTSIM_TX_ENDPOINT, tx_packet); |
|
|
usb_tx(FLIGHTSIM_TX_ENDPOINT, tx_packet); |
|
|
tx_packet = NULL; |
|
|
tx_packet = NULL; |
|
|
needAdditionalFragment = true; |
|
|
|
|
|
|
|
|
writeFragmentHeader = true; |
|
|
} else { |
|
|
} else { |
|
|
remaining = n1+n2; |
|
|
remaining = n1+n2; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
while (remaining >0) { |
|
|
while (remaining >0) { |
|
|
while (1) { |
|
|
while (1) { |
|
|
|
|
|
// get memory for next packet |
|
|
if (usb_tx_packet_count(FLIGHTSIM_TX_ENDPOINT) < TX_PACKET_LIMIT) { |
|
|
if (usb_tx_packet_count(FLIGHTSIM_TX_ENDPOINT) < TX_PACKET_LIMIT) { |
|
|
tx_packet = usb_malloc(); |
|
|
tx_packet = usb_malloc(); |
|
|
if (tx_packet) break; |
|
|
|
|
|
|
|
|
if (tx_packet) { |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!enabled || !usb_configuration) { |
|
|
if (!enabled || !usb_configuration) { |
|
|
|
|
|
// teensy disconnected |
|
|
tx_noautoflush = 0; |
|
|
tx_noautoflush = 0; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
tx_noautoflush = 0; // you can pick up my data, if you like |
|
|
tx_noautoflush = 0; // you can pick up my data, if you like |
|
|
yield(); |
|
|
|
|
|
|
|
|
yield(); // do other things and wait for memory to become free |
|
|
tx_noautoflush = 1; // wait, I'm working on the packet data |
|
|
tx_noautoflush = 1; // wait, I'm working on the packet data |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (needAdditionalFragment) { |
|
|
|
|
|
// fragment header |
|
|
|
|
|
|
|
|
if (writeFragmentHeader) { |
|
|
tx_packet->buf[0]=(remaining+3 <= FLIGHTSIM_TX_SIZE) ? (byte) remaining+3 : FLIGHTSIM_TX_SIZE; |
|
|
tx_packet->buf[0]=(remaining+3 <= FLIGHTSIM_TX_SIZE) ? (byte) remaining+3 : FLIGHTSIM_TX_SIZE; |
|
|
tx_packet->buf[1]=0xff; |
|
|
tx_packet->buf[1]=0xff; |
|
|
tx_packet->buf[2]=fragmentCounter++; |
|
|
tx_packet->buf[2]=fragmentCounter++; |
|
|
tx_packet->index=3; |
|
|
tx_packet->index=3; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
if (!part2) { |
|
|
if (!part2) { |
|
|
// we still need to send the first part |
|
|
// we still need to send the first part |
|
|
|
|
|
|
|
|
remaining -= partLen; |
|
|
remaining -= partLen; |
|
|
if (!remainingPart1) { |
|
|
if (!remainingPart1) { |
|
|
part2=true; |
|
|
part2=true; |
|
|
dataPtr = p2; |
|
|
|
|
|
|
|
|
dataPtr = (const uint8_t*)p2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dataPtr += partLen; |
|
|
dataPtr += partLen; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
needAdditionalFragment = true; |
|
|
|
|
|
|
|
|
writeFragmentHeader = true; |
|
|
|
|
|
|
|
|
if (tx_packet->index >= FLIGHTSIM_TX_SIZE) { |
|
|
if (tx_packet->index >= FLIGHTSIM_TX_SIZE) { |
|
|
|
|
|
// queue packet for sending |
|
|
tx_packet->len = FLIGHTSIM_TX_SIZE; |
|
|
tx_packet->len = FLIGHTSIM_TX_SIZE; |
|
|
usb_tx(FLIGHTSIM_TX_ENDPOINT, tx_packet); |
|
|
usb_tx(FLIGHTSIM_TX_ENDPOINT, tx_packet); |
|
|
tx_packet = NULL; |
|
|
tx_packet = NULL; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
extern "C" { |
|
|
extern "C" { |
|
|
// This gets called when a USB start token arrives. |
|
|
|
|
|
|
|
|
// This gets called from usb_isr when a USB start token arrives. |
|
|
// If we have a packet to transmit AND transmission isn't disabled |
|
|
// If we have a packet to transmit AND transmission isn't disabled |
|
|
// by tx_noautoflush, we fill it up with zeros and send it out |
|
|
// by tx_noautoflush, we fill it up with zeros and send it out |
|
|
// to USB |
|
|
// to USB |