@@ -29,6 +29,7 @@ | |||
*/ | |||
#include "usb_dev.h" | |||
#include "usb_desc.h" | |||
#include "usb_flightsim.h" | |||
#include "core_pins.h" // for yield(), millis() | |||
#include <string.h> // for memcpy() | |||
@@ -106,6 +107,8 @@ FlightSimInteger::FlightSimInteger() | |||
next = NULL; | |||
value = 0; | |||
change_callback = NULL; | |||
callbackInfo = NULL; | |||
hasCallbackInfo = false; | |||
FlightSimClass::request_id_messages = 1; | |||
} | |||
@@ -142,7 +145,13 @@ void FlightSimInteger::write(long val) | |||
void FlightSimInteger::update(long val) | |||
{ | |||
value = val; | |||
if (change_callback) (*change_callback)(val); | |||
if (change_callback) { | |||
if (!hasCallbackInfo) { | |||
(*change_callback)(val); | |||
} else { | |||
(*(void(*)(long,void*))change_callback)(val,callbackInfo); | |||
} | |||
} | |||
} | |||
FlightSimInteger * FlightSimInteger::find(unsigned int n) | |||
@@ -169,6 +178,8 @@ FlightSimFloat::FlightSimFloat() | |||
next = NULL; | |||
value = 0; | |||
change_callback = NULL; | |||
hasCallbackInfo = false; | |||
callbackInfo = NULL; | |||
FlightSimClass::request_id_messages = 1; | |||
} | |||
@@ -205,7 +216,13 @@ void FlightSimFloat::write(float val) | |||
void FlightSimFloat::update(float val) | |||
{ | |||
value = val; | |||
if (change_callback) (*change_callback)(val); | |||
if (change_callback) { // add: JB | |||
if (!hasCallbackInfo) { | |||
(*change_callback)(val); | |||
} else { | |||
(*(void(*)(long,void*))change_callback)(val,callbackInfo); | |||
} | |||
} | |||
} | |||
FlightSimFloat * FlightSimFloat::find(unsigned int n) | |||
@@ -282,6 +299,7 @@ void FlightSimClass::update(void) | |||
switch (p[2]) { | |||
case 1: | |||
request_id_messages = 1; | |||
/* no break */ | |||
case 2: | |||
enable(); | |||
frameCount++; | |||
@@ -332,7 +350,10 @@ void FlightSimClass::xmit(const void *p1, uint8_t n1, const void *p2, uint8_t n2 | |||
uint8_t total; | |||
total = n1 + n2; | |||
if (total > FLIGHTSIM_TX_SIZE) return; | |||
if (total > FLIGHTSIM_TX_SIZE) { | |||
xmit_big_packet(p1, n1, p2, n2); | |||
return; | |||
} | |||
if (!enabled || !usb_configuration) return; | |||
tx_noautoflush = 1; | |||
if (tx_packet) { | |||
@@ -372,8 +393,123 @@ send: | |||
tx_noautoflush = 0; | |||
} | |||
void FlightSimClass::xmit_big_packet(const void *p1, uint16_t n1, const void *p2, uint16_t n2) | |||
{ | |||
if (!enabled || !usb_configuration) return; | |||
bool part2 = false; | |||
uint16_t remainingPart1 = n1; | |||
uint16_t remaining; | |||
const void *dataPtr = p1; | |||
bool needAdditionalFragment = false; | |||
uint8_t fragmentCounter = 1; | |||
tx_noautoflush =1; // don't mess with my data, I'm working on it! | |||
if (tx_packet) { | |||
// If we have a current packet, fill it with whatever fits | |||
uint8_t partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; | |||
if (partLen > n1) partLen=n1; | |||
// copy first part | |||
memcpy(tx_packet->buf + tx_packet->index, dataPtr, partLen); | |||
remainingPart1 -= partLen; | |||
tx_packet->index += partLen; | |||
if (remainingPart1) { | |||
remaining = remainingPart1+n2; | |||
dataPtr += partLen; | |||
} else { | |||
// maybe we have space for more | |||
part2=true; | |||
partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; | |||
remaining = n2; | |||
if (partLen) { | |||
memcpy(tx_packet->buf + tx_packet->index, p2, partLen); | |||
remaining -= partLen; | |||
tx_packet->index += partLen; | |||
dataPtr = p2 + partLen; | |||
} | |||
} | |||
// Packet padding should not be necessary, as xmit_big_packet | |||
// will only be called for data that doesn't fit in a single | |||
// packet. So, the previous code should always fill up the | |||
// first packet. Right? | |||
for (int i = tx_packet->index; i < FLIGHTSIM_TX_SIZE; i++) { | |||
tx_packet->buf[i] = 0; | |||
} | |||
tx_packet->len = FLIGHTSIM_TX_SIZE; | |||
usb_tx(FLIGHTSIM_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
needAdditionalFragment = true; | |||
} else { | |||
remaining = n1+n2; | |||
} | |||
while (remaining >0) { | |||
while (1) { | |||
if (usb_tx_packet_count(FLIGHTSIM_TX_ENDPOINT) < TX_PACKET_LIMIT) { | |||
tx_packet = usb_malloc(); | |||
if (tx_packet) break; | |||
} | |||
if (!enabled || !usb_configuration) { | |||
tx_noautoflush = 0; | |||
return; | |||
} | |||
tx_noautoflush = 0; // you can pick up my data, if you like | |||
yield(); | |||
tx_noautoflush = 1; // wait, I'm working on the packet data | |||
} | |||
if (needAdditionalFragment) { | |||
// fragment header | |||
tx_packet->buf[0]=(remaining+3 <= FLIGHTSIM_TX_SIZE) ? (byte) remaining+3 : FLIGHTSIM_TX_SIZE; | |||
tx_packet->buf[1]=0xff; | |||
tx_packet->buf[2]=fragmentCounter++; | |||
tx_packet->index=3; | |||
} | |||
if (!part2) { | |||
// we still need to send the first part | |||
uint8_t partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; | |||
if (partLen > remainingPart1) | |||
partLen=remainingPart1; | |||
memcpy(tx_packet->buf + tx_packet->index, dataPtr, partLen); | |||
dataPtr += partLen; | |||
remainingPart1 -= partLen; | |||
tx_packet->index += partLen; | |||
remaining -= partLen; | |||
if (!remainingPart1) { | |||
part2=true; | |||
dataPtr = p2; | |||
} | |||
} | |||
if (part2) { | |||
uint8_t partLen = FLIGHTSIM_TX_SIZE - tx_packet->index; | |||
if (partLen) { | |||
if (partLen > remaining) | |||
partLen=remaining; | |||
memcpy(tx_packet->buf + tx_packet->index, dataPtr, partLen); | |||
remaining -= partLen; | |||
tx_packet->index += partLen; | |||
dataPtr += partLen; | |||
} | |||
} | |||
needAdditionalFragment = true; | |||
if (tx_packet->index >= FLIGHTSIM_TX_SIZE) { | |||
tx_packet->len = FLIGHTSIM_TX_SIZE; | |||
usb_tx(FLIGHTSIM_TX_ENDPOINT, tx_packet); | |||
tx_packet = NULL; | |||
} | |||
} | |||
tx_noautoflush = 0; // data is ready to be transmitted on start of USB token | |||
} | |||
extern "C" { | |||
// This gets called when a USB start token arrives. | |||
// 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 | |||
// to USB | |||
void usb_flightsim_flush_callback(void) | |||
{ | |||
if (tx_noautoflush || !tx_packet || tx_packet->index == 0) return; |
@@ -66,6 +66,7 @@ private: | |||
static void enable(void) { enabled = 1; enableTimeout = 0; } | |||
static void disable(void) { enabled = 0; } | |||
static void xmit(const void *p1, uint8_t n1, const void *p2, uint8_t n2); | |||
static void xmit_big_packet(const void *p1, uint16_t n1, const void *p2, uint16_t n2); | |||
friend class FlightSimCommand; | |||
friend class FlightSimInteger; | |||
friend class FlightSimFloat; | |||
@@ -114,13 +115,23 @@ public: | |||
void identify(void); | |||
void update(long val); | |||
static FlightSimInteger * find(unsigned int n); | |||
void onChange(void (*fptr)(long)) { change_callback = fptr; } | |||
void onChange(void (*fptr)(long)) { | |||
hasCallbackInfo=false; | |||
change_callback = fptr; | |||
} | |||
void onChange(void (*fptr)(long,void*), void* info) { | |||
hasCallbackInfo=true; | |||
change_callback = (void (*)(long))fptr; | |||
callbackInfo = info; | |||
} | |||
// TODO: math operators.... + - * / % ++ -- | |||
private: | |||
unsigned int id; | |||
const _XpRefStr_ *name; | |||
long value; | |||
void (*change_callback)(long); | |||
void* callbackInfo; | |||
bool hasCallbackInfo; | |||
FlightSimInteger *next; | |||
static FlightSimInteger *first; | |||
static FlightSimInteger *last; | |||
@@ -148,13 +159,23 @@ public: | |||
void identify(void); | |||
void update(float val); | |||
static FlightSimFloat * find(unsigned int n); | |||
void onChange(void (*fptr)(float)) { change_callback = fptr; } | |||
void onChange(void (*fptr)(float)) { | |||
hasCallbackInfo=false; | |||
change_callback = fptr; | |||
} | |||
void onChange(void (*fptr)(float,void*), void* info) { | |||
hasCallbackInfo=true; | |||
change_callback = (void (*)(float))fptr; | |||
callbackInfo = info; | |||
} | |||
// TODO: math operators.... + - * / % ++ -- | |||
private: | |||
unsigned int id; | |||
const _XpRefStr_ *name; | |||
float value; | |||
void (*change_callback)(float); | |||
void* callbackInfo; | |||
bool hasCallbackInfo; | |||
FlightSimFloat *next; | |||
static FlightSimFloat *first; | |||
static FlightSimFloat *last; |
@@ -64,7 +64,8 @@ FlightSimCommand::FlightSimCommand() | |||
void FlightSimCommand::identify(void) | |||
{ | |||
uint8_t len, buf[6]; | |||
uint16_t len; | |||
uint8_t buf[6]; | |||
if (!FlightSim.enabled || !name) return; | |||
len = strlen_P((const char *)name); | |||
@@ -108,7 +109,8 @@ FlightSimInteger::FlightSimInteger() | |||
void FlightSimInteger::identify(void) | |||
{ | |||
uint8_t len, buf[6]; | |||
uint16_t len; | |||
uint8_t buf[6]; | |||
if (!FlightSim.enabled || !name) return; | |||
len = strlen_P((const char *)name); | |||
@@ -139,7 +141,13 @@ void FlightSimInteger::write(long val) | |||
void FlightSimInteger::update(long val) | |||
{ | |||
value = val; | |||
if (change_callback) (*change_callback)(val); | |||
if (change_callback) { | |||
if (!hasCallbackInfo) { | |||
(*change_callback)(val); | |||
} else { | |||
(*(void(*)(long,void*))change_callback)(val,callbackInfo); | |||
} | |||
} | |||
} | |||
FlightSimInteger * FlightSimInteger::find(unsigned int n) | |||
@@ -171,7 +179,8 @@ FlightSimFloat::FlightSimFloat() | |||
void FlightSimFloat::identify(void) | |||
{ | |||
uint8_t len, buf[6]; | |||
uint16_t len; | |||
uint8_t buf[6]; | |||
if (!FlightSim.enabled || !name) return; | |||
len = strlen_P((const char *)name); | |||
@@ -202,7 +211,13 @@ void FlightSimFloat::write(float val) | |||
void FlightSimFloat::update(float val) | |||
{ | |||
value = val; | |||
if (change_callback) (*change_callback)(val); | |||
if (change_callback) { | |||
if (!hasCallbackInfo) { | |||
(*change_callback)(val); | |||
} else { | |||
(*(void(*)(long,void*))change_callback)(val,callbackInfo); | |||
} | |||
} | |||
} | |||
FlightSimFloat * FlightSimFloat::find(unsigned int n) | |||
@@ -337,7 +352,6 @@ void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1) | |||
{ | |||
uint8_t intr_state, avail; | |||
if (n1 > FLIGHTSIM_TX_SIZE) return; | |||
if (!enabled || !usb_configuration) return; | |||
intr_state = SREG; | |||
cli(); | |||
@@ -374,7 +388,6 @@ void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const uint8_t *p2, uint | |||
uint8_t intr_state, total, avail; | |||
total = n1 + n2; | |||
if (total > FLIGHTSIM_TX_SIZE) return; | |||
if (!enabled || !usb_configuration) return; | |||
intr_state = SREG; | |||
cli(); | |||
@@ -409,13 +422,15 @@ send: | |||
} | |||
void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint8_t n2) | |||
{ | |||
void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint16_t n2) { | |||
uint8_t intr_state, total, avail; | |||
const char *s2 = (const char *)p2; | |||
const char * PROGMEM s2 = (const char *)p2; | |||
total = n1 + n2; | |||
if (total > FLIGHTSIM_TX_SIZE) return; | |||
if (total > FLIGHTSIM_TX_SIZE) { | |||
xmit_big_packet(p1, n1, p2, n2); | |||
return; | |||
} | |||
if (!enabled || !usb_configuration) return; | |||
intr_state = SREG; | |||
cli(); | |||
@@ -449,6 +464,54 @@ send: | |||
SREG = intr_state; | |||
} | |||
void FlightSimClass::xmit_big_packet(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint16_t n2) { | |||
uint8_t intr_state, avail; | |||
uint16_t total; | |||
bool part1 = true; | |||
const char * PROGMEM s2 = (const char *)p2; | |||
uint8_t packet_id = 1; | |||
total = n1 + n2; | |||
if (!enabled || !usb_configuration) return; | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = FLIGHTSIM_TX_ENDPOINT; | |||
avail = FLIGHTSIM_TX_SIZE - UEBCLX; | |||
while (total>0) { | |||
if (part1) { | |||
UEDATX = *p1++; | |||
part1 = (--n1 != 0); | |||
} else { | |||
pgm_read_byte_postinc(UEDATX, s2); | |||
n2--; | |||
} | |||
total--; | |||
if (!--avail) { | |||
// transmit packet | |||
UEINTX = 0x3A; | |||
while (1) { | |||
if (UEINTX & (1<<RWAL)) break; | |||
SREG = intr_state; | |||
if (!enabled || !usb_configuration) return; | |||
intr_state = SREG; | |||
cli(); | |||
UENUM = FLIGHTSIM_TX_ENDPOINT; | |||
} | |||
// start new fragment with length and fragment ID | |||
UEDATX = (total<(FLIGHTSIM_TX_SIZE-3) ? total+3 : FLIGHTSIM_TX_SIZE); // length byte | |||
UEDATX = 0xff; | |||
UEDATX = packet_id++; | |||
avail = FLIGHTSIM_TX_SIZE - 3; | |||
} | |||
} | |||
if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A; | |||
SREG = intr_state; | |||
} | |||
FlightSimClass FlightSim; |
@@ -31,7 +31,8 @@ private: | |||
static uint8_t recv(uint8_t *buffer); | |||
static void xmit(const uint8_t *p1, uint8_t n1); | |||
static void xmit(const uint8_t *p1, uint8_t n1, const uint8_t *p2, uint8_t n2); | |||
static void xmit(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint8_t n2); | |||
static void xmit(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint16_t n2); | |||
static void xmit_big_packet(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint16_t n2); | |||
friend class FlightSimCommand; | |||
friend class FlightSimInteger; | |||
friend class FlightSimFloat; | |||
@@ -80,13 +81,23 @@ public: | |||
void identify(void); | |||
void update(long val); | |||
static FlightSimInteger * find(unsigned int n); | |||
void onChange(void (*fptr)(long)) { change_callback = fptr; } | |||
void onChange(void (*fptr)(long)) { | |||
hasCallbackInfo=false; | |||
change_callback = fptr; | |||
} | |||
void onChange(void (*fptr)(long,void*), void* info) { | |||
hasCallbackInfo=true; | |||
change_callback = (void (*)(long))fptr; | |||
callbackInfo = info; | |||
} | |||
// TODO: math operators.... + - * / % ++ -- | |||
private: | |||
unsigned int id; | |||
const _XpRefStr_ *name; | |||
long value; | |||
void (*change_callback)(long); | |||
void* callbackInfo; | |||
bool hasCallbackInfo; | |||
FlightSimInteger *next; | |||
static FlightSimInteger *first; | |||
static FlightSimInteger *last; | |||
@@ -114,13 +125,23 @@ public: | |||
void identify(void); | |||
void update(float val); | |||
static FlightSimFloat * find(unsigned int n); | |||
void onChange(void (*fptr)(float)) { change_callback = fptr; } | |||
void onChange(void (*fptr)(float)) { | |||
hasCallbackInfo=false; | |||
change_callback = fptr; | |||
} | |||
void onChange(void (*fptr)(float,void*), void* info) { | |||
hasCallbackInfo=true; | |||
change_callback = (void (*)(float))fptr; | |||
callbackInfo = info; | |||
} | |||
// TODO: math operators.... + - * / % ++ -- | |||
private: | |||
unsigned int id; | |||
const _XpRefStr_ *name; | |||
float value; | |||
void (*change_callback)(float); | |||
void* callbackInfo; | |||
bool hasCallbackInfo; | |||
FlightSimFloat *next; | |||
static FlightSimFloat *first; | |||
static FlightSimFloat *last; |