| @@ -1,4 +1,4 @@ | |||
| Teensy 2.0, 3.x, LC core libraries for Arduino. | |||
| Teensy 2.0, LC, 3.x, 4.x core libraries for Arduino. | |||
| The latest stable version of Teensy's core library is always available in the Teensyduino installer, at this page: | |||
| @@ -8,6 +8,7 @@ nullptr LITERAL1 | |||
| noexcept LITERAL1 | |||
| static_assert LITERAL1 | |||
| thread_local LITERAL1 | |||
| size_t LITERAL1 | |||
| # teensy specific functions | |||
| elapsedMillis LITERAL1 | |||
| @@ -26,18 +27,28 @@ IntervalTimer KEYWORD2 | |||
| printf KEYWORD2 | |||
| digitalWriteFast KEYWORD2 | |||
| digitalReadFast KEYWORD2 | |||
| digitalToggleFast KEYWORD2 | |||
| digitalToggle KEYWORD2 | |||
| transmitterEnable KEYWORD2 | |||
| attachRts KEYWORD2 | |||
| attachCts KEYWORD2 | |||
| PROGMEM LITERAL1 | |||
| FLASHMEM LITERAL1 | |||
| DMAMEM LITERAL1 | |||
| EXTMEM LITERAL1 | |||
| FASTRUN LITERAL1 | |||
| Serial4 KEYWORD1 | |||
| Serial5 KEYWORD1 | |||
| Serial6 KEYWORD1 | |||
| Serial7 KEYWORD1 | |||
| Serial8 KEYWORD1 | |||
| SerialUSB1 KEYWORD1 | |||
| SerialUSB2 KEYWORD1 | |||
| setRX KEYWORD2 | |||
| setTX KEYWORD2 | |||
| write9bit KEYWORD2 | |||
| addMemoryForRead KEYWORD2 | |||
| addMemoryForWrite KEYWORD2 | |||
| clear KEYWORD2 | |||
| EventResponder LITERAL1 | |||
| EventResponderRef LITERAL1 | |||
| @@ -51,9 +62,15 @@ getContext KEYWORD2 | |||
| waitForEvent KEYWORD2 | |||
| MillisTimer LITERAL1 | |||
| beginRepeating KEYWORD2 | |||
| delayNanoseconds KEYWORD2 | |||
| extmem_malloc KEYWORD2 | |||
| extmem_free KEYWORD2 | |||
| extmem_calloc KEYWORD2 | |||
| extmem_realloc KEYWORD2 | |||
| strcasecmp KEYWORD2 | |||
| # removed by Arduino 1.0, but still in Teensyduino | |||
| BYTE LITERAL1 | |||
| # removed by Arduino 1.0, now also removed from Teensyduino | |||
| #BYTE LITERAL1 | |||
| # Arduino constants | |||
| A0 LITERAL1 | |||
| @@ -95,6 +112,9 @@ analogInputToDigitalPin KEYWORD2 | |||
| digitalPinHasPWM KEYWORD2 | |||
| NOT_AN_INTERRUPT LITERAL1 | |||
| digitalPinToInterrupt KEYWORD2 | |||
| FILE_READ LITERAL1 | |||
| FILE_WRITE LITERAL1 | |||
| FILE_WRITE_BEGIN LITERAL1 | |||
| # HardwareSerial modes | |||
| SERIAL_7E1 LITERAL1 | |||
| @@ -503,6 +523,8 @@ FlightSimCommand KEYWORD2 | |||
| FlightSimInteger KEYWORD2 | |||
| FlightSimFloat KEYWORD2 | |||
| FlightSimElapsedFrames KEYWORD2 | |||
| FlightSimData KEYWORD2 | |||
| FlightSimEvent KEYWORD2 | |||
| onChange KEYWORD2 | |||
| update KEYWORD2 | |||
| isEnabled KEYWORD2 | |||
| @@ -0,0 +1,183 @@ | |||
| /* Teensyduino Core Library - File base class | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2020 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #ifndef FS_H | |||
| #define FS_H | |||
| #ifdef __cplusplus | |||
| #include <Arduino.h> | |||
| #define FILE_READ 0 | |||
| #define FILE_WRITE 1 | |||
| #define FILE_WRITE_BEGIN 2 | |||
| enum SeekMode { | |||
| SeekSet = 0, | |||
| SeekCur = 1, | |||
| SeekEnd = 2 | |||
| }; | |||
| //#define FILE_WHOAMI | |||
| class File : public Stream { | |||
| public: | |||
| File() : f(nullptr) { } | |||
| File(File *file) { | |||
| // "file" must only be a class derived from File | |||
| // can we use is_same or is_polymorphic with static_assert? | |||
| // or is_base_of | |||
| //static_assert(std::is_same<decltype(*file),File>::value, | |||
| //"File(File *file) constructor only accepts pointers " | |||
| //"to derived classes, not File itself"); | |||
| f = file; | |||
| if (f) f->refcount++; | |||
| } | |||
| File(const File &file) { | |||
| //Serial.println("File copy constructor"); | |||
| //static int copycount=0; | |||
| //if (++copycount > 20) while (1) ; | |||
| f = file.f; | |||
| if (f) f->refcount++; | |||
| } | |||
| File& operator = (const File &file) { | |||
| //Serial.println("File assignment"); | |||
| //static int assigncount=0; | |||
| //if (++assigncount > 20) while (1) ; | |||
| invalidate(); | |||
| f = file.f; | |||
| if (f) f->refcount++; | |||
| return *this; | |||
| } | |||
| virtual ~File() { | |||
| invalidate(); | |||
| } | |||
| #ifdef FILE_WHOAMI | |||
| virtual void whoami() { // testing only | |||
| Serial.printf(" File this=%x, f=%x\n", (int)this, (int)f); | |||
| if (f) f->whoami(); | |||
| } | |||
| unsigned int getRefcount() { // testing only | |||
| return refcount; | |||
| } | |||
| #endif | |||
| virtual size_t read(void *buf, size_t nbyte) { | |||
| return (f) ? f->read(buf, nbyte) : 0; | |||
| } | |||
| virtual size_t write(const void *buf, size_t size) { | |||
| return (f) ? f->write(buf, size) : 0; | |||
| } | |||
| virtual int available() { | |||
| return (f) ? f->available() : 0; | |||
| } | |||
| virtual int peek() { | |||
| return (f) ? f->peek() : -1; | |||
| } | |||
| virtual void flush() { | |||
| if (f) f->flush(); | |||
| } | |||
| virtual bool truncate(uint64_t size=0) { | |||
| return (f) ? f->truncate(size) : false; | |||
| } | |||
| virtual bool seek(uint64_t pos, int mode) { | |||
| return (f) ? f->seek(pos, mode) : false; | |||
| } | |||
| virtual uint64_t position() { | |||
| return (f) ? f->position() : 0; | |||
| } | |||
| virtual uint64_t size() { | |||
| return (f) ? f->size() : 0; | |||
| } | |||
| virtual void close() { | |||
| if (f) f->close(); | |||
| } | |||
| virtual operator bool() { | |||
| return (f) ? (bool)*f : false; | |||
| } | |||
| virtual const char* name() { | |||
| return (f) ? f->name() : ""; | |||
| } | |||
| virtual bool isDirectory() { | |||
| return (f) ? f->isDirectory() : false; | |||
| } | |||
| virtual File openNextFile(uint8_t mode=0) { | |||
| return (f) ? f->openNextFile(mode) : *this; | |||
| } | |||
| virtual void rewindDirectory(void) { | |||
| if (f) f->rewindDirectory(); | |||
| } | |||
| bool seek(uint64_t pos) { | |||
| return seek(pos, SeekSet); | |||
| } | |||
| int read() { | |||
| if (!f) return -1; | |||
| unsigned char b; | |||
| if (f->read(&b, 1) < 1) return -1; | |||
| return b; | |||
| } | |||
| size_t write(uint8_t b) { | |||
| return write(&b, 1); | |||
| } | |||
| size_t write(const char *str) { | |||
| return write(str, strlen(str)); | |||
| } | |||
| size_t readBytes(char *buffer, size_t length) { | |||
| return read(buffer, length); | |||
| } | |||
| private: | |||
| void invalidate() { | |||
| if (f && --(f->refcount) == 0) delete f; | |||
| } | |||
| union { | |||
| // instances of base File class use this pointer | |||
| File *f; | |||
| // instances of derived classes (which actually access media) | |||
| // use this reference count which is managed by the base class | |||
| unsigned int refcount; | |||
| }; | |||
| }; | |||
| class FS | |||
| { | |||
| public: | |||
| FS() {} | |||
| virtual File open(const char *filename, uint8_t mode = FILE_READ); | |||
| virtual bool exists(const char *filepath); | |||
| virtual bool mkdir(const char *filepath); | |||
| virtual bool rename(const char *oldfilepath, const char *newfilepath); | |||
| virtual bool remove(const char *filepath); | |||
| virtual bool rmdir(const char *filepath); | |||
| virtual uint64_t usedSize(); | |||
| virtual uint64_t totalSize(); | |||
| }; | |||
| #endif // __cplusplus | |||
| #endif // FS_H | |||
| @@ -353,6 +353,39 @@ size_t Print::printNumberAny(unsigned long n, uint8_t base) | |||
| return write(p, sizeof(buf) - (p - buf)); | |||
| } | |||
| size_t Print::print(int64_t n) | |||
| { | |||
| if (n < 0) return printNumber64(-n, 10, 1); | |||
| return printNumber64(n, 10, 0); | |||
| } | |||
| size_t Print::printNumber64(uint64_t n, uint8_t base, uint8_t sign) | |||
| { | |||
| uint8_t buf[66]; | |||
| uint8_t digit, i; | |||
| if (base < 2) return 0; | |||
| if (n == 0) { | |||
| buf[sizeof(buf) - 1] = '0'; | |||
| i = sizeof(buf) - 1; | |||
| } else { | |||
| i = sizeof(buf) - 1; | |||
| while (1) { | |||
| digit = n % base; | |||
| buf[i] = ((digit < 10) ? '0' + digit : 'A' + digit - 10); | |||
| n /= base; | |||
| if (n == 0) break; | |||
| i--; | |||
| } | |||
| } | |||
| if (sign) { | |||
| i--; | |||
| buf[i] = '-'; | |||
| } | |||
| return write(buf + i, sizeof(buf) - i); | |||
| } | |||
| size_t Print::printFloat(double number, uint8_t digits) | |||
| { | |||
| uint8_t sign=0; | |||
| @@ -34,9 +34,9 @@ | |||
| // BYTE was defined in very old versions of Arduino | |||
| // maybe this now causes more trouble than it's worth? | |||
| #ifndef BYTE | |||
| #define BYTE 0 | |||
| #endif | |||
| //#ifndef BYTE | |||
| //#define BYTE 0 | |||
| //#endif | |||
| class __FlashStringHelper; | |||
| @@ -60,12 +60,16 @@ class Print | |||
| size_t print(unsigned int n) { return printNumber(n, 0, 10); } | |||
| size_t print(long n); | |||
| size_t print(unsigned long n) { return printNumber(n, 0, 10); } | |||
| size_t print(int64_t n); | |||
| size_t print(uint64_t n) { return printNumber64(n, 10, 0); } | |||
| size_t print(unsigned char n, int base) { return printNumber(n, 0, base); } | |||
| size_t print(int n, int base) { return (base == 10) ? print(n) : printNumber(n, 0, base); } | |||
| size_t print(unsigned int n, int base) { return printNumber(n, 0, base); } | |||
| size_t print(long n, int base) { return (base == 10) ? print(n) : printNumber(n, 0, base); } | |||
| size_t print(unsigned long n, int base) { return printNumber(n, 0, base); } | |||
| size_t print(int64_t n, int base) { return (base == 10) ? print(n) : printNumber64(n, base, 0); } | |||
| size_t print(uint64_t n, int base) { return printNumber64(n, base, 0); } | |||
| size_t print(double n, int digits = 2) { return printFloat(n, digits); } | |||
| size_t print(const Printable &obj) { return obj.printTo(*this); } | |||
| @@ -80,12 +84,16 @@ class Print | |||
| size_t println(unsigned int n) { return print(n) + println(); } | |||
| size_t println(long n) { return print(n) + println(); } | |||
| size_t println(unsigned long n) { return print(n) + println(); } | |||
| size_t println(int64_t n) { return print(n) + println(); } | |||
| size_t println(uint64_t n) { return print(n) + println(); } | |||
| size_t println(unsigned char n, int base) { return print(n, base) + println(); } | |||
| size_t println(int n, int base) { return print(n, base) + println(); } | |||
| size_t println(unsigned int n, int base) { return print(n, base) + println(); } | |||
| size_t println(long n, int base) { return print(n, base) + println(); } | |||
| size_t println(unsigned long n, int base) { return print(n, base) + println(); } | |||
| size_t println(int64_t n, int base) { return print(n, base) + println(); } | |||
| size_t println(uint64_t n, int base) { return print(n, base) + println(); } | |||
| size_t println(double n, int digits = 2) { return print(n, digits) + println(); } | |||
| size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | |||
| @@ -111,6 +119,7 @@ class Print | |||
| if (base == 2) return printNumberBin(n); | |||
| return printNumberAny(n, base); | |||
| } | |||
| size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||
| size_t printFloat(double n, uint8_t digits); | |||
| }; | |||
| @@ -44,6 +44,7 @@ class UDP : public Stream { | |||
| public: | |||
| virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use | |||
| virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } | |||
| virtual void stop() =0; // Finish with the UDP socket | |||
| // Sending UDP packets | |||
| @@ -1935,6 +1935,253 @@ static inline void pinMode(uint8_t pin, uint8_t mode) | |||
| } | |||
| } | |||
| static inline void digitalToggle(uint8_t) __attribute__((always_inline, unused)); | |||
| static inline void digitalToggle(uint8_t pin) | |||
| { | |||
| if (__builtin_constant_p(pin)) { | |||
| if (pin == 0) { | |||
| CORE_PIN0_PINREG = CORE_PIN0_BITMASK; | |||
| } else if (pin == 1) { | |||
| CORE_PIN1_PINREG = CORE_PIN1_BITMASK; | |||
| } else if (pin == 2) { | |||
| CORE_PIN2_PINREG = CORE_PIN2_BITMASK; | |||
| } else if (pin == 3) { | |||
| CORE_PIN3_PINREG = CORE_PIN3_BITMASK; | |||
| } else if (pin == 4) { | |||
| CORE_PIN4_PINREG = CORE_PIN4_BITMASK; | |||
| } else if (pin == 5) { | |||
| CORE_PIN5_PINREG = CORE_PIN5_BITMASK; | |||
| } else if (pin == 6) { | |||
| CORE_PIN6_PINREG = CORE_PIN6_BITMASK; | |||
| } else if (pin == 7) { | |||
| CORE_PIN7_PINREG = CORE_PIN7_BITMASK; | |||
| } else if (pin == 8) { | |||
| CORE_PIN8_PINREG = CORE_PIN8_BITMASK; | |||
| } else if (pin == 9) { | |||
| CORE_PIN9_PINREG = CORE_PIN9_BITMASK; | |||
| } else if (pin == 10) { | |||
| CORE_PIN10_PINREG = CORE_PIN10_BITMASK; | |||
| } else if (pin == 11) { | |||
| CORE_PIN11_PINREG = CORE_PIN11_BITMASK; | |||
| } else if (pin == 12) { | |||
| CORE_PIN12_PINREG = CORE_PIN12_BITMASK; | |||
| } else if (pin == 13) { | |||
| CORE_PIN13_PINREG = CORE_PIN13_BITMASK; | |||
| } else if (pin == 14) { | |||
| CORE_PIN14_PINREG = CORE_PIN14_BITMASK; | |||
| } else if (pin == 15) { | |||
| CORE_PIN15_PINREG = CORE_PIN15_BITMASK; | |||
| } else if (pin == 16) { | |||
| CORE_PIN16_PINREG = CORE_PIN16_BITMASK; | |||
| } else if (pin == 17) { | |||
| CORE_PIN17_PINREG = CORE_PIN17_BITMASK; | |||
| } else if (pin == 18) { | |||
| CORE_PIN18_PINREG = CORE_PIN18_BITMASK; | |||
| } else if (pin == 19) { | |||
| CORE_PIN19_PINREG = CORE_PIN19_BITMASK; | |||
| } else if (pin == 20) { | |||
| CORE_PIN20_PINREG = CORE_PIN20_BITMASK; | |||
| } | |||
| #if CORE_NUM_TOTAL_PINS > 21 | |||
| else if (pin == 21) { | |||
| CORE_PIN21_PINREG = CORE_PIN21_BITMASK; | |||
| } else if (pin == 22) { | |||
| CORE_PIN22_PINREG = CORE_PIN22_BITMASK; | |||
| } else if (pin == 23) { | |||
| CORE_PIN23_PINREG = CORE_PIN23_BITMASK; | |||
| } else if (pin == 24) { | |||
| CORE_PIN24_PINREG = CORE_PIN24_BITMASK; | |||
| } | |||
| #endif | |||
| #if CORE_NUM_TOTAL_PINS > 25 | |||
| else if (pin == 25) { | |||
| CORE_PIN25_PINREG = CORE_PIN25_BITMASK; | |||
| } else if (pin == 26) { | |||
| CORE_PIN26_PINREG = CORE_PIN26_BITMASK; | |||
| } else if (pin == 27) { | |||
| CORE_PIN27_PINREG = CORE_PIN27_BITMASK; | |||
| } else if (pin == 28) { | |||
| CORE_PIN28_PINREG = CORE_PIN28_BITMASK; | |||
| } else if (pin == 29) { | |||
| CORE_PIN29_PINREG = CORE_PIN29_BITMASK; | |||
| } else if (pin == 30) { | |||
| CORE_PIN30_PINREG = CORE_PIN30_BITMASK; | |||
| } else if (pin == 31) { | |||
| CORE_PIN31_PINREG = CORE_PIN31_BITMASK; | |||
| } else if (pin == 32) { | |||
| CORE_PIN32_PINREG = CORE_PIN32_BITMASK; | |||
| } else if (pin == 33) { | |||
| CORE_PIN33_PINREG = CORE_PIN33_BITMASK; | |||
| } else if (pin == 34) { | |||
| CORE_PIN34_PINREG = CORE_PIN34_BITMASK; | |||
| } else if (pin == 35) { | |||
| CORE_PIN35_PINREG = CORE_PIN35_BITMASK; | |||
| } else if (pin == 36) { | |||
| CORE_PIN36_PINREG = CORE_PIN36_BITMASK; | |||
| } else if (pin == 37) { | |||
| CORE_PIN37_PINREG = CORE_PIN37_BITMASK; | |||
| } else if (pin == 38) { | |||
| CORE_PIN38_PINREG = CORE_PIN38_BITMASK; | |||
| } else if (pin == 39) { | |||
| CORE_PIN39_PINREG = CORE_PIN39_BITMASK; | |||
| } else if (pin == 40) { | |||
| CORE_PIN40_PINREG = CORE_PIN40_BITMASK; | |||
| } else if (pin == 41) { | |||
| CORE_PIN41_PINREG = CORE_PIN41_BITMASK; | |||
| } else if (pin == 42) { | |||
| CORE_PIN42_PINREG = CORE_PIN42_BITMASK; | |||
| } else if (pin == 43) { | |||
| CORE_PIN43_PINREG = CORE_PIN43_BITMASK; | |||
| } else if (pin == 44) { | |||
| CORE_PIN44_PINREG = CORE_PIN44_BITMASK; | |||
| } else if (pin == 45) { | |||
| CORE_PIN45_PINREG = CORE_PIN45_BITMASK; | |||
| } | |||
| #endif | |||
| if (pin == CORE_OC0B_PIN) { | |||
| _SFR_BYTE(TCCR0A) &= ~(1<<COM0B1); | |||
| } else if (pin == CORE_OC1A_PIN) { | |||
| TCCR1A &= ~(1<<COM1A1); | |||
| } else if (pin == CORE_OC1B_PIN) { | |||
| TCCR1A &= ~(1<<COM1B1); | |||
| } else if (pin == CORE_OC1C_PIN) { | |||
| TCCR1A &= ~(1<<COM1C1); | |||
| } | |||
| #if defined(__AVR_ATmega32U4__) | |||
| else if (pin == CORE_OC3A_PIN) { | |||
| TCCR3A &= ~(1<<COM3A1); | |||
| } else if (pin == CORE_OC4A_PIN) { | |||
| TCCR4A &= ~(1<<COM4A1); | |||
| } else if (pin == CORE_OC4D_PIN) { | |||
| TCCR4C &= ~(1<<COM4D1); | |||
| } | |||
| #endif | |||
| #if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||
| else if (pin == CORE_OC2A_PIN) { | |||
| TCCR2A &= ~(1<<COM2A1); | |||
| } else if (pin == CORE_OC2B_PIN) { | |||
| TCCR2A &= ~(1<<COM2B1); | |||
| } else if (pin == CORE_OC3A_PIN) { | |||
| TCCR3A &= ~(1<<COM3A1); | |||
| } else if (pin == CORE_OC3B_PIN) { | |||
| TCCR3A &= ~(1<<COM3B1); | |||
| } else if (pin == CORE_OC3C_PIN) { | |||
| TCCR3A &= ~(1<<COM3C1); | |||
| } | |||
| #endif | |||
| } else { | |||
| digitalWrite(pin, !(digitalRead(pin))); | |||
| } | |||
| } | |||
| static inline void digitalToggleFast(uint8_t) __attribute__((always_inline, unused)); | |||
| static inline void digitalToggleFast(uint8_t pin) | |||
| { | |||
| if (__builtin_constant_p(pin)) { | |||
| if (pin == 0) { | |||
| CORE_PIN0_PINREG = CORE_PIN0_BITMASK; | |||
| } else if (pin == 1) { | |||
| CORE_PIN1_PINREG = CORE_PIN1_BITMASK; | |||
| } else if (pin == 2) { | |||
| CORE_PIN2_PINREG = CORE_PIN2_BITMASK; | |||
| } else if (pin == 3) { | |||
| CORE_PIN3_PINREG = CORE_PIN3_BITMASK; | |||
| } else if (pin == 4) { | |||
| CORE_PIN4_PINREG = CORE_PIN4_BITMASK; | |||
| } else if (pin == 5) { | |||
| CORE_PIN5_PINREG = CORE_PIN5_BITMASK; | |||
| } else if (pin == 6) { | |||
| CORE_PIN6_PINREG = CORE_PIN6_BITMASK; | |||
| } else if (pin == 7) { | |||
| CORE_PIN7_PINREG = CORE_PIN7_BITMASK; | |||
| } else if (pin == 8) { | |||
| CORE_PIN8_PINREG = CORE_PIN8_BITMASK; | |||
| } else if (pin == 9) { | |||
| CORE_PIN9_PINREG = CORE_PIN9_BITMASK; | |||
| } else if (pin == 10) { | |||
| CORE_PIN10_PINREG = CORE_PIN10_BITMASK; | |||
| } else if (pin == 11) { | |||
| CORE_PIN11_PINREG = CORE_PIN11_BITMASK; | |||
| } else if (pin == 12) { | |||
| CORE_PIN12_PINREG = CORE_PIN12_BITMASK; | |||
| } else if (pin == 13) { | |||
| CORE_PIN13_PINREG = CORE_PIN13_BITMASK; | |||
| } else if (pin == 14) { | |||
| CORE_PIN14_PINREG = CORE_PIN14_BITMASK; | |||
| } else if (pin == 15) { | |||
| CORE_PIN15_PINREG = CORE_PIN15_BITMASK; | |||
| } else if (pin == 16) { | |||
| CORE_PIN16_PINREG = CORE_PIN16_BITMASK; | |||
| } else if (pin == 17) { | |||
| CORE_PIN17_PINREG = CORE_PIN17_BITMASK; | |||
| } else if (pin == 18) { | |||
| CORE_PIN18_PINREG = CORE_PIN18_BITMASK; | |||
| } else if (pin == 19) { | |||
| CORE_PIN19_PINREG = CORE_PIN19_BITMASK; | |||
| } else if (pin == 20) { | |||
| CORE_PIN20_PINREG = CORE_PIN20_BITMASK; | |||
| } | |||
| #if CORE_NUM_TOTAL_PINS > 21 | |||
| else if (pin == 21) { | |||
| CORE_PIN21_PINREG = CORE_PIN21_BITMASK; | |||
| } else if (pin == 22) { | |||
| CORE_PIN22_PINREG = CORE_PIN22_BITMASK; | |||
| } else if (pin == 23) { | |||
| CORE_PIN23_PINREG = CORE_PIN23_BITMASK; | |||
| } else if (pin == 24) { | |||
| CORE_PIN24_PINREG = CORE_PIN24_BITMASK; | |||
| } | |||
| #endif | |||
| #if CORE_NUM_TOTAL_PINS > 25 | |||
| else if (pin == 25) { | |||
| CORE_PIN25_PINREG = CORE_PIN25_BITMASK; | |||
| } else if (pin == 26) { | |||
| CORE_PIN26_PINREG = CORE_PIN26_BITMASK; | |||
| } else if (pin == 27) { | |||
| CORE_PIN27_PINREG = CORE_PIN27_BITMASK; | |||
| } else if (pin == 28) { | |||
| CORE_PIN28_PINREG = CORE_PIN28_BITMASK; | |||
| } else if (pin == 29) { | |||
| CORE_PIN29_PINREG = CORE_PIN29_BITMASK; | |||
| } else if (pin == 30) { | |||
| CORE_PIN30_PINREG = CORE_PIN30_BITMASK; | |||
| } else if (pin == 31) { | |||
| CORE_PIN31_PINREG = CORE_PIN31_BITMASK; | |||
| } else if (pin == 32) { | |||
| CORE_PIN32_PINREG = CORE_PIN32_BITMASK; | |||
| } else if (pin == 33) { | |||
| CORE_PIN33_PINREG = CORE_PIN33_BITMASK; | |||
| } else if (pin == 34) { | |||
| CORE_PIN34_PINREG = CORE_PIN34_BITMASK; | |||
| } else if (pin == 35) { | |||
| CORE_PIN35_PINREG = CORE_PIN35_BITMASK; | |||
| } else if (pin == 36) { | |||
| CORE_PIN36_PINREG = CORE_PIN36_BITMASK; | |||
| } else if (pin == 37) { | |||
| CORE_PIN37_PINREG = CORE_PIN37_BITMASK; | |||
| } else if (pin == 38) { | |||
| CORE_PIN38_PINREG = CORE_PIN38_BITMASK; | |||
| } else if (pin == 39) { | |||
| CORE_PIN39_PINREG = CORE_PIN39_BITMASK; | |||
| } else if (pin == 40) { | |||
| CORE_PIN40_PINREG = CORE_PIN40_BITMASK; | |||
| } else if (pin == 41) { | |||
| CORE_PIN41_PINREG = CORE_PIN41_BITMASK; | |||
| } else if (pin == 42) { | |||
| CORE_PIN42_PINREG = CORE_PIN42_BITMASK; | |||
| } else if (pin == 43) { | |||
| CORE_PIN43_PINREG = CORE_PIN43_BITMASK; | |||
| } else if (pin == 44) { | |||
| CORE_PIN44_PINREG = CORE_PIN44_BITMASK; | |||
| } else if (pin == 45) { | |||
| CORE_PIN45_PINREG = CORE_PIN45_BITMASK; | |||
| } | |||
| #endif | |||
| } else { | |||
| digitalWrite(pin, !(digitalRead(pin))); | |||
| } | |||
| } | |||
| extern void _init_Teensyduino_internal_(void); | |||
| extern int analogRead(uint8_t); | |||
| @@ -2198,6 +2445,94 @@ static inline void delayMicroseconds(uint16_t usec) | |||
| } | |||
| static inline void delayNanoseconds(uint16_t) __attribute__((always_inline, unused)); | |||
| static inline void delayNanoseconds(uint16_t nsec) | |||
| { | |||
| if (__builtin_constant_p(nsec)) { | |||
| // use NOPs for the common usage of a constexpr input and short delay | |||
| if (nsec == 0) return; | |||
| if (nsec <= 1000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 2000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 3000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 4000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 5000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 6000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 7000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 8000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 9000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 10000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 11000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 12000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 13000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 14000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 15000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| } | |||
| // if we can't use NOPs, just round up to the nearest microsecond... | |||
| // not ideal, but AVR is too slow to do anything more complex | |||
| delayMicroseconds((nsec >> 10) + 1); | |||
| } | |||
| #ifdef __cplusplus | |||
| @@ -1451,7 +1451,7 @@ extern "C"{ | |||
| #define ASCII_20 KEY_SPACE // 32 | |||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
| #define ASCII_23 KEY_BACKSPACE // 35 # | |||
| #define ASCII_23 KEY_BACKSLASH // 35 # | |||
| #define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | |||
| @@ -4533,7 +4533,7 @@ extern "C"{ | |||
| #define ASCII_20 KEY_SPACE // 32 | |||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
| #define ASCII_23 KEY_BACKSPACE // 35 # | |||
| #define ASCII_23 KEY_BACKSLASH // 35 # | |||
| #define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | |||
| @@ -73,7 +73,7 @@ struct __freelist *__flp; // freelist pointer (head of freelist) | |||
| void * | |||
| malloc(size_t len) | |||
| { | |||
| struct __freelist *fp1, *fp2, *sfp1, *sfp2; | |||
| struct __freelist *fp1, *fp2, *sfp1=NULL, *sfp2=NULL; | |||
| char *cp; | |||
| size_t s, avail; | |||
| @@ -36,6 +36,12 @@ const static uint8_t SCL = CORE_SCL0_PIN; | |||
| #define NUM_DIGITAL_PINS CORE_NUM_TOTAL_PINS | |||
| #define NUM_ANALOG_INPUTS CORE_NUM_ANALOG | |||
| // default CS pin to use for Ethernet library | |||
| #if defined(__AVR_ATmega32U4__) | |||
| #define PIN_SPI_SS_ETHERNET_LIB 0 | |||
| #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||
| #define PIN_SPI_SS_ETHERNET_LIB 20 | |||
| #endif | |||
| // This allows CapSense to work. Do any libraries | |||
| // depend on these to be zero? | |||
| @@ -27,6 +27,7 @@ | |||
| #include <avr/io.h> | |||
| #include <stdlib.h> | |||
| #include <stdbool.h> | |||
| #include <math.h> | |||
| #include "binary.h" | |||
| #include "core_id.h" | |||
| @@ -39,9 +40,6 @@ | |||
| extern "C"{ | |||
| #endif | |||
| #define true 1 | |||
| #define false 0 | |||
| #define PI 3.1415926535897932384626433832795 | |||
| #define HALF_PI 1.5707963267948966192313216916398 | |||
| #define TWO_PI 6.283185307179586476925286766559 | |||
| @@ -93,7 +91,7 @@ typedef unsigned int word; | |||
| #define bit(b) (1UL << (b)) | |||
| typedef uint8_t boolean; | |||
| typedef bool boolean; | |||
| typedef uint8_t byte; | |||
| unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); | |||
| @@ -1,4 +1,9 @@ | |||
| // This header file is in the public domain. | |||
| #ifndef Arduino_h | |||
| #define Arduino_h | |||
| #include "WProgram.h" | |||
| #include "pins_arduino.h" | |||
| #endif | |||
| @@ -29,9 +29,8 @@ | |||
| */ | |||
| #include <string.h> // for memcpy | |||
| #include "AudioStream.h" | |||
| #include <Arduino.h> | |||
| #include "AudioStream.h" | |||
| #if defined(__MKL26Z64__) | |||
| #define MAX_AUDIO_MEMORY 6144 | |||
| @@ -244,6 +243,8 @@ void AudioConnection::disconnect(void) | |||
| // Remove destination from source list | |||
| p = src.destination_list; | |||
| if (p == NULL) { | |||
| //>>> PAH re-enable the IRQ | |||
| __enable_irq(); | |||
| return; | |||
| } else if (p == this) { | |||
| if (p->next_dest) { | |||
| @@ -265,8 +266,14 @@ void AudioConnection::disconnect(void) | |||
| p = p->next_dest; | |||
| } | |||
| } | |||
| //>>> PAH release the audio buffer properly | |||
| //Remove possible pending src block from destination | |||
| dst.inputQueue[dest_index] = NULL; | |||
| if(dst.inputQueue[dest_index] != NULL) { | |||
| AudioStream::release(dst.inputQueue[dest_index]); | |||
| // release() re-enables the IRQ. Need it to be disabled a little longer | |||
| __disable_irq(); | |||
| dst.inputQueue[dest_index] = NULL; | |||
| } | |||
| //Check if the disconnected AudioStream objects should still be active | |||
| src.numConnections--; | |||
| @@ -313,9 +320,13 @@ void software_isr(void) // AudioStream::update_all() | |||
| { | |||
| AudioStream *p; | |||
| #if defined(KINETISK) | |||
| ARM_DEMCR |= ARM_DEMCR_TRCENA; | |||
| ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; | |||
| uint32_t totalcycles = ARM_DWT_CYCCNT; | |||
| #elif defined(KINETISL) | |||
| uint32_t totalcycles = micros(); | |||
| #endif | |||
| //digitalWriteFast(2, HIGH); | |||
| for (p = AudioStream::first_update; p; p = p->next_update) { | |||
| if (p->active) { | |||
| @@ -329,7 +340,11 @@ void software_isr(void) // AudioStream::update_all() | |||
| } | |||
| } | |||
| //digitalWriteFast(2, LOW); | |||
| totalcycles = (ARM_DWT_CYCCNT - totalcycles) >> 4;; | |||
| #if defined(KINETISK) | |||
| totalcycles = (ARM_DWT_CYCCNT - totalcycles) >> 4; | |||
| #elif defined(KINETISL) | |||
| totalcycles = micros() - totalcycles; | |||
| #endif | |||
| AudioStream::cpu_cycles_total = totalcycles; | |||
| if (totalcycles > AudioStream::cpu_cycles_total_max) | |||
| AudioStream::cpu_cycles_total_max = totalcycles; | |||
| @@ -59,7 +59,8 @@ | |||
| #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| #define AUDIO_SAMPLE_RATE_EXACT 44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256 | |||
| #elif defined(__MKL26Z64__) | |||
| #define AUDIO_SAMPLE_RATE_EXACT 22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256 | |||
| //#define AUDIO_SAMPLE_RATE_EXACT 22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256 | |||
| #define AUDIO_SAMPLE_RATE_EXACT 44117.64706 | |||
| #endif | |||
| #endif | |||
| @@ -113,7 +114,11 @@ protected: | |||
| AudioStream::initialize_memory(data, num); \ | |||
| }) | |||
| #if defined(KINETISK) | |||
| #define CYCLE_COUNTER_APPROX_PERCENT(n) (((n) + (F_CPU / 32 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) / (F_CPU / 16 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) | |||
| #elif defined(KINETISL) | |||
| #define CYCLE_COUNTER_APPROX_PERCENT(n) ((n) * (int)(AUDIO_SAMPLE_RATE) + (int)(AUDIO_SAMPLE_RATE/2)) / (AUDIO_BLOCK_SAMPLES * 10000) | |||
| #endif | |||
| #define AudioProcessorUsage() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total)) | |||
| #define AudioProcessorUsageMax() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total_max)) | |||
| @@ -380,6 +380,7 @@ protected: | |||
| DMABaseClass() {} | |||
| static inline void copy_tcd(TCD_t *dst, const TCD_t *src) { | |||
| dst->CSR = 0; | |||
| const uint32_t *p = (const uint32_t *)src; | |||
| uint32_t *q = (uint32_t *)dst; | |||
| uint32_t t1, t2, t3, t4; | |||
| @@ -534,6 +535,12 @@ public: | |||
| NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
| } | |||
| void attachInterrupt(void (*isr)(void), uint8_t prio) { | |||
| _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | |||
| NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
| NVIC_SET_PRIORITY(IRQ_DMA_CH0 + channel, prio); | |||
| } | |||
| void detachInterrupt(void) { | |||
| NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
| } | |||
| @@ -811,11 +818,11 @@ public: | |||
| void transferSize(unsigned int len) { | |||
| uint32_t dcr = CFG->DCR & 0xF0C8FFFF; | |||
| if (len == 4) { | |||
| CFG->DCR = dcr | DMA_DCR_DSIZE(0) | DMA_DCR_DSIZE(0); | |||
| CFG->DCR = dcr | DMA_DCR_SSIZE(0) | DMA_DCR_DSIZE(0); | |||
| } else if (len == 2) { | |||
| CFG->DCR = dcr | DMA_DCR_DSIZE(2) | DMA_DCR_DSIZE(2); | |||
| CFG->DCR = dcr | DMA_DCR_SSIZE(2) | DMA_DCR_DSIZE(2); | |||
| } else { | |||
| CFG->DCR = dcr | DMA_DCR_DSIZE(1) | DMA_DCR_DSIZE(1); | |||
| CFG->DCR = dcr | DMA_DCR_SSIZE(1) | DMA_DCR_DSIZE(1); | |||
| } | |||
| } | |||
| @@ -1034,7 +1041,13 @@ public: | |||
| _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | |||
| NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
| } | |||
| void attachInterrupt(void (*isr)(void), uint8_t prio) { | |||
| _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | |||
| NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
| NVIC_SET_PRIORITY(IRQ_DMA_CH0 + channel, prio); | |||
| } | |||
| void detachInterrupt(void) { | |||
| NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | |||
| } | |||
| @@ -31,6 +31,7 @@ | |||
| * https://forum.pjrc.com/threads/44723-Arduino-Events | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "EventResponder.h" | |||
| EventResponder * EventResponder::firstYield = nullptr; | |||
| @@ -40,6 +41,10 @@ EventResponder * EventResponder::lastInterrupt = nullptr; | |||
| bool EventResponder::runningFromYield = false; | |||
| // TODO: interrupt disable/enable needed in many places!!! | |||
| // BUGBUG: See if file name order makes difference? | |||
| uint8_t _serialEvent_default __attribute__((weak)) PROGMEM = 0 ; | |||
| uint8_t _serialEventUSB1_default __attribute__((weak)) PROGMEM = 0 ; | |||
| uint8_t _serialEventUSB2_default __attribute__((weak)) PROGMEM = 0 ; | |||
| void EventResponder::triggerEventNotImmediate() | |||
| { | |||
| @@ -334,10 +339,17 @@ void MillisTimer::runFromTimer() | |||
| // with libraries using mid-to-high priority interrupts. | |||
| extern "C" volatile uint32_t systick_millis_count; | |||
| void systick_isr(void) | |||
| { | |||
| systick_millis_count++; | |||
| } | |||
| extern "C" void systick_isr_with_timer_events(void) | |||
| { | |||
| systick_millis_count++; | |||
| MillisTimer::runFromTimer(); | |||
| } | |||
| @@ -59,6 +59,7 @@ | |||
| * your function is called only one time, based on the last trigger | |||
| * event. | |||
| */ | |||
| extern "C" void systick_isr_with_timer_events(void); | |||
| class EventResponder; | |||
| typedef EventResponder& EventResponderRef; | |||
| @@ -87,6 +88,7 @@ public: | |||
| detachNoInterrupts(); | |||
| _function = function; | |||
| _type = EventTypeYield; | |||
| yield_active_check_flags |= YIELD_CHECK_EVENT_RESPONDER; // user setup a yield type... | |||
| enableInterrupts(irq); | |||
| } | |||
| @@ -112,6 +114,8 @@ public: | |||
| _function = function; | |||
| _type = EventTypeInterrupt; | |||
| SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority | |||
| // Make sure we are using the systic ISR that process this | |||
| _VectorsRam[15] = systick_isr_with_timer_events; | |||
| enableInterrupts(irq); | |||
| } | |||
| @@ -170,6 +174,7 @@ public: | |||
| EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | |||
| static void runFromYield() { | |||
| if (!firstYield) return; | |||
| // First, check if yield was called from an interrupt | |||
| // never call normal handler functions from any interrupt context | |||
| uint32_t ipsr; | |||
| @@ -1,43 +1,146 @@ | |||
| /* Experimental File & Dir base classes. VERY experimental! | |||
| These are intended to someday allow libraries using files, | |||
| such as a JPEG decoder, to accept a File object from SD, | |||
| Bridge, USB Host, ESP SPIFFS, and others. Perhaps only a | |||
| distant dream at this point, but maybe someday.... | |||
| */ | |||
| /* Teensyduino Core Library - File base class | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2020 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #ifndef FS_H | |||
| #define FS_H | |||
| #ifdef __cplusplus | |||
| #include "Stream.h" | |||
| #include "WString.h" | |||
| #include <Arduino.h> | |||
| #define FILE_READ 0 | |||
| #define FILE_WRITE 1 | |||
| #define FILE_WRITE_BEGIN 2 | |||
| enum SeekMode { | |||
| SeekSet = 0, | |||
| SeekCur = 1, | |||
| SeekEnd = 2 | |||
| }; | |||
| #define FILE_WHOAMI | |||
| class File : public Stream { | |||
| public: | |||
| constexpr File() {} | |||
| enum SeekMode { | |||
| SeekSet = 0, | |||
| SeekCur = 1, | |||
| SeekEnd = 2 | |||
| }; | |||
| virtual size_t read(void *buf, size_t nbyte); | |||
| virtual size_t write(const void *buf, size_t size); | |||
| virtual int available(); | |||
| virtual int read(); | |||
| virtual int peek(); | |||
| virtual void flush(); | |||
| virtual bool seek(uint32_t pos, int mode); | |||
| virtual uint32_t position() const; | |||
| virtual uint32_t size() const; | |||
| virtual void close(); | |||
| virtual operator bool() const; | |||
| //virtual const char* name() const; // why does ESP have this in File? | |||
| bool seek(uint32_t pos) { | |||
| constexpr File() : f(nullptr) { } | |||
| File(File *file) { | |||
| // "file" must only be a class derived from File | |||
| // can we use is_same or is_polymorphic with static_assert? | |||
| // or is_base_of | |||
| //static_assert(std::is_same<decltype(*file),File>::value, | |||
| //"File(File *file) constructor only accepts pointers " | |||
| //"to derived classes, not File itself"); | |||
| f = file; | |||
| if (f) f->refcount++; | |||
| } | |||
| File(const File &file) { | |||
| //Serial.println("File copy constructor"); | |||
| //static int copycount=0; | |||
| //if (++copycount > 20) while (1) ; | |||
| f = file.f; | |||
| if (f) f->refcount++; | |||
| } | |||
| File& operator = (const File &file) { | |||
| //Serial.println("File assignment"); | |||
| //static int assigncount=0; | |||
| //if (++assigncount > 20) while (1) ; | |||
| invalidate(); | |||
| f = file.f; | |||
| if (f) f->refcount++; | |||
| return *this; | |||
| } | |||
| virtual ~File() { | |||
| invalidate(); | |||
| } | |||
| #ifdef FILE_WHOAMI | |||
| virtual void whoami() { // testing only | |||
| Serial.printf(" File this=%x, f=%x\n", (int)this, (int)f); | |||
| if (f) f->whoami(); | |||
| } | |||
| unsigned int getRefcount() { // testing only | |||
| return refcount; | |||
| } | |||
| #endif | |||
| virtual size_t read(void *buf, size_t nbyte) { | |||
| return (f) ? f->read(buf, nbyte) : 0; | |||
| } | |||
| virtual size_t write(const void *buf, size_t size) { | |||
| return (f) ? f->write(buf, size) : 0; | |||
| } | |||
| virtual int available() { | |||
| return (f) ? f->available() : 0; | |||
| } | |||
| virtual int peek() { | |||
| return (f) ? f->peek() : -1; | |||
| } | |||
| virtual void flush() { | |||
| if (f) f->flush(); | |||
| } | |||
| virtual bool truncate(uint64_t size=0) { | |||
| return (f) ? f->truncate(size) : false; | |||
| } | |||
| virtual bool seek(uint64_t pos, int mode) { | |||
| return (f) ? f->seek(pos, mode) : false; | |||
| } | |||
| virtual uint64_t position() { | |||
| return (f) ? f->position() : 0; | |||
| } | |||
| virtual uint64_t size() { | |||
| return (f) ? f->size() : 0; | |||
| } | |||
| virtual void close() { | |||
| if (f) f->close(); | |||
| } | |||
| virtual operator bool() { | |||
| return (f) ? (bool)*f : false; | |||
| } | |||
| virtual const char* name() { | |||
| return (f) ? f->name() : ""; | |||
| } | |||
| virtual bool isDirectory() { | |||
| return (f) ? f->isDirectory() : false; | |||
| } | |||
| virtual File openNextFile(uint8_t mode=0) { | |||
| return (f) ? f->openNextFile(mode) : *this; | |||
| } | |||
| virtual void rewindDirectory(void) { | |||
| if (f) f->rewindDirectory(); | |||
| } | |||
| bool seek(uint64_t pos) { | |||
| return seek(pos, SeekSet); | |||
| } | |||
| int read() { | |||
| if (!f) return -1; | |||
| unsigned char b; | |||
| if (f->read(&b, 1) < 1) return -1; | |||
| return b; | |||
| } | |||
| size_t write(uint8_t b) { | |||
| return write(&b, 1); | |||
| } | |||
| @@ -47,26 +150,34 @@ public: | |||
| size_t readBytes(char *buffer, size_t length) { | |||
| return read(buffer, length); | |||
| } | |||
| // needed for compatiblity with Arduino's SD & Bridge libs | |||
| virtual const char* name(); | |||
| virtual bool isDirectory(); | |||
| virtual File openNextFile(uint8_t mode=0); | |||
| virtual void rewindDirectory(void); | |||
| private: | |||
| void invalidate() { | |||
| if (f && --(f->refcount) == 0) delete f; | |||
| } | |||
| union { | |||
| // instances of base File class use this pointer | |||
| File *f; | |||
| // instances of derived classes (which actually access media) | |||
| // use this reference count which is managed by the base class | |||
| unsigned int refcount; | |||
| }; | |||
| }; | |||
| class Dir { | |||
| class FS | |||
| { | |||
| public: | |||
| constexpr Dir() {} | |||
| virtual const char *name(); // from SD's File (and ESP's File) | |||
| virtual uint32_t fileSize(); | |||
| virtual bool isDirectory(); // from SD, not in ESP | |||
| virtual File openFile(const char *mode); | |||
| virtual bool next(); | |||
| String fileName() { | |||
| return String(name()); | |||
| } | |||
| FS() {} | |||
| virtual File open(const char *filename, uint8_t mode = FILE_READ); | |||
| virtual bool exists(const char *filepath); | |||
| virtual bool mkdir(const char *filepath); | |||
| virtual bool rename(const char *oldfilepath, const char *newfilepath); | |||
| virtual bool remove(const char *filepath); | |||
| virtual bool rmdir(const char *filepath); | |||
| virtual uint64_t usedSize(); | |||
| virtual uint64_t totalSize(); | |||
| }; | |||
| #endif // __cplusplus | |||
| #endif // FS_H | |||
| @@ -0,0 +1,45 @@ | |||
| /* Teensyduino Core Library | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2019 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #include "HardwareSerial.h" | |||
| #include "core_pins.h" | |||
| #include "Arduino.h" | |||
| // define our static objects | |||
| HardwareSerial *HardwareSerial::s_serials_with_serial_events[CNT_HARDWARE_SERIAL]; | |||
| uint8_t HardwareSerial::s_count_serials_with_serial_events = 0; | |||
| // simple helper function that add us to the list of Serial ports that have | |||
| // their own serialEvent code defined that needs to be called at yield. | |||
| void HardwareSerial::addToSerialEventsList() { | |||
| s_serials_with_serial_events[s_count_serials_with_serial_events++] = this; | |||
| yield_active_check_flags |= YIELD_CHECK_HARDWARE_SERIAL; | |||
| } | |||
| @@ -253,8 +253,13 @@ void serial6_clear(void); | |||
| class HardwareSerial : public Stream | |||
| { | |||
| public: | |||
| constexpr HardwareSerial() {} | |||
| virtual void begin(uint32_t baud) { serial_begin(BAUD2DIV(baud)); } | |||
| constexpr HardwareSerial(void (* const se)()) : _serialEvent(se) {} | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| enum {CNT_HARDWARE_SERIAL = 6}; | |||
| #else //(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| enum {CNT_HARDWARE_SERIAL = 3}; | |||
| #endif | |||
| virtual void begin(uint32_t baud); | |||
| virtual void begin(uint32_t baud, uint32_t format) { | |||
| serial_begin(BAUD2DIV(baud)); | |||
| serial_format(format); } | |||
| @@ -283,6 +288,21 @@ public: | |||
| return len; } | |||
| virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | |||
| operator bool() { return true; } | |||
| static inline void processSerialEventsList() { | |||
| for (uint8_t i = 0; i < s_count_serials_with_serial_events; i++) { | |||
| s_serials_with_serial_events[i]->doYieldCode(); | |||
| } | |||
| } | |||
| protected: | |||
| static HardwareSerial *s_serials_with_serial_events[CNT_HARDWARE_SERIAL]; | |||
| static uint8_t s_count_serials_with_serial_events; | |||
| void (* const _serialEvent)(); | |||
| void addToSerialEventsList(); | |||
| inline void doYieldCode() { | |||
| if (available()) (*_serialEvent)(); | |||
| } | |||
| }; | |||
| extern HardwareSerial Serial1; | |||
| extern void serialEvent1(void); | |||
| @@ -290,8 +310,8 @@ extern void serialEvent1(void); | |||
| class HardwareSerial2 : public HardwareSerial | |||
| { | |||
| public: | |||
| constexpr HardwareSerial2() {} | |||
| virtual void begin(uint32_t baud) { serial2_begin(BAUD2DIV2(baud)); } | |||
| constexpr HardwareSerial2(void (* const se)()) : HardwareSerial(se) {} | |||
| virtual void begin(uint32_t baud); | |||
| virtual void begin(uint32_t baud, uint32_t format) { | |||
| serial2_begin(BAUD2DIV2(baud)); | |||
| serial2_format(format); } | |||
| @@ -327,8 +347,8 @@ extern void serialEvent2(void); | |||
| class HardwareSerial3 : public HardwareSerial | |||
| { | |||
| public: | |||
| constexpr HardwareSerial3() {} | |||
| virtual void begin(uint32_t baud) { serial3_begin(BAUD2DIV3(baud)); } | |||
| constexpr HardwareSerial3(void (* const se)()) : HardwareSerial(se) {} | |||
| virtual void begin(uint32_t baud); | |||
| virtual void begin(uint32_t baud, uint32_t format) { | |||
| serial3_begin(BAUD2DIV3(baud)); | |||
| serial3_format(format); } | |||
| @@ -364,8 +384,8 @@ extern void serialEvent3(void); | |||
| class HardwareSerial4 : public HardwareSerial | |||
| { | |||
| public: | |||
| constexpr HardwareSerial4() {} | |||
| virtual void begin(uint32_t baud) { serial4_begin(BAUD2DIV3(baud)); } | |||
| constexpr HardwareSerial4(void (* const se)()) : HardwareSerial(se) {} | |||
| virtual void begin(uint32_t baud); | |||
| virtual void begin(uint32_t baud, uint32_t format) { | |||
| serial4_begin(BAUD2DIV3(baud)); | |||
| serial4_format(format); } | |||
| @@ -401,8 +421,8 @@ extern void serialEvent4(void); | |||
| class HardwareSerial5 : public HardwareSerial | |||
| { | |||
| public: | |||
| constexpr HardwareSerial5() {} | |||
| virtual void begin(uint32_t baud) { serial5_begin(BAUD2DIV3(baud)); } | |||
| constexpr HardwareSerial5(void (* const se)()) : HardwareSerial(se) {} | |||
| virtual void begin(uint32_t baud); | |||
| virtual void begin(uint32_t baud, uint32_t format) { | |||
| serial5_begin(BAUD2DIV3(baud)); | |||
| serial5_format(format); } | |||
| @@ -438,14 +458,14 @@ extern void serialEvent5(void); | |||
| class HardwareSerial6 : public HardwareSerial | |||
| { | |||
| public: | |||
| constexpr HardwareSerial6() {} | |||
| constexpr HardwareSerial6(void (* const se)()) : HardwareSerial(se) {} | |||
| #if defined(__MK66FX1M0__) // For LPUART just pass baud straight in. | |||
| virtual void begin(uint32_t baud) { serial6_begin(baud); } | |||
| virtual void begin(uint32_t baud); | |||
| virtual void begin(uint32_t baud, uint32_t format) { | |||
| serial6_begin(baud); | |||
| serial6_format(format); } | |||
| #else | |||
| virtual void begin(uint32_t baud) { serial6_begin(BAUD2DIV3(baud)); } | |||
| virtual void begin(uint32_t baud); | |||
| virtual void begin(uint32_t baud, uint32_t format) { | |||
| serial6_begin(BAUD2DIV3(baud)); | |||
| serial6_format(format); } | |||
| @@ -28,9 +28,16 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| HardwareSerial Serial1; | |||
| void serialEvent1() __attribute__((weak)); | |||
| void serialEvent1() {} | |||
| uint8_t _serialEvent1_default __attribute__((weak)) PROGMEM = 0 ; | |||
| HardwareSerial Serial1(&serialEvent1); | |||
| void HardwareSerial::begin(uint32_t baud) { | |||
| serial_begin(BAUD2DIV(baud)); | |||
| if (!_serialEvent1_default) addToSerialEventsList(); | |||
| } | |||
| @@ -27,10 +27,14 @@ | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| HardwareSerial2 Serial2; | |||
| HardwareSerial2 Serial2(&serialEvent2); | |||
| uint8_t _serialEvent2_default __attribute__((weak)) PROGMEM = 0 ; | |||
| void serialEvent2() __attribute__((weak)); | |||
| void serialEvent2() {} | |||
| void HardwareSerial2::begin(uint32_t baud) { | |||
| serial2_begin(BAUD2DIV2(baud)); | |||
| if (!_serialEvent2_default) addToSerialEventsList(); | |||
| } | |||
| @@ -28,9 +28,14 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| HardwareSerial3 Serial3; | |||
| HardwareSerial3 Serial3(&serialEvent3); | |||
| void serialEvent3() __attribute__((weak)); | |||
| void serialEvent3() {} | |||
| uint8_t _serialEvent3_default __attribute__((weak)) PROGMEM = 0 ; | |||
| void HardwareSerial3::begin(uint32_t baud) { | |||
| serial3_begin(BAUD2DIV3(baud)); | |||
| if (!_serialEvent3_default) addToSerialEventsList(); | |||
| } | |||
| @@ -28,13 +28,18 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| #ifdef HAS_KINETISK_UART3 | |||
| HardwareSerial4 Serial4; | |||
| HardwareSerial4 Serial4(&serialEvent4); | |||
| void serialEvent4() __attribute__((weak)); | |||
| void serialEvent4() {} | |||
| uint8_t _serialEvent4_default __attribute__((weak)) PROGMEM = 0 ; | |||
| void HardwareSerial4::begin(uint32_t baud) { | |||
| serial4_begin(BAUD2DIV3(baud)); | |||
| if (!_serialEvent4_default) addToSerialEventsList(); | |||
| } | |||
| #endif | |||
| @@ -28,13 +28,18 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| #ifdef HAS_KINETISK_UART4 | |||
| HardwareSerial5 Serial5; | |||
| HardwareSerial5 Serial5(&serialEvent5); | |||
| void serialEvent5() __attribute__((weak)); | |||
| void serialEvent5() {} | |||
| uint8_t _serialEvent5_default __attribute__((weak)) PROGMEM = 0 ; | |||
| void HardwareSerial5::begin(uint32_t baud) { | |||
| serial5_begin(BAUD2DIV3(baud)); | |||
| if (!_serialEvent5_default) addToSerialEventsList(); | |||
| } | |||
| #endif | |||
| @@ -28,13 +28,22 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| #if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | |||
| HardwareSerial6 Serial6; | |||
| HardwareSerial6 Serial6(&serialEvent6); | |||
| void serialEvent6() __attribute__((weak)); | |||
| void serialEvent6() {} | |||
| uint8_t _serialEvent6_default __attribute__((weak)) PROGMEM = 0 ; | |||
| void HardwareSerial6::begin(uint32_t baud) { | |||
| #if defined(__MK66FX1M0__) // For LPUART just pass baud straight in. | |||
| serial6_begin(baud); | |||
| #else | |||
| serial6_begin(BAUD2DIV3(baud)); | |||
| #endif | |||
| if (!_serialEvent6_default) addToSerialEventsList(); | |||
| } | |||
| #endif | |||
| @@ -17,7 +17,7 @@ | |||
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "Arduino.h" | |||
| #include <Arduino.h> | |||
| #include "IPAddress.h" | |||
| size_t IPAddress::printTo(Print& p) const | |||
| @@ -53,7 +53,7 @@ endif | |||
| OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE | |||
| # options needed by many Arduino libraries to configure for Teensy 3.x | |||
| OPTIONS += -D__$(MCU)__ -DARDUINO=10805 -DTEENSYDUINO=141 | |||
| OPTIONS += -D__$(MCU)__ -DARDUINO=10805 -DTEENSYDUINO=144 | |||
| # use "cortex-m4" for Teensy 3.x | |||
| # use "cortex-m0plus" for Teensy LC | |||
| @@ -34,15 +34,12 @@ | |||
| // developed for Teensyduino have made their way back into | |||
| // Arduino's code base. :-) | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "Print.h" | |||
| #include <Arduino.h> | |||
| size_t Print::write(const uint8_t *buffer, size_t size) | |||
| { | |||
| if (buffer == nullptr) return 0; | |||
| size_t count = 0; | |||
| while (size--) count += write(*buffer++); | |||
| return count; | |||
| @@ -290,6 +287,38 @@ size_t Print::printNumber(unsigned long n, uint8_t base, uint8_t sign) | |||
| #endif | |||
| size_t Print::print(int64_t n) | |||
| { | |||
| if (n < 0) return printNumber64(-n, 10, 1); | |||
| return printNumber64(n, 10, 0); | |||
| } | |||
| size_t Print::printNumber64(uint64_t n, uint8_t base, uint8_t sign) | |||
| { | |||
| uint8_t buf[66]; | |||
| uint8_t digit, i; | |||
| if (base < 2) return 0; | |||
| if (n == 0) { | |||
| buf[sizeof(buf) - 1] = '0'; | |||
| i = sizeof(buf) - 1; | |||
| } else { | |||
| i = sizeof(buf) - 1; | |||
| while (1) { | |||
| digit = n % base; | |||
| buf[i] = ((digit < 10) ? '0' + digit : 'A' + digit - 10); | |||
| n /= base; | |||
| if (n == 0) break; | |||
| i--; | |||
| } | |||
| } | |||
| if (sign) { | |||
| i--; | |||
| buf[i] = '-'; | |||
| } | |||
| return write(buf + i, sizeof(buf) - i); | |||
| } | |||
| size_t Print::printFloat(double number, uint8_t digits) | |||
| { | |||
| uint8_t sign=0; | |||
| @@ -45,9 +45,9 @@ | |||
| // BYTE was defined in very old versions of Arduino | |||
| // maybe this now causes more trouble than it's worth? | |||
| #ifndef BYTE | |||
| #define BYTE 0 | |||
| #endif | |||
| //#ifndef BYTE | |||
| //#define BYTE 0 | |||
| //#endif | |||
| class __FlashStringHelper; | |||
| @@ -71,12 +71,16 @@ class Print | |||
| size_t print(unsigned int n) { return printNumber(n, 10, 0); } | |||
| size_t print(long n); | |||
| size_t print(unsigned long n) { return printNumber(n, 10, 0); } | |||
| size_t print(int64_t n); | |||
| size_t print(uint64_t n) { return printNumber64(n, 10, 0); } | |||
| size_t print(unsigned char n, int base) { return printNumber(n, base, 0); } | |||
| size_t print(int n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); } | |||
| size_t print(unsigned int n, int base) { return printNumber(n, base, 0); } | |||
| size_t print(long n, int base) { return (base == 10) ? print(n) : printNumber(n, base, 0); } | |||
| size_t print(unsigned long n, int base) { return printNumber(n, base, 0); } | |||
| size_t print(int64_t n, int base) { return (base == 10) ? print(n) : printNumber64(n, base, 0); } | |||
| size_t print(uint64_t n, int base) { return printNumber64(n, base, 0); } | |||
| size_t print(double n, int digits = 2) { return printFloat(n, digits); } | |||
| size_t print(const Printable &obj) { return obj.printTo(*this); } | |||
| @@ -91,18 +95,24 @@ class Print | |||
| size_t println(unsigned int n) { return print(n) + println(); } | |||
| size_t println(long n) { return print(n) + println(); } | |||
| size_t println(unsigned long n) { return print(n) + println(); } | |||
| size_t println(int64_t n) { return print(n) + println(); } | |||
| size_t println(uint64_t n) { return print(n) + println(); } | |||
| size_t println(unsigned char n, int base) { return print(n, base) + println(); } | |||
| size_t println(int n, int base) { return print(n, base) + println(); } | |||
| size_t println(unsigned int n, int base) { return print(n, base) + println(); } | |||
| size_t println(long n, int base) { return print(n, base) + println(); } | |||
| size_t println(unsigned long n, int base) { return print(n, base) + println(); } | |||
| size_t println(int64_t n, int base) { return print(n, base) + println(); } | |||
| size_t println(uint64_t n, int base) { return print(n, base) + println(); } | |||
| size_t println(double n, int digits = 2) { return print(n, digits) + println(); } | |||
| size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | |||
| int getWriteError() { return write_error; } | |||
| void clearWriteError() { setWriteError(0); } | |||
| int printf(const char *format, ...); | |||
| // format warnings are too pedantic - disable until newer toolchain offers better... | |||
| // https://forum.pjrc.com/threads/62473?p=256873&viewfull=1#post256873 | |||
| int printf(const char *format, ...) /*__attribute__ ((format (printf, 2, 3)))*/; | |||
| int printf(const __FlashStringHelper *format, ...); | |||
| protected: | |||
| void setWriteError(int err = 1) { write_error = err; } | |||
| @@ -126,6 +136,7 @@ class Print | |||
| #else | |||
| size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | |||
| #endif | |||
| size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||
| }; | |||
| @@ -37,7 +37,16 @@ | |||
| // The preferred way to set SPI speed is with SPI.beginTransaction() | |||
| #if F_BUS == 120000000 | |||
| #if F_BUS == 128000000 | |||
| #define HAS_SPIFIFO | |||
| #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(128 / 3) * ((1+0)/2) = 21.3MHz | |||
| #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(128 / 2) * ((1+0)/4) | |||
| #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(2)) //(128 / 3) * ((1+0)/4) = 10.6 MHz | |||
| #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(6)) //(128 / 2) * ((1+0)/8) | |||
| #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(6)) //(128 / 3) * ((1+0)/8) = 5.3 MHz | |||
| #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(6)) //(128 / 5) * ((1+0)/8) = 3.2MHz | |||
| #elif F_BUS == 120000000 | |||
| #define HAS_SPIFIFO | |||
| #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(120 / 5) * ((1+1)/2) | |||
| #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(120 / 2) * ((1+0)/4) = 15 MHz | |||
| @@ -20,8 +20,7 @@ | |||
| parsing functions based on TextFinder library by Michael Margolis | |||
| */ | |||
| #include "Arduino.h" | |||
| #include "Stream.h" | |||
| #include <Arduino.h> | |||
| #define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait | |||
| #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field | |||
| @@ -90,7 +89,9 @@ bool Stream::find(const char *target, size_t length) | |||
| // as find but search ends if the terminator string is found | |||
| bool Stream::findUntil(const char *target, const char *terminator) | |||
| { | |||
| return findUntil(target, strlen(target), terminator, strlen(terminator)); | |||
| if(target == nullptr) return true; | |||
| size_t tlen = (terminator==nullptr)?0:strlen(terminator); | |||
| return findUntil(target, strlen(target), terminator, tlen); | |||
| } | |||
| // reads data from the stream until the target string of the given length is found | |||
| @@ -101,9 +102,10 @@ bool Stream::findUntil(const char *target, size_t targetLen, const char *termina | |||
| size_t index = 0; // maximum target string length is 64k bytes! | |||
| size_t termIndex = 0; | |||
| int c; | |||
| if( target == nullptr) return true; | |||
| if( *target == 0) return true; // return true if target is a null string | |||
| if (terminator == nullptr) termLen = 0; | |||
| if( *target == 0) | |||
| return true; // return true if target is a null string | |||
| while( (c = timedRead()) > 0){ | |||
| if( c == target[index]){ | |||
| //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); | |||
| @@ -216,6 +218,7 @@ float Stream::parseFloat(char skipChar){ | |||
| // | |||
| size_t Stream::readBytes(char *buffer, size_t length) | |||
| { | |||
| if (buffer == nullptr) return 0; | |||
| size_t count = 0; | |||
| while (count < length) { | |||
| int c = timedRead(); | |||
| @@ -236,6 +239,7 @@ size_t Stream::readBytes(char *buffer, size_t length) | |||
| size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) | |||
| { | |||
| if (buffer == nullptr) return 0; | |||
| if (length < 1) return 0; | |||
| length--; | |||
| size_t index = 0; | |||
| @@ -28,10 +28,7 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include "core_pins.h" | |||
| #include "pins_arduino.h" | |||
| #include "HardwareSerial.h" | |||
| #include "IntervalTimer.h" | |||
| #include <Arduino.h> | |||
| // IntervalTimer based tone. This allows tone() to share the timers with other | |||
| // libraries, rather than permanently hogging one PIT timer even for projects | |||
| @@ -44,6 +44,7 @@ class UDP : public Stream { | |||
| public: | |||
| virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use | |||
| virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } | |||
| virtual void stop() =0; // Finish with the UDP socket | |||
| // Sending UDP packets | |||
| @@ -61,7 +61,7 @@ inline boolean isAlpha(int c) | |||
| // that fits into the ASCII character set. | |||
| inline boolean isAscii(int c) | |||
| { | |||
| return ( isascii (c) == 0 ? false : true); | |||
| return ((c & ~0x7F) != 0 ? false : true); | |||
| } | |||
| @@ -143,7 +143,7 @@ inline boolean isHexadecimalDigit(int c) | |||
| // ASCII character set, by clearing the high-order bits. | |||
| inline int toAscii(int c) | |||
| { | |||
| return toascii (c); | |||
| return (c & 0x7F); | |||
| } | |||
| @@ -52,6 +52,8 @@ | |||
| #include "avr_emulation.h" | |||
| #include "usb_serial.h" | |||
| #include "usb_serial2.h" | |||
| #include "usb_serial3.h" | |||
| #include "usb_seremu.h" | |||
| #include "usb_keyboard.h" | |||
| #include "usb_mouse.h" | |||
| @@ -19,7 +19,7 @@ | |||
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "WString.h" | |||
| #include <Arduino.h> | |||
| /*********************************************/ | |||
| @@ -484,6 +484,8 @@ unsigned char String::endsWith( const String &s2 ) const | |||
| /* Character Access */ | |||
| /*********************************************/ | |||
| const char String::zerotermination = 0; | |||
| char String::charAt(unsigned int loc) const | |||
| { | |||
| return operator[](loc); | |||
| @@ -164,7 +164,10 @@ public: | |||
| void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; | |||
| void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const | |||
| {getBytes((unsigned char *)buf, bufsize, index);} | |||
| const char * c_str() const { return buffer; } | |||
| const char * c_str() const { | |||
| if (!buffer) return &zerotermination; // https://forum.pjrc.com/threads/63842 | |||
| return buffer; | |||
| } | |||
| // search | |||
| int indexOf( char ch ) const; | |||
| @@ -205,6 +208,7 @@ private: | |||
| // for more information http://www.artima.com/cppsource/safebool.html | |||
| typedef void (String::*StringIfHelperType)() const; | |||
| void StringIfHelper() const {} | |||
| static const char zerotermination; | |||
| public: | |||
| operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } | |||
| }; | |||
| @@ -40,8 +40,12 @@ static uint8_t analog_reference_internal = 0; | |||
| // the alternate clock is connected to OSCERCLK (16 MHz). | |||
| // datasheet says ADC clock should be 2 to 12 MHz for 16 bit mode | |||
| // datasheet says ADC clock should be 1 to 18 MHz for 8-12 bit mode | |||
| #if F_BUS == 120000000 | |||
| #if F_BUS == 128000000 | |||
| #define ADC_CFG1_16BIT ADC_CFG1_ADIV(3) + ADC_CFG1_ADICLK(1) // 8 MHz | |||
| #define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||
| #define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||
| #define ADC_CFG1_8BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 16 MHz | |||
| #elif F_BUS == 120000000 | |||
| #define ADC_CFG1_16BIT ADC_CFG1_ADIV(3) + ADC_CFG1_ADICLK(1) // 7.5 MHz | |||
| #define ADC_CFG1_12BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | |||
| #define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | |||
| @@ -127,7 +131,7 @@ static uint8_t analog_reference_internal = 0; | |||
| #define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | |||
| #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | |||
| #else | |||
| #error "F_BUS must be 120, 108, 96, 90, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 4 or 2 MHz" | |||
| #error "F_BUS must be 128, 120, 108, 96, 90, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 4 or 2 MHz" | |||
| #endif | |||
| void analog_init(void) | |||
| @@ -524,8 +528,7 @@ void analogWriteDAC0(int val) | |||
| } else { | |||
| DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | |||
| } | |||
| if (val < 0) val = 0; // TODO: saturate instruction? | |||
| else if (val > 4095) val = 4095; | |||
| __asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||
| *(volatile aliased_int16_t *)&(DAC0_DAT0L) = val; | |||
| #elif defined(__MKL26Z64__) | |||
| @@ -554,8 +557,7 @@ void analogWriteDAC1(int val) | |||
| } else { | |||
| DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | |||
| } | |||
| if (val < 0) val = 0; // TODO: saturate instruction? | |||
| else if (val > 4095) val = 4095; | |||
| __asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095 | |||
| *(volatile aliased_int16_t *)&(DAC1_DAT0L) = val; | |||
| } | |||
| @@ -20,6 +20,9 @@ | |||
| * THE SOFTWARE. | |||
| */ | |||
| // Guidelines for editing this file: | |||
| // https://forum.pjrc.com/threads/34537-Teensy-LC-Increase-EEPROM-Size/page2 | |||
| #ifndef _AVR_EEPROM_H_ | |||
| #define _AVR_EEPROM_H_ 1 | |||
| @@ -26,6 +26,7 @@ | |||
| #include <inttypes.h> | |||
| #define PROGMEM | |||
| #define FLASHMEM | |||
| #define PGM_P const char * | |||
| #define PSTR(str) (str) | |||
| @@ -29,7 +29,7 @@ | |||
| */ | |||
| #include "avr_emulation.h" | |||
| #include <Arduino.h> | |||
| #include "SPIFIFO.h" | |||
| uint8_t SPCRemulation::pinout = 0; | |||
| @@ -602,7 +602,7 @@ public: | |||
| int ret = 0; | |||
| if (digitalReadFast(14)) ret |= (1<<0); | |||
| if (digitalReadFast(15)) ret |= (1<<1); | |||
| if (digitalReadFast(15)) ret |= (1<<2); | |||
| if (digitalReadFast(16)) ret |= (1<<2); | |||
| if (digitalReadFast(17)) ret |= (1<<3); | |||
| if (digitalReadFast(18)) ret |= (1<<4); | |||
| if (digitalReadFast(19)) ret |= (1<<5); | |||
| @@ -95,7 +95,7 @@ static inline void eeprom_update_block(const void *buf, void *addr, uint32_t len | |||
| char * ultoa(unsigned long val, char *buf, int radix); | |||
| char * ltoa(long val, char *buf, int radix); | |||
| #if defined(_NEWLIB_VERSION) && (__NEWLIB__ < 2 || __NEWLIB__ == 2 && __NEWLIB_MINOR__ < 2) | |||
| #if defined(__STRICT_ANSI__) || (defined(_NEWLIB_VERSION) && (__NEWLIB__ < 2 || __NEWLIB__ == 2 && __NEWLIB_MINOR__ < 2)) | |||
| static inline char * utoa(unsigned int val, char *buf, int radix) __attribute__((always_inline, unused)); | |||
| static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); } | |||
| static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused)); | |||
| @@ -292,6 +292,41 @@ | |||
| #define CORE_PIN32_PORTSET GPIOB_PSOR | |||
| #define CORE_PIN33_PORTSET GPIOA_PSOR | |||
| #define CORE_PIN0_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN1_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN2_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN3_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN4_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN5_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN6_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN7_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN8_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN9_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN10_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN11_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN12_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN13_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN14_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN15_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN16_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN17_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN18_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN19_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN20_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN21_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN22_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN23_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN24_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN25_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN26_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN27_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN28_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN29_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN30_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN31_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN32_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN33_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN0_PORTCLEAR GPIOB_PCOR | |||
| #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | |||
| #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | |||
| @@ -605,6 +640,34 @@ | |||
| #define CORE_PIN25_PORTSET FGPIOE_PSOR | |||
| #define CORE_PIN26_PORTSET FGPIOE_PSOR | |||
| #define CORE_PIN0_PORTTOGGLE FGPIOB_PTOR | |||
| #define CORE_PIN1_PORTTOGGLE FGPIOB_PTOR | |||
| #define CORE_PIN2_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN3_PORTTOGGLE FGPIOA_PTOR | |||
| #define CORE_PIN4_PORTTOGGLE FGPIOA_PTOR | |||
| #define CORE_PIN5_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN6_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN7_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN8_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN9_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN10_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN11_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN12_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN13_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN14_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN15_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN16_PORTTOGGLE FGPIOB_PTOR | |||
| #define CORE_PIN17_PORTTOGGLE FGPIOB_PTOR | |||
| #define CORE_PIN18_PORTTOGGLE FGPIOB_PTOR | |||
| #define CORE_PIN19_PORTTOGGLE FGPIOB_PTOR | |||
| #define CORE_PIN20_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN21_PORTTOGGLE FGPIOD_PTOR | |||
| #define CORE_PIN22_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN23_PORTTOGGLE FGPIOC_PTOR | |||
| #define CORE_PIN24_PORTTOGGLE FGPIOE_PTOR | |||
| #define CORE_PIN25_PORTTOGGLE FGPIOE_PTOR | |||
| #define CORE_PIN26_PORTTOGGLE FGPIOE_PTOR | |||
| #define CORE_PIN0_PORTCLEAR FGPIOB_PCOR | |||
| #define CORE_PIN1_PORTCLEAR FGPIOB_PCOR | |||
| #define CORE_PIN2_PORTCLEAR FGPIOD_PCOR | |||
| @@ -1021,6 +1084,71 @@ | |||
| #define CORE_PIN62_PORTSET GPIOE_PSOR | |||
| #define CORE_PIN63_PORTSET GPIOE_PSOR | |||
| #define CORE_PIN0_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN1_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN2_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN3_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN4_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN5_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN6_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN7_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN8_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN9_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN10_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN11_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN12_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN13_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN14_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN15_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN16_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN17_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN18_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN19_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN20_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN21_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN22_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN23_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN24_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN25_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN26_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN27_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN28_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN29_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN30_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN31_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN32_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN33_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN34_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN35_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN36_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN37_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN38_PORTTOGGLE GPIOC_PTOR | |||
| #define CORE_PIN39_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN40_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN41_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN42_PORTTOGGLE GPIOA_PTOR | |||
| #define CORE_PIN43_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN44_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN45_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN46_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN47_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN48_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN49_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN50_PORTTOGGLE GPIOB_PTOR | |||
| #define CORE_PIN51_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN52_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN53_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN54_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN55_PORTTOGGLE GPIOD_PTOR | |||
| #define CORE_PIN56_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN57_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN58_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN59_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN60_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN61_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN62_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN63_PORTTOGGLE GPIOE_PTOR | |||
| #define CORE_PIN0_PORTCLEAR GPIOB_PCOR | |||
| #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | |||
| #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | |||
| @@ -1762,6 +1890,213 @@ static inline void digitalWriteFast(uint8_t pin, uint8_t val) | |||
| } | |||
| } | |||
| void digitalToggle(uint8_t pin); | |||
| static inline void digitalToggleFast(uint8_t pin) __attribute__((always_inline, unused)); | |||
| static inline void digitalToggleFast(uint8_t pin) | |||
| { | |||
| if (__builtin_constant_p(pin)) { | |||
| if (pin == 0) { | |||
| CORE_PIN0_PORTTOGGLE = CORE_PIN0_BITMASK; | |||
| } | |||
| else if (pin == 1) { | |||
| CORE_PIN1_PORTTOGGLE = CORE_PIN1_BITMASK; | |||
| } | |||
| else if (pin == 2) { | |||
| CORE_PIN2_PORTTOGGLE = CORE_PIN2_BITMASK; | |||
| } | |||
| else if (pin == 3) { | |||
| CORE_PIN3_PORTTOGGLE = CORE_PIN3_BITMASK; | |||
| } | |||
| else if (pin == 4) { | |||
| CORE_PIN4_PORTTOGGLE = CORE_PIN4_BITMASK; | |||
| } | |||
| else if (pin == 5) { | |||
| CORE_PIN5_PORTTOGGLE = CORE_PIN5_BITMASK; | |||
| } | |||
| else if (pin == 6) { | |||
| CORE_PIN6_PORTTOGGLE = CORE_PIN6_BITMASK; | |||
| } | |||
| else if (pin == 7) { | |||
| CORE_PIN7_PORTTOGGLE = CORE_PIN7_BITMASK; | |||
| } | |||
| else if (pin == 8) { | |||
| CORE_PIN8_PORTTOGGLE = CORE_PIN8_BITMASK; | |||
| } | |||
| else if (pin == 9) { | |||
| CORE_PIN9_PORTTOGGLE = CORE_PIN9_BITMASK; | |||
| } | |||
| else if (pin == 10) { | |||
| CORE_PIN10_PORTTOGGLE = CORE_PIN10_BITMASK; | |||
| } | |||
| else if (pin == 11) { | |||
| CORE_PIN11_PORTTOGGLE = CORE_PIN11_BITMASK; | |||
| } | |||
| else if (pin == 12) { | |||
| CORE_PIN12_PORTTOGGLE = CORE_PIN12_BITMASK; | |||
| } | |||
| else if (pin == 13) { | |||
| CORE_PIN13_PORTTOGGLE = CORE_PIN13_BITMASK; | |||
| } | |||
| else if (pin == 14) { | |||
| CORE_PIN14_PORTTOGGLE = CORE_PIN14_BITMASK; | |||
| } | |||
| else if (pin == 15) { | |||
| CORE_PIN15_PORTTOGGLE = CORE_PIN15_BITMASK; | |||
| } | |||
| else if (pin == 16) { | |||
| CORE_PIN16_PORTTOGGLE = CORE_PIN16_BITMASK; | |||
| } | |||
| else if (pin == 17) { | |||
| CORE_PIN17_PORTTOGGLE = CORE_PIN17_BITMASK; | |||
| } | |||
| else if (pin == 18) { | |||
| CORE_PIN18_PORTTOGGLE = CORE_PIN18_BITMASK; | |||
| } | |||
| else if (pin == 19) { | |||
| CORE_PIN19_PORTTOGGLE = CORE_PIN19_BITMASK; | |||
| } | |||
| else if (pin == 20) { | |||
| CORE_PIN20_PORTTOGGLE = CORE_PIN20_BITMASK; | |||
| } | |||
| else if (pin == 21) { | |||
| CORE_PIN21_PORTTOGGLE = CORE_PIN21_BITMASK; | |||
| } | |||
| else if (pin == 22) { | |||
| CORE_PIN22_PORTTOGGLE = CORE_PIN22_BITMASK; | |||
| } | |||
| else if (pin == 23) { | |||
| CORE_PIN23_PORTTOGGLE = CORE_PIN23_BITMASK; | |||
| } | |||
| else if (pin == 24) { | |||
| CORE_PIN24_PORTTOGGLE = CORE_PIN24_BITMASK; | |||
| } | |||
| else if (pin == 25) { | |||
| CORE_PIN25_PORTTOGGLE = CORE_PIN25_BITMASK; | |||
| } | |||
| else if (pin == 26) { | |||
| CORE_PIN26_PORTTOGGLE = CORE_PIN26_BITMASK; | |||
| } | |||
| #if defined(CORE_PIN27_PORTTOGGLE) | |||
| else if (pin == 27) { | |||
| CORE_PIN27_PORTTOGGLE = CORE_PIN27_BITMASK; | |||
| } | |||
| else if (pin == 28) { | |||
| CORE_PIN28_PORTTOGGLE = CORE_PIN28_BITMASK; | |||
| } | |||
| else if (pin == 29) { | |||
| CORE_PIN29_PORTTOGGLE = CORE_PIN29_BITMASK; | |||
| } | |||
| else if (pin == 30) { | |||
| CORE_PIN30_PORTTOGGLE = CORE_PIN30_BITMASK; | |||
| } | |||
| else if (pin == 31) { | |||
| CORE_PIN31_PORTTOGGLE = CORE_PIN31_BITMASK; | |||
| } | |||
| else if (pin == 32) { | |||
| CORE_PIN32_PORTTOGGLE = CORE_PIN32_BITMASK; | |||
| } | |||
| else if (pin == 33) { | |||
| CORE_PIN33_PORTTOGGLE = CORE_PIN33_BITMASK; | |||
| } | |||
| #endif | |||
| #if defined(CORE_PIN34_PORTSET) | |||
| else if (pin == 34) { | |||
| CORE_PIN34_PORTTOGGLE = CORE_PIN34_BITMASK; | |||
| } | |||
| else if (pin == 35) { | |||
| CORE_PIN35_PORTTOGGLE = CORE_PIN35_BITMASK; | |||
| } | |||
| else if (pin == 36) { | |||
| CORE_PIN36_PORTTOGGLE = CORE_PIN36_BITMASK; | |||
| } | |||
| else if (pin == 37) { | |||
| CORE_PIN37_PORTTOGGLE = CORE_PIN37_BITMASK; | |||
| } | |||
| else if (pin == 38) { | |||
| CORE_PIN38_PORTTOGGLE = CORE_PIN38_BITMASK; | |||
| } | |||
| else if (pin == 39) { | |||
| CORE_PIN39_PORTTOGGLE = CORE_PIN39_BITMASK; | |||
| } | |||
| else if (pin == 40) { | |||
| CORE_PIN40_PORTTOGGLE = CORE_PIN40_BITMASK; | |||
| } | |||
| else if (pin == 41) { | |||
| CORE_PIN41_PORTTOGGLE = CORE_PIN41_BITMASK; | |||
| } | |||
| else if (pin == 42) { | |||
| CORE_PIN42_PORTTOGGLE = CORE_PIN42_BITMASK; | |||
| } | |||
| else if (pin == 43) { | |||
| CORE_PIN43_PORTTOGGLE = CORE_PIN43_BITMASK; | |||
| } | |||
| else if (pin == 44) { | |||
| CORE_PIN44_PORTTOGGLE = CORE_PIN44_BITMASK; | |||
| } | |||
| else if (pin == 45) { | |||
| CORE_PIN45_PORTTOGGLE = CORE_PIN45_BITMASK; | |||
| } | |||
| else if (pin == 46) { | |||
| CORE_PIN46_PORTTOGGLE = CORE_PIN46_BITMASK; | |||
| } | |||
| else if (pin == 47) { | |||
| CORE_PIN47_PORTTOGGLE = CORE_PIN47_BITMASK; | |||
| } | |||
| else if (pin == 48) { | |||
| CORE_PIN48_PORTTOGGLE = CORE_PIN48_BITMASK; | |||
| } | |||
| else if (pin == 49) { | |||
| CORE_PIN49_PORTTOGGLE = CORE_PIN49_BITMASK; | |||
| } | |||
| else if (pin == 50) { | |||
| CORE_PIN50_PORTTOGGLE = CORE_PIN50_BITMASK; | |||
| } | |||
| else if (pin == 51) { | |||
| CORE_PIN51_PORTTOGGLE = CORE_PIN51_BITMASK; | |||
| } | |||
| else if (pin == 52) { | |||
| CORE_PIN52_PORTTOGGLE = CORE_PIN52_BITMASK; | |||
| } | |||
| else if (pin == 53) { | |||
| CORE_PIN53_PORTTOGGLE = CORE_PIN53_BITMASK; | |||
| } | |||
| else if (pin == 54) { | |||
| CORE_PIN54_PORTTOGGLE = CORE_PIN54_BITMASK; | |||
| } | |||
| else if (pin == 55) { | |||
| CORE_PIN55_PORTTOGGLE = CORE_PIN55_BITMASK; | |||
| } | |||
| else if (pin == 56) { | |||
| CORE_PIN56_PORTTOGGLE = CORE_PIN56_BITMASK; | |||
| } | |||
| else if (pin == 57) { | |||
| CORE_PIN57_PORTTOGGLE = CORE_PIN57_BITMASK; | |||
| } | |||
| else if (pin == 58) { | |||
| CORE_PIN58_PORTTOGGLE = CORE_PIN58_BITMASK; | |||
| } | |||
| else if (pin == 59) { | |||
| CORE_PIN59_PORTTOGGLE = CORE_PIN59_BITMASK; | |||
| } | |||
| else if (pin == 60) { | |||
| CORE_PIN60_PORTTOGGLE = CORE_PIN60_BITMASK; | |||
| } | |||
| else if (pin == 61) { | |||
| CORE_PIN61_PORTTOGGLE = CORE_PIN61_BITMASK; | |||
| } | |||
| else if (pin == 62) { | |||
| CORE_PIN62_PORTTOGGLE = CORE_PIN62_BITMASK; | |||
| } | |||
| else if (pin == 63) { | |||
| CORE_PIN63_PORTTOGGLE = CORE_PIN63_BITMASK; | |||
| } | |||
| #endif | |||
| } | |||
| else { | |||
| *portToggleRegister(pin) = digitalPinToBitMask(pin); | |||
| } | |||
| } | |||
| uint8_t digitalRead(uint8_t pin); | |||
| static inline uint8_t digitalReadFast(uint8_t pin) __attribute__((always_inline, unused)); | |||
| static inline uint8_t digitalReadFast(uint8_t pin) | |||
| @@ -1996,6 +2331,16 @@ static inline uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrde | |||
| void _reboot_Teensyduino_(void) __attribute__((noreturn)); | |||
| void _restart_Teensyduino_(void) __attribute__((noreturn)); | |||
| // Define a set of flags to know which things yield should check when called. | |||
| // Probably should be in a better spot. | |||
| extern uint8_t yield_active_check_flags; | |||
| #define YIELD_CHECK_USB_SERIAL 0x1 // check the USB for Serial.available() | |||
| #define YIELD_CHECK_HARDWARE_SERIAL 0x2 // check Hardware Serial ports available | |||
| #define YIELD_CHECK_EVENT_RESPONDER 0x4 // User has created eventResponders that use yield | |||
| #define YIELD_CHECK_USB_SERIALUSB1 0x8 // Check for SerialUSB1 | |||
| #define YIELD_CHECK_USB_SERIALUSB2 0x10 // Check for SerialUSB2 | |||
| void yield(void); | |||
| void delay(uint32_t msec); | |||
| @@ -2023,7 +2368,9 @@ uint32_t micros(void); | |||
| static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); | |||
| static inline void delayMicroseconds(uint32_t usec) | |||
| { | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| uint32_t n = usec * 85; | |||
| #elif F_CPU == 240000000 | |||
| uint32_t n = usec * 80; | |||
| #elif F_CPU == 216000000 | |||
| uint32_t n = usec * 72; | |||
| @@ -2063,11 +2410,13 @@ static inline void delayMicroseconds(uint32_t usec) | |||
| #endif | |||
| #ifdef KINETISL | |||
| "sub %0, #1" "\n\t" | |||
| "bne L_%=_delayMicroseconds" "\n" | |||
| : "+l" (n) : | |||
| #else | |||
| "subs %0, #1" "\n\t" | |||
| #endif | |||
| "bne L_%=_delayMicroseconds" "\n" | |||
| : "+r" (n) : | |||
| #endif | |||
| ); | |||
| } | |||
| @@ -2075,9 +2424,103 @@ static inline void delayMicroseconds(uint32_t usec) | |||
| } | |||
| #endif | |||
| static inline void delayNanoseconds(uint32_t) __attribute__((always_inline, unused)); | |||
| static inline void delayNanoseconds(uint32_t nsec) | |||
| { | |||
| if (__builtin_constant_p(nsec)) { | |||
| // use NOPs for the common usage of a constexpr input and short delay | |||
| if (nsec == 0) return; | |||
| if (nsec <= 1000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 2000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 3000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 4000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 5000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 6000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 7000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 8000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 9000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 10000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 11000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 12000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 13000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 14000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| if (nsec <= 15000 / (F_CPU / 1000000)) { | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| __asm__ volatile("nop\n nop\n nop\n nop\n nop"); | |||
| return; | |||
| } | |||
| } | |||
| uint32_t n = nsec * (F_CPU / 45776) >> 16; | |||
| if (n == 0) return; | |||
| __asm__ volatile( | |||
| "L_%=_delayNanoseconds:" "\n\t" | |||
| #ifdef KINETISL | |||
| "sub %0, #1" "\n\t" | |||
| "bne L_%=_delayNanoseconds" "\n" | |||
| : "+l" (n) : | |||
| #else | |||
| "subs %0, #1" "\n\t" | |||
| "bne L_%=_delayNanoseconds" "\n" | |||
| : "+r" (n) : | |||
| #endif | |||
| ); | |||
| } | |||
| @@ -28,6 +28,14 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| // To configure the EEPROM size, edit E2END in avr/eeprom.h. | |||
| // | |||
| // Do *NOT* edit EEPROM_SIZE in this file. It will automatically | |||
| // change based on your changes to E2END in avr/eeprom.h. | |||
| // | |||
| // Generally you should avoid editing this code, unless you really | |||
| // know what you're doing. | |||
| #include "kinetis.h" | |||
| #include <avr/eeprom.h> | |||
| //#include "HardwareSerial.h" | |||
| @@ -1451,7 +1451,7 @@ extern "C"{ | |||
| #define ASCII_20 KEY_SPACE // 32 | |||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
| #define ASCII_23 KEY_BACKSPACE // 35 # | |||
| #define ASCII_23 KEY_BACKSLASH // 35 # | |||
| #define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | |||
| @@ -4533,7 +4533,7 @@ extern "C"{ | |||
| #define ASCII_20 KEY_SPACE // 32 | |||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | |||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | |||
| #define ASCII_23 KEY_BACKSPACE // 35 # | |||
| #define ASCII_23 KEY_BACKSLASH // 35 # | |||
| #define ASCII_24 KEY_4 + SHIFT_MASK // 36 $ | |||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | |||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | |||
| @@ -761,8 +761,14 @@ enum IRQ_NUMBER_t { | |||
| #endif // end of board-specific definitions | |||
| #if (F_CPU == 240000000) | |||
| #if (F_CPU == 256000000) | |||
| #define F_PLL 256000000 | |||
| #ifndef F_BUS | |||
| #define F_BUS 64000000 | |||
| //#define F_BUS 128000000 // all the usual overclocking caveats apply... | |||
| #endif | |||
| #define F_MEM 32000000 | |||
| #elif (F_CPU == 240000000) | |||
| #define F_PLL 240000000 | |||
| #ifndef F_BUS | |||
| #define F_BUS 60000000 | |||
| @@ -864,6 +870,7 @@ enum IRQ_NUMBER_t { | |||
| #define PORTA_PCR0 (*(volatile uint32_t *)0x40049000) // Pin Control Register n | |||
| #define PORT_PCR_ISF ((uint32_t)0x01000000) // Interrupt Status Flag | |||
| // how to use PORT_PCR_ISF with polling: https://forum.pjrc.com/threads/58193 | |||
| #define PORT_PCR_IRQC(n) ((uint32_t)(((n) & 15) << 16)) // Interrupt Configuration | |||
| #define PORT_PCR_IRQC_MASK ((uint32_t)0x000F0000) | |||
| #define PORT_PCR_LK ((uint32_t)0x00008000) // Lock Register | |||
| @@ -3329,8 +3336,8 @@ typedef struct { | |||
| #define FTM0_CONF (*(volatile uint32_t *)0x40038084) // Configuration | |||
| #define FTM_CONF_GTBEOUT 0x400 // Global Time Base Output | |||
| #define FTM_CONF_GTBEEN 0x200 // Global Time Base Enable | |||
| #define FTM_CONF_BDMMODE (((n) & 3) << 6) // Behavior when in debug mode | |||
| #define FTM_CONF_NUMTOF (((n) & 31) << 0) // ratio of counter overflows to TOF bit set | |||
| #define FTM_CONF_BDMMODE(n) (((n) & 3) << 6) // Behavior when in debug mode | |||
| #define FTM_CONF_NUMTOF(n) (((n) & 31) << 0) // ratio of counter overflows to TOF bit set | |||
| #define FTM0_FLTPOL (*(volatile uint32_t *)0x40038088) // FTM Fault Input Polarity | |||
| #define FTM_FLTPOL_FLT3POL 0x08 // Fault Input 3 Polarity | |||
| #define FTM_FLTPOL_FLT2POL 0x04 // Fault Input 2 Polarity | |||
| @@ -3621,22 +3628,22 @@ typedef struct { | |||
| #define ENET_EIR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available | |||
| #define ENET_EIR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer | |||
| #define ENET_EIMR (*(volatile uint32_t *)0x400C0008) // Interrupt Mask Register | |||
| #define ENET_EIRM_BABR ((uint32_t)0x40000000) // Babbling Receive Error Mask | |||
| #define ENET_EIRM_BABT ((uint32_t)0x20000000) // Babbling Transmit Error Mask | |||
| #define ENET_EIRM_GRA ((uint32_t)0x10000000) // Graceful Stop Complete Mask | |||
| #define ENET_EIRM_TXF ((uint32_t)0x08000000) // Transmit Frame Interrupt Mask | |||
| #define ENET_EIRM_TXB ((uint32_t)0x04000000) // Transmit Buffer Interrupt Mask | |||
| #define ENET_EIRM_RXF ((uint32_t)0x02000000) // Receive Frame Interrupt Mask | |||
| #define ENET_EIRM_RXB ((uint32_t)0x01000000) // Receive Buffer Interrupt Mask | |||
| #define ENET_EIRM_MII ((uint32_t)0x00800000) // MII Interrupt Mask | |||
| #define ENET_EIRM_EBERR ((uint32_t)0x00400000) // Ethernet Bus Error Mask | |||
| #define ENET_EIRM_LC ((uint32_t)0x00200000) // Late Collision Mask | |||
| #define ENET_EIRM_RL ((uint32_t)0x00100000) // Collision Retry Limit Mask | |||
| #define ENET_EIRM_UN ((uint32_t)0x00080000) // Transmit FIFO Underrun Mask | |||
| #define ENET_EIRM_PLR ((uint32_t)0x00040000) // Payload Receive Error Mask | |||
| #define ENET_EIRM_WAKEUP ((uint32_t)0x00020000) // Node Wakeup Request Indication Mask | |||
| #define ENET_EIRM_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available Mask | |||
| #define ENET_EIRM_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer Mask | |||
| #define ENET_EIMR_BABR ((uint32_t)0x40000000) // Babbling Receive Error Mask | |||
| #define ENET_EIMR_BABT ((uint32_t)0x20000000) // Babbling Transmit Error Mask | |||
| #define ENET_EIMR_GRA ((uint32_t)0x10000000) // Graceful Stop Complete Mask | |||
| #define ENET_EIMR_TXF ((uint32_t)0x08000000) // Transmit Frame Interrupt Mask | |||
| #define ENET_EIMR_TXB ((uint32_t)0x04000000) // Transmit Buffer Interrupt Mask | |||
| #define ENET_EIMR_RXF ((uint32_t)0x02000000) // Receive Frame Interrupt Mask | |||
| #define ENET_EIMR_RXB ((uint32_t)0x01000000) // Receive Buffer Interrupt Mask | |||
| #define ENET_EIMR_MII ((uint32_t)0x00800000) // MII Interrupt Mask | |||
| #define ENET_EIMR_EBERR ((uint32_t)0x00400000) // Ethernet Bus Error Mask | |||
| #define ENET_EIMR_LC ((uint32_t)0x00200000) // Late Collision Mask | |||
| #define ENET_EIMR_RL ((uint32_t)0x00100000) // Collision Retry Limit Mask | |||
| #define ENET_EIMR_UN ((uint32_t)0x00080000) // Transmit FIFO Underrun Mask | |||
| #define ENET_EIMR_PLR ((uint32_t)0x00040000) // Payload Receive Error Mask | |||
| #define ENET_EIMR_WAKEUP ((uint32_t)0x00020000) // Node Wakeup Request Indication Mask | |||
| #define ENET_EIMR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available Mask | |||
| #define ENET_EIMR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer Mask | |||
| #define ENET_RDAR (*(volatile uint32_t *)0x400C0010) // Receive Descriptor Active Register | |||
| #define ENET_RDAR_RDAR ((uint32_t)0x01000000) | |||
| #define ENET_TDAR (*(volatile uint32_t *)0x400C0014) // Transmit Descriptor Active Register | |||
| @@ -4545,7 +4552,7 @@ typedef struct { | |||
| #define SPI1_MH (KINETISL_SPI1.MH) // Match High | |||
| #define SPI1_DL (KINETISL_SPI1.DL) // Data Low | |||
| #define SPI1_DH (KINETISL_SPI1.DH) // Data High | |||
| #define SPI1_CI (KINETISL_SPI1.CI) // Dlear Interrupt | |||
| #define SPI1_CI (KINETISL_SPI1.CI) // Clear Interrupt | |||
| #define SPI1_C3 (KINETISL_SPI1.C3) // Control Register 3 | |||
| #endif | |||
| @@ -5851,6 +5858,14 @@ extern void software_isr(void); | |||
| extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | |||
| extern void (* const _VectorsFlash[NVIC_NUM_INTERRUPTS+16])(void); | |||
| // Cache management functions for compatibility with Teensy 4.0 | |||
| __attribute__((always_inline, unused)) | |||
| static inline void arm_dcache_flush(void *addr, uint32_t size) { } | |||
| __attribute__((always_inline, unused)) | |||
| static inline void arm_dcache_delete(void *addr, uint32_t size) { } | |||
| __attribute__((always_inline, unused)) | |||
| static inline void arm_dcache_flush_delete(void *addr, uint32_t size) { } | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -28,7 +28,7 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include "WProgram.h" | |||
| #include <Arduino.h> | |||
| extern "C" int main(void) | |||
| { | |||
| @@ -745,8 +745,10 @@ void ResetHandler(void) | |||
| UART0_C2 = UART_C2_TE; | |||
| PORTB_PCR17 = PORT_PCR_MUX(3); | |||
| #endif | |||
| #ifdef KINETISK | |||
| // if the RTC oscillator isn't enabled, get it started early | |||
| #if defined(KINETISK) && !defined(__MK66FX1M0__) | |||
| // If the RTC oscillator isn't enabled, get it started early. | |||
| // But don't do this early on Teensy 3.6 - RTC_CR depends on 3.3V+VBAT | |||
| // which may be ~0.4V "behind" 3.3V if the power ramps up slowly. | |||
| if (!(RTC_CR & RTC_CR_OSCE)) { | |||
| RTC_SR = 0; | |||
| RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | |||
| @@ -841,7 +843,12 @@ void ResetHandler(void) | |||
| SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode | |||
| while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN | |||
| #endif | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| //See table in 27.4.6 MCG Control 6 Register (MCG_C6) | |||
| //16 -> Multiply factor 32. 32*8MHz =256MHz | |||
| MCG_C5 = MCG_C5_PRDIV0(0); | |||
| MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(16); | |||
| #elif F_CPU == 240000000 | |||
| MCG_C5 = MCG_C5_PRDIV0(0); | |||
| MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14); | |||
| #elif F_CPU == 216000000 | |||
| @@ -900,7 +907,18 @@ void ResetHandler(void) | |||
| #endif | |||
| #endif | |||
| // now program the clock dividers | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| // config divisors: 256 MHz core, 64 MHz bus, 32 MHz flash, USB = IRC48M | |||
| // TODO: gradual ramp-up for HSRUN mode | |||
| #if F_BUS == 64000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(7); | |||
| #elif F_BUS == 128000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||
| #else | |||
| #error "This F_CPU & F_BUS combination is not supported" | |||
| #endif | |||
| SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(0); | |||
| #elif F_CPU == 240000000 | |||
| // config divisors: 240 MHz core, 60 MHz bus, 30 MHz flash, USB = 240 / 5 | |||
| // TODO: gradual ramp-up for HSRUN mode | |||
| #if F_BUS == 60000000 | |||
| @@ -921,7 +939,8 @@ void ResetHandler(void) | |||
| #elif F_BUS == 72000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | |||
| #elif F_BUS == 108000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(7); | |||
| #else | |||
| #error "This F_CPU & F_BUS combination is not supported" | |||
| #endif | |||
| @@ -1046,7 +1065,7 @@ void ResetHandler(void) | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(1); | |||
| #endif | |||
| #else | |||
| #error "Error, F_CPU must be 192, 180, 168, 144, 120, 96, 72, 48, 24, 16, 8, 4, or 2 MHz" | |||
| #error "Error, F_CPU must be 256, 240, 216, 192, 180, 168, 144, 120, 96, 72, 48, 24, 16, 8, 4, or 2 MHz" | |||
| #endif | |||
| #if F_CPU > 16000000 | |||
| @@ -1055,11 +1074,13 @@ void ResetHandler(void) | |||
| // wait for PLL clock to be used | |||
| while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; | |||
| // now we're in PEE mode | |||
| // USB uses PLL clock, trace is CPU clock, CLKOUT=OSCERCLK0 | |||
| // trace is CPU clock, CLKOUT=OSCERCLK0 | |||
| #if defined(KINETISK) | |||
| #if F_CPU == 216000000 || F_CPU == 180000000 | |||
| #if F_CPU == 256000000 || F_CPU == 216000000 || F_CPU == 180000000 | |||
| // USB uses IRC48 | |||
| SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | |||
| #else | |||
| // USB uses PLL clock | |||
| SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | |||
| #endif | |||
| #elif defined(KINETISL) | |||
| @@ -1081,6 +1102,15 @@ void ResetHandler(void) | |||
| SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-) | |||
| #endif | |||
| #if defined(__MK66FX1M0__) | |||
| // If the RTC oscillator isn't enabled, get it started. For Teensy 3.6 | |||
| // we don't do this early. See comment above about slow rising power. | |||
| if (!(RTC_CR & RTC_CR_OSCE)) { | |||
| RTC_SR = 0; | |||
| RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | |||
| } | |||
| #endif | |||
| // initialize the SysTick counter | |||
| SYST_RVR = (F_CPU / 1000) - 1; | |||
| SYST_CVR = 0; | |||
| @@ -1128,6 +1158,7 @@ void ResetHandler(void) | |||
| startup_late_hook(); | |||
| main(); | |||
| while (1) ; | |||
| } | |||
| @@ -1259,7 +1290,11 @@ int kinetis_hsrun_disable(void) | |||
| // the peripheral speed (F_BUS). Serial1 & Serial2 baud | |||
| // rates will be impacted, but most other peripherals | |||
| // will continue functioning at the same speed. | |||
| #if F_CPU == 240000000 && F_BUS == 60000000 | |||
| #if F_CPU == 256000000 && F_BUS == 64000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // TODO: TEST | |||
| #elif F_CPU == 256000000 && F_BUS == 128000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // TODO: TEST | |||
| #elif F_CPU == 240000000 && F_BUS == 60000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok | |||
| #elif F_CPU == 240000000 && F_BUS == 80000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | |||
| @@ -1305,7 +1340,11 @@ int kinetis_hsrun_enable(void) | |||
| SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | |||
| while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | |||
| // Then configure clock for full speed | |||
| #if F_CPU == 240000000 && F_BUS == 60000000 | |||
| #if F_CPU == 256000000 && F_BUS == 64000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||
| #elif F_CPU == 256000000 && F_BUS == 128000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7); | |||
| #elif F_CPU == 240000000 && F_BUS == 60000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | |||
| #elif F_CPU == 240000000 && F_BUS == 80000000 | |||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); | |||
| @@ -34,6 +34,7 @@ MEMORY | |||
| RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K | |||
| } | |||
| ENTRY(_VectorsFlash) | |||
| SECTIONS | |||
| { | |||
| @@ -107,6 +108,7 @@ SECTIONS | |||
| } > RAM | |||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | |||
| _teensy_model_identifier = 0x1D; | |||
| } | |||
| @@ -34,6 +34,7 @@ MEMORY | |||
| RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K | |||
| } | |||
| ENTRY(_VectorsFlash) | |||
| SECTIONS | |||
| { | |||
| @@ -107,6 +108,7 @@ SECTIONS | |||
| } > RAM | |||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | |||
| _teensy_model_identifier = 0x21; | |||
| } | |||
| @@ -31,9 +31,10 @@ | |||
| MEMORY | |||
| { | |||
| FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K | |||
| RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 192K | |||
| RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 262136 | |||
| } | |||
| ENTRY(_VectorsFlash) | |||
| SECTIONS | |||
| { | |||
| @@ -107,6 +108,7 @@ SECTIONS | |||
| } > RAM | |||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | |||
| _teensy_model_identifier = 0x1F; | |||
| } | |||
| @@ -34,6 +34,7 @@ MEMORY | |||
| RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K | |||
| } | |||
| ENTRY(_VectorsFlash) | |||
| SECTIONS | |||
| { | |||
| @@ -107,6 +108,7 @@ SECTIONS | |||
| } > RAM | |||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | |||
| _teensy_model_identifier = 0x22; | |||
| } | |||
| @@ -34,6 +34,7 @@ MEMORY | |||
| RAM (rwx) : ORIGIN = 0x1FFFF800, LENGTH = 8K | |||
| } | |||
| ENTRY(_VectorsFlash) | |||
| SECTIONS | |||
| { | |||
| @@ -107,6 +108,7 @@ SECTIONS | |||
| } > RAM | |||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | |||
| _teensy_model_identifier = 0x20; | |||
| } | |||
| @@ -173,11 +173,14 @@ const static uint8_t SCL = 19; | |||
| #define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 12) ? (p) + 14 : -1)) | |||
| #define digitalPinHasPWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 16 || (p) == 17 || (p) == 20 || (p) == 22 || (p) == 23) | |||
| #define digitalPinToInterrupt(p) ((((p) >= 2 && (p) <= 15) || ((p) >= 20 && (p) <= 23)) ? (p) : -1) | |||
| #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| // TODO analogInputToDigitalPin needs update... | |||
| #define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : -1)) | |||
| #elif defined(__MK64FX512__) | |||
| #define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : (((p) == 23 || (p) == 24) ? (p) + 26 : -1))) | |||
| #define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 10) || (p) == 14 || ((p) >= 20 && (p) <= 23) || (p) == 29 || (p) == 30 || ((p) >= 35 && (p) <= 38)) | |||
| #define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) | |||
| #elif defined(__MK66FX1M0__) | |||
| #define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) >= 12 && (p) <= 20) ? (p) + 19 : (((p) == 23 || (p) == 24) ? (p) + 26 : -1))) | |||
| #define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 10) || (p) == 14 || (p) == 16 || (p) == 17 || ((p) >= 20 && (p) <= 23) || (p) == 29 || (p) == 30 || ((p) >= 35 && (p) <= 38)) | |||
| #define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) | |||
| #endif | |||
| #define digitalPinToPCICR(p) ((volatile uint8_t *)0) | |||
| @@ -166,7 +166,7 @@ voidFuncPtr isr_table_portE[CORE_MAX_PIN_PORTE+1] = { [0 ... CORE_MAX_PIN_PORTE] | |||
| // The Pin Config Register is used to look up the correct interrupt table | |||
| // for the corresponding port. | |||
| inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||
| static inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||
| voidFuncPtr* isr_table = NULL; | |||
| if(&PORTA_PCR0 <= config && config <= &PORTA_PCR31) isr_table = isr_table_portA; | |||
| else if(&PORTB_PCR0 <= config && config <= &PORTB_PCR31) isr_table = isr_table_portB; | |||
| @@ -456,7 +456,10 @@ extern void usb_init(void); | |||
| #endif | |||
| #if F_TIMER == 120000000 | |||
| #if F_TIMER == 128000000 | |||
| #define DEFAULT_FTM_MOD (65536 - 1) | |||
| #define DEFAULT_FTM_PRESCALE 2 | |||
| #elif F_TIMER == 120000000 | |||
| #define DEFAULT_FTM_MOD (61440 - 1) | |||
| #define DEFAULT_FTM_PRESCALE 2 | |||
| #elif F_TIMER == 108000000 | |||
| @@ -580,12 +583,30 @@ void _init_Teensyduino_internal_(void) | |||
| TPM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); | |||
| #endif | |||
| analog_init(); | |||
| #if !defined(TEENSY_INIT_USB_DELAY_BEFORE) | |||
| #if TEENSYDUINO >= 142 | |||
| #define TEENSY_INIT_USB_DELAY_BEFORE 25 | |||
| #else | |||
| #define TEENSY_INIT_USB_DELAY_BEFORE 50 | |||
| #endif | |||
| #endif | |||
| #if !defined(TEENSY_INIT_USB_DELAY_AFTER) | |||
| #if TEENSYDUINO >= 142 | |||
| #define TEENSY_INIT_USB_DELAY_AFTER 275 | |||
| #else | |||
| #define TEENSY_INIT_USB_DELAY_AFTER 350 | |||
| #endif | |||
| #endif | |||
| // for background about this startup delay, please see these conversations | |||
| // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980 | |||
| // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273 | |||
| delay(50); | |||
| delay(TEENSY_INIT_USB_DELAY_BEFORE); | |||
| usb_init(); | |||
| delay(350); | |||
| delay(TEENSY_INIT_USB_DELAY_AFTER); | |||
| } | |||
| @@ -1044,6 +1065,16 @@ void digitalWrite(uint8_t pin, uint8_t val) | |||
| } | |||
| void digitalToggle(uint8_t pin) | |||
| { | |||
| if (pin >= CORE_NUM_DIGITAL) return; | |||
| #ifdef KINETISK | |||
| *portToggleRegister(pin) = 1; | |||
| #else | |||
| *portToggleRegister(pin) = digitalPinToBitMask(pin); | |||
| #endif | |||
| } | |||
| uint8_t digitalRead(uint8_t pin) | |||
| { | |||
| if (pin >= CORE_NUM_DIGITAL) return 0; | |||
| @@ -1200,7 +1231,9 @@ void delay(uint32_t ms) | |||
| } | |||
| // TODO: verify these result in correct timeouts... | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| #define PULSEIN_LOOPS_PER_USEC 34 | |||
| #elif F_CPU == 240000000 | |||
| #define PULSEIN_LOOPS_PER_USEC 33 | |||
| #elif F_CPU == 216000000 | |||
| #define PULSEIN_LOOPS_PER_USEC 31 | |||
| @@ -79,14 +79,20 @@ static volatile uint8_t transmitting = 0; | |||
| #define rts_assert() *(rts_pin+8) = rts_mask; | |||
| #define rts_deassert() *(rts_pin+4) = rts_mask; | |||
| #endif | |||
| #if SERIAL1_TX_BUFFER_SIZE > 255 | |||
| #if SERIAL1_TX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t tx_buffer_head = 0; | |||
| static volatile uint32_t tx_buffer_tail = 0; | |||
| #elif SERIAL1_TX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t tx_buffer_head = 0; | |||
| static volatile uint16_t tx_buffer_tail = 0; | |||
| #else | |||
| static volatile uint8_t tx_buffer_head = 0; | |||
| static volatile uint8_t tx_buffer_tail = 0; | |||
| #endif | |||
| #if SERIAL1_RX_BUFFER_SIZE > 255 | |||
| #if SERIAL1_RX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t rx_buffer_head = 0; | |||
| static volatile uint32_t rx_buffer_tail = 0; | |||
| #elif SERIAL1_RX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t rx_buffer_head = 0; | |||
| static volatile uint16_t rx_buffer_tail = 0; | |||
| #else | |||
| @@ -222,6 +228,8 @@ void serial_end(void) | |||
| case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| #endif | |||
| } | |||
| UART0_S1; | |||
| UART0_D; // clear leftover error status | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -78,14 +78,20 @@ static volatile uint8_t transmitting = 0; | |||
| #define rts_assert() *(rts_pin+8) = rts_mask; | |||
| #define rts_deassert() *(rts_pin+4) = rts_mask; | |||
| #endif | |||
| #if SERIAL2_TX_BUFFER_SIZE > 255 | |||
| #if SERIAL2_TX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t tx_buffer_head = 0; | |||
| static volatile uint32_t tx_buffer_tail = 0; | |||
| #elif SERIAL2_TX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t tx_buffer_head = 0; | |||
| static volatile uint16_t tx_buffer_tail = 0; | |||
| #else | |||
| static volatile uint8_t tx_buffer_head = 0; | |||
| static volatile uint8_t tx_buffer_tail = 0; | |||
| #endif | |||
| #if SERIAL2_RX_BUFFER_SIZE > 255 | |||
| #if SERIAL2_RX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t rx_buffer_head = 0; | |||
| static volatile uint32_t rx_buffer_tail = 0; | |||
| #elif SERIAL2_RX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t rx_buffer_head = 0; | |||
| static volatile uint16_t rx_buffer_tail = 0; | |||
| #else | |||
| @@ -221,6 +227,8 @@ void serial2_end(void) | |||
| CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC3 | |||
| CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC4 | |||
| #endif | |||
| UART1_S1; | |||
| UART1_D; // clear leftover error status | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -79,14 +79,20 @@ static volatile uint8_t transmitting = 0; | |||
| #define rts_assert() *(rts_pin+8) = rts_mask; | |||
| #define rts_deassert() *(rts_pin+4) = rts_mask; | |||
| #endif | |||
| #if SERIAL3_TX_BUFFER_SIZE > 255 | |||
| #if SERIAL3_TX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t tx_buffer_head = 0; | |||
| static volatile uint32_t tx_buffer_tail = 0; | |||
| #elif SERIAL3_TX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t tx_buffer_head = 0; | |||
| static volatile uint16_t tx_buffer_tail = 0; | |||
| #else | |||
| static volatile uint8_t tx_buffer_head = 0; | |||
| static volatile uint8_t tx_buffer_tail = 0; | |||
| #endif | |||
| #if SERIAL3_RX_BUFFER_SIZE > 255 | |||
| #if SERIAL3_RX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t rx_buffer_head = 0; | |||
| static volatile uint32_t rx_buffer_tail = 0; | |||
| #elif SERIAL3_RX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t rx_buffer_head = 0; | |||
| static volatile uint16_t rx_buffer_tail = 0; | |||
| #else | |||
| @@ -196,6 +202,8 @@ void serial3_end(void) | |||
| case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | |||
| } | |||
| #endif | |||
| UART2_S1; | |||
| UART2_D; // clear leftover error status | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -70,14 +70,20 @@ static volatile uint8_t *transmit_pin=NULL; | |||
| static volatile uint8_t *rts_pin=NULL; | |||
| #define rts_assert() *rts_pin = 0 | |||
| #define rts_deassert() *rts_pin = 1 | |||
| #if SERIAL4_TX_BUFFER_SIZE > 255 | |||
| #if SERIAL4_TX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t tx_buffer_head = 0; | |||
| static volatile uint32_t tx_buffer_tail = 0; | |||
| #elif SERIAL4_TX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t tx_buffer_head = 0; | |||
| static volatile uint16_t tx_buffer_tail = 0; | |||
| #else | |||
| static volatile uint8_t tx_buffer_head = 0; | |||
| static volatile uint8_t tx_buffer_tail = 0; | |||
| #endif | |||
| #if SERIAL4_RX_BUFFER_SIZE > 255 | |||
| #if SERIAL4_RX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t rx_buffer_head = 0; | |||
| static volatile uint32_t rx_buffer_tail = 0; | |||
| #elif SERIAL4_RX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t rx_buffer_head = 0; | |||
| static volatile uint16_t rx_buffer_tail = 0; | |||
| #else | |||
| @@ -168,6 +174,8 @@ void serial4_end(void) | |||
| case 32: CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | |||
| case 62: CORE_PIN62_CONFIG = 0; break; | |||
| } | |||
| UART3_S1; | |||
| UART3_D; // clear leftover error status | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -70,14 +70,20 @@ static volatile uint8_t *transmit_pin=NULL; | |||
| static volatile uint8_t *rts_pin=NULL; | |||
| #define rts_assert() *rts_pin = 0 | |||
| #define rts_deassert() *rts_pin = 1 | |||
| #if SERIAL5_TX_BUFFER_SIZE > 255 | |||
| #if SERIAL5_TX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t tx_buffer_head = 0; | |||
| static volatile uint32_t tx_buffer_tail = 0; | |||
| #elif SERIAL5_TX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t tx_buffer_head = 0; | |||
| static volatile uint16_t tx_buffer_tail = 0; | |||
| #else | |||
| static volatile uint8_t tx_buffer_head = 0; | |||
| static volatile uint8_t tx_buffer_tail = 0; | |||
| #endif | |||
| #if SERIAL5_RX_BUFFER_SIZE > 255 | |||
| #if SERIAL5_RX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t rx_buffer_head = 0; | |||
| static volatile uint32_t rx_buffer_tail = 0; | |||
| #elif SERIAL5_RX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t rx_buffer_head = 0; | |||
| static volatile uint16_t rx_buffer_tail = 0; | |||
| #else | |||
| @@ -153,6 +159,8 @@ void serial5_end(void) | |||
| UART4_C2 = 0; | |||
| CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| CORE_PIN33_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| UART4_S1; | |||
| UART4_D; // clear leftover error status | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -70,14 +70,20 @@ static volatile uint8_t *transmit_pin=NULL; | |||
| static volatile uint8_t *rts_pin=NULL; | |||
| #define rts_assert() *rts_pin = 0 | |||
| #define rts_deassert() *rts_pin = 1 | |||
| #if SERIAL6_TX_BUFFER_SIZE > 255 | |||
| #if SERIAL6_TX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t tx_buffer_head = 0; | |||
| static volatile uint32_t tx_buffer_tail = 0; | |||
| #elif SERIAL6_TX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t tx_buffer_head = 0; | |||
| static volatile uint16_t tx_buffer_tail = 0; | |||
| #else | |||
| static volatile uint8_t tx_buffer_head = 0; | |||
| static volatile uint8_t tx_buffer_tail = 0; | |||
| #endif | |||
| #if SERIAL6_RX_BUFFER_SIZE > 255 | |||
| #if SERIAL6_RX_BUFFER_SIZE > 65535 | |||
| static volatile uint32_t rx_buffer_head = 0; | |||
| static volatile uint32_t rx_buffer_tail = 0; | |||
| #elif SERIAL6_RX_BUFFER_SIZE > 255 | |||
| static volatile uint16_t rx_buffer_head = 0; | |||
| static volatile uint16_t rx_buffer_tail = 0; | |||
| #else | |||
| @@ -153,6 +159,8 @@ void serial6_end(void) | |||
| UART5_C2 = 0; | |||
| CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| CORE_PIN48_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | |||
| UART5_S1; | |||
| UART5_D; // clear leftover error status | |||
| rx_buffer_head = 0; | |||
| rx_buffer_tail = 0; | |||
| if (rts_pin) rts_deassert(); | |||
| @@ -460,4 +460,4 @@ void lpuart0_status_isr(void) | |||
| } | |||
| } | |||
| #endif // HAS_KINETISK_UART4 | |||
| #endif // HAS_KINETISK_LPUART0 | |||
| @@ -0,0 +1,6 @@ | |||
| #include <Arduino.h> | |||
| void serialEvent() __attribute__((weak)); | |||
| void serialEvent() { | |||
| } | |||
| uint8_t _serialEvent_default PROGMEM = 1; | |||
| @@ -0,0 +1,6 @@ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| void serialEvent1() __attribute__((weak)); | |||
| void serialEvent1() {} // No use calling this so disable if called... | |||
| uint8_t _serialEvent1_default PROGMEM = 1; | |||
| @@ -0,0 +1,6 @@ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| void serialEvent2() __attribute__((weak)); | |||
| void serialEvent2() {} // No use calling this so disable if called... | |||
| uint8_t _serialEvent2_default PROGMEM = 1; | |||
| @@ -0,0 +1,6 @@ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| void serialEvent3() __attribute__((weak)); | |||
| void serialEvent3() {} // No use calling this so disable if called... | |||
| uint8_t _serialEvent3_default PROGMEM = 1; | |||
| @@ -0,0 +1,8 @@ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| #ifdef HAS_KINETISK_UART3 | |||
| void serialEvent4() __attribute__((weak)); | |||
| void serialEvent4() {} // No use calling this so disable if called... | |||
| uint8_t _serialEvent4_default PROGMEM = 1; | |||
| #endif | |||
| @@ -0,0 +1,8 @@ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| #ifdef HAS_KINETISK_UART4 | |||
| void serialEvent5() __attribute__((weak)); | |||
| void serialEvent5() {} // No use calling this so disable if called... | |||
| uint8_t _serialEvent5_default PROGMEM = 1; | |||
| #endif | |||
| @@ -0,0 +1,8 @@ | |||
| #include <Arduino.h> | |||
| #include "HardwareSerial.h" | |||
| #if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | |||
| void serialEvent6() __attribute__((weak)); | |||
| void serialEvent6() {} // No use calling this so disable if called... | |||
| uint8_t _serialEvent6_default PROGMEM = 1; | |||
| #endif | |||
| @@ -0,0 +1,5 @@ | |||
| #include <Arduino.h> | |||
| void serialEventUSB1() __attribute__((weak)); | |||
| void serialEventUSB1() {} | |||
| uint8_t _serialEventUSB1_default PROGMEM = 1; | |||
| @@ -0,0 +1,5 @@ | |||
| #include <Arduino.h> | |||
| void serialEventUSB2() __attribute__((weak)); | |||
| void serialEventUSB2() {} | |||
| uint8_t _serialEventUSB2_default PROGMEM = 1; | |||
| @@ -28,10 +28,8 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "usb_dev.h" | |||
| #include "usb_audio.h" | |||
| #include "HardwareSerial.h" | |||
| #include <string.h> // for memcpy() | |||
| #ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h | |||
| #if F_CPU >= 20000000 | |||
| @@ -90,7 +90,22 @@ static uint8_t device_descriptor[] = { | |||
| #ifdef BCD_DEVICE | |||
| LSB(BCD_DEVICE), MSB(BCD_DEVICE), // bcdDevice | |||
| #else | |||
| // For USB types that don't explicitly define BCD_DEVICE, | |||
| // use the minor version number to help teensy_ports | |||
| // identify which Teensy model is used. | |||
| #if defined(__MKL26Z64__) | |||
| 0x73, 0x02, | |||
| #elif defined(__MK20DX128__) | |||
| 0x74, 0x02, | |||
| #elif defined(__MK20DX256__) | |||
| 0x75, 0x02, | |||
| #elif defined(__MK64FX512__) | |||
| 0x76, 0x02, | |||
| #elif defined(__MK66FX1M0__) | |||
| 0x77, 0x02, | |||
| #else | |||
| 0x00, 0x02, | |||
| #endif | |||
| #endif | |||
| 1, // iManufacturer | |||
| 2, // iProduct | |||
| @@ -379,6 +394,11 @@ static uint8_t multitouch_report_desc[] = { | |||
| 0x95, 0x01, // Report Count (1) | |||
| 0x09, 0x56, // Usage (Scan Time) | |||
| 0x81, 0x02, // Input (variable,absolute) | |||
| 0x09, 0x54, // USAGE (Contact count) | |||
| 0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |||
| 0x95, 0x01, // REPORT_COUNT (1) | |||
| 0x75, 0x08, // REPORT_SIZE (8) | |||
| 0x81, 0x02, // INPUT (Data,Var,Abs) | |||
| 0x05, 0x0D, // Usage Page (Digitizers) | |||
| 0x09, 0x55, // Usage (Contact Count Maximum) | |||
| 0x25, MULTITOUCH_FINGERS, // Logical Maximum (10) | |||
| @@ -469,7 +489,21 @@ static uint8_t flightsim_report_desc[] = { | |||
| #define CDC_DATA_INTERFACE_DESC_SIZE 0 | |||
| #endif | |||
| #define MIDI_INTERFACE_DESC_POS CDC_DATA_INTERFACE_DESC_POS+CDC_DATA_INTERFACE_DESC_SIZE | |||
| #define CDC2_DATA_INTERFACE_DESC_POS CDC_DATA_INTERFACE_DESC_POS+CDC_DATA_INTERFACE_DESC_SIZE | |||
| #ifdef CDC2_DATA_INTERFACE | |||
| #define CDC2_DATA_INTERFACE_DESC_SIZE 8 + 9+5+5+4+5+7+9+7+7 | |||
| #else | |||
| #define CDC2_DATA_INTERFACE_DESC_SIZE 0 | |||
| #endif | |||
| #define CDC3_DATA_INTERFACE_DESC_POS CDC2_DATA_INTERFACE_DESC_POS+CDC2_DATA_INTERFACE_DESC_SIZE | |||
| #ifdef CDC3_DATA_INTERFACE | |||
| #define CDC3_DATA_INTERFACE_DESC_SIZE 8 + 9+5+5+4+5+7+9+7+7 | |||
| #else | |||
| #define CDC3_DATA_INTERFACE_DESC_SIZE 0 | |||
| #endif | |||
| #define MIDI_INTERFACE_DESC_POS CDC3_DATA_INTERFACE_DESC_POS+CDC3_DATA_INTERFACE_DESC_SIZE | |||
| #ifdef MIDI_INTERFACE | |||
| #if !defined(MIDI_NUM_CABLES) || MIDI_NUM_CABLES < 1 || MIDI_NUM_CABLES > 16 | |||
| #error "MIDI_NUM_CABLES must be defined between 1 to 16" | |||
| @@ -588,7 +622,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
| 0x02, // bFunctionClass | |||
| 0x02, // bFunctionSubClass | |||
| 0x01, // bFunctionProtocol | |||
| 4, // iFunction | |||
| 0, // iFunction | |||
| #endif | |||
| #ifdef CDC_DATA_INTERFACE | |||
| @@ -657,6 +691,156 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
| 0, // bInterval | |||
| #endif // CDC_DATA_INTERFACE | |||
| #ifdef CDC2_DATA_INTERFACE | |||
| // interface association descriptor, USB ECN, Table 9-Z | |||
| 8, // bLength | |||
| 11, // bDescriptorType | |||
| CDC2_STATUS_INTERFACE, // bFirstInterface | |||
| 2, // bInterfaceCount | |||
| 0x02, // bFunctionClass | |||
| 0x02, // bFunctionSubClass | |||
| 0x01, // bFunctionProtocol | |||
| 0, // iFunction | |||
| // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
| 9, // bLength | |||
| 4, // bDescriptorType | |||
| CDC2_STATUS_INTERFACE, // bInterfaceNumber | |||
| 0, // bAlternateSetting | |||
| 1, // bNumEndpoints | |||
| 0x02, // bInterfaceClass | |||
| 0x02, // bInterfaceSubClass | |||
| 0x01, // bInterfaceProtocol | |||
| 0, // iInterface | |||
| // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 | |||
| 5, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x00, // bDescriptorSubtype | |||
| 0x10, 0x01, // bcdCDC | |||
| // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 | |||
| 5, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x01, // bDescriptorSubtype | |||
| 0x01, // bmCapabilities | |||
| 1, // bDataInterface | |||
| // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 | |||
| 4, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x02, // bDescriptorSubtype | |||
| 0x06, // bmCapabilities | |||
| // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 | |||
| 5, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x06, // bDescriptorSubtype | |||
| CDC2_STATUS_INTERFACE, // bMasterInterface | |||
| CDC2_DATA_INTERFACE, // bSlaveInterface0 | |||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
| 7, // bLength | |||
| 5, // bDescriptorType | |||
| CDC2_ACM_ENDPOINT | 0x80, // bEndpointAddress | |||
| 0x03, // bmAttributes (0x03=intr) | |||
| CDC2_ACM_SIZE, 0, // wMaxPacketSize | |||
| 64, // bInterval | |||
| // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
| 9, // bLength | |||
| 4, // bDescriptorType | |||
| CDC2_DATA_INTERFACE, // bInterfaceNumber | |||
| 0, // bAlternateSetting | |||
| 2, // bNumEndpoints | |||
| 0x0A, // bInterfaceClass | |||
| 0x00, // bInterfaceSubClass | |||
| 0x00, // bInterfaceProtocol | |||
| 0, // iInterface | |||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
| 7, // bLength | |||
| 5, // bDescriptorType | |||
| CDC2_RX_ENDPOINT, // bEndpointAddress | |||
| 0x02, // bmAttributes (0x02=bulk) | |||
| CDC2_RX_SIZE, 0, // wMaxPacketSize | |||
| 0, // bInterval | |||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
| 7, // bLength | |||
| 5, // bDescriptorType | |||
| CDC2_TX_ENDPOINT | 0x80, // bEndpointAddress | |||
| 0x02, // bmAttributes (0x02=bulk) | |||
| CDC2_TX_SIZE, 0, // wMaxPacketSize | |||
| 0, // bInterval | |||
| #endif // CDC2_DATA_INTERFACE | |||
| #ifdef CDC3_DATA_INTERFACE | |||
| // interface association descriptor, USB ECN, Table 9-Z | |||
| 8, // bLength | |||
| 11, // bDescriptorType | |||
| CDC3_STATUS_INTERFACE, // bFirstInterface | |||
| 2, // bInterfaceCount | |||
| 0x02, // bFunctionClass | |||
| 0x02, // bFunctionSubClass | |||
| 0x01, // bFunctionProtocol | |||
| 0, // iFunction | |||
| // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
| 9, // bLength | |||
| 4, // bDescriptorType | |||
| CDC3_STATUS_INTERFACE, // bInterfaceNumber | |||
| 0, // bAlternateSetting | |||
| 1, // bNumEndpoints | |||
| 0x02, // bInterfaceClass | |||
| 0x02, // bInterfaceSubClass | |||
| 0x01, // bInterfaceProtocol | |||
| 0, // iInterface | |||
| // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 | |||
| 5, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x00, // bDescriptorSubtype | |||
| 0x10, 0x01, // bcdCDC | |||
| // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 | |||
| 5, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x01, // bDescriptorSubtype | |||
| 0x01, // bmCapabilities | |||
| 1, // bDataInterface | |||
| // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 | |||
| 4, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x02, // bDescriptorSubtype | |||
| 0x06, // bmCapabilities | |||
| // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 | |||
| 5, // bFunctionLength | |||
| 0x24, // bDescriptorType | |||
| 0x06, // bDescriptorSubtype | |||
| CDC3_STATUS_INTERFACE, // bMasterInterface | |||
| CDC3_DATA_INTERFACE, // bSlaveInterface0 | |||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
| 7, // bLength | |||
| 5, // bDescriptorType | |||
| CDC3_ACM_ENDPOINT | 0x80, // bEndpointAddress | |||
| 0x03, // bmAttributes (0x03=intr) | |||
| CDC3_ACM_SIZE, 0, // wMaxPacketSize | |||
| 64, // bInterval | |||
| // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
| 9, // bLength | |||
| 4, // bDescriptorType | |||
| CDC3_DATA_INTERFACE, // bInterfaceNumber | |||
| 0, // bAlternateSetting | |||
| 2, // bNumEndpoints | |||
| 0x0A, // bInterfaceClass | |||
| 0x00, // bInterfaceSubClass | |||
| 0x00, // bInterfaceProtocol | |||
| 0, // iInterface | |||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
| 7, // bLength | |||
| 5, // bDescriptorType | |||
| CDC3_RX_ENDPOINT, // bEndpointAddress | |||
| 0x02, // bmAttributes (0x02=bulk) | |||
| CDC3_RX_SIZE, 0, // wMaxPacketSize | |||
| 0, // bInterval | |||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
| 7, // bLength | |||
| 5, // bDescriptorType | |||
| CDC3_TX_ENDPOINT | 0x80, // bEndpointAddress | |||
| 0x02, // bmAttributes (0x02=bulk) | |||
| CDC3_TX_SIZE, 0, // wMaxPacketSize | |||
| 0, // bInterval | |||
| #endif // CDC3_DATA_INTERFACE | |||
| #ifdef MIDI_INTERFACE | |||
| // Standard MS Interface Descriptor, | |||
| 9, // bLength | |||
| @@ -1086,7 +1270,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||
| 0x06, // bInterfaceClass (0x06 = still image) | |||
| 0x01, // bInterfaceSubClass | |||
| 0x01, // bInterfaceProtocol | |||
| 4, // iInterface | |||
| 0, // iInterface | |||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||
| 7, // bLength | |||
| 5, // bDescriptorType | |||
| @@ -40,7 +40,7 @@ | |||
| #include <stddef.h> | |||
| #define ENDPOINT_UNUSED 0x00 | |||
| #define ENDPOINT_TRANSIMIT_ONLY 0x15 | |||
| #define ENDPOINT_TRANSMIT_ONLY 0x15 | |||
| #define ENDPOINT_RECEIVE_ONLY 0x19 | |||
| #define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | |||
| #define ENDPOINT_RECEIVE_ISOCHRONOUS 0x18 | |||
| @@ -136,9 +136,90 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define CDC_ACM_SIZE 16 | |||
| #define CDC_RX_SIZE 64 | |||
| #define CDC_TX_SIZE 64 | |||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_DUAL_SERIAL) | |||
| #define VENDOR_ID 0x16C0 | |||
| #define PRODUCT_ID 0x048B | |||
| #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} | |||
| #define MANUFACTURER_NAME_LEN 11 | |||
| #define PRODUCT_NAME {'D','u','a','l',' ','S','e','r','i','a','l'} | |||
| #define PRODUCT_NAME_LEN 11 | |||
| #define EP0_SIZE 64 | |||
| #define NUM_ENDPOINTS 7 | |||
| #define NUM_USB_BUFFERS 22 | |||
| #define NUM_INTERFACE 4 | |||
| #define CDC_IAD_DESCRIPTOR 1 // Serial | |||
| #define CDC_STATUS_INTERFACE 0 | |||
| #define CDC_DATA_INTERFACE 1 | |||
| #define CDC_ACM_ENDPOINT 2 | |||
| #define CDC_RX_ENDPOINT 3 | |||
| #define CDC_TX_ENDPOINT 4 | |||
| #define CDC_ACM_SIZE 16 | |||
| #define CDC_RX_SIZE 64 | |||
| #define CDC_TX_SIZE 64 | |||
| #define CDC2_STATUS_INTERFACE 2 // SerialUSB1 | |||
| #define CDC2_DATA_INTERFACE 3 | |||
| #define CDC2_ACM_ENDPOINT 5 | |||
| #define CDC2_RX_ENDPOINT 6 | |||
| #define CDC2_TX_ENDPOINT 7 | |||
| #define CDC2_ACM_SIZE 16 | |||
| #define CDC2_RX_SIZE 64 | |||
| #define CDC2_TX_SIZE 64 | |||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_TRIPLE_SERIAL) | |||
| #define VENDOR_ID 0x16C0 | |||
| #define PRODUCT_ID 0x048C | |||
| #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} | |||
| #define MANUFACTURER_NAME_LEN 11 | |||
| #define PRODUCT_NAME {'T','r','i','p','l','e',' ','S','e','r','i','a','l'} | |||
| #define PRODUCT_NAME_LEN 13 | |||
| #define EP0_SIZE 64 | |||
| #define NUM_ENDPOINTS 10 | |||
| #define NUM_USB_BUFFERS 32 | |||
| #define NUM_INTERFACE 6 | |||
| #define CDC_IAD_DESCRIPTOR 1 // Serial | |||
| #define CDC_STATUS_INTERFACE 0 | |||
| #define CDC_DATA_INTERFACE 1 | |||
| #define CDC_ACM_ENDPOINT 2 | |||
| #define CDC_RX_ENDPOINT 3 | |||
| #define CDC_TX_ENDPOINT 4 | |||
| #define CDC_ACM_SIZE 16 | |||
| #define CDC_RX_SIZE 64 | |||
| #define CDC_TX_SIZE 64 | |||
| #define CDC2_STATUS_INTERFACE 2 // SerialUSB1 | |||
| #define CDC2_DATA_INTERFACE 3 | |||
| #define CDC2_ACM_ENDPOINT 5 | |||
| #define CDC2_RX_ENDPOINT 6 | |||
| #define CDC2_TX_ENDPOINT 7 | |||
| #define CDC2_ACM_SIZE 16 | |||
| #define CDC2_RX_SIZE 64 | |||
| #define CDC2_TX_SIZE 64 | |||
| #define CDC3_STATUS_INTERFACE 4 // SerialUSB2 | |||
| #define CDC3_DATA_INTERFACE 5 | |||
| #define CDC3_ACM_ENDPOINT 8 | |||
| #define CDC3_RX_ENDPOINT 9 | |||
| #define CDC3_TX_ENDPOINT 10 | |||
| #define CDC3_ACM_SIZE 16 | |||
| #define CDC3_RX_SIZE 64 | |||
| #define CDC3_TX_SIZE 64 | |||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT8_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT9_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT10_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_KEYBOARDONLY) | |||
| #define VENDOR_ID 0x16C0 | |||
| @@ -166,12 +247,12 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define KEYMEDIA_ENDPOINT 4 | |||
| #define KEYMEDIA_SIZE 8 | |||
| #define KEYMEDIA_INTERVAL 4 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_HID) | |||
| #define VENDOR_ID 0x16C0 | |||
| @@ -207,12 +288,12 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define JOYSTICK_ENDPOINT 4 | |||
| #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | |||
| #define JOYSTICK_INTERVAL 2 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_SERIAL_HID) | |||
| #define VENDOR_ID 0x16C0 | |||
| @@ -253,13 +334,13 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define JOYSTICK_ENDPOINT 6 | |||
| #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | |||
| #define JOYSTICK_INTERVAL 1 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_TOUCHSCREEN) | |||
| #define VENDOR_ID 0x16C0 | |||
| @@ -289,13 +370,13 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define KEYMEDIA_INTERVAL 4 | |||
| #define MULTITOUCH_INTERFACE 3 // Touchscreen | |||
| #define MULTITOUCH_ENDPOINT 5 | |||
| #define MULTITOUCH_SIZE 8 | |||
| #define MULTITOUCH_SIZE 16 | |||
| #define MULTITOUCH_FINGERS 10 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_HID_TOUCHSCREEN) | |||
| #define VENDOR_ID 0x16C0 | |||
| @@ -329,14 +410,14 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MOUSE_INTERVAL 2 | |||
| #define MULTITOUCH_INTERFACE 4 // Touchscreen | |||
| #define MULTITOUCH_ENDPOINT 5 | |||
| #define MULTITOUCH_SIZE 8 | |||
| #define MULTITOUCH_SIZE 16 | |||
| #define MULTITOUCH_FINGERS 10 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_MIDI) | |||
| #define VENDOR_ID 0x16C0 | |||
| @@ -362,9 +443,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MIDI_TX_SIZE 64 | |||
| #define MIDI_RX_ENDPOINT 4 | |||
| #define MIDI_RX_SIZE 64 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_MIDI4) | |||
| @@ -392,9 +473,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MIDI_TX_SIZE 64 | |||
| #define MIDI_RX_ENDPOINT 4 | |||
| #define MIDI_RX_SIZE 64 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_MIDI16) | |||
| @@ -422,9 +503,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MIDI_TX_SIZE 64 | |||
| #define MIDI_RX_ENDPOINT 4 | |||
| #define MIDI_RX_SIZE 64 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_MIDI_SERIAL) | |||
| @@ -453,10 +534,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MIDI_TX_SIZE 64 | |||
| #define MIDI_RX_ENDPOINT 5 | |||
| #define MIDI_RX_SIZE 64 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_MIDI4_SERIAL) | |||
| @@ -486,10 +567,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MIDI_TX_SIZE 64 | |||
| #define MIDI_RX_ENDPOINT 5 | |||
| #define MIDI_RX_SIZE 64 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_MIDI16_SERIAL) | |||
| @@ -519,10 +600,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MIDI_TX_SIZE 64 | |||
| #define MIDI_RX_ENDPOINT 5 | |||
| #define MIDI_RX_SIZE 64 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_RAWHID) | |||
| @@ -552,9 +633,9 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define SEREMU_RX_ENDPOINT 2 | |||
| #define SEREMU_RX_SIZE 32 | |||
| #define SEREMU_RX_INTERVAL 2 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_FLIGHTSIM) | |||
| @@ -582,14 +663,15 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define SEREMU_RX_ENDPOINT 2 | |||
| #define SEREMU_RX_SIZE 32 | |||
| #define SEREMU_RX_INTERVAL 2 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_FLIGHTSIM_JOYSTICK) | |||
| #define VENDOR_ID 0x16C0 | |||
| #define PRODUCT_ID 0x04D9 | |||
| #define PRODUCT_ID 0x0488 | |||
| #define BCD_DEVICE 0x0211 | |||
| #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} | |||
| #define MANUFACTURER_NAME_LEN 11 | |||
| #define PRODUCT_NAME {'T','e','e','n','s','y',' ','F','l','i','g','h','t',' ','S','i','m',' ','C','o','n','t','r','o','l','s'} | |||
| @@ -616,11 +698,11 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define JOYSTICK_ENDPOINT 5 | |||
| #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | |||
| #define JOYSTICK_INTERVAL 1 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #elif defined(USB_MTPDISK) | |||
| @@ -649,9 +731,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define SEREMU_RX_ENDPOINT 2 | |||
| #define SEREMU_RX_SIZE 32 | |||
| #define SEREMU_RX_INTERVAL 2 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
| // TODO: Should ENDPOINT4_CONFIG be ENDPOINT_TRANSMIT_ONLY ??? | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #elif defined(USB_AUDIO) | |||
| @@ -678,7 +761,7 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define AUDIO_RX_ENDPOINT 4 | |||
| #define AUDIO_RX_SIZE 180 | |||
| #define AUDIO_SYNC_ENDPOINT 5 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | |||
| @@ -716,10 +799,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define AUDIO_RX_ENDPOINT 7 | |||
| #define AUDIO_RX_SIZE 180 | |||
| #define AUDIO_SYNC_ENDPOINT 8 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
| #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | |||
| @@ -758,10 +841,10 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define AUDIO_RX_ENDPOINT 7 | |||
| #define AUDIO_RX_SIZE 180 | |||
| #define AUDIO_SYNC_ENDPOINT 8 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
| #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | |||
| @@ -848,21 +931,21 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports | |||
| #define MULTITOUCH_ENDPOINT 15 | |||
| #define MULTITOUCH_SIZE 8 | |||
| #define MULTITOUCH_FINGERS 10 | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
| #define ENDPOINT7_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
| #define ENDPOINT8_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT8_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT9_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
| #define ENDPOINT10_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT10_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT11_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | |||
| #define ENDPOINT12_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT12_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #define ENDPOINT13_CONFIG (ENDPOINT_RECEIVE_ISOCHRONOUS|ENDPOINT_TRANSMIT_ISOCHRONOUS) | |||
| #define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | |||
| #define ENDPOINT15_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||
| #define ENDPOINT15_CONFIG ENDPOINT_TRANSMIT_ONLY | |||
| #endif | |||
| @@ -45,6 +45,14 @@ | |||
| #include "usb_mem.h" | |||
| #include <string.h> // for memset | |||
| // This code has a known bug with compiled with -O2 optimization on gcc 5.4.1 | |||
| // https://forum.pjrc.com/threads/53574-Teensyduino-1-43-Beta-2?p=186177&viewfull=1#post186177 | |||
| #if defined(__MKL26Z64__) | |||
| #pragma GCC optimize ("Os") | |||
| #else | |||
| #pragma GCC optimize ("O3") | |||
| #endif | |||
| // buffer descriptor table | |||
| typedef struct { | |||
| @@ -345,12 +353,30 @@ static void usb_setup(void) | |||
| //serial_print("desc: not found\n"); | |||
| endpoint0_stall(); | |||
| return; | |||
| #if defined(CDC_STATUS_INTERFACE) | |||
| case 0x2221: // CDC_SET_CONTROL_LINE_STATE | |||
| usb_cdc_line_rtsdtr_millis = systick_millis_count; | |||
| usb_cdc_line_rtsdtr = setup.wValue; | |||
| switch (setup.wIndex) { | |||
| #ifdef CDC_STATUS_INTERFACE | |||
| case CDC_STATUS_INTERFACE: | |||
| usb_cdc_line_rtsdtr_millis = systick_millis_count; | |||
| usb_cdc_line_rtsdtr = setup.wValue; | |||
| break; | |||
| #endif | |||
| #ifdef CDC2_STATUS_INTERFACE | |||
| case CDC2_STATUS_INTERFACE: | |||
| usb_cdc2_line_rtsdtr_millis = systick_millis_count; | |||
| usb_cdc2_line_rtsdtr = setup.wValue; | |||
| break; | |||
| #endif | |||
| #ifdef CDC3_STATUS_INTERFACE | |||
| case CDC3_STATUS_INTERFACE: | |||
| usb_cdc3_line_rtsdtr_millis = systick_millis_count; | |||
| usb_cdc3_line_rtsdtr = setup.wValue; | |||
| break; | |||
| #endif | |||
| } | |||
| //serial_print("set control line state\n"); | |||
| break; | |||
| #ifdef CDC_STATUS_INTERFACE | |||
| case 0x2321: // CDC_SEND_BREAK | |||
| break; | |||
| case 0x2021: // CDC_SET_LINE_CODING | |||
| @@ -586,21 +612,39 @@ static void usb_control(uint32_t stat) | |||
| case 0x01: // OUT transaction received from host | |||
| case 0x02: | |||
| //serial_print("PID=OUT\n"); | |||
| #ifdef CDC_STATUS_INTERFACE | |||
| if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { | |||
| int i; | |||
| uint8_t *dst = (uint8_t *)usb_cdc_line_coding; | |||
| //serial_print("set line coding "); | |||
| for (i=0; i<7; i++) { | |||
| //serial_phex(*buf); | |||
| *dst++ = *buf++; | |||
| uint32_t *line_coding = NULL; | |||
| switch (setup.wIndex) { | |||
| #ifdef CDC_STATUS_INTERFACE | |||
| case CDC_STATUS_INTERFACE: | |||
| line_coding = usb_cdc_line_coding; | |||
| break; | |||
| #endif | |||
| #ifdef CDC2_STATUS_INTERFACE | |||
| case CDC2_STATUS_INTERFACE: | |||
| line_coding = usb_cdc2_line_coding; | |||
| break; | |||
| #endif | |||
| #ifdef CDC3_STATUS_INTERFACE | |||
| case CDC3_STATUS_INTERFACE: | |||
| line_coding = usb_cdc3_line_coding; | |||
| break; | |||
| #endif | |||
| } | |||
| if (line_coding) { | |||
| uint8_t *dst = (uint8_t *)line_coding; | |||
| //serial_print("set line coding "); | |||
| for (i=0; i<7; i++) { | |||
| //serial_phex(*buf); | |||
| *dst++ = *buf++; | |||
| } | |||
| //serial_phex32(line_coding[0]); | |||
| //serial_print("\n"); | |||
| if (line_coding[0] == 134) usb_reboot_timer = 15; | |||
| } | |||
| //serial_phex32(usb_cdc_line_coding[0]); | |||
| //serial_print("\n"); | |||
| if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15; | |||
| endpoint0_transmit(NULL, 0); | |||
| } | |||
| #endif | |||
| #ifdef KEYBOARD_INTERFACE | |||
| if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { | |||
| keyboard_leds = buf[0]; | |||
| @@ -711,6 +755,9 @@ uint32_t usb_tx_byte_count(uint32_t endpoint) | |||
| return usb_queue_byte_count(tx_first[endpoint]); | |||
| } | |||
| // Discussion about using this function and USB transmit latency | |||
| // https://forum.pjrc.com/threads/58663?p=223513&viewfull=1#post223513 | |||
| // | |||
| uint32_t usb_tx_packet_count(uint32_t endpoint) | |||
| { | |||
| const usb_packet_t *p; | |||
| @@ -848,6 +895,7 @@ void _reboot_Teensyduino_(void) | |||
| { | |||
| // TODO: initialize R0 with a code.... | |||
| __asm__ volatile("bkpt"); | |||
| __builtin_unreachable(); | |||
| } | |||
| @@ -877,6 +925,20 @@ void usb_isr(void) | |||
| if (t == 0) usb_serial_flush_callback(); | |||
| } | |||
| #endif | |||
| #ifdef CDC2_DATA_INTERFACE | |||
| t = usb_cdc2_transmit_flush_timer; | |||
| if (t) { | |||
| usb_cdc2_transmit_flush_timer = --t; | |||
| if (t == 0) usb_serial2_flush_callback(); | |||
| } | |||
| #endif | |||
| #ifdef CDC3_DATA_INTERFACE | |||
| t = usb_cdc3_transmit_flush_timer; | |||
| if (t) { | |||
| usb_cdc3_transmit_flush_timer = --t; | |||
| if (t == 0) usb_serial3_flush_callback(); | |||
| } | |||
| #endif | |||
| #ifdef SEREMU_INTERFACE | |||
| t = usb_seremu_transmit_flush_timer; | |||
| if (t) { | |||
| @@ -1107,7 +1169,7 @@ void usb_init(void) | |||
| usb_init_serialnumber(); | |||
| for (i=0; i <= NUM_ENDPOINTS*4; i++) { | |||
| for (i=0; i < (NUM_ENDPOINTS+1)*4; i++) { | |||
| table[i].desc = 0; | |||
| table[i].addr = 0; | |||
| } | |||
| @@ -1121,7 +1183,7 @@ void usb_init(void) | |||
| #ifdef HAS_KINETIS_MPU | |||
| MPU_RGDAAC0 |= 0x03000000; | |||
| #endif | |||
| #if F_CPU == 180000000 || F_CPU == 216000000 | |||
| #if F_CPU == 180000000 || F_CPU == 216000000 || F_CPU == 256000000 | |||
| // if using IRC48M, turn on the USB clock recovery hardware | |||
| USB0_CLK_RECOVER_IRC_EN = USB_CLK_RECOVER_IRC_EN_IRC_EN | USB_CLK_RECOVER_IRC_EN_REG_EN; | |||
| USB0_CLK_RECOVER_CTRL = USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN | | |||
| @@ -67,15 +67,6 @@ static inline uint32_t usb_rx_byte_count(uint32_t endpoint) | |||
| return usb_rx_byte_count_data[endpoint]; | |||
| } | |||
| #ifdef CDC_DATA_INTERFACE | |||
| extern uint32_t usb_cdc_line_coding[2]; | |||
| extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | |||
| extern volatile uint32_t systick_millis_count; | |||
| extern volatile uint8_t usb_cdc_line_rtsdtr; | |||
| extern volatile uint8_t usb_cdc_transmit_flush_timer; | |||
| extern void usb_serial_flush_callback(void); | |||
| #endif | |||
| #ifdef SEREMU_INTERFACE | |||
| extern volatile uint8_t usb_seremu_transmit_flush_timer; | |||
| extern void usb_seremu_flush_callback(void); | |||
| @@ -119,6 +110,18 @@ extern void usb_touchscreen_update_callback(void); | |||
| } | |||
| #endif | |||
| #ifdef CDC_DATA_INTERFACE | |||
| #include "usb_serial.h" | |||
| #endif | |||
| #ifdef CDC2_DATA_INTERFACE | |||
| #include "usb_serial2.h" | |||
| #endif | |||
| #ifdef CDC3_DATA_INTERFACE | |||
| #include "usb_serial3.h" | |||
| #endif | |||
| #else // F_CPU < 20000000 | |||
| #ifdef __cplusplus | |||
| @@ -42,6 +42,12 @@ FlightSimInteger * FlightSimInteger::first = NULL; | |||
| FlightSimInteger * FlightSimInteger::last = NULL; | |||
| FlightSimFloat * FlightSimFloat::first = NULL; | |||
| FlightSimFloat * FlightSimFloat::last = NULL; | |||
| /// JB | |||
| FlightSimEvent * FlightSimEvent::first = NULL; | |||
| FlightSimEvent * FlightSimEvent::last = NULL; | |||
| FlightSimData * FlightSimData::first = NULL; | |||
| FlightSimData * FlightSimData::last = NULL; | |||
| /// JB End | |||
| uint8_t FlightSimClass::enabled = 0; | |||
| uint8_t FlightSimClass::request_id_messages = 0; | |||
| @@ -92,6 +98,146 @@ void FlightSimCommand::sendcmd(uint8_t n) | |||
| FlightSimClass::xmit(buf, 4, NULL, 0); | |||
| } | |||
| /// JB | |||
| FlightSimEvent::FlightSimEvent() | |||
| { | |||
| id = unassigned_id++; | |||
| if (!first) { | |||
| first = this; | |||
| } else { | |||
| last->next = this; | |||
| } | |||
| last = this; | |||
| name = NULL; | |||
| next = NULL; | |||
| occur_callback = NULL; | |||
| occurredFlag = 0; | |||
| callbackInfo = NULL; | |||
| hasCallbackInfo = 0; | |||
| value = 0; | |||
| FlightSimClass::request_id_messages = 1; | |||
| } | |||
| void FlightSimEvent::identify(void) | |||
| { | |||
| uint8_t len, buf[6]; | |||
| if (!FlightSim.enabled || !name) return; | |||
| len = strlen((const char *)name); | |||
| buf[0] = len + 6; | |||
| buf[1] = 1; | |||
| buf[2] = id; | |||
| buf[3] = id >> 8; | |||
| buf[4] = 3; | |||
| buf[5] = 0; | |||
| FlightSimClass::xmit(buf, 6, name, len); | |||
| } | |||
| void FlightSimEvent::send(unsigned int data, unsigned int flags) | |||
| { | |||
| uint8_t buf[4]; | |||
| uint32_t txData[2]; | |||
| if (!FlightSim.enabled || !name) return; | |||
| buf[0] = 12; | |||
| buf[1] = 7; | |||
| buf[2] = id; | |||
| buf[3] = id >> 8; | |||
| value = data; | |||
| txData[0] = data; | |||
| txData[1] = flags; | |||
| FlightSimClass::xmit(buf, 4, (uint8_t *)&txData, 8); | |||
| } | |||
| void FlightSimEvent::update(long val) | |||
| { | |||
| value = (unsigned int) val; | |||
| occurredFlag = true; | |||
| if (occur_callback) { | |||
| if (!hasCallbackInfo) { | |||
| (*occur_callback)(val); | |||
| } else { | |||
| (*(void(*)(long,void*))occur_callback)(val,callbackInfo); | |||
| } | |||
| } | |||
| } | |||
| FlightSimEvent * FlightSimEvent::find(unsigned int n) | |||
| { | |||
| for (FlightSimEvent *p = first; p; p = p->next) { | |||
| if (p->id == n) return p; | |||
| } | |||
| return NULL; | |||
| } | |||
| FlightSimData::FlightSimData() | |||
| { | |||
| id = unassigned_id++; | |||
| if (!first) { | |||
| first = this; | |||
| } else { | |||
| last->next = this; | |||
| } | |||
| last = this; | |||
| name = NULL; | |||
| next = NULL; | |||
| valueLen = 0; | |||
| hasCallbackInfo = 0; | |||
| callbackWithObject = 0; | |||
| callbackInfo = NULL; | |||
| change_callback = NULL; | |||
| FlightSimClass::request_id_messages = 1; | |||
| } | |||
| void FlightSimData::identify(void) | |||
| { | |||
| uint8_t len, buf[6]; | |||
| if (!FlightSim.enabled || !name) return; | |||
| len = strlen((const char *)name); | |||
| buf[0] = len + 6; | |||
| buf[1] = 1; | |||
| buf[2] = id; | |||
| buf[3] = id >> 8; | |||
| buf[4] = 4; | |||
| buf[5] = 0; | |||
| FlightSimClass::xmit(buf, 6, name, len); | |||
| } | |||
| void FlightSimData::update(char *val, size_t len) | |||
| { | |||
| valueLen = len; | |||
| memcpy(value, val, len); | |||
| if (len<FLIGHTSIM_DATA_MAXLEN) { | |||
| memset(value+len,0,FLIGHTSIM_DATA_MAXLEN-len); | |||
| } | |||
| if (change_callback) { | |||
| if (!callbackWithObject) { | |||
| if (!hasCallbackInfo) { | |||
| (*change_callback)(value); | |||
| } else { | |||
| (*(void(*)(char*,void*))change_callback)(value,callbackInfo); | |||
| } | |||
| } else { | |||
| if (!hasCallbackInfo) { | |||
| (*(void(*)(FlightSimData*))change_callback)(this); | |||
| } else { | |||
| (*(void(*)(FlightSimData*,void*))change_callback)(this,callbackInfo); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| FlightSimData * FlightSimData::find(unsigned int n) | |||
| { | |||
| for (FlightSimData *p = first; p; p = p->next) { | |||
| if (p->id == n) return p; | |||
| } | |||
| return NULL; | |||
| } | |||
| /// JB End | |||
| FlightSimInteger::FlightSimInteger() | |||
| { | |||
| @@ -287,6 +433,24 @@ void FlightSimClass::update(void) | |||
| data.b[2] = p[8]; | |||
| data.b[3] = p[9]; | |||
| item->update(data.f); | |||
| /// JB | |||
| } else if (type == 3) { | |||
| FlightSimEvent *item = FlightSimEvent::find(id); | |||
| if (!item) break; | |||
| #ifdef KINETISK | |||
| data.l = *(long *)(p + 6); | |||
| #else | |||
| data.b[0] = p[6]; | |||
| data.b[1] = p[7]; | |||
| data.b[2] = p[8]; | |||
| data.b[3] = p[9]; | |||
| #endif | |||
| item->update(data.f); | |||
| } else if (type == 4) { | |||
| FlightSimData *item = FlightSimData::find(id); | |||
| if (!item) break; | |||
| item->update(((char*)p)+6,len-6); | |||
| /// JB End | |||
| } | |||
| break; | |||
| case 0x03: // enable/disable | |||
| @@ -313,6 +477,14 @@ void FlightSimClass::update(void) | |||
| for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) { | |||
| p->identify(); | |||
| } | |||
| /// JB | |||
| for (FlightSimEvent *p = FlightSimEvent::first; p; p = p->next) { | |||
| p->identify(); | |||
| } | |||
| for (FlightSimData *p = FlightSimData::first; p; p=p->next) { | |||
| p->identify(); | |||
| } | |||
| /// JB End | |||
| for (FlightSimInteger *p = FlightSimInteger::first; p; p = p->next) { | |||
| p->identify(); | |||
| // TODO: send any dirty data | |||
| @@ -70,6 +70,10 @@ private: | |||
| friend class FlightSimCommand; | |||
| friend class FlightSimInteger; | |||
| friend class FlightSimFloat; | |||
| /// JB | |||
| friend class FlightSimEvent; | |||
| friend class FlightSimData; | |||
| /// JB End | |||
| }; | |||
| @@ -94,6 +98,101 @@ private: | |||
| friend class FlightSimClass; | |||
| }; | |||
| /// JB | |||
| class FlightSimEvent | |||
| { | |||
| public: | |||
| FlightSimEvent(); | |||
| void assign(const _XpRefStr_ *s) { name = s; if (FlightSimClass::enabled) identify(); } | |||
| FlightSimEvent & operator = (const _XpRefStr_ *s) { assign(s); return *this; } | |||
| void send() { send(0,0); } | |||
| void send(int data) { send(data,0); } | |||
| void sendOnce() { send(0,0); } | |||
| void sendOnce(int data) { send(data,0); } | |||
| void sendRepeat(int data, uint16_t initialDelay, uint16_t repeatDelay) { send(data, initialDelay<<16 | repeatDelay); } | |||
| void sendRepeat(uint16_t initialDelay, uint16_t repeatDelay) { send(0, initialDelay<<16 | repeatDelay); } | |||
| void stopRepeat() { send(0,-1); } | |||
| FlightSimEvent & operator = (int n) { send(n,0); return *this; } | |||
| bool occurred() { bool hasOccurred = occurredFlag; occurredFlag = 0; return hasOccurred; } | |||
| void identify(); | |||
| static FlightSimEvent * find(unsigned int n); | |||
| void update(long val); | |||
| void onOccur(void (*fptr)(long)) { | |||
| hasCallbackInfo=false; | |||
| occur_callback = fptr; | |||
| } | |||
| void onOccur(void (*fptr)(long,void*), void* info) { | |||
| hasCallbackInfo=true; | |||
| occur_callback = (void (*)(long))fptr; | |||
| callbackInfo = info; | |||
| } | |||
| private: | |||
| void send(unsigned int data, unsigned int flags); | |||
| unsigned int id; | |||
| const _XpRefStr_ *name; | |||
| bool occurredFlag; | |||
| unsigned int value; | |||
| FlightSimEvent *next; | |||
| void (*occur_callback)(long); | |||
| void* callbackInfo; | |||
| bool hasCallbackInfo; | |||
| static FlightSimEvent *first; | |||
| static FlightSimEvent *last; | |||
| friend class FlightSimClass; | |||
| }; | |||
| #define FLIGHTSIM_DATA_MAXLEN 58 | |||
| class FlightSimData | |||
| { | |||
| public: | |||
| FlightSimData(); | |||
| void assign(const _XpRefStr_ *s) { name = s; if (FlightSimClass::enabled) identify(); } | |||
| FlightSimData & operator = (const _XpRefStr_ *s) { assign(s); return *this; } | |||
| char *read() { return value; } | |||
| operator char* () { return value; } | |||
| void identify(); | |||
| void update(char *val, size_t len); | |||
| size_t len() { return valueLen; } | |||
| static FlightSimData * find(unsigned int n); | |||
| void onChange(void (*fptr)(char *)) { | |||
| hasCallbackInfo = false; | |||
| change_callback = fptr; | |||
| } | |||
| void onChange(void (*fptr)(char *,void *), void *info) { | |||
| hasCallbackInfo = true; | |||
| change_callback = (void (*)(char*)) fptr; | |||
| callbackInfo = info; | |||
| } | |||
| void onChange(void (*fptr)(FlightSimData *)) { | |||
| callbackWithObject = true; | |||
| hasCallbackInfo = false; | |||
| change_callback = (void (*)(char*)) fptr; | |||
| } | |||
| void onChange(void (*fptr)(FlightSimData *, void*), void* info) { | |||
| callbackWithObject = true; | |||
| hasCallbackInfo = true; | |||
| change_callback = (void (*)(char*)) fptr; | |||
| callbackInfo = info; | |||
| } | |||
| private: | |||
| unsigned int id; | |||
| const _XpRefStr_ *name; | |||
| char value[FLIGHTSIM_DATA_MAXLEN]; | |||
| size_t valueLen; | |||
| void (*change_callback)(char *); | |||
| void* callbackInfo; | |||
| bool hasCallbackInfo; | |||
| bool callbackWithObject; | |||
| FlightSimData *next; | |||
| static FlightSimData *first; | |||
| static FlightSimData *last; | |||
| friend class FlightSimClass; | |||
| }; | |||
| /// JB End | |||
| class FlightSimInteger | |||
| { | |||
| @@ -28,7 +28,7 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include "WProgram.h" | |||
| #include <Arduino.h> | |||
| #include "usb_desc.h" | |||
| #if F_CPU >= 20000000 | |||
| @@ -39,6 +39,18 @@ usb_serial_class Serial; | |||
| #endif | |||
| #endif | |||
| #ifdef CDC2_DATA_INTERFACE | |||
| #ifdef CDC2_STATUS_INTERFACE | |||
| usb_serial2_class SerialUSB1; | |||
| #endif | |||
| #endif | |||
| #ifdef CDC3_DATA_INTERFACE | |||
| #ifdef CDC3_STATUS_INTERFACE | |||
| usb_serial3_class SerialUSB2; | |||
| #endif | |||
| #endif | |||
| #ifdef MIDI_INTERFACE | |||
| usb_midi_class usbMIDI; | |||
| #endif | |||
| @@ -75,7 +87,8 @@ usb_serial_class Serial; | |||
| #else // F_CPU < 20 MHz | |||
| #if defined(USB_SERIAL) || defined(USB_SERIAL_HID) | |||
| #if defined(USB_SERIAL) || defined(USB_DUAL_SERIAL) || \ | |||
| defined(USB_TRIPLE_SERIAL) || defined(USB_SERIAL_HID) | |||
| usb_serial_class Serial; | |||
| #elif (USB_DISABLED) | |||
| usb_serial_class Serial; | |||
| @@ -84,6 +97,3 @@ usb_seremu_class Serial; | |||
| #endif | |||
| #endif // F_CPU | |||
| void serialEvent() __attribute__((weak)); | |||
| void serialEvent() {} | |||
| @@ -48,8 +48,9 @@ static uint8_t transmit_previous_timeout=0; | |||
| // When the PC isn't listening, how long do we wait before discarding data? | |||
| #define TX_TIMEOUT_MSEC 30 | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| @@ -496,8 +496,9 @@ static uint8_t transmit_previous_timeout=0; | |||
| // When the PC isn't listening, how long do we wait before discarding data? | |||
| #define TX_TIMEOUT_MSEC 50 | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| @@ -87,6 +87,7 @@ public: | |||
| void set_key4(uint8_t c) { keyboard_keys[3] = c; } | |||
| void set_key5(uint8_t c) { keyboard_keys[4] = c; } | |||
| void set_key6(uint8_t c) { keyboard_keys[5] = c; } | |||
| #ifdef KEYMEDIA_INTERFACE | |||
| void set_media(uint16_t c) { | |||
| if (c == 0) { | |||
| usb_keymedia_release_all(); | |||
| @@ -94,6 +95,7 @@ public: | |||
| press(c); | |||
| } | |||
| } | |||
| #endif | |||
| void send_now(void) { usb_keyboard_send(); } | |||
| void press(uint16_t n) { usb_keyboard_press_keycode(n); } | |||
| void release(uint16_t n) { usb_keyboard_release_keycode(n); } | |||
| @@ -76,8 +76,9 @@ static uint8_t tx_noautoflush=0; | |||
| // When the PC isn't listening, how long do we wait before discarding data? | |||
| #define TX_TIMEOUT_MSEC 40 | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| @@ -102,6 +103,13 @@ static uint8_t tx_noautoflush=0; | |||
| #endif | |||
| // This 32 bit input format is documented in the "Universal Serial Bus Device Class | |||
| // Definition for MIDI Devices" specification, version 1.0, Nov 1, 1999. It can be | |||
| // downloaded from www.usb.org. https://www.usb.org/sites/default/files/midi10.pdf | |||
| // If the USB-IF reorganizes their website and this link no longer works, Google | |||
| // search the name to find it. This data format is shown on page 16 in Figure #8. | |||
| // Byte 0 (shown on the left hand side of Figure #8) is the least significant byte | |||
| // of this 32 bit input. | |||
| void usb_midi_write_packed(uint32_t n) | |||
| { | |||
| uint32_t index, wait_count=0; | |||
| @@ -133,7 +141,7 @@ void usb_midi_write_packed(uint32_t n) | |||
| } else { | |||
| tx_packet->len = MIDI_TX_SIZE; | |||
| usb_tx(MIDI_TX_ENDPOINT, tx_packet); | |||
| tx_packet = usb_malloc(); | |||
| tx_packet = NULL; | |||
| } | |||
| tx_noautoflush = 0; | |||
| } | |||
| @@ -189,7 +197,7 @@ void usb_midi_flush_output(void) | |||
| if (tx_noautoflush == 0 && tx_packet && tx_packet->index > 0) { | |||
| tx_packet->len = tx_packet->index * 4; | |||
| usb_tx(MIDI_TX_ENDPOINT, tx_packet); | |||
| tx_packet = usb_malloc(); | |||
| tx_packet = NULL; | |||
| } | |||
| } | |||
| @@ -116,8 +116,9 @@ static uint8_t transmit_previous_timeout=0; | |||
| // When the PC isn't listening, how long do we wait before discarding data? | |||
| #define TX_TIMEOUT_MSEC 30 | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| @@ -138,8 +138,9 @@ void usb_seremu_flush_input(void) | |||
| // too short, we risk losing data during the stalls that are common with ordinary desktop | |||
| // software. If it's too long, we stall the user's program when no software is running. | |||
| #define TX_TIMEOUT_MSEC 30 | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| @@ -148,8 +148,9 @@ void usb_serial_flush_input(void) | |||
| // too short, we risk losing data during the stalls that are common with ordinary desktop | |||
| // software. If it's too long, we stall the user's program when no software is running. | |||
| #define TX_TIMEOUT_MSEC 70 | |||
| #if F_CPU == 240000000 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| @@ -39,6 +39,8 @@ | |||
| #if F_CPU >= 20000000 && !defined(USB_DISABLED) | |||
| #include "core_pins.h" // for millis() | |||
| // C language implementation | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| @@ -52,6 +54,7 @@ int usb_serial_putchar(uint8_t c); | |||
| int usb_serial_write(const void *buffer, uint32_t size); | |||
| int usb_serial_write_buffer_free(void); | |||
| void usb_serial_flush_output(void); | |||
| void usb_serial_flush_callback(void); | |||
| extern uint32_t usb_cdc_line_coding[2]; | |||
| extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | |||
| extern volatile uint32_t systick_millis_count; | |||
| @@ -106,9 +109,8 @@ public: | |||
| uint8_t numbits(void) { return usb_cdc_line_coding[1] >> 16; } | |||
| uint8_t dtr(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; } | |||
| uint8_t rts(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; } | |||
| operator bool() { return usb_configuration && | |||
| (usb_cdc_line_rtsdtr & (USB_SERIAL_DTR | USB_SERIAL_RTS)) && | |||
| ((uint32_t)(systick_millis_count - usb_cdc_line_rtsdtr_millis) >= 25); | |||
| operator bool() { return usb_configuration && (usb_cdc_line_rtsdtr & USB_SERIAL_DTR) && | |||
| ((uint32_t)(systick_millis_count - usb_cdc_line_rtsdtr_millis) >= 15); | |||
| } | |||
| size_t readBytes(char *buffer, size_t length) { | |||
| size_t count=0; | |||
| @@ -0,0 +1,306 @@ | |||
| /* Teensyduino Core Library | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2017 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #include "usb_dev.h" | |||
| #include "usb_serial2.h" | |||
| #include "core_pins.h" // for yield() | |||
| //#include "HardwareSerial.h" | |||
| #include <string.h> // for memcpy() | |||
| // defined by usb_dev.h -> usb_desc.h | |||
| #if defined(CDC2_STATUS_INTERFACE) && defined(CDC2_DATA_INTERFACE) | |||
| #if F_CPU >= 20000000 | |||
| uint32_t usb_cdc2_line_coding[2]; | |||
| volatile uint32_t usb_cdc2_line_rtsdtr_millis; | |||
| volatile uint8_t usb_cdc2_line_rtsdtr=0; | |||
| volatile uint8_t usb_cdc2_transmit_flush_timer=0; | |||
| static usb_packet_t *rx_packet=NULL; | |||
| static usb_packet_t *tx_packet=NULL; | |||
| static volatile uint8_t tx_noautoflush=0; | |||
| #define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ | |||
| // get the next character, or -1 if nothing received | |||
| int usb_serial2_getchar(void) | |||
| { | |||
| unsigned int i; | |||
| int c; | |||
| if (!rx_packet) { | |||
| if (!usb_configuration) return -1; | |||
| rx_packet = usb_rx(CDC2_RX_ENDPOINT); | |||
| if (!rx_packet) return -1; | |||
| } | |||
| i = rx_packet->index; | |||
| c = rx_packet->buf[i++]; | |||
| if (i >= rx_packet->len) { | |||
| usb_free(rx_packet); | |||
| rx_packet = NULL; | |||
| } else { | |||
| rx_packet->index = i; | |||
| } | |||
| return c; | |||
| } | |||
| // peek at the next character, or -1 if nothing received | |||
| int usb_serial2_peekchar(void) | |||
| { | |||
| if (!rx_packet) { | |||
| if (!usb_configuration) return -1; | |||
| rx_packet = usb_rx(CDC2_RX_ENDPOINT); | |||
| if (!rx_packet) return -1; | |||
| } | |||
| if (!rx_packet) return -1; | |||
| return rx_packet->buf[rx_packet->index]; | |||
| } | |||
| // number of bytes available in the receive buffer | |||
| int usb_serial2_available(void) | |||
| { | |||
| int count; | |||
| count = usb_rx_byte_count(CDC2_RX_ENDPOINT); | |||
| if (rx_packet) count += rx_packet->len - rx_packet->index; | |||
| return count; | |||
| } | |||
| // read a block of bytes to a buffer | |||
| int usb_serial2_read(void *buffer, uint32_t size) | |||
| { | |||
| uint8_t *p = (uint8_t *)buffer; | |||
| uint32_t qty, count=0; | |||
| while (size) { | |||
| if (!usb_configuration) break; | |||
| if (!rx_packet) { | |||
| rx: | |||
| rx_packet = usb_rx(CDC2_RX_ENDPOINT); | |||
| if (!rx_packet) break; | |||
| if (rx_packet->len == 0) { | |||
| usb_free(rx_packet); | |||
| goto rx; | |||
| } | |||
| } | |||
| qty = rx_packet->len - rx_packet->index; | |||
| if (qty > size) qty = size; | |||
| memcpy(p, rx_packet->buf + rx_packet->index, qty); | |||
| p += qty; | |||
| count += qty; | |||
| size -= qty; | |||
| rx_packet->index += qty; | |||
| if (rx_packet->index >= rx_packet->len) { | |||
| usb_free(rx_packet); | |||
| rx_packet = NULL; | |||
| } | |||
| } | |||
| return count; | |||
| } | |||
| // discard any buffered input | |||
| void usb_serial2_flush_input(void) | |||
| { | |||
| usb_packet_t *rx; | |||
| if (!usb_configuration) return; | |||
| if (rx_packet) { | |||
| usb_free(rx_packet); | |||
| rx_packet = NULL; | |||
| } | |||
| while (1) { | |||
| rx = usb_rx(CDC2_RX_ENDPOINT); | |||
| if (!rx) break; | |||
| usb_free(rx); | |||
| } | |||
| } | |||
| // Maximum number of transmit packets to queue so we don't starve other endpoints for memory | |||
| #define TX_PACKET_LIMIT 8 | |||
| // When the PC isn't listening, how long do we wait before discarding data? If this is | |||
| // too short, we risk losing data during the stalls that are common with ordinary desktop | |||
| // software. If it's too long, we stall the user's program when no software is running. | |||
| #define TX_TIMEOUT_MSEC 70 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| #elif F_CPU == 192000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280) | |||
| #elif F_CPU == 180000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200) | |||
| #elif F_CPU == 168000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100) | |||
| #elif F_CPU == 144000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932) | |||
| #elif F_CPU == 120000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764) | |||
| #elif F_CPU == 96000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596) | |||
| #elif F_CPU == 72000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512) | |||
| #elif F_CPU == 48000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428) | |||
| #elif F_CPU == 24000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) | |||
| #endif | |||
| // When we've suffered the transmit timeout, don't wait again until the computer | |||
| // begins accepting data. If no software is running to receive, we'll just discard | |||
| // data as rapidly as Serial.print() can generate it, until there's something to | |||
| // actually receive it. | |||
| static uint8_t transmit_previous_timeout=0; | |||
| // transmit a character. 0 returned on success, -1 on error | |||
| int usb_serial2_putchar(uint8_t c) | |||
| { | |||
| return usb_serial2_write(&c, 1); | |||
| } | |||
| int usb_serial2_write(const void *buffer, uint32_t size) | |||
| { | |||
| uint32_t ret = size; | |||
| uint32_t len; | |||
| uint32_t wait_count; | |||
| const uint8_t *src = (const uint8_t *)buffer; | |||
| uint8_t *dest; | |||
| tx_noautoflush = 1; | |||
| while (size > 0) { | |||
| if (!tx_packet) { | |||
| wait_count = 0; | |||
| while (1) { | |||
| if (!usb_configuration) { | |||
| tx_noautoflush = 0; | |||
| return -1; | |||
| } | |||
| if (usb_tx_packet_count(CDC2_TX_ENDPOINT) < TX_PACKET_LIMIT) { | |||
| tx_noautoflush = 1; | |||
| tx_packet = usb_malloc(); | |||
| if (tx_packet) break; | |||
| tx_noautoflush = 0; | |||
| } | |||
| if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) { | |||
| transmit_previous_timeout = 1; | |||
| return -1; | |||
| } | |||
| yield(); | |||
| } | |||
| } | |||
| transmit_previous_timeout = 0; | |||
| len = CDC2_TX_SIZE - tx_packet->index; | |||
| if (len > size) len = size; | |||
| dest = tx_packet->buf + tx_packet->index; | |||
| tx_packet->index += len; | |||
| size -= len; | |||
| while (len-- > 0) *dest++ = *src++; | |||
| if (tx_packet->index >= CDC2_TX_SIZE) { | |||
| tx_packet->len = CDC2_TX_SIZE; | |||
| usb_tx(CDC2_TX_ENDPOINT, tx_packet); | |||
| tx_packet = NULL; | |||
| } | |||
| usb_cdc2_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; | |||
| } | |||
| tx_noautoflush = 0; | |||
| return ret; | |||
| } | |||
| int usb_serial2_write_buffer_free(void) | |||
| { | |||
| uint32_t len; | |||
| tx_noautoflush = 1; | |||
| if (!tx_packet) { | |||
| if (!usb_configuration || | |||
| usb_tx_packet_count(CDC2_TX_ENDPOINT) >= TX_PACKET_LIMIT || | |||
| (tx_packet = usb_malloc()) == NULL) { | |||
| tx_noautoflush = 0; | |||
| return 0; | |||
| } | |||
| } | |||
| len = CDC2_TX_SIZE - tx_packet->index; | |||
| // TODO: Perhaps we need "usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT" | |||
| // added here, so the SOF interrupt can't take away the available buffer | |||
| // space we just promised the user could write without blocking? | |||
| // But does this come with other performance downsides? Could it lead to | |||
| // buffer data never actually transmitting in some usage cases? More | |||
| // investigation is needed. | |||
| // https://github.com/PaulStoffregen/cores/issues/10#issuecomment-61514955 | |||
| tx_noautoflush = 0; | |||
| return len; | |||
| } | |||
| void usb_serial2_flush_output(void) | |||
| { | |||
| if (!usb_configuration) return; | |||
| tx_noautoflush = 1; | |||
| if (tx_packet) { | |||
| usb_cdc2_transmit_flush_timer = 0; | |||
| tx_packet->len = tx_packet->index; | |||
| usb_tx(CDC2_TX_ENDPOINT, tx_packet); | |||
| tx_packet = NULL; | |||
| } else { | |||
| usb_packet_t *tx = usb_malloc(); | |||
| if (tx) { | |||
| usb_cdc2_transmit_flush_timer = 0; | |||
| usb_tx(CDC2_TX_ENDPOINT, tx); | |||
| } else { | |||
| usb_cdc2_transmit_flush_timer = 1; | |||
| } | |||
| } | |||
| tx_noautoflush = 0; | |||
| } | |||
| void usb_serial2_flush_callback(void) | |||
| { | |||
| if (tx_noautoflush) return; | |||
| if (tx_packet) { | |||
| tx_packet->len = tx_packet->index; | |||
| usb_tx(CDC2_TX_ENDPOINT, tx_packet); | |||
| tx_packet = NULL; | |||
| } else { | |||
| usb_packet_t *tx = usb_malloc(); | |||
| if (tx) { | |||
| usb_tx(CDC2_TX_ENDPOINT, tx); | |||
| } else { | |||
| usb_cdc2_transmit_flush_timer = 1; | |||
| } | |||
| } | |||
| } | |||
| #endif // F_CPU | |||
| #endif // CDC2_STATUS_INTERFACE && CDC2_DATA_INTERFACE | |||
| @@ -0,0 +1,139 @@ | |||
| /* Teensyduino Core Library | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2017 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #ifndef USBserial2_h_ | |||
| #define USBserial2_h_ | |||
| #include "usb_desc.h" | |||
| #if defined(CDC2_STATUS_INTERFACE) && defined(CDC2_DATA_INTERFACE) | |||
| #include <inttypes.h> | |||
| #if F_CPU >= 20000000 | |||
| #include "core_pins.h" // for millis() | |||
| // C language implementation | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| int usb_serial2_getchar(void); | |||
| int usb_serial2_peekchar(void); | |||
| int usb_serial2_available(void); | |||
| int usb_serial2_read(void *buffer, uint32_t size); | |||
| void usb_serial2_flush_input(void); | |||
| int usb_serial2_putchar(uint8_t c); | |||
| int usb_serial2_write(const void *buffer, uint32_t size); | |||
| int usb_serial2_write_buffer_free(void); | |||
| void usb_serial2_flush_output(void); | |||
| void usb_serial2_flush_callback(void); | |||
| extern uint32_t usb_cdc2_line_coding[2]; | |||
| extern volatile uint32_t usb_cdc2_line_rtsdtr_millis; | |||
| extern volatile uint32_t systick_millis_count; | |||
| extern volatile uint8_t usb_cdc2_line_rtsdtr; | |||
| extern volatile uint8_t usb_cdc2_transmit_flush_timer; | |||
| extern volatile uint8_t usb_configuration; | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #ifndef USB_SERIAL_DTR | |||
| #define USB_SERIAL_DTR 0x01 | |||
| #endif | |||
| #ifndef USB_SERIAL_RTS | |||
| #define USB_SERIAL_RTS 0x02 | |||
| #endif | |||
| // C++ interface | |||
| #ifdef __cplusplus | |||
| #include "Stream.h" | |||
| class usb_serial2_class : public Stream | |||
| { | |||
| public: | |||
| constexpr usb_serial2_class() {} | |||
| void begin(long) { | |||
| //uint32_t millis_begin = systick_millis_count; | |||
| //disabled for now - causes more trouble than it solves? | |||
| //while (!(*this)) { | |||
| // wait up to 2.5 seconds for Arduino Serial Monitor | |||
| // Yes, this is a long time, but some Windows systems open | |||
| // the port very slowly. This wait allows programs for | |||
| // Arduino Uno to "just work" (without forcing a reboot when | |||
| // the port is opened), and when no PC is connected the user's | |||
| // sketch still gets to run normally after this wait time. | |||
| //if ((uint32_t)(systick_millis_count - millis_begin) > 2500) break; | |||
| //} | |||
| } | |||
| void end() { /* TODO: flush output and shut down USB port */ }; | |||
| virtual int available() { return usb_serial2_available(); } | |||
| virtual int read() { return usb_serial2_getchar(); } | |||
| virtual int peek() { return usb_serial2_peekchar(); } | |||
| virtual void flush() { usb_serial2_flush_output(); } // TODO: actually wait for data to leave USB... | |||
| virtual void clear(void) { usb_serial2_flush_input(); } | |||
| virtual size_t write(uint8_t c) { return usb_serial2_putchar(c); } | |||
| virtual size_t write(const uint8_t *buffer, size_t size) { return usb_serial2_write(buffer, size); } | |||
| size_t write(unsigned long n) { return write((uint8_t)n); } | |||
| size_t write(long n) { return write((uint8_t)n); } | |||
| size_t write(unsigned int n) { return write((uint8_t)n); } | |||
| size_t write(int n) { return write((uint8_t)n); } | |||
| virtual int availableForWrite() { return usb_serial2_write_buffer_free(); } | |||
| using Print::write; | |||
| void send_now(void) { usb_serial2_flush_output(); } | |||
| uint32_t baud(void) { return usb_cdc2_line_coding[0]; } | |||
| uint8_t stopbits(void) { uint8_t b = usb_cdc2_line_coding[1]; if (!b) b = 1; return b; } | |||
| uint8_t paritytype(void) { return usb_cdc2_line_coding[1] >> 8; } // 0=none, 1=odd, 2=even | |||
| uint8_t numbits(void) { return usb_cdc2_line_coding[1] >> 16; } | |||
| uint8_t dtr(void) { return (usb_cdc2_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; } | |||
| uint8_t rts(void) { return (usb_cdc2_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; } | |||
| operator bool() { return usb_configuration && (usb_cdc2_line_rtsdtr & USB_SERIAL_DTR) && | |||
| ((uint32_t)(systick_millis_count - usb_cdc2_line_rtsdtr_millis) >= 15); | |||
| } | |||
| size_t readBytes(char *buffer, size_t length) { | |||
| size_t count=0; | |||
| unsigned long startMillis = millis(); | |||
| do { | |||
| count += usb_serial2_read(buffer + count, length - count); | |||
| if (count >= length) return count; | |||
| } while(millis() - startMillis < _timeout); | |||
| setReadError(); | |||
| return count; | |||
| } | |||
| }; | |||
| extern usb_serial2_class SerialUSB1; | |||
| extern void serialEventUSB1(void); | |||
| #endif // __cplusplus | |||
| #endif // F_CPU | |||
| #endif // CDC2_STATUS_INTERFACE && CDC2_DATA_INTERFACE | |||
| #endif // USBserial2_h_ | |||
| @@ -0,0 +1,306 @@ | |||
| /* Teensyduino Core Library | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2017 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #include "usb_dev.h" | |||
| #include "usb_serial3.h" | |||
| #include "core_pins.h" // for yield() | |||
| //#include "HardwareSerial.h" | |||
| #include <string.h> // for memcpy() | |||
| // defined by usb_dev.h -> usb_desc.h | |||
| #if defined(CDC3_STATUS_INTERFACE) && defined(CDC3_DATA_INTERFACE) | |||
| #if F_CPU >= 20000000 | |||
| uint32_t usb_cdc3_line_coding[2]; | |||
| volatile uint32_t usb_cdc3_line_rtsdtr_millis; | |||
| volatile uint8_t usb_cdc3_line_rtsdtr=0; | |||
| volatile uint8_t usb_cdc3_transmit_flush_timer=0; | |||
| static usb_packet_t *rx_packet=NULL; | |||
| static usb_packet_t *tx_packet=NULL; | |||
| static volatile uint8_t tx_noautoflush=0; | |||
| #define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ | |||
| // get the next character, or -1 if nothing received | |||
| int usb_serial3_getchar(void) | |||
| { | |||
| unsigned int i; | |||
| int c; | |||
| if (!rx_packet) { | |||
| if (!usb_configuration) return -1; | |||
| rx_packet = usb_rx(CDC3_RX_ENDPOINT); | |||
| if (!rx_packet) return -1; | |||
| } | |||
| i = rx_packet->index; | |||
| c = rx_packet->buf[i++]; | |||
| if (i >= rx_packet->len) { | |||
| usb_free(rx_packet); | |||
| rx_packet = NULL; | |||
| } else { | |||
| rx_packet->index = i; | |||
| } | |||
| return c; | |||
| } | |||
| // peek at the next character, or -1 if nothing received | |||
| int usb_serial3_peekchar(void) | |||
| { | |||
| if (!rx_packet) { | |||
| if (!usb_configuration) return -1; | |||
| rx_packet = usb_rx(CDC3_RX_ENDPOINT); | |||
| if (!rx_packet) return -1; | |||
| } | |||
| if (!rx_packet) return -1; | |||
| return rx_packet->buf[rx_packet->index]; | |||
| } | |||
| // number of bytes available in the receive buffer | |||
| int usb_serial3_available(void) | |||
| { | |||
| int count; | |||
| count = usb_rx_byte_count(CDC3_RX_ENDPOINT); | |||
| if (rx_packet) count += rx_packet->len - rx_packet->index; | |||
| return count; | |||
| } | |||
| // read a block of bytes to a buffer | |||
| int usb_serial3_read(void *buffer, uint32_t size) | |||
| { | |||
| uint8_t *p = (uint8_t *)buffer; | |||
| uint32_t qty, count=0; | |||
| while (size) { | |||
| if (!usb_configuration) break; | |||
| if (!rx_packet) { | |||
| rx: | |||
| rx_packet = usb_rx(CDC3_RX_ENDPOINT); | |||
| if (!rx_packet) break; | |||
| if (rx_packet->len == 0) { | |||
| usb_free(rx_packet); | |||
| goto rx; | |||
| } | |||
| } | |||
| qty = rx_packet->len - rx_packet->index; | |||
| if (qty > size) qty = size; | |||
| memcpy(p, rx_packet->buf + rx_packet->index, qty); | |||
| p += qty; | |||
| count += qty; | |||
| size -= qty; | |||
| rx_packet->index += qty; | |||
| if (rx_packet->index >= rx_packet->len) { | |||
| usb_free(rx_packet); | |||
| rx_packet = NULL; | |||
| } | |||
| } | |||
| return count; | |||
| } | |||
| // discard any buffered input | |||
| void usb_serial3_flush_input(void) | |||
| { | |||
| usb_packet_t *rx; | |||
| if (!usb_configuration) return; | |||
| if (rx_packet) { | |||
| usb_free(rx_packet); | |||
| rx_packet = NULL; | |||
| } | |||
| while (1) { | |||
| rx = usb_rx(CDC3_RX_ENDPOINT); | |||
| if (!rx) break; | |||
| usb_free(rx); | |||
| } | |||
| } | |||
| // Maximum number of transmit packets to queue so we don't starve other endpoints for memory | |||
| #define TX_PACKET_LIMIT 8 | |||
| // When the PC isn't listening, how long do we wait before discarding data? If this is | |||
| // too short, we risk losing data during the stalls that are common with ordinary desktop | |||
| // software. If it's too long, we stall the user's program when no software is running. | |||
| #define TX_TIMEOUT_MSEC 70 | |||
| #if F_CPU == 256000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706) | |||
| #elif F_CPU == 240000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | |||
| #elif F_CPU == 216000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | |||
| #elif F_CPU == 192000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280) | |||
| #elif F_CPU == 180000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200) | |||
| #elif F_CPU == 168000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100) | |||
| #elif F_CPU == 144000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932) | |||
| #elif F_CPU == 120000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764) | |||
| #elif F_CPU == 96000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596) | |||
| #elif F_CPU == 72000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512) | |||
| #elif F_CPU == 48000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428) | |||
| #elif F_CPU == 24000000 | |||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) | |||
| #endif | |||
| // When we've suffered the transmit timeout, don't wait again until the computer | |||
| // begins accepting data. If no software is running to receive, we'll just discard | |||
| // data as rapidly as Serial.print() can generate it, until there's something to | |||
| // actually receive it. | |||
| static uint8_t transmit_previous_timeout=0; | |||
| // transmit a character. 0 returned on success, -1 on error | |||
| int usb_serial3_putchar(uint8_t c) | |||
| { | |||
| return usb_serial3_write(&c, 1); | |||
| } | |||
| int usb_serial3_write(const void *buffer, uint32_t size) | |||
| { | |||
| uint32_t ret = size; | |||
| uint32_t len; | |||
| uint32_t wait_count; | |||
| const uint8_t *src = (const uint8_t *)buffer; | |||
| uint8_t *dest; | |||
| tx_noautoflush = 1; | |||
| while (size > 0) { | |||
| if (!tx_packet) { | |||
| wait_count = 0; | |||
| while (1) { | |||
| if (!usb_configuration) { | |||
| tx_noautoflush = 0; | |||
| return -1; | |||
| } | |||
| if (usb_tx_packet_count(CDC3_TX_ENDPOINT) < TX_PACKET_LIMIT) { | |||
| tx_noautoflush = 1; | |||
| tx_packet = usb_malloc(); | |||
| if (tx_packet) break; | |||
| tx_noautoflush = 0; | |||
| } | |||
| if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) { | |||
| transmit_previous_timeout = 1; | |||
| return -1; | |||
| } | |||
| yield(); | |||
| } | |||
| } | |||
| transmit_previous_timeout = 0; | |||
| len = CDC3_TX_SIZE - tx_packet->index; | |||
| if (len > size) len = size; | |||
| dest = tx_packet->buf + tx_packet->index; | |||
| tx_packet->index += len; | |||
| size -= len; | |||
| while (len-- > 0) *dest++ = *src++; | |||
| if (tx_packet->index >= CDC3_TX_SIZE) { | |||
| tx_packet->len = CDC3_TX_SIZE; | |||
| usb_tx(CDC3_TX_ENDPOINT, tx_packet); | |||
| tx_packet = NULL; | |||
| } | |||
| usb_cdc3_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; | |||
| } | |||
| tx_noautoflush = 0; | |||
| return ret; | |||
| } | |||
| int usb_serial3_write_buffer_free(void) | |||
| { | |||
| uint32_t len; | |||
| tx_noautoflush = 1; | |||
| if (!tx_packet) { | |||
| if (!usb_configuration || | |||
| usb_tx_packet_count(CDC3_TX_ENDPOINT) >= TX_PACKET_LIMIT || | |||
| (tx_packet = usb_malloc()) == NULL) { | |||
| tx_noautoflush = 0; | |||
| return 0; | |||
| } | |||
| } | |||
| len = CDC3_TX_SIZE - tx_packet->index; | |||
| // TODO: Perhaps we need "usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT" | |||
| // added here, so the SOF interrupt can't take away the available buffer | |||
| // space we just promised the user could write without blocking? | |||
| // But does this come with other performance downsides? Could it lead to | |||
| // buffer data never actually transmitting in some usage cases? More | |||
| // investigation is needed. | |||
| // https://github.com/PaulStoffregen/cores/issues/10#issuecomment-61514955 | |||
| tx_noautoflush = 0; | |||
| return len; | |||
| } | |||
| void usb_serial3_flush_output(void) | |||
| { | |||
| if (!usb_configuration) return; | |||
| tx_noautoflush = 1; | |||
| if (tx_packet) { | |||
| usb_cdc3_transmit_flush_timer = 0; | |||
| tx_packet->len = tx_packet->index; | |||
| usb_tx(CDC3_TX_ENDPOINT, tx_packet); | |||
| tx_packet = NULL; | |||
| } else { | |||
| usb_packet_t *tx = usb_malloc(); | |||
| if (tx) { | |||
| usb_cdc3_transmit_flush_timer = 0; | |||
| usb_tx(CDC3_TX_ENDPOINT, tx); | |||
| } else { | |||
| usb_cdc3_transmit_flush_timer = 1; | |||
| } | |||
| } | |||
| tx_noautoflush = 0; | |||
| } | |||
| void usb_serial3_flush_callback(void) | |||
| { | |||
| if (tx_noautoflush) return; | |||
| if (tx_packet) { | |||
| tx_packet->len = tx_packet->index; | |||
| usb_tx(CDC3_TX_ENDPOINT, tx_packet); | |||
| tx_packet = NULL; | |||
| } else { | |||
| usb_packet_t *tx = usb_malloc(); | |||
| if (tx) { | |||
| usb_tx(CDC3_TX_ENDPOINT, tx); | |||
| } else { | |||
| usb_cdc3_transmit_flush_timer = 1; | |||
| } | |||
| } | |||
| } | |||
| #endif // F_CPU | |||
| #endif // CDC3_STATUS_INTERFACE && CDC3_DATA_INTERFACE | |||
| @@ -0,0 +1,139 @@ | |||
| /* Teensyduino Core Library | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2017 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #ifndef USBserial3_h_ | |||
| #define USBserial3_h_ | |||
| #include "usb_desc.h" | |||
| #if defined(CDC3_STATUS_INTERFACE) && defined(CDC3_DATA_INTERFACE) | |||
| #include <inttypes.h> | |||
| #if F_CPU >= 20000000 | |||
| #include "core_pins.h" // for millis() | |||
| // C language implementation | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| int usb_serial3_getchar(void); | |||
| int usb_serial3_peekchar(void); | |||
| int usb_serial3_available(void); | |||
| int usb_serial3_read(void *buffer, uint32_t size); | |||
| void usb_serial3_flush_input(void); | |||
| int usb_serial3_putchar(uint8_t c); | |||
| int usb_serial3_write(const void *buffer, uint32_t size); | |||
| int usb_serial3_write_buffer_free(void); | |||
| void usb_serial3_flush_output(void); | |||
| void usb_serial3_flush_callback(void); | |||
| extern uint32_t usb_cdc3_line_coding[2]; | |||
| extern volatile uint32_t usb_cdc3_line_rtsdtr_millis; | |||
| extern volatile uint32_t systick_millis_count; | |||
| extern volatile uint8_t usb_cdc3_line_rtsdtr; | |||
| extern volatile uint8_t usb_cdc3_transmit_flush_timer; | |||
| extern volatile uint8_t usb_configuration; | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #ifndef USB_SERIAL_DTR | |||
| #define USB_SERIAL_DTR 0x01 | |||
| #endif | |||
| #ifndef USB_SERIAL_RTS | |||
| #define USB_SERIAL_RTS 0x02 | |||
| #endif | |||
| // C++ interface | |||
| #ifdef __cplusplus | |||
| #include "Stream.h" | |||
| class usb_serial3_class : public Stream | |||
| { | |||
| public: | |||
| constexpr usb_serial3_class() {} | |||
| void begin(long) { | |||
| //uint32_t millis_begin = systick_millis_count; | |||
| //disabled for now - causes more trouble than it solves? | |||
| //while (!(*this)) { | |||
| // wait up to 2.5 seconds for Arduino Serial Monitor | |||
| // Yes, this is a long time, but some Windows systems open | |||
| // the port very slowly. This wait allows programs for | |||
| // Arduino Uno to "just work" (without forcing a reboot when | |||
| // the port is opened), and when no PC is connected the user's | |||
| // sketch still gets to run normally after this wait time. | |||
| //if ((uint32_t)(systick_millis_count - millis_begin) > 2500) break; | |||
| //} | |||
| } | |||
| void end() { /* TODO: flush output and shut down USB port */ }; | |||
| virtual int available() { return usb_serial3_available(); } | |||
| virtual int read() { return usb_serial3_getchar(); } | |||
| virtual int peek() { return usb_serial3_peekchar(); } | |||
| virtual void flush() { usb_serial3_flush_output(); } // TODO: actually wait for data to leave USB... | |||
| virtual void clear(void) { usb_serial3_flush_input(); } | |||
| virtual size_t write(uint8_t c) { return usb_serial3_putchar(c); } | |||
| virtual size_t write(const uint8_t *buffer, size_t size) { return usb_serial3_write(buffer, size); } | |||
| size_t write(unsigned long n) { return write((uint8_t)n); } | |||
| size_t write(long n) { return write((uint8_t)n); } | |||
| size_t write(unsigned int n) { return write((uint8_t)n); } | |||
| size_t write(int n) { return write((uint8_t)n); } | |||
| virtual int availableForWrite() { return usb_serial3_write_buffer_free(); } | |||
| using Print::write; | |||
| void send_now(void) { usb_serial3_flush_output(); } | |||
| uint32_t baud(void) { return usb_cdc3_line_coding[0]; } | |||
| uint8_t stopbits(void) { uint8_t b = usb_cdc3_line_coding[1]; if (!b) b = 1; return b; } | |||
| uint8_t paritytype(void) { return usb_cdc3_line_coding[1] >> 8; } // 0=none, 1=odd, 2=even | |||
| uint8_t numbits(void) { return usb_cdc3_line_coding[1] >> 16; } | |||
| uint8_t dtr(void) { return (usb_cdc3_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; } | |||
| uint8_t rts(void) { return (usb_cdc3_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; } | |||
| operator bool() { return usb_configuration && (usb_cdc3_line_rtsdtr & USB_SERIAL_DTR) && | |||
| ((uint32_t)(systick_millis_count - usb_cdc3_line_rtsdtr_millis) >= 15); | |||
| } | |||
| size_t readBytes(char *buffer, size_t length) { | |||
| size_t count=0; | |||
| unsigned long startMillis = millis(); | |||
| do { | |||
| count += usb_serial3_read(buffer + count, length - count); | |||
| if (count >= length) return count; | |||
| } while(millis() - startMillis < _timeout); | |||
| setReadError(); | |||
| return count; | |||
| } | |||
| }; | |||
| extern usb_serial3_class SerialUSB2; | |||
| extern void serialEventUSB2(void); | |||
| #endif // __cplusplus | |||
| #endif // F_CPU | |||
| #endif // CDC3_STATUS_INTERFACE && CDC3_DATA_INTERFACE | |||
| #endif // USBserial3_h_ | |||
| @@ -86,12 +86,14 @@ void usb_touchscreen_release(uint8_t finger) | |||
| // 5: Y msb | |||
| // 6: scan time lsb | |||
| // 7: scan time msb | |||
| // 8: contact count | |||
| // Called by the start-of-frame interrupt. | |||
| // | |||
| void usb_touchscreen_update_callback(void) | |||
| { | |||
| uint8_t contact_count = 0; | |||
| if (scan_index == 0) { | |||
| if (usb_tx_packet_count(MULTITOUCH_ENDPOINT) > 1) { | |||
| // wait to begin another scan if if more than | |||
| @@ -100,7 +102,16 @@ void usb_touchscreen_update_callback(void) | |||
| } | |||
| scan_timestamp = millis() * 10; | |||
| scan_count = 0; | |||
| // Get the contact count (usage 0x54) | |||
| // Only set this value on first contact | |||
| // Subsequent concurrent contacts should report 0 | |||
| for (uint8_t i = 0; i < MULTITOUCH_FINGERS; i++) | |||
| { | |||
| if (contactid[i]) contact_count++; | |||
| } | |||
| } | |||
| while (scan_index < MULTITOUCH_FINGERS) { | |||
| uint32_t press = pressure[scan_index]; | |||
| uint32_t id = contactid[scan_index]; | |||
| @@ -123,7 +134,8 @@ void usb_touchscreen_update_callback(void) | |||
| *(tx_packet->buf + 5) = ypos[scan_index] >> 8; | |||
| *(tx_packet->buf + 6) = scan_timestamp; | |||
| *(tx_packet->buf + 7) = scan_timestamp >> 8; | |||
| tx_packet->len = 8; | |||
| *(tx_packet->buf + 8) = contact_count; | |||
| tx_packet->len = 9; | |||
| usb_tx(MULTITOUCH_ENDPOINT, tx_packet); | |||
| scan_index++; | |||
| return; | |||
| @@ -41,8 +41,8 @@ | |||
| #ifdef ENDPOINT_UNUSED | |||
| #undef ENDPOINT_UNUSED | |||
| #endif | |||
| #ifdef ENDPOINT_TRANSIMIT_ONLY | |||
| #undef ENDPOINT_TRANSIMIT_ONLY | |||
| #ifdef ENDPOINT_TRANSMIT_ONLY | |||
| #undef ENDPOINT_TRANSMIT_ONLY | |||
| #endif | |||
| #ifdef ENDPOINT_RECEIVE_ONLY | |||
| #undef ENDPOINT_RECEIVE_ONLY | |||
| @@ -110,6 +110,54 @@ | |||
| #ifdef CDC_TX_SIZE | |||
| #undef CDC_TX_SIZE | |||
| #endif | |||
| #ifdef CDC2_STATUS_INTERFACE | |||
| #undef CDC2_STATUS_INTERFACE | |||
| #endif | |||
| #ifdef CDC2_DATA_INTERFACE | |||
| #undef CDC2_DATA_INTERFACE | |||
| #endif | |||
| #ifdef CDC2_ACM_ENDPOINT | |||
| #undef CDC2_ACM_ENDPOINT | |||
| #endif | |||
| #ifdef CDC2_RX_ENDPOINT | |||
| #undef CDC2_RX_ENDPOINT | |||
| #endif | |||
| #ifdef CDC2_TX_ENDPOINT | |||
| #undef CDC2_TX_ENDPOINT | |||
| #endif | |||
| #ifdef CDC2_ACM_SIZE | |||
| #undef CDC2_ACM_SIZE | |||
| #endif | |||
| #ifdef CDC2_RX_SIZE | |||
| #undef CDC2_RX_SIZE | |||
| #endif | |||
| #ifdef CDC2_TX_SIZE | |||
| #undef CDC2_TX_SIZE | |||
| #endif | |||
| #ifdef CDC3_STATUS_INTERFACE | |||
| #undef CDC3_STATUS_INTERFACE | |||
| #endif | |||
| #ifdef CDC3_DATA_INTERFACE | |||
| #undef CDC3_DATA_INTERFACE | |||
| #endif | |||
| #ifdef CDC3_ACM_ENDPOINT | |||
| #undef CDC3_ACM_ENDPOINT | |||
| #endif | |||
| #ifdef CDC3_RX_ENDPOINT | |||
| #undef CDC3_RX_ENDPOINT | |||
| #endif | |||
| #ifdef CDC3_TX_ENDPOINT | |||
| #undef CDC3_TX_ENDPOINT | |||
| #endif | |||
| #ifdef CDC3_ACM_SIZE | |||
| #undef CDC3_ACM_SIZE | |||
| #endif | |||
| #ifdef CDC3_RX_SIZE | |||
| #undef CDC3_RX_SIZE | |||
| #endif | |||
| #ifdef CDC3_TX_SIZE | |||
| #undef CDC3_TX_SIZE | |||
| #endif | |||
| #ifdef SEREMU_INTERFACE | |||
| #undef SEREMU_INTERFACE | |||
| #endif | |||
| @@ -33,6 +33,7 @@ | |||
| #include <stdint.h> | |||
| #include <stdlib.h> | |||
| #include <stdbool.h> | |||
| #include "binary.h" | |||
| #include "core_id.h" | |||
| #include "core_pins.h" | |||
| @@ -48,15 +49,35 @@ long map(T _x, A _in_min, B _in_max, C _out_min, D _out_max, typename std::enabl | |||
| { | |||
| long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max; | |||
| // Arduino's traditional algorithm | |||
| //return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |||
| #if 0 | |||
| return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |||
| #endif | |||
| #if 0 | |||
| // st42's suggestion: https://github.com/arduino/Arduino/issues/2466#issuecomment-69873889 | |||
| // more conversation: | |||
| // https://forum.pjrc.com/threads/44503-map()-function-improvements | |||
| if ((in_max - in_min) > (out_max - out_min)) { | |||
| return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min; | |||
| } else { | |||
| return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |||
| } | |||
| #endif | |||
| long in_range = in_max - in_min; | |||
| long out_range = out_max - out_min; | |||
| if (in_range == 0) return out_min + out_range / 2; | |||
| long num = (x - in_min) * out_range; | |||
| if (out_range >= 0) { | |||
| num += in_range / 2; | |||
| } else { | |||
| num -= in_range / 2; | |||
| } | |||
| long result = num / in_range + out_min; | |||
| if (out_range >= 0) { | |||
| if (in_range * num < 0) return result - 1; | |||
| } else { | |||
| if (in_range * num >= 0) return result + 1; | |||
| } | |||
| return result; | |||
| // more conversation: | |||
| // https://forum.pjrc.com/threads/44503-map()-function-improvements | |||
| } | |||
| // when the input is a float or double, do all math using the input's type | |||
| template <class T, class A, class B, class C, class D> | |||
| @@ -64,7 +85,7 @@ T map(T x, A in_min, B in_max, C out_min, D out_max, typename std::enable_if<std | |||
| { | |||
| return (x - (T)in_min) * ((T)out_max - (T)out_min) / ((T)in_max - (T)in_min) + (T)out_min; | |||
| } | |||
| #include <algorithm> // c++ min, max | |||
| //#include <algorithm> // this isn't really needed, is it? (slows down compiling) | |||
| #include <utility> | |||
| // https://forum.pjrc.com/threads/44596-Teensyduino-1-37-Beta-2-(Arduino-1-8-3-support)?p=145150&viewfull=1#post145150 | |||
| template<class A, class B> | |||
| @@ -190,8 +211,6 @@ void loop(void); | |||
| typedef bool boolean; | |||
| #else | |||
| typedef uint8_t boolean; | |||
| #define false 0 | |||
| #define true (!false) | |||
| #endif | |||
| #endif | |||
| @@ -28,32 +28,56 @@ | |||
| * SOFTWARE. | |||
| */ | |||
| #include "core_pins.h" | |||
| #include "HardwareSerial.h" | |||
| #include "usb_serial.h" | |||
| #include "usb_seremu.h" | |||
| #include <Arduino.h> | |||
| #include "EventResponder.h" | |||
| #ifdef USB_TRIPLE_SERIAL | |||
| uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL | YIELD_CHECK_USB_SERIALUSB1 | YIELD_CHECK_USB_SERIALUSB2; // default to check USB. | |||
| extern const uint8_t _serialEventUSB2_default; | |||
| extern const uint8_t _serialEventUSB1_default; | |||
| #elif defined(USB_DUAL_SERIAL) | |||
| uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL | YIELD_CHECK_USB_SERIALUSB1; // default to check USB. | |||
| extern const uint8_t _serialEventUSB1_default; | |||
| #else | |||
| uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL; // default to check USB. | |||
| #endif | |||
| extern const uint8_t _serialEvent_default; | |||
| void yield(void) __attribute__ ((weak)); | |||
| void yield(void) | |||
| { | |||
| static uint8_t running=0; | |||
| if (!yield_active_check_flags) return; // nothing to do | |||
| if (running) return; // TODO: does this need to be atomic? | |||
| running = 1; | |||
| if (Serial.available()) serialEvent(); | |||
| if (Serial1.available()) serialEvent1(); | |||
| if (Serial2.available()) serialEvent2(); | |||
| if (Serial3.available()) serialEvent3(); | |||
| #ifdef HAS_KINETISK_UART3 | |||
| if (Serial4.available()) serialEvent4(); | |||
| #endif | |||
| #ifdef HAS_KINETISK_UART4 | |||
| if (Serial5.available()) serialEvent5(); | |||
| // USB Serail - Add hack to minimize impact... | |||
| if (yield_active_check_flags & YIELD_CHECK_USB_SERIAL) { | |||
| if (Serial.available()) serialEvent(); | |||
| if (_serialEvent_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIAL; | |||
| } | |||
| // Current workaround until integrate with EventResponder. | |||
| #if defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL) | |||
| if (yield_active_check_flags & YIELD_CHECK_USB_SERIALUSB1) { | |||
| if (SerialUSB1.available()) serialEventUSB1(); | |||
| if (_serialEventUSB1_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIALUSB1; | |||
| } | |||
| #endif | |||
| #if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | |||
| if (Serial6.available()) serialEvent6(); | |||
| #ifdef USB_TRIPLE_SERIAL | |||
| if (yield_active_check_flags & YIELD_CHECK_USB_SERIALUSB2) { | |||
| if (SerialUSB2.available()) serialEventUSB2(); | |||
| if (_serialEventUSB2_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIALUSB2; | |||
| } | |||
| #endif | |||
| if (yield_active_check_flags & YIELD_CHECK_HARDWARE_SERIAL) { | |||
| HardwareSerial::processSerialEventsList(); | |||
| } | |||
| running = 0; | |||
| EventResponder::runFromYield(); | |||
| if (yield_active_check_flags & YIELD_CHECK_EVENT_RESPONDER) EventResponder::runFromYield(); | |||
| }; | |||
| @@ -0,0 +1,9 @@ | |||
| // This header file is in the public domain. | |||
| #ifndef Arduino_h | |||
| #define Arduino_h | |||
| #include "WProgram.h" | |||
| #include "pins_arduino.h" | |||
| #endif | |||
| @@ -0,0 +1,337 @@ | |||
| /* Teensyduino Core Library | |||
| * http://www.pjrc.com/teensy/ | |||
| * Copyright (c) 2017 PJRC.COM, LLC. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining | |||
| * a copy of this software and associated documentation files (the | |||
| * "Software"), to deal in the Software without restriction, including | |||
| * without limitation the rights to use, copy, modify, merge, publish, | |||
| * distribute, sublicense, and/or sell copies of the Software, and to | |||
| * permit persons to whom the Software is furnished to do so, subject to | |||
| * the following conditions: | |||
| * | |||
| * 1. The above copyright notice and this permission notice shall be | |||
| * included in all copies or substantial portions of the Software. | |||
| * | |||
| * 2. If the Software is incorporated into a build system that allows | |||
| * selection among a list of target devices, then similar target | |||
| * devices manufactured by PJRC.COM must be included in the list of | |||
| * target devices and selectable in the same manner. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| * SOFTWARE. | |||
| */ | |||
| #include <Arduino.h> | |||
| #include "AudioStream.h" | |||
| #if defined(__IMXRT1062__) | |||
| #define MAX_AUDIO_MEMORY 229376 | |||
| #endif | |||
| #define NUM_MASKS (((MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2) + 31) / 32) | |||
| audio_block_t * AudioStream::memory_pool; | |||
| uint32_t AudioStream::memory_pool_available_mask[NUM_MASKS]; | |||
| uint16_t AudioStream::memory_pool_first_mask; | |||
| uint16_t AudioStream::cpu_cycles_total = 0; | |||
| uint16_t AudioStream::cpu_cycles_total_max = 0; | |||
| uint16_t AudioStream::memory_used = 0; | |||
| uint16_t AudioStream::memory_used_max = 0; | |||
| void software_isr(void); | |||
| // Set up the pool of audio data blocks | |||
| // placing them all onto the free list | |||
| FLASHMEM void AudioStream::initialize_memory(audio_block_t *data, unsigned int num) | |||
| { | |||
| unsigned int i; | |||
| unsigned int maxnum = MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2; | |||
| //Serial.println("AudioStream initialize_memory"); | |||
| //delay(10); | |||
| if (num > maxnum) num = maxnum; | |||
| __disable_irq(); | |||
| memory_pool = data; | |||
| memory_pool_first_mask = 0; | |||
| for (i=0; i < NUM_MASKS; i++) { | |||
| memory_pool_available_mask[i] = 0; | |||
| } | |||
| for (i=0; i < num; i++) { | |||
| memory_pool_available_mask[i >> 5] |= (1 << (i & 0x1F)); | |||
| } | |||
| for (i=0; i < num; i++) { | |||
| data[i].memory_pool_index = i; | |||
| } | |||
| __enable_irq(); | |||
| } | |||
| // Allocate 1 audio data block. If successful | |||
| // the caller is the only owner of this new block | |||
| audio_block_t * AudioStream::allocate(void) | |||
| { | |||
| uint32_t n, index, avail; | |||
| uint32_t *p, *end; | |||
| audio_block_t *block; | |||
| uint32_t used; | |||
| p = memory_pool_available_mask; | |||
| end = p + NUM_MASKS; | |||
| __disable_irq(); | |||
| index = memory_pool_first_mask; | |||
| p += index; | |||
| while (1) { | |||
| if (p >= end) { | |||
| __enable_irq(); | |||
| //Serial.println("alloc:null"); | |||
| return NULL; | |||
| } | |||
| avail = *p; | |||
| if (avail) break; | |||
| index++; | |||
| p++; | |||
| } | |||
| n = __builtin_clz(avail); | |||
| avail &= ~(0x80000000 >> n); | |||
| *p = avail; | |||
| if (!avail) index++; | |||
| memory_pool_first_mask = index; | |||
| used = memory_used + 1; | |||
| memory_used = used; | |||
| __enable_irq(); | |||
| index = p - memory_pool_available_mask; | |||
| block = memory_pool + ((index << 5) + (31 - n)); | |||
| block->ref_count = 1; | |||
| if (used > memory_used_max) memory_used_max = used; | |||
| //Serial.print("alloc:"); | |||
| //Serial.println((uint32_t)block, HEX); | |||
| return block; | |||
| } | |||
| // Release ownership of a data block. If no | |||
| // other streams have ownership, the block is | |||
| // returned to the free pool | |||
| void AudioStream::release(audio_block_t *block) | |||
| { | |||
| //if (block == NULL) return; | |||
| uint32_t mask = (0x80000000 >> (31 - (block->memory_pool_index & 0x1F))); | |||
| uint32_t index = block->memory_pool_index >> 5; | |||
| __disable_irq(); | |||
| if (block->ref_count > 1) { | |||
| block->ref_count--; | |||
| } else { | |||
| //Serial.print("reles:"); | |||
| //Serial.println((uint32_t)block, HEX); | |||
| memory_pool_available_mask[index] |= mask; | |||
| if (index < memory_pool_first_mask) memory_pool_first_mask = index; | |||
| memory_used--; | |||
| } | |||
| __enable_irq(); | |||
| } | |||
| // Transmit an audio data block | |||
| // to all streams that connect to an output. The block | |||
| // becomes owned by all the recepients, but also is still | |||
| // owned by this object. Normally, a block must be released | |||
| // by the caller after it's transmitted. This allows the | |||
| // caller to transmit to same block to more than 1 output, | |||
| // and then release it once after all transmit calls. | |||
| void AudioStream::transmit(audio_block_t *block, unsigned char index) | |||
| { | |||
| for (AudioConnection *c = destination_list; c != NULL; c = c->next_dest) { | |||
| if (c->src_index == index) { | |||
| if (c->dst.inputQueue[c->dest_index] == NULL) { | |||
| c->dst.inputQueue[c->dest_index] = block; | |||
| block->ref_count++; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Receive block from an input. The block's data | |||
| // may be shared with other streams, so it must not be written | |||
| audio_block_t * AudioStream::receiveReadOnly(unsigned int index) | |||
| { | |||
| audio_block_t *in; | |||
| if (index >= num_inputs) return NULL; | |||
| in = inputQueue[index]; | |||
| inputQueue[index] = NULL; | |||
| return in; | |||
| } | |||
| // Receive block from an input. The block will not | |||
| // be shared, so its contents may be changed. | |||
| audio_block_t * AudioStream::receiveWritable(unsigned int index) | |||
| { | |||
| audio_block_t *in, *p; | |||
| if (index >= num_inputs) return NULL; | |||
| in = inputQueue[index]; | |||
| inputQueue[index] = NULL; | |||
| if (in && in->ref_count > 1) { | |||
| p = allocate(); | |||
| if (p) memcpy(p->data, in->data, sizeof(p->data)); | |||
| in->ref_count--; | |||
| in = p; | |||
| } | |||
| return in; | |||
| } | |||
| void AudioConnection::connect(void) | |||
| { | |||
| AudioConnection *p; | |||
| if (isConnected) return; | |||
| if (dest_index > dst.num_inputs) return; | |||
| __disable_irq(); | |||
| p = src.destination_list; | |||
| if (p == NULL) { | |||
| src.destination_list = this; | |||
| } else { | |||
| while (p->next_dest) { | |||
| if (&p->src == &this->src && &p->dst == &this->dst | |||
| && p->src_index == this->src_index && p->dest_index == this->dest_index) { | |||
| //Source and destination already connected through another connection, abort | |||
| __enable_irq(); | |||
| return; | |||
| } | |||
| p = p->next_dest; | |||
| } | |||
| p->next_dest = this; | |||
| } | |||
| this->next_dest = NULL; | |||
| src.numConnections++; | |||
| src.active = true; | |||
| dst.numConnections++; | |||
| dst.active = true; | |||
| isConnected = true; | |||
| __enable_irq(); | |||
| } | |||
| void AudioConnection::disconnect(void) | |||
| { | |||
| AudioConnection *p; | |||
| if (!isConnected) return; | |||
| if (dest_index > dst.num_inputs) return; | |||
| __disable_irq(); | |||
| // Remove destination from source list | |||
| p = src.destination_list; | |||
| if (p == NULL) { | |||
| //>>> PAH re-enable the IRQ | |||
| __enable_irq(); | |||
| return; | |||
| } else if (p == this) { | |||
| if (p->next_dest) { | |||
| src.destination_list = next_dest; | |||
| } else { | |||
| src.destination_list = NULL; | |||
| } | |||
| } else { | |||
| while (p) { | |||
| if (p == this) { | |||
| if (p->next_dest) { | |||
| p = next_dest; | |||
| break; | |||
| } else { | |||
| p = NULL; | |||
| break; | |||
| } | |||
| } | |||
| p = p->next_dest; | |||
| } | |||
| } | |||
| //>>> PAH release the audio buffer properly | |||
| //Remove possible pending src block from destination | |||
| if(dst.inputQueue[dest_index] != NULL) { | |||
| AudioStream::release(dst.inputQueue[dest_index]); | |||
| // release() re-enables the IRQ. Need it to be disabled a little longer | |||
| __disable_irq(); | |||
| dst.inputQueue[dest_index] = NULL; | |||
| } | |||
| //Check if the disconnected AudioStream objects should still be active | |||
| src.numConnections--; | |||
| if (src.numConnections == 0) { | |||
| src.active = false; | |||
| } | |||
| dst.numConnections--; | |||
| if (dst.numConnections == 0) { | |||
| dst.active = false; | |||
| } | |||
| isConnected = false; | |||
| __enable_irq(); | |||
| } | |||
| // When an object has taken responsibility for calling update_all() | |||
| // at each block interval (approx 2.9ms), this variable is set to | |||
| // true. Objects that are capable of calling update_all(), typically | |||
| // input and output based on interrupts, must check this variable in | |||
| // their constructors. | |||
| bool AudioStream::update_scheduled = false; | |||
| bool AudioStream::update_setup(void) | |||
| { | |||
| if (update_scheduled) return false; | |||
| attachInterruptVector(IRQ_SOFTWARE, software_isr); | |||
| NVIC_SET_PRIORITY(IRQ_SOFTWARE, 208); // 255 = lowest priority | |||
| NVIC_ENABLE_IRQ(IRQ_SOFTWARE); | |||
| update_scheduled = true; | |||
| return true; | |||
| } | |||
| void AudioStream::update_stop(void) | |||
| { | |||
| NVIC_DISABLE_IRQ(IRQ_SOFTWARE); | |||
| update_scheduled = false; | |||
| } | |||
| AudioStream * AudioStream::first_update = NULL; | |||
| void software_isr(void) // AudioStream::update_all() | |||
| { | |||
| AudioStream *p; | |||
| uint32_t totalcycles = ARM_DWT_CYCCNT; | |||
| //digitalWriteFast(2, HIGH); | |||
| for (p = AudioStream::first_update; p; p = p->next_update) { | |||
| if (p->active) { | |||
| uint32_t cycles = ARM_DWT_CYCCNT; | |||
| p->update(); | |||
| // TODO: traverse inputQueueArray and release | |||
| // any input blocks that weren't consumed? | |||
| cycles = (ARM_DWT_CYCCNT - cycles) >> 6; | |||
| p->cpu_cycles = cycles; | |||
| if (cycles > p->cpu_cycles_max) p->cpu_cycles_max = cycles; | |||
| } | |||
| } | |||
| //digitalWriteFast(2, LOW); | |||
| totalcycles = (ARM_DWT_CYCCNT - totalcycles) >> 6; | |||
| AudioStream::cpu_cycles_total = totalcycles; | |||
| if (totalcycles > AudioStream::cpu_cycles_total_max) | |||
| AudioStream::cpu_cycles_total_max = totalcycles; | |||
| asm("DSB"); | |||
| } | |||