Long datarefs for USB flight sim controlsteensy4-core
| @@ -106,6 +106,8 @@ FlightSimInteger::FlightSimInteger() | |||
| next = NULL; | |||
| value = 0; | |||
| change_callback = NULL; | |||
| callbackInfo = NULL; | |||
| hasCallbackInfo = false; | |||
| FlightSimClass::request_id_messages = 1; | |||
| } | |||
| @@ -142,7 +144,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 +177,8 @@ FlightSimFloat::FlightSimFloat() | |||
| next = NULL; | |||
| value = 0; | |||
| change_callback = NULL; | |||
| hasCallbackInfo = false; | |||
| callbackInfo = NULL; | |||
| FlightSimClass::request_id_messages = 1; | |||
| } | |||
| @@ -205,7 +215,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 +298,7 @@ void FlightSimClass::update(void) | |||
| switch (p[2]) { | |||
| case 1: | |||
| request_id_messages = 1; | |||
| /* no break */ | |||
| case 2: | |||
| enable(); | |||
| frameCount++; | |||
| @@ -329,10 +346,13 @@ static volatile uint8_t tx_noautoflush=0; | |||
| void FlightSimClass::xmit(const void *p1, uint8_t n1, const void *p2, uint8_t n2) | |||
| { | |||
| uint8_t total; | |||
| uint16_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 +392,138 @@ send: | |||
| tx_noautoflush = 0; | |||
| } | |||
| void FlightSimClass::xmit_big_packet(const void *p1, uint8_t n1, const void *p2, uint8_t n2) | |||
| { | |||
| if (!enabled || !usb_configuration) return; | |||
| uint16_t remaining = n1 + n2; | |||
| if (remaining > 255) return; | |||
| bool part2 = false; | |||
| uint8_t remainingPart1 = n1; | |||
| const uint8_t *dataPtr = (const uint8_t*)p1; | |||
| bool writeFragmentHeader = 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, containing total packet length | |||
| memcpy(tx_packet->buf + tx_packet->index, dataPtr, partLen); | |||
| remainingPart1 -= partLen; | |||
| tx_packet->index += partLen; | |||
| 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; | |||
| dataPtr += partLen; | |||
| } else { | |||
| // maybe we have space for some data from the second part | |||
| part2=true; | |||
| 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; | |||
| if (partLen) { | |||
| memcpy(tx_packet->buf + tx_packet->index, p2, partLen); | |||
| remaining -= partLen; | |||
| tx_packet->index += partLen; | |||
| } | |||
| dataPtr = (const uint8_t*)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; | |||
| } | |||
| // queue first packet for sending | |||
| tx_packet->len = FLIGHTSIM_TX_SIZE; | |||
| usb_tx(FLIGHTSIM_TX_ENDPOINT, tx_packet); | |||
| tx_packet = NULL; | |||
| writeFragmentHeader = true; | |||
| } else { | |||
| remaining = n1+n2; | |||
| } | |||
| while (remaining >0) { | |||
| while (1) { | |||
| // get memory for next packet | |||
| if (usb_tx_packet_count(FLIGHTSIM_TX_ENDPOINT) < TX_PACKET_LIMIT) { | |||
| tx_packet = usb_malloc(); | |||
| if (tx_packet) { | |||
| break; | |||
| } | |||
| } | |||
| if (!enabled || !usb_configuration) { | |||
| // teensy disconnected | |||
| tx_noautoflush = 0; | |||
| return; | |||
| } | |||
| tx_noautoflush = 0; // you can pick up my data, if you like | |||
| yield(); // do other things and wait for memory to become free | |||
| tx_noautoflush = 1; // wait, I'm working on the packet data | |||
| } | |||
| if (writeFragmentHeader) { | |||
| 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 = (const uint8_t*)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; | |||
| } | |||
| } | |||
| writeFragmentHeader = true; | |||
| if (tx_packet->index >= FLIGHTSIM_TX_SIZE) { | |||
| // queue packet for sending | |||
| 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 from usb_isr 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, uint8_t n1, const void *p2, uint8_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; | |||