| 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: | The latest stable version of Teensy's core library is always available in the Teensyduino installer, at this page: | ||||
| noexcept LITERAL1 | noexcept LITERAL1 | ||||
| static_assert LITERAL1 | static_assert LITERAL1 | ||||
| thread_local LITERAL1 | thread_local LITERAL1 | ||||
| size_t LITERAL1 | |||||
| # teensy specific functions | # teensy specific functions | ||||
| elapsedMillis LITERAL1 | elapsedMillis LITERAL1 | ||||
| printf KEYWORD2 | printf KEYWORD2 | ||||
| digitalWriteFast KEYWORD2 | digitalWriteFast KEYWORD2 | ||||
| digitalReadFast KEYWORD2 | digitalReadFast KEYWORD2 | ||||
| digitalToggleFast KEYWORD2 | |||||
| digitalToggle KEYWORD2 | |||||
| transmitterEnable KEYWORD2 | transmitterEnable KEYWORD2 | ||||
| attachRts KEYWORD2 | attachRts KEYWORD2 | ||||
| attachCts KEYWORD2 | attachCts KEYWORD2 | ||||
| PROGMEM LITERAL1 | PROGMEM LITERAL1 | ||||
| FLASHMEM LITERAL1 | |||||
| DMAMEM LITERAL1 | DMAMEM LITERAL1 | ||||
| EXTMEM LITERAL1 | |||||
| FASTRUN LITERAL1 | FASTRUN LITERAL1 | ||||
| Serial4 KEYWORD1 | Serial4 KEYWORD1 | ||||
| Serial5 KEYWORD1 | Serial5 KEYWORD1 | ||||
| Serial6 KEYWORD1 | Serial6 KEYWORD1 | ||||
| Serial7 KEYWORD1 | |||||
| Serial8 KEYWORD1 | |||||
| SerialUSB1 KEYWORD1 | |||||
| SerialUSB2 KEYWORD1 | |||||
| setRX KEYWORD2 | setRX KEYWORD2 | ||||
| setTX KEYWORD2 | setTX KEYWORD2 | ||||
| write9bit KEYWORD2 | write9bit KEYWORD2 | ||||
| addMemoryForRead KEYWORD2 | |||||
| addMemoryForWrite KEYWORD2 | |||||
| clear KEYWORD2 | clear KEYWORD2 | ||||
| EventResponder LITERAL1 | EventResponder LITERAL1 | ||||
| EventResponderRef LITERAL1 | EventResponderRef LITERAL1 | ||||
| waitForEvent KEYWORD2 | waitForEvent KEYWORD2 | ||||
| MillisTimer LITERAL1 | MillisTimer LITERAL1 | ||||
| beginRepeating KEYWORD2 | 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 | # Arduino constants | ||||
| A0 LITERAL1 | A0 LITERAL1 | ||||
| digitalPinHasPWM KEYWORD2 | digitalPinHasPWM KEYWORD2 | ||||
| NOT_AN_INTERRUPT LITERAL1 | NOT_AN_INTERRUPT LITERAL1 | ||||
| digitalPinToInterrupt KEYWORD2 | digitalPinToInterrupt KEYWORD2 | ||||
| FILE_READ LITERAL1 | |||||
| FILE_WRITE LITERAL1 | |||||
| FILE_WRITE_BEGIN LITERAL1 | |||||
| # HardwareSerial modes | # HardwareSerial modes | ||||
| SERIAL_7E1 LITERAL1 | SERIAL_7E1 LITERAL1 | ||||
| FlightSimInteger KEYWORD2 | FlightSimInteger KEYWORD2 | ||||
| FlightSimFloat KEYWORD2 | FlightSimFloat KEYWORD2 | ||||
| FlightSimElapsedFrames KEYWORD2 | FlightSimElapsedFrames KEYWORD2 | ||||
| FlightSimData KEYWORD2 | |||||
| FlightSimEvent KEYWORD2 | |||||
| onChange KEYWORD2 | onChange KEYWORD2 | ||||
| update KEYWORD2 | update KEYWORD2 | ||||
| isEnabled KEYWORD2 | isEnabled KEYWORD2 |
| /* 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 |
| return write(p, sizeof(buf) - (p - buf)); | 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) | size_t Print::printFloat(double number, uint8_t digits) | ||||
| { | { | ||||
| uint8_t sign=0; | uint8_t sign=0; |
| // BYTE was defined in very old versions of Arduino | // BYTE was defined in very old versions of Arduino | ||||
| // maybe this now causes more trouble than it's worth? | // maybe this now causes more trouble than it's worth? | ||||
| #ifndef BYTE | |||||
| #define BYTE 0 | |||||
| #endif | |||||
| //#ifndef BYTE | |||||
| //#define BYTE 0 | |||||
| //#endif | |||||
| class __FlashStringHelper; | class __FlashStringHelper; | ||||
| size_t print(unsigned int n) { return printNumber(n, 0, 10); } | size_t print(unsigned int n) { return printNumber(n, 0, 10); } | ||||
| size_t print(long n); | size_t print(long n); | ||||
| size_t print(unsigned long n) { return printNumber(n, 0, 10); } | 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(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(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(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(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(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(double n, int digits = 2) { return printFloat(n, digits); } | ||||
| size_t print(const Printable &obj) { return obj.printTo(*this); } | size_t print(const Printable &obj) { return obj.printTo(*this); } | ||||
| size_t println(unsigned int n) { return print(n) + println(); } | size_t println(unsigned int n) { return print(n) + println(); } | ||||
| size_t println(long 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(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(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(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(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(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(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(double n, int digits = 2) { return print(n, digits) + println(); } | ||||
| size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | ||||
| if (base == 2) return printNumberBin(n); | if (base == 2) return printNumberBin(n); | ||||
| return printNumberAny(n, base); | return printNumberAny(n, base); | ||||
| } | } | ||||
| size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||||
| size_t printFloat(double n, uint8_t digits); | size_t printFloat(double n, uint8_t digits); | ||||
| }; | }; | ||||
| public: | 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 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 | virtual void stop() =0; // Finish with the UDP socket | ||||
| // Sending UDP packets | // Sending UDP packets |
| } | } | ||||
| } | } | ||||
| 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 void _init_Teensyduino_internal_(void); | ||||
| extern int analogRead(uint8_t); | extern int analogRead(uint8_t); | ||||
| } | } | ||||
| 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 | #ifdef __cplusplus |
| #define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | ||||
| #define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & |
| void * | void * | ||||
| malloc(size_t len) | malloc(size_t len) | ||||
| { | { | ||||
| struct __freelist *fp1, *fp2, *sfp1, *sfp2; | |||||
| struct __freelist *fp1, *fp2, *sfp1=NULL, *sfp2=NULL; | |||||
| char *cp; | char *cp; | ||||
| size_t s, avail; | size_t s, avail; | ||||
| #define NUM_DIGITAL_PINS CORE_NUM_TOTAL_PINS | #define NUM_DIGITAL_PINS CORE_NUM_TOTAL_PINS | ||||
| #define NUM_ANALOG_INPUTS CORE_NUM_ANALOG | #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 | // This allows CapSense to work. Do any libraries | ||||
| // depend on these to be zero? | // depend on these to be zero? |
| #include <avr/io.h> | #include <avr/io.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <stdbool.h> | |||||
| #include <math.h> | #include <math.h> | ||||
| #include "binary.h" | #include "binary.h" | ||||
| #include "core_id.h" | #include "core_id.h" | ||||
| extern "C"{ | extern "C"{ | ||||
| #endif | #endif | ||||
| #define true 1 | |||||
| #define false 0 | |||||
| #define PI 3.1415926535897932384626433832795 | #define PI 3.1415926535897932384626433832795 | ||||
| #define HALF_PI 1.5707963267948966192313216916398 | #define HALF_PI 1.5707963267948966192313216916398 | ||||
| #define TWO_PI 6.283185307179586476925286766559 | #define TWO_PI 6.283185307179586476925286766559 | ||||
| #define bit(b) (1UL << (b)) | #define bit(b) (1UL << (b)) | ||||
| typedef uint8_t boolean; | |||||
| typedef bool boolean; | |||||
| typedef uint8_t byte; | typedef uint8_t byte; | ||||
| unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); | unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); |
| // This header file is in the public domain. | // This header file is in the public domain. | ||||
| #ifndef Arduino_h | |||||
| #define Arduino_h | |||||
| #include "WProgram.h" | #include "WProgram.h" | ||||
| #include "pins_arduino.h" | #include "pins_arduino.h" | ||||
| #endif |
| */ | */ | ||||
| #include <string.h> // for memcpy | |||||
| #include "AudioStream.h" | |||||
| #include <Arduino.h> | #include <Arduino.h> | ||||
| #include "AudioStream.h" | |||||
| #if defined(__MKL26Z64__) | #if defined(__MKL26Z64__) | ||||
| #define MAX_AUDIO_MEMORY 6144 | #define MAX_AUDIO_MEMORY 6144 | ||||
| // Remove destination from source list | // Remove destination from source list | ||||
| p = src.destination_list; | p = src.destination_list; | ||||
| if (p == NULL) { | if (p == NULL) { | ||||
| //>>> PAH re-enable the IRQ | |||||
| __enable_irq(); | |||||
| return; | return; | ||||
| } else if (p == this) { | } else if (p == this) { | ||||
| if (p->next_dest) { | if (p->next_dest) { | ||||
| p = p->next_dest; | p = p->next_dest; | ||||
| } | } | ||||
| } | } | ||||
| //>>> PAH release the audio buffer properly | |||||
| //Remove possible pending src block from destination | //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 | //Check if the disconnected AudioStream objects should still be active | ||||
| src.numConnections--; | src.numConnections--; | ||||
| { | { | ||||
| AudioStream *p; | AudioStream *p; | ||||
| #if defined(KINETISK) | |||||
| ARM_DEMCR |= ARM_DEMCR_TRCENA; | ARM_DEMCR |= ARM_DEMCR_TRCENA; | ||||
| ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; | ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; | ||||
| uint32_t totalcycles = ARM_DWT_CYCCNT; | uint32_t totalcycles = ARM_DWT_CYCCNT; | ||||
| #elif defined(KINETISL) | |||||
| uint32_t totalcycles = micros(); | |||||
| #endif | |||||
| //digitalWriteFast(2, HIGH); | //digitalWriteFast(2, HIGH); | ||||
| for (p = AudioStream::first_update; p; p = p->next_update) { | for (p = AudioStream::first_update; p; p = p->next_update) { | ||||
| if (p->active) { | if (p->active) { | ||||
| } | } | ||||
| } | } | ||||
| //digitalWriteFast(2, LOW); | //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; | AudioStream::cpu_cycles_total = totalcycles; | ||||
| if (totalcycles > AudioStream::cpu_cycles_total_max) | if (totalcycles > AudioStream::cpu_cycles_total_max) | ||||
| AudioStream::cpu_cycles_total_max = totalcycles; | AudioStream::cpu_cycles_total_max = totalcycles; |
| #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | #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 | #define AUDIO_SAMPLE_RATE_EXACT 44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256 | ||||
| #elif defined(__MKL26Z64__) | #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 | ||||
| #endif | #endif | ||||
| AudioStream::initialize_memory(data, num); \ | 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)) | #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 AudioProcessorUsage() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total)) | ||||
| #define AudioProcessorUsageMax() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total_max)) | #define AudioProcessorUsageMax() (CYCLE_COUNTER_APPROX_PERCENT(AudioStream::cpu_cycles_total_max)) |
| DMABaseClass() {} | DMABaseClass() {} | ||||
| static inline void copy_tcd(TCD_t *dst, const TCD_t *src) { | static inline void copy_tcd(TCD_t *dst, const TCD_t *src) { | ||||
| dst->CSR = 0; | |||||
| const uint32_t *p = (const uint32_t *)src; | const uint32_t *p = (const uint32_t *)src; | ||||
| uint32_t *q = (uint32_t *)dst; | uint32_t *q = (uint32_t *)dst; | ||||
| uint32_t t1, t2, t3, t4; | uint32_t t1, t2, t3, t4; | ||||
| NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | 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) { | void detachInterrupt(void) { | ||||
| NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | ||||
| } | } | ||||
| void transferSize(unsigned int len) { | void transferSize(unsigned int len) { | ||||
| uint32_t dcr = CFG->DCR & 0xF0C8FFFF; | uint32_t dcr = CFG->DCR & 0xF0C8FFFF; | ||||
| if (len == 4) { | 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) { | } 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 { | } else { | ||||
| CFG->DCR = dcr | DMA_DCR_DSIZE(1) | DMA_DCR_DSIZE(1); | |||||
| CFG->DCR = dcr | DMA_DCR_SSIZE(1) | DMA_DCR_DSIZE(1); | |||||
| } | } | ||||
| } | } | ||||
| _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; | ||||
| NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); | 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) { | void detachInterrupt(void) { | ||||
| NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel); | ||||
| } | } |
| * https://forum.pjrc.com/threads/44723-Arduino-Events | * https://forum.pjrc.com/threads/44723-Arduino-Events | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "EventResponder.h" | #include "EventResponder.h" | ||||
| EventResponder * EventResponder::firstYield = nullptr; | EventResponder * EventResponder::firstYield = nullptr; | ||||
| bool EventResponder::runningFromYield = false; | bool EventResponder::runningFromYield = false; | ||||
| // TODO: interrupt disable/enable needed in many places!!! | // 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() | void EventResponder::triggerEventNotImmediate() | ||||
| { | { | ||||
| // with libraries using mid-to-high priority interrupts. | // with libraries using mid-to-high priority interrupts. | ||||
| extern "C" volatile uint32_t systick_millis_count; | extern "C" volatile uint32_t systick_millis_count; | ||||
| void systick_isr(void) | void systick_isr(void) | ||||
| { | |||||
| systick_millis_count++; | |||||
| } | |||||
| extern "C" void systick_isr_with_timer_events(void) | |||||
| { | { | ||||
| systick_millis_count++; | systick_millis_count++; | ||||
| MillisTimer::runFromTimer(); | MillisTimer::runFromTimer(); | ||||
| } | } | ||||
| * your function is called only one time, based on the last trigger | * your function is called only one time, based on the last trigger | ||||
| * event. | * event. | ||||
| */ | */ | ||||
| extern "C" void systick_isr_with_timer_events(void); | |||||
| class EventResponder; | class EventResponder; | ||||
| typedef EventResponder& EventResponderRef; | typedef EventResponder& EventResponderRef; | ||||
| detachNoInterrupts(); | detachNoInterrupts(); | ||||
| _function = function; | _function = function; | ||||
| _type = EventTypeYield; | _type = EventTypeYield; | ||||
| yield_active_check_flags |= YIELD_CHECK_EVENT_RESPONDER; // user setup a yield type... | |||||
| enableInterrupts(irq); | enableInterrupts(irq); | ||||
| } | } | ||||
| _function = function; | _function = function; | ||||
| _type = EventTypeInterrupt; | _type = EventTypeInterrupt; | ||||
| SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority | 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); | enableInterrupts(irq); | ||||
| } | } | ||||
| EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | ||||
| static void runFromYield() { | static void runFromYield() { | ||||
| if (!firstYield) return; | |||||
| // First, check if yield was called from an interrupt | // First, check if yield was called from an interrupt | ||||
| // never call normal handler functions from any interrupt context | // never call normal handler functions from any interrupt context | ||||
| uint32_t ipsr; | uint32_t ipsr; |
| /* 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 | #ifndef FS_H | ||||
| #define FS_H | #define FS_H | ||||
| #ifdef __cplusplus | #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 { | class File : public Stream { | ||||
| public: | 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); | 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) { | size_t write(uint8_t b) { | ||||
| return write(&b, 1); | return write(&b, 1); | ||||
| } | } | ||||
| size_t readBytes(char *buffer, size_t length) { | size_t readBytes(char *buffer, size_t length) { | ||||
| return read(buffer, 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: | 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 // __cplusplus | ||||
| #endif // FS_H | #endif // FS_H |
| /* 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; | |||||
| } | |||||
| class HardwareSerial : public Stream | class HardwareSerial : public Stream | ||||
| { | { | ||||
| public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
| serial_begin(BAUD2DIV(baud)); | serial_begin(BAUD2DIV(baud)); | ||||
| serial_format(format); } | serial_format(format); } | ||||
| return len; } | return len; } | ||||
| virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } | ||||
| operator bool() { return true; } | 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 HardwareSerial Serial1; | ||||
| extern void serialEvent1(void); | extern void serialEvent1(void); | ||||
| class HardwareSerial2 : public HardwareSerial | class HardwareSerial2 : public HardwareSerial | ||||
| { | { | ||||
| public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
| serial2_begin(BAUD2DIV2(baud)); | serial2_begin(BAUD2DIV2(baud)); | ||||
| serial2_format(format); } | serial2_format(format); } | ||||
| class HardwareSerial3 : public HardwareSerial | class HardwareSerial3 : public HardwareSerial | ||||
| { | { | ||||
| public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
| serial3_begin(BAUD2DIV3(baud)); | serial3_begin(BAUD2DIV3(baud)); | ||||
| serial3_format(format); } | serial3_format(format); } | ||||
| class HardwareSerial4 : public HardwareSerial | class HardwareSerial4 : public HardwareSerial | ||||
| { | { | ||||
| public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
| serial4_begin(BAUD2DIV3(baud)); | serial4_begin(BAUD2DIV3(baud)); | ||||
| serial4_format(format); } | serial4_format(format); } | ||||
| class HardwareSerial5 : public HardwareSerial | class HardwareSerial5 : public HardwareSerial | ||||
| { | { | ||||
| public: | 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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
| serial5_begin(BAUD2DIV3(baud)); | serial5_begin(BAUD2DIV3(baud)); | ||||
| serial5_format(format); } | serial5_format(format); } | ||||
| class HardwareSerial6 : public HardwareSerial | class HardwareSerial6 : public HardwareSerial | ||||
| { | { | ||||
| public: | public: | ||||
| constexpr HardwareSerial6() {} | |||||
| constexpr HardwareSerial6(void (* const se)()) : HardwareSerial(se) {} | |||||
| #if defined(__MK66FX1M0__) // For LPUART just pass baud straight in. | #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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
| serial6_begin(baud); | serial6_begin(baud); | ||||
| serial6_format(format); } | serial6_format(format); } | ||||
| #else | #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) { | virtual void begin(uint32_t baud, uint32_t format) { | ||||
| serial6_begin(BAUD2DIV3(baud)); | serial6_begin(BAUD2DIV3(baud)); | ||||
| serial6_format(format); } | serial6_format(format); } |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "HardwareSerial.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(); | |||||
| } | |||||
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "HardwareSerial.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(); | |||||
| } |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "HardwareSerial.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(); | |||||
| } |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
| #ifdef HAS_KINETISK_UART3 | #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 | #endif |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
| #ifdef HAS_KINETISK_UART4 | #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 | #endif |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "HardwareSerial.h" | #include "HardwareSerial.h" | ||||
| #if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0) | #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 | #endif |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| #include "Arduino.h" | |||||
| #include <Arduino.h> | |||||
| #include "IPAddress.h" | #include "IPAddress.h" | ||||
| size_t IPAddress::printTo(Print& p) const | size_t IPAddress::printTo(Print& p) const |
| OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE | OPTIONS = -DF_CPU=48000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE | ||||
| # options needed by many Arduino libraries to configure for Teensy 3.x | # 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-m4" for Teensy 3.x | ||||
| # use "cortex-m0plus" for Teensy LC | # use "cortex-m0plus" for Teensy LC |
| // developed for Teensyduino have made their way back into | // developed for Teensyduino have made their way back into | ||||
| // Arduino's code base. :-) | // 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) | size_t Print::write(const uint8_t *buffer, size_t size) | ||||
| { | { | ||||
| if (buffer == nullptr) return 0; | |||||
| size_t count = 0; | size_t count = 0; | ||||
| while (size--) count += write(*buffer++); | while (size--) count += write(*buffer++); | ||||
| return count; | return count; | ||||
| #endif | #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) | size_t Print::printFloat(double number, uint8_t digits) | ||||
| { | { | ||||
| uint8_t sign=0; | uint8_t sign=0; |
| // BYTE was defined in very old versions of Arduino | // BYTE was defined in very old versions of Arduino | ||||
| // maybe this now causes more trouble than it's worth? | // maybe this now causes more trouble than it's worth? | ||||
| #ifndef BYTE | |||||
| #define BYTE 0 | |||||
| #endif | |||||
| //#ifndef BYTE | |||||
| //#define BYTE 0 | |||||
| //#endif | |||||
| class __FlashStringHelper; | class __FlashStringHelper; | ||||
| size_t print(unsigned int n) { return printNumber(n, 10, 0); } | size_t print(unsigned int n) { return printNumber(n, 10, 0); } | ||||
| size_t print(long n); | size_t print(long n); | ||||
| size_t print(unsigned long n) { return printNumber(n, 10, 0); } | 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(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(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(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(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(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(double n, int digits = 2) { return printFloat(n, digits); } | ||||
| size_t print(const Printable &obj) { return obj.printTo(*this); } | size_t print(const Printable &obj) { return obj.printTo(*this); } | ||||
| size_t println(unsigned int n) { return print(n) + println(); } | size_t println(unsigned int n) { return print(n) + println(); } | ||||
| size_t println(long 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(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(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(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(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(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(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(double n, int digits = 2) { return print(n, digits) + println(); } | ||||
| size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | size_t println(const Printable &obj) { return obj.printTo(*this) + println(); } | ||||
| int getWriteError() { return write_error; } | int getWriteError() { return write_error; } | ||||
| void clearWriteError() { setWriteError(0); } | 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, ...); | int printf(const __FlashStringHelper *format, ...); | ||||
| protected: | protected: | ||||
| void setWriteError(int err = 1) { write_error = err; } | void setWriteError(int err = 1) { write_error = err; } | ||||
| #else | #else | ||||
| size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | size_t printNumber(unsigned long n, uint8_t base, uint8_t sign); | ||||
| #endif | #endif | ||||
| size_t printNumber64(uint64_t n, uint8_t base, uint8_t sign); | |||||
| }; | }; | ||||
| // The preferred way to set SPI speed is with SPI.beginTransaction() | // 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 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_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 | #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(120 / 2) * ((1+0)/4) = 15 MHz |
| parsing functions based on TextFinder library by Michael Margolis | 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 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 | #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field | ||||
| // as find but search ends if the terminator string is found | // as find but search ends if the terminator string is found | ||||
| bool Stream::findUntil(const char *target, const char *terminator) | 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 | // reads data from the stream until the target string of the given length is found | ||||
| size_t index = 0; // maximum target string length is 64k bytes! | size_t index = 0; // maximum target string length is 64k bytes! | ||||
| size_t termIndex = 0; | size_t termIndex = 0; | ||||
| int c; | 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){ | while( (c = timedRead()) > 0){ | ||||
| if( c == target[index]){ | if( c == target[index]){ | ||||
| //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); | //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); | ||||
| // | // | ||||
| size_t Stream::readBytes(char *buffer, size_t length) | size_t Stream::readBytes(char *buffer, size_t length) | ||||
| { | { | ||||
| if (buffer == nullptr) return 0; | |||||
| size_t count = 0; | size_t count = 0; | ||||
| while (count < length) { | while (count < length) { | ||||
| int c = timedRead(); | int c = timedRead(); | ||||
| size_t Stream::readBytesUntil(char terminator, 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; | if (length < 1) return 0; | ||||
| length--; | length--; | ||||
| size_t index = 0; | size_t index = 0; |
| * SOFTWARE. | * 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 | // IntervalTimer based tone. This allows tone() to share the timers with other | ||||
| // libraries, rather than permanently hogging one PIT timer even for projects | // libraries, rather than permanently hogging one PIT timer even for projects |
| public: | 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 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 | virtual void stop() =0; // Finish with the UDP socket | ||||
| // Sending UDP packets | // Sending UDP packets |
| // that fits into the ASCII character set. | // that fits into the ASCII character set. | ||||
| inline boolean isAscii(int c) | inline boolean isAscii(int c) | ||||
| { | { | ||||
| return ( isascii (c) == 0 ? false : true); | |||||
| return ((c & ~0x7F) != 0 ? false : true); | |||||
| } | } | ||||
| // ASCII character set, by clearing the high-order bits. | // ASCII character set, by clearing the high-order bits. | ||||
| inline int toAscii(int c) | inline int toAscii(int c) | ||||
| { | { | ||||
| return toascii (c); | |||||
| return (c & 0x7F); | |||||
| } | } | ||||
| #include "avr_emulation.h" | #include "avr_emulation.h" | ||||
| #include "usb_serial.h" | #include "usb_serial.h" | ||||
| #include "usb_serial2.h" | |||||
| #include "usb_serial3.h" | |||||
| #include "usb_seremu.h" | #include "usb_seremu.h" | ||||
| #include "usb_keyboard.h" | #include "usb_keyboard.h" | ||||
| #include "usb_mouse.h" | #include "usb_mouse.h" |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| #include "WString.h" | |||||
| #include <Arduino.h> | |||||
| /*********************************************/ | /*********************************************/ | ||||
| /* Character Access */ | /* Character Access */ | ||||
| /*********************************************/ | /*********************************************/ | ||||
| const char String::zerotermination = 0; | |||||
| char String::charAt(unsigned int loc) const | char String::charAt(unsigned int loc) const | ||||
| { | { | ||||
| return operator[](loc); | return operator[](loc); |
| void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; | 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 | void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const | ||||
| {getBytes((unsigned char *)buf, bufsize, index);} | {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 | // search | ||||
| int indexOf( char ch ) const; | int indexOf( char ch ) const; | ||||
| // for more information http://www.artima.com/cppsource/safebool.html | // for more information http://www.artima.com/cppsource/safebool.html | ||||
| typedef void (String::*StringIfHelperType)() const; | typedef void (String::*StringIfHelperType)() const; | ||||
| void StringIfHelper() const {} | void StringIfHelper() const {} | ||||
| static const char zerotermination; | |||||
| public: | public: | ||||
| operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } | operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } | ||||
| }; | }; |
| // the alternate clock is connected to OSCERCLK (16 MHz). | // 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 2 to 12 MHz for 16 bit mode | ||||
| // datasheet says ADC clock should be 1 to 18 MHz for 8-12 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_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_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 | #define ADC_CFG1_10BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 15 MHz | ||||
| #define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | #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 | #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz | ||||
| #else | #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 | #endif | ||||
| void analog_init(void) | void analog_init(void) | ||||
| } else { | } else { | ||||
| DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | 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; | *(volatile aliased_int16_t *)&(DAC0_DAT0L) = val; | ||||
| #elif defined(__MKL26Z64__) | #elif defined(__MKL26Z64__) | ||||
| } else { | } else { | ||||
| DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 | 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; | *(volatile aliased_int16_t *)&(DAC1_DAT0L) = val; | ||||
| } | } |
| * THE SOFTWARE. | * THE SOFTWARE. | ||||
| */ | */ | ||||
| // Guidelines for editing this file: | |||||
| // https://forum.pjrc.com/threads/34537-Teensy-LC-Increase-EEPROM-Size/page2 | |||||
| #ifndef _AVR_EEPROM_H_ | #ifndef _AVR_EEPROM_H_ | ||||
| #define _AVR_EEPROM_H_ 1 | #define _AVR_EEPROM_H_ 1 | ||||
| #include <inttypes.h> | #include <inttypes.h> | ||||
| #define PROGMEM | #define PROGMEM | ||||
| #define FLASHMEM | |||||
| #define PGM_P const char * | #define PGM_P const char * | ||||
| #define PSTR(str) (str) | #define PSTR(str) (str) | ||||
| */ | */ | ||||
| #include "avr_emulation.h" | |||||
| #include <Arduino.h> | |||||
| #include "SPIFIFO.h" | #include "SPIFIFO.h" | ||||
| uint8_t SPCRemulation::pinout = 0; | uint8_t SPCRemulation::pinout = 0; |
| int ret = 0; | int ret = 0; | ||||
| if (digitalReadFast(14)) ret |= (1<<0); | if (digitalReadFast(14)) ret |= (1<<0); | ||||
| if (digitalReadFast(15)) ret |= (1<<1); | 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(17)) ret |= (1<<3); | ||||
| if (digitalReadFast(18)) ret |= (1<<4); | if (digitalReadFast(18)) ret |= (1<<4); | ||||
| if (digitalReadFast(19)) ret |= (1<<5); | if (digitalReadFast(19)) ret |= (1<<5); |
| char * ultoa(unsigned long val, char *buf, int radix); | char * ultoa(unsigned long val, char *buf, int radix); | ||||
| char * ltoa(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) __attribute__((always_inline, unused)); | ||||
| static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); } | 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)); | static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused)); |
| #define CORE_PIN32_PORTSET GPIOB_PSOR | #define CORE_PIN32_PORTSET GPIOB_PSOR | ||||
| #define CORE_PIN33_PORTSET GPIOA_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_PIN0_PORTCLEAR GPIOB_PCOR | ||||
| #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | ||||
| #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | ||||
| #define CORE_PIN25_PORTSET FGPIOE_PSOR | #define CORE_PIN25_PORTSET FGPIOE_PSOR | ||||
| #define CORE_PIN26_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_PIN0_PORTCLEAR FGPIOB_PCOR | ||||
| #define CORE_PIN1_PORTCLEAR FGPIOB_PCOR | #define CORE_PIN1_PORTCLEAR FGPIOB_PCOR | ||||
| #define CORE_PIN2_PORTCLEAR FGPIOD_PCOR | #define CORE_PIN2_PORTCLEAR FGPIOD_PCOR | ||||
| #define CORE_PIN62_PORTSET GPIOE_PSOR | #define CORE_PIN62_PORTSET GPIOE_PSOR | ||||
| #define CORE_PIN63_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_PIN0_PORTCLEAR GPIOB_PCOR | ||||
| #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | #define CORE_PIN1_PORTCLEAR GPIOB_PCOR | ||||
| #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | #define CORE_PIN2_PORTCLEAR GPIOD_PCOR | ||||
| } | } | ||||
| } | } | ||||
| 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); | 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) __attribute__((always_inline, unused)); | ||||
| static inline uint8_t digitalReadFast(uint8_t pin) | static inline uint8_t digitalReadFast(uint8_t pin) | ||||
| void _reboot_Teensyduino_(void) __attribute__((noreturn)); | void _reboot_Teensyduino_(void) __attribute__((noreturn)); | ||||
| void _restart_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 yield(void); | ||||
| void delay(uint32_t msec); | void delay(uint32_t msec); | ||||
| static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); | static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); | ||||
| static inline void delayMicroseconds(uint32_t usec) | 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; | uint32_t n = usec * 80; | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| uint32_t n = usec * 72; | uint32_t n = usec * 72; | ||||
| #endif | #endif | ||||
| #ifdef KINETISL | #ifdef KINETISL | ||||
| "sub %0, #1" "\n\t" | "sub %0, #1" "\n\t" | ||||
| "bne L_%=_delayMicroseconds" "\n" | |||||
| : "+l" (n) : | |||||
| #else | #else | ||||
| "subs %0, #1" "\n\t" | "subs %0, #1" "\n\t" | ||||
| #endif | |||||
| "bne L_%=_delayMicroseconds" "\n" | "bne L_%=_delayMicroseconds" "\n" | ||||
| : "+r" (n) : | : "+r" (n) : | ||||
| #endif | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| #endif | #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 | |||||
| ); | |||||
| } | |||||
| * SOFTWARE. | * 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 "kinetis.h" | ||||
| #include <avr/eeprom.h> | #include <avr/eeprom.h> | ||||
| //#include "HardwareSerial.h" | //#include "HardwareSerial.h" |
| #define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | ||||
| #define ASCII_20 KEY_SPACE // 32 | #define ASCII_20 KEY_SPACE // 32 | ||||
| #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | #define ASCII_21 KEY_1 + SHIFT_MASK // 33 ! | ||||
| #define ASCII_22 KEY_2 + SHIFT_MASK // 34 " | #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_24 KEY_4 + SHIFT_MASK // 36 $ | ||||
| #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | #define ASCII_25 KEY_5 + SHIFT_MASK // 37 % | ||||
| #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & | #define ASCII_26 KEY_7 + SHIFT_MASK // 38 & |
| #endif // end of board-specific definitions | #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 | #define F_PLL 240000000 | ||||
| #ifndef F_BUS | #ifndef F_BUS | ||||
| #define F_BUS 60000000 | #define F_BUS 60000000 | ||||
| #define PORTA_PCR0 (*(volatile uint32_t *)0x40049000) // Pin Control Register n | #define PORTA_PCR0 (*(volatile uint32_t *)0x40049000) // Pin Control Register n | ||||
| #define PORT_PCR_ISF ((uint32_t)0x01000000) // Interrupt Status Flag | #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(n) ((uint32_t)(((n) & 15) << 16)) // Interrupt Configuration | ||||
| #define PORT_PCR_IRQC_MASK ((uint32_t)0x000F0000) | #define PORT_PCR_IRQC_MASK ((uint32_t)0x000F0000) | ||||
| #define PORT_PCR_LK ((uint32_t)0x00008000) // Lock Register | #define PORT_PCR_LK ((uint32_t)0x00008000) // Lock Register | ||||
| #define FTM0_CONF (*(volatile uint32_t *)0x40038084) // Configuration | #define FTM0_CONF (*(volatile uint32_t *)0x40038084) // Configuration | ||||
| #define FTM_CONF_GTBEOUT 0x400 // Global Time Base Output | #define FTM_CONF_GTBEOUT 0x400 // Global Time Base Output | ||||
| #define FTM_CONF_GTBEEN 0x200 // Global Time Base Enable | #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 FTM0_FLTPOL (*(volatile uint32_t *)0x40038088) // FTM Fault Input Polarity | ||||
| #define FTM_FLTPOL_FLT3POL 0x08 // Fault Input 3 Polarity | #define FTM_FLTPOL_FLT3POL 0x08 // Fault Input 3 Polarity | ||||
| #define FTM_FLTPOL_FLT2POL 0x04 // Fault Input 2 Polarity | #define FTM_FLTPOL_FLT2POL 0x04 // Fault Input 2 Polarity | ||||
| #define ENET_EIR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available | #define ENET_EIR_TS_AVAIL ((uint32_t)0x00010000) // Transmit Timestamp Available | ||||
| #define ENET_EIR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer | #define ENET_EIR_TS_TIMER ((uint32_t)0x00008000) // Timestamp Timer | ||||
| #define ENET_EIMR (*(volatile uint32_t *)0x400C0008) // Interrupt Mask Register | #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 (*(volatile uint32_t *)0x400C0010) // Receive Descriptor Active Register | ||||
| #define ENET_RDAR_RDAR ((uint32_t)0x01000000) | #define ENET_RDAR_RDAR ((uint32_t)0x01000000) | ||||
| #define ENET_TDAR (*(volatile uint32_t *)0x400C0014) // Transmit Descriptor Active Register | #define ENET_TDAR (*(volatile uint32_t *)0x400C0014) // Transmit Descriptor Active Register | ||||
| #define SPI1_MH (KINETISL_SPI1.MH) // Match High | #define SPI1_MH (KINETISL_SPI1.MH) // Match High | ||||
| #define SPI1_DL (KINETISL_SPI1.DL) // Data Low | #define SPI1_DL (KINETISL_SPI1.DL) // Data Low | ||||
| #define SPI1_DH (KINETISL_SPI1.DH) // Data High | #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 | #define SPI1_C3 (KINETISL_SPI1.C3) // Control Register 3 | ||||
| #endif | #endif | ||||
| extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void); | ||||
| extern void (* const _VectorsFlash[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 | #ifdef __cplusplus | ||||
| } | } | ||||
| #endif | #endif |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include "WProgram.h" | |||||
| #include <Arduino.h> | |||||
| extern "C" int main(void) | extern "C" int main(void) | ||||
| { | { |
| UART0_C2 = UART_C2_TE; | UART0_C2 = UART_C2_TE; | ||||
| PORTB_PCR17 = PORT_PCR_MUX(3); | PORTB_PCR17 = PORT_PCR_MUX(3); | ||||
| #endif | #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)) { | if (!(RTC_CR & RTC_CR_OSCE)) { | ||||
| RTC_SR = 0; | RTC_SR = 0; | ||||
| RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; | ||||
| SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode | SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode | ||||
| while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN | while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN | ||||
| #endif | #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_C5 = MCG_C5_PRDIV0(0); | ||||
| MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14); | MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(14); | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| // now program the clock dividers | // 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 | // config divisors: 240 MHz core, 60 MHz bus, 30 MHz flash, USB = 240 / 5 | ||||
| // TODO: gradual ramp-up for HSRUN mode | // TODO: gradual ramp-up for HSRUN mode | ||||
| #if F_BUS == 60000000 | #if F_BUS == 60000000 | ||||
| #elif F_BUS == 72000000 | #elif F_BUS == 72000000 | ||||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(7); | ||||
| #elif F_BUS == 108000000 | #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 | #else | ||||
| #error "This F_CPU & F_BUS combination is not supported" | #error "This F_CPU & F_BUS combination is not supported" | ||||
| #endif | #endif | ||||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(1); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(1); | ||||
| #endif | #endif | ||||
| #else | #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 | #endif | ||||
| #if F_CPU > 16000000 | #if F_CPU > 16000000 | ||||
| // wait for PLL clock to be used | // wait for PLL clock to be used | ||||
| while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; | while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; | ||||
| // now we're in PEE mode | // 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 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); | SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | ||||
| #else | #else | ||||
| // USB uses PLL clock | |||||
| SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); | ||||
| #endif | #endif | ||||
| #elif defined(KINETISL) | #elif defined(KINETISL) | ||||
| SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-) | SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-) | ||||
| #endif | #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 | // initialize the SysTick counter | ||||
| SYST_RVR = (F_CPU / 1000) - 1; | SYST_RVR = (F_CPU / 1000) - 1; | ||||
| SYST_CVR = 0; | SYST_CVR = 0; | ||||
| startup_late_hook(); | startup_late_hook(); | ||||
| main(); | main(); | ||||
| while (1) ; | while (1) ; | ||||
| } | } | ||||
| // the peripheral speed (F_BUS). Serial1 & Serial2 baud | // the peripheral speed (F_BUS). Serial1 & Serial2 baud | ||||
| // rates will be impacted, but most other peripherals | // rates will be impacted, but most other peripherals | ||||
| // will continue functioning at the same speed. | // 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 | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok | ||||
| #elif F_CPU == 240000000 && F_BUS == 80000000 | #elif F_CPU == 240000000 && F_BUS == 80000000 | ||||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok | ||||
| SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | SMC_PMCTRL = SMC_PMCTRL_RUNM(3); | ||||
| while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) {;} // wait | ||||
| // Then configure clock for full speed | // 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); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7); | ||||
| #elif F_CPU == 240000000 && F_BUS == 80000000 | #elif F_CPU == 240000000 && F_BUS == 80000000 | ||||
| SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); | SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7); |
| RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K | RAM (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 16K | ||||
| } | } | ||||
| ENTRY(_VectorsFlash) | |||||
| SECTIONS | SECTIONS | ||||
| { | { | ||||
| } > RAM | } > RAM | ||||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
| _teensy_model_identifier = 0x1D; | |||||
| } | } | ||||
| RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K | RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K | ||||
| } | } | ||||
| ENTRY(_VectorsFlash) | |||||
| SECTIONS | SECTIONS | ||||
| { | { | ||||
| } > RAM | } > RAM | ||||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
| _teensy_model_identifier = 0x21; | |||||
| } | } | ||||
| MEMORY | MEMORY | ||||
| { | { | ||||
| FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K | ||||
| RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 192K | |||||
| RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 262136 | |||||
| } | } | ||||
| ENTRY(_VectorsFlash) | |||||
| SECTIONS | SECTIONS | ||||
| { | { | ||||
| } > RAM | } > RAM | ||||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
| _teensy_model_identifier = 0x1F; | |||||
| } | } | ||||
| RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K | ||||
| } | } | ||||
| ENTRY(_VectorsFlash) | |||||
| SECTIONS | SECTIONS | ||||
| { | { | ||||
| } > RAM | } > RAM | ||||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
| _teensy_model_identifier = 0x22; | |||||
| } | } | ||||
| RAM (rwx) : ORIGIN = 0x1FFFF800, LENGTH = 8K | RAM (rwx) : ORIGIN = 0x1FFFF800, LENGTH = 8K | ||||
| } | } | ||||
| ENTRY(_VectorsFlash) | |||||
| SECTIONS | SECTIONS | ||||
| { | { | ||||
| } > RAM | } > RAM | ||||
| _estack = ORIGIN(RAM) + LENGTH(RAM); | _estack = ORIGIN(RAM) + LENGTH(RAM); | ||||
| _teensy_model_identifier = 0x20; | |||||
| } | } | ||||
| #define analogInputToDigitalPin(p) (((p) <= 9) ? (p) + 14 : (((p) <= 12) ? (p) + 14 : -1)) | #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 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) | #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 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) | #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 | #endif | ||||
| #define digitalPinToPCICR(p) ((volatile uint8_t *)0) | #define digitalPinToPCICR(p) ((volatile uint8_t *)0) |
| // The Pin Config Register is used to look up the correct interrupt table | // The Pin Config Register is used to look up the correct interrupt table | ||||
| // for the corresponding port. | // for the corresponding port. | ||||
| inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||||
| static inline voidFuncPtr* getIsrTable(volatile uint32_t *config) { | |||||
| voidFuncPtr* isr_table = NULL; | voidFuncPtr* isr_table = NULL; | ||||
| if(&PORTA_PCR0 <= config && config <= &PORTA_PCR31) isr_table = isr_table_portA; | 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; | else if(&PORTB_PCR0 <= config && config <= &PORTB_PCR31) isr_table = isr_table_portB; | ||||
| #endif | #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_MOD (61440 - 1) | ||||
| #define DEFAULT_FTM_PRESCALE 2 | #define DEFAULT_FTM_PRESCALE 2 | ||||
| #elif F_TIMER == 108000000 | #elif F_TIMER == 108000000 | ||||
| TPM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); | TPM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); | ||||
| #endif | #endif | ||||
| analog_init(); | 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 | // 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/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 | // 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(); | usb_init(); | ||||
| delay(350); | |||||
| delay(TEENSY_INIT_USB_DELAY_AFTER); | |||||
| } | } | ||||
| } | } | ||||
| 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) | uint8_t digitalRead(uint8_t pin) | ||||
| { | { | ||||
| if (pin >= CORE_NUM_DIGITAL) return 0; | if (pin >= CORE_NUM_DIGITAL) return 0; | ||||
| } | } | ||||
| // TODO: verify these result in correct timeouts... | // 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 | #define PULSEIN_LOOPS_PER_USEC 33 | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #define PULSEIN_LOOPS_PER_USEC 31 | #define PULSEIN_LOOPS_PER_USEC 31 |
| #define rts_assert() *(rts_pin+8) = rts_mask; | #define rts_assert() *(rts_pin+8) = rts_mask; | ||||
| #define rts_deassert() *(rts_pin+4) = rts_mask; | #define rts_deassert() *(rts_pin+4) = rts_mask; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
| #else | #else | ||||
| static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
| static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
| #else | #else | ||||
| case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | case 26: CORE_PIN26_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | ||||
| #endif | #endif | ||||
| } | } | ||||
| UART0_S1; | |||||
| UART0_D; // clear leftover error status | |||||
| rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
| rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
| if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
| #define rts_assert() *(rts_pin+8) = rts_mask; | #define rts_assert() *(rts_pin+8) = rts_mask; | ||||
| #define rts_deassert() *(rts_pin+4) = rts_mask; | #define rts_deassert() *(rts_pin+4) = rts_mask; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
| #else | #else | ||||
| static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
| static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
| #else | #else | ||||
| CORE_PIN9_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC3 | 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 | CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); // PTC4 | ||||
| #endif | #endif | ||||
| UART1_S1; | |||||
| UART1_D; // clear leftover error status | |||||
| rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
| rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
| if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
| #define rts_assert() *(rts_pin+8) = rts_mask; | #define rts_assert() *(rts_pin+8) = rts_mask; | ||||
| #define rts_deassert() *(rts_pin+4) = rts_mask; | #define rts_deassert() *(rts_pin+4) = rts_mask; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
| #else | #else | ||||
| static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
| static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
| #else | #else | ||||
| case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| UART2_S1; | |||||
| UART2_D; // clear leftover error status | |||||
| rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
| rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
| if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
| static volatile uint8_t *rts_pin=NULL; | static volatile uint8_t *rts_pin=NULL; | ||||
| #define rts_assert() *rts_pin = 0 | #define rts_assert() *rts_pin = 0 | ||||
| #define rts_deassert() *rts_pin = 1 | #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_head = 0; | ||||
| static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
| #else | #else | ||||
| static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
| static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
| #else | #else | ||||
| case 32: CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | case 32: CORE_PIN32_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); break; // PTC4 | ||||
| case 62: CORE_PIN62_CONFIG = 0; break; | case 62: CORE_PIN62_CONFIG = 0; break; | ||||
| } | } | ||||
| UART3_S1; | |||||
| UART3_D; // clear leftover error status | |||||
| rx_buffer_head = 0; | rx_buffer_head = 0; | ||||
| rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
| if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
| static volatile uint8_t *rts_pin=NULL; | static volatile uint8_t *rts_pin=NULL; | ||||
| #define rts_assert() *rts_pin = 0 | #define rts_assert() *rts_pin = 0 | ||||
| #define rts_deassert() *rts_pin = 1 | #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_head = 0; | ||||
| static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
| #else | #else | ||||
| static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
| static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
| #else | #else | ||||
| UART4_C2 = 0; | UART4_C2 = 0; | ||||
| CORE_PIN34_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | 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); | 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_head = 0; | ||||
| rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
| if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
| static volatile uint8_t *rts_pin=NULL; | static volatile uint8_t *rts_pin=NULL; | ||||
| #define rts_assert() *rts_pin = 0 | #define rts_assert() *rts_pin = 0 | ||||
| #define rts_deassert() *rts_pin = 1 | #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_head = 0; | ||||
| static volatile uint16_t tx_buffer_tail = 0; | static volatile uint16_t tx_buffer_tail = 0; | ||||
| #else | #else | ||||
| static volatile uint8_t tx_buffer_head = 0; | static volatile uint8_t tx_buffer_head = 0; | ||||
| static volatile uint8_t tx_buffer_tail = 0; | static volatile uint8_t tx_buffer_tail = 0; | ||||
| #endif | #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_head = 0; | ||||
| static volatile uint16_t rx_buffer_tail = 0; | static volatile uint16_t rx_buffer_tail = 0; | ||||
| #else | #else | ||||
| UART5_C2 = 0; | UART5_C2 = 0; | ||||
| CORE_PIN47_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_MUX(1); | 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); | 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_head = 0; | ||||
| rx_buffer_tail = 0; | rx_buffer_tail = 0; | ||||
| if (rts_pin) rts_deassert(); | if (rts_pin) rts_deassert(); |
| } | } | ||||
| } | } | ||||
| #endif // HAS_KINETISK_UART4 | |||||
| #endif // HAS_KINETISK_LPUART0 |
| #include <Arduino.h> | |||||
| void serialEvent() __attribute__((weak)); | |||||
| void serialEvent() { | |||||
| } | |||||
| uint8_t _serialEvent_default PROGMEM = 1; |
| #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; |
| #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; |
| #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; |
| #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 |
| #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 |
| #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 |
| #include <Arduino.h> | |||||
| void serialEventUSB1() __attribute__((weak)); | |||||
| void serialEventUSB1() {} | |||||
| uint8_t _serialEventUSB1_default PROGMEM = 1; |
| #include <Arduino.h> | |||||
| void serialEventUSB2() __attribute__((weak)); | |||||
| void serialEventUSB2() {} | |||||
| uint8_t _serialEventUSB2_default PROGMEM = 1; |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include <Arduino.h> | |||||
| #include "usb_dev.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 | #ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h | ||||
| #if F_CPU >= 20000000 | #if F_CPU >= 20000000 |
| #ifdef BCD_DEVICE | #ifdef BCD_DEVICE | ||||
| LSB(BCD_DEVICE), MSB(BCD_DEVICE), // bcdDevice | LSB(BCD_DEVICE), MSB(BCD_DEVICE), // bcdDevice | ||||
| #else | #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, | 0x00, 0x02, | ||||
| #endif | |||||
| #endif | #endif | ||||
| 1, // iManufacturer | 1, // iManufacturer | ||||
| 2, // iProduct | 2, // iProduct | ||||
| 0x95, 0x01, // Report Count (1) | 0x95, 0x01, // Report Count (1) | ||||
| 0x09, 0x56, // Usage (Scan Time) | 0x09, 0x56, // Usage (Scan Time) | ||||
| 0x81, 0x02, // Input (variable,absolute) | 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) | 0x05, 0x0D, // Usage Page (Digitizers) | ||||
| 0x09, 0x55, // Usage (Contact Count Maximum) | 0x09, 0x55, // Usage (Contact Count Maximum) | ||||
| 0x25, MULTITOUCH_FINGERS, // Logical Maximum (10) | 0x25, MULTITOUCH_FINGERS, // Logical Maximum (10) | ||||
| #define CDC_DATA_INTERFACE_DESC_SIZE 0 | #define CDC_DATA_INTERFACE_DESC_SIZE 0 | ||||
| #endif | #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 | #ifdef MIDI_INTERFACE | ||||
| #if !defined(MIDI_NUM_CABLES) || MIDI_NUM_CABLES < 1 || MIDI_NUM_CABLES > 16 | #if !defined(MIDI_NUM_CABLES) || MIDI_NUM_CABLES < 1 || MIDI_NUM_CABLES > 16 | ||||
| #error "MIDI_NUM_CABLES must be defined between 1 to 16" | #error "MIDI_NUM_CABLES must be defined between 1 to 16" | ||||
| 0x02, // bFunctionClass | 0x02, // bFunctionClass | ||||
| 0x02, // bFunctionSubClass | 0x02, // bFunctionSubClass | ||||
| 0x01, // bFunctionProtocol | 0x01, // bFunctionProtocol | ||||
| 4, // iFunction | |||||
| 0, // iFunction | |||||
| #endif | #endif | ||||
| #ifdef CDC_DATA_INTERFACE | #ifdef CDC_DATA_INTERFACE | ||||
| 0, // bInterval | 0, // bInterval | ||||
| #endif // CDC_DATA_INTERFACE | #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 | #ifdef MIDI_INTERFACE | ||||
| // Standard MS Interface Descriptor, | // Standard MS Interface Descriptor, | ||||
| 9, // bLength | 9, // bLength | ||||
| 0x06, // bInterfaceClass (0x06 = still image) | 0x06, // bInterfaceClass (0x06 = still image) | ||||
| 0x01, // bInterfaceSubClass | 0x01, // bInterfaceSubClass | ||||
| 0x01, // bInterfaceProtocol | 0x01, // bInterfaceProtocol | ||||
| 4, // iInterface | |||||
| 0, // iInterface | |||||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||||
| 7, // bLength | 7, // bLength | ||||
| 5, // bDescriptorType | 5, // bDescriptorType |
| #include <stddef.h> | #include <stddef.h> | ||||
| #define ENDPOINT_UNUSED 0x00 | #define ENDPOINT_UNUSED 0x00 | ||||
| #define ENDPOINT_TRANSIMIT_ONLY 0x15 | |||||
| #define ENDPOINT_TRANSMIT_ONLY 0x15 | |||||
| #define ENDPOINT_RECEIVE_ONLY 0x19 | #define ENDPOINT_RECEIVE_ONLY 0x19 | ||||
| #define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | #define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D | ||||
| #define ENDPOINT_RECEIVE_ISOCHRONOUS 0x18 | #define ENDPOINT_RECEIVE_ISOCHRONOUS 0x18 | ||||
| #define CDC_ACM_SIZE 16 | #define CDC_ACM_SIZE 16 | ||||
| #define CDC_RX_SIZE 64 | #define CDC_RX_SIZE 64 | ||||
| #define CDC_TX_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 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) | #elif defined(USB_KEYBOARDONLY) | ||||
| #define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
| #define KEYMEDIA_ENDPOINT 4 | #define KEYMEDIA_ENDPOINT 4 | ||||
| #define KEYMEDIA_SIZE 8 | #define KEYMEDIA_SIZE 8 | ||||
| #define KEYMEDIA_INTERVAL 4 | #define KEYMEDIA_INTERVAL 4 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_HID) | ||||
| #define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
| #define JOYSTICK_ENDPOINT 4 | #define JOYSTICK_ENDPOINT 4 | ||||
| #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | ||||
| #define JOYSTICK_INTERVAL 2 | #define JOYSTICK_INTERVAL 2 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_SERIAL_HID) | ||||
| #define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
| #define JOYSTICK_ENDPOINT 6 | #define JOYSTICK_ENDPOINT 6 | ||||
| #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | ||||
| #define JOYSTICK_INTERVAL 1 | #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 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) | #elif defined(USB_TOUCHSCREEN) | ||||
| #define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
| #define KEYMEDIA_INTERVAL 4 | #define KEYMEDIA_INTERVAL 4 | ||||
| #define MULTITOUCH_INTERFACE 3 // Touchscreen | #define MULTITOUCH_INTERFACE 3 // Touchscreen | ||||
| #define MULTITOUCH_ENDPOINT 5 | #define MULTITOUCH_ENDPOINT 5 | ||||
| #define MULTITOUCH_SIZE 8 | |||||
| #define MULTITOUCH_SIZE 16 | |||||
| #define MULTITOUCH_FINGERS 10 | #define MULTITOUCH_FINGERS 10 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_HID_TOUCHSCREEN) | ||||
| #define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
| #define MOUSE_INTERVAL 2 | #define MOUSE_INTERVAL 2 | ||||
| #define MULTITOUCH_INTERFACE 4 // Touchscreen | #define MULTITOUCH_INTERFACE 4 // Touchscreen | ||||
| #define MULTITOUCH_ENDPOINT 5 | #define MULTITOUCH_ENDPOINT 5 | ||||
| #define MULTITOUCH_SIZE 8 | |||||
| #define MULTITOUCH_SIZE 16 | |||||
| #define MULTITOUCH_FINGERS 10 | #define MULTITOUCH_FINGERS 10 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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) | #elif defined(USB_MIDI) | ||||
| #define VENDOR_ID 0x16C0 | #define VENDOR_ID 0x16C0 | ||||
| #define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
| #define MIDI_RX_ENDPOINT 4 | #define MIDI_RX_ENDPOINT 4 | ||||
| #define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_MIDI4) | #elif defined(USB_MIDI4) | ||||
| #define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
| #define MIDI_RX_ENDPOINT 4 | #define MIDI_RX_ENDPOINT 4 | ||||
| #define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_MIDI16) | #elif defined(USB_MIDI16) | ||||
| #define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
| #define MIDI_RX_ENDPOINT 4 | #define MIDI_RX_ENDPOINT 4 | ||||
| #define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_MIDI_SERIAL) | #elif defined(USB_MIDI_SERIAL) | ||||
| #define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
| #define MIDI_RX_ENDPOINT 5 | #define MIDI_RX_ENDPOINT 5 | ||||
| #define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_MIDI4_SERIAL) | #elif defined(USB_MIDI4_SERIAL) | ||||
| #define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
| #define MIDI_RX_ENDPOINT 5 | #define MIDI_RX_ENDPOINT 5 | ||||
| #define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_MIDI16_SERIAL) | #elif defined(USB_MIDI16_SERIAL) | ||||
| #define MIDI_TX_SIZE 64 | #define MIDI_TX_SIZE 64 | ||||
| #define MIDI_RX_ENDPOINT 5 | #define MIDI_RX_ENDPOINT 5 | ||||
| #define MIDI_RX_SIZE 64 | #define MIDI_RX_SIZE 64 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_RAWHID) | #elif defined(USB_RAWHID) | ||||
| #define SEREMU_RX_ENDPOINT 2 | #define SEREMU_RX_ENDPOINT 2 | ||||
| #define SEREMU_RX_SIZE 32 | #define SEREMU_RX_SIZE 32 | ||||
| #define SEREMU_RX_INTERVAL 2 | #define SEREMU_RX_INTERVAL 2 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_FLIGHTSIM) | #elif defined(USB_FLIGHTSIM) | ||||
| #define SEREMU_RX_ENDPOINT 2 | #define SEREMU_RX_ENDPOINT 2 | ||||
| #define SEREMU_RX_SIZE 32 | #define SEREMU_RX_SIZE 32 | ||||
| #define SEREMU_RX_INTERVAL 2 | #define SEREMU_RX_INTERVAL 2 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_FLIGHTSIM_JOYSTICK) | #elif defined(USB_FLIGHTSIM_JOYSTICK) | ||||
| #define VENDOR_ID 0x16C0 | #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 {'T','e','e','n','s','y','d','u','i','n','o'} | ||||
| #define MANUFACTURER_NAME_LEN 11 | #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'} | #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'} | ||||
| #define JOYSTICK_ENDPOINT 5 | #define JOYSTICK_ENDPOINT 5 | ||||
| #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | #define JOYSTICK_SIZE 12 // 12 = normal, 64 = extreme joystick | ||||
| #define JOYSTICK_INTERVAL 1 | #define JOYSTICK_INTERVAL 1 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #elif defined(USB_MTPDISK) | #elif defined(USB_MTPDISK) | ||||
| #define SEREMU_RX_ENDPOINT 2 | #define SEREMU_RX_ENDPOINT 2 | ||||
| #define SEREMU_RX_SIZE 32 | #define SEREMU_RX_SIZE 32 | ||||
| #define SEREMU_RX_INTERVAL 2 | #define SEREMU_RX_INTERVAL 2 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | ||||
| // TODO: Should ENDPOINT4_CONFIG be ENDPOINT_TRANSMIT_ONLY ??? | |||||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #elif defined(USB_AUDIO) | #elif defined(USB_AUDIO) | ||||
| #define AUDIO_RX_ENDPOINT 4 | #define AUDIO_RX_ENDPOINT 4 | ||||
| #define AUDIO_RX_SIZE 180 | #define AUDIO_RX_SIZE 180 | ||||
| #define AUDIO_SYNC_ENDPOINT 5 | #define AUDIO_SYNC_ENDPOINT 5 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
| #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | ||||
| #define AUDIO_RX_ENDPOINT 7 | #define AUDIO_RX_ENDPOINT 7 | ||||
| #define AUDIO_RX_SIZE 180 | #define AUDIO_RX_SIZE 180 | ||||
| #define AUDIO_SYNC_ENDPOINT 8 | #define AUDIO_SYNC_ENDPOINT 8 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
| #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | ||||
| #define AUDIO_RX_ENDPOINT 7 | #define AUDIO_RX_ENDPOINT 7 | ||||
| #define AUDIO_RX_SIZE 180 | #define AUDIO_RX_SIZE 180 | ||||
| #define AUDIO_SYNC_ENDPOINT 8 | #define AUDIO_SYNC_ENDPOINT 8 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_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 ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY | ||||
| #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
| #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | #define ENDPOINT7_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS | ||||
| #define MULTITOUCH_ENDPOINT 15 | #define MULTITOUCH_ENDPOINT 15 | ||||
| #define MULTITOUCH_SIZE 8 | #define MULTITOUCH_SIZE 8 | ||||
| #define MULTITOUCH_FINGERS 10 | #define MULTITOUCH_FINGERS 10 | ||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | #define ENDPOINT2_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | ||||
| #define ENDPOINT3_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 ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE | ||||
| #define ENDPOINT7_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 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 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 ENDPOINT13_CONFIG (ENDPOINT_RECEIVE_ISOCHRONOUS|ENDPOINT_TRANSMIT_ISOCHRONOUS) | ||||
| #define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS | ||||
| #define ENDPOINT15_CONFIG ENDPOINT_TRANSIMIT_ONLY | |||||
| #define ENDPOINT15_CONFIG ENDPOINT_TRANSMIT_ONLY | |||||
| #endif | #endif | ||||
| #include "usb_mem.h" | #include "usb_mem.h" | ||||
| #include <string.h> // for memset | #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 | // buffer descriptor table | ||||
| typedef struct { | typedef struct { | ||||
| //serial_print("desc: not found\n"); | //serial_print("desc: not found\n"); | ||||
| endpoint0_stall(); | endpoint0_stall(); | ||||
| return; | return; | ||||
| #if defined(CDC_STATUS_INTERFACE) | |||||
| case 0x2221: // CDC_SET_CONTROL_LINE_STATE | 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"); | //serial_print("set control line state\n"); | ||||
| break; | break; | ||||
| #ifdef CDC_STATUS_INTERFACE | |||||
| case 0x2321: // CDC_SEND_BREAK | case 0x2321: // CDC_SEND_BREAK | ||||
| break; | break; | ||||
| case 0x2021: // CDC_SET_LINE_CODING | case 0x2021: // CDC_SET_LINE_CODING | ||||
| case 0x01: // OUT transaction received from host | case 0x01: // OUT transaction received from host | ||||
| case 0x02: | case 0x02: | ||||
| //serial_print("PID=OUT\n"); | //serial_print("PID=OUT\n"); | ||||
| #ifdef CDC_STATUS_INTERFACE | |||||
| if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { | if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { | ||||
| int i; | 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); | endpoint0_transmit(NULL, 0); | ||||
| } | } | ||||
| #endif | |||||
| #ifdef KEYBOARD_INTERFACE | #ifdef KEYBOARD_INTERFACE | ||||
| if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { | if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { | ||||
| keyboard_leds = buf[0]; | keyboard_leds = buf[0]; | ||||
| return usb_queue_byte_count(tx_first[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) | uint32_t usb_tx_packet_count(uint32_t endpoint) | ||||
| { | { | ||||
| const usb_packet_t *p; | const usb_packet_t *p; | ||||
| { | { | ||||
| // TODO: initialize R0 with a code.... | // TODO: initialize R0 with a code.... | ||||
| __asm__ volatile("bkpt"); | __asm__ volatile("bkpt"); | ||||
| __builtin_unreachable(); | |||||
| } | } | ||||
| if (t == 0) usb_serial_flush_callback(); | if (t == 0) usb_serial_flush_callback(); | ||||
| } | } | ||||
| #endif | #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 | #ifdef SEREMU_INTERFACE | ||||
| t = usb_seremu_transmit_flush_timer; | t = usb_seremu_transmit_flush_timer; | ||||
| if (t) { | if (t) { | ||||
| usb_init_serialnumber(); | 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].desc = 0; | ||||
| table[i].addr = 0; | table[i].addr = 0; | ||||
| } | } | ||||
| #ifdef HAS_KINETIS_MPU | #ifdef HAS_KINETIS_MPU | ||||
| MPU_RGDAAC0 |= 0x03000000; | MPU_RGDAAC0 |= 0x03000000; | ||||
| #endif | #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 | // 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_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 | | USB0_CLK_RECOVER_CTRL = USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN | |
| return usb_rx_byte_count_data[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 | #ifdef SEREMU_INTERFACE | ||||
| extern volatile uint8_t usb_seremu_transmit_flush_timer; | extern volatile uint8_t usb_seremu_transmit_flush_timer; | ||||
| extern void usb_seremu_flush_callback(void); | extern void usb_seremu_flush_callback(void); | ||||
| } | } | ||||
| #endif | #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 | #else // F_CPU < 20000000 | ||||
| #ifdef __cplusplus | #ifdef __cplusplus |
| FlightSimInteger * FlightSimInteger::last = NULL; | FlightSimInteger * FlightSimInteger::last = NULL; | ||||
| FlightSimFloat * FlightSimFloat::first = NULL; | FlightSimFloat * FlightSimFloat::first = NULL; | ||||
| FlightSimFloat * FlightSimFloat::last = 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::enabled = 0; | ||||
| uint8_t FlightSimClass::request_id_messages = 0; | uint8_t FlightSimClass::request_id_messages = 0; | ||||
| FlightSimClass::xmit(buf, 4, NULL, 0); | 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() | FlightSimInteger::FlightSimInteger() | ||||
| { | { | ||||
| data.b[2] = p[8]; | data.b[2] = p[8]; | ||||
| data.b[3] = p[9]; | data.b[3] = p[9]; | ||||
| item->update(data.f); | 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; | break; | ||||
| case 0x03: // enable/disable | case 0x03: // enable/disable | ||||
| for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) { | for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) { | ||||
| p->identify(); | 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) { | for (FlightSimInteger *p = FlightSimInteger::first; p; p = p->next) { | ||||
| p->identify(); | p->identify(); | ||||
| // TODO: send any dirty data | // TODO: send any dirty data |
| friend class FlightSimCommand; | friend class FlightSimCommand; | ||||
| friend class FlightSimInteger; | friend class FlightSimInteger; | ||||
| friend class FlightSimFloat; | friend class FlightSimFloat; | ||||
| /// JB | |||||
| friend class FlightSimEvent; | |||||
| friend class FlightSimData; | |||||
| /// JB End | |||||
| }; | }; | ||||
| friend class FlightSimClass; | 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 | class FlightSimInteger | ||||
| { | { |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include "WProgram.h" | |||||
| #include <Arduino.h> | |||||
| #include "usb_desc.h" | #include "usb_desc.h" | ||||
| #if F_CPU >= 20000000 | #if F_CPU >= 20000000 | ||||
| #endif | #endif | ||||
| #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 | #ifdef MIDI_INTERFACE | ||||
| usb_midi_class usbMIDI; | usb_midi_class usbMIDI; | ||||
| #endif | #endif | ||||
| #else // F_CPU < 20 MHz | #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; | usb_serial_class Serial; | ||||
| #elif (USB_DISABLED) | #elif (USB_DISABLED) | ||||
| usb_serial_class Serial; | usb_serial_class Serial; | ||||
| #endif | #endif | ||||
| #endif // F_CPU | #endif // F_CPU | ||||
| void serialEvent() __attribute__((weak)); | |||||
| void serialEvent() {} |
| // When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
| #define TX_TIMEOUT_MSEC 30 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
| // When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
| #define TX_TIMEOUT_MSEC 50 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
| void set_key4(uint8_t c) { keyboard_keys[3] = c; } | void set_key4(uint8_t c) { keyboard_keys[3] = c; } | ||||
| void set_key5(uint8_t c) { keyboard_keys[4] = c; } | void set_key5(uint8_t c) { keyboard_keys[4] = c; } | ||||
| void set_key6(uint8_t c) { keyboard_keys[5] = c; } | void set_key6(uint8_t c) { keyboard_keys[5] = c; } | ||||
| #ifdef KEYMEDIA_INTERFACE | |||||
| void set_media(uint16_t c) { | void set_media(uint16_t c) { | ||||
| if (c == 0) { | if (c == 0) { | ||||
| usb_keymedia_release_all(); | usb_keymedia_release_all(); | ||||
| press(c); | press(c); | ||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| void send_now(void) { usb_keyboard_send(); } | void send_now(void) { usb_keyboard_send(); } | ||||
| void press(uint16_t n) { usb_keyboard_press_keycode(n); } | void press(uint16_t n) { usb_keyboard_press_keycode(n); } | ||||
| void release(uint16_t n) { usb_keyboard_release_keycode(n); } | void release(uint16_t n) { usb_keyboard_release_keycode(n); } |
| // When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
| #define TX_TIMEOUT_MSEC 40 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | ||||
| #endif | #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) | void usb_midi_write_packed(uint32_t n) | ||||
| { | { | ||||
| uint32_t index, wait_count=0; | uint32_t index, wait_count=0; | ||||
| } else { | } else { | ||||
| tx_packet->len = MIDI_TX_SIZE; | tx_packet->len = MIDI_TX_SIZE; | ||||
| usb_tx(MIDI_TX_ENDPOINT, tx_packet); | usb_tx(MIDI_TX_ENDPOINT, tx_packet); | ||||
| tx_packet = usb_malloc(); | |||||
| tx_packet = NULL; | |||||
| } | } | ||||
| tx_noautoflush = 0; | tx_noautoflush = 0; | ||||
| } | } | ||||
| if (tx_noautoflush == 0 && tx_packet && tx_packet->index > 0) { | if (tx_noautoflush == 0 && tx_packet && tx_packet->index > 0) { | ||||
| tx_packet->len = tx_packet->index * 4; | tx_packet->len = tx_packet->index * 4; | ||||
| usb_tx(MIDI_TX_ENDPOINT, tx_packet); | usb_tx(MIDI_TX_ENDPOINT, tx_packet); | ||||
| tx_packet = usb_malloc(); | |||||
| tx_packet = NULL; | |||||
| } | } | ||||
| } | } | ||||
| // When the PC isn't listening, how long do we wait before discarding data? | // When the PC isn't listening, how long do we wait before discarding data? | ||||
| #define TX_TIMEOUT_MSEC 30 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
| // too short, we risk losing data during the stalls that are common with ordinary desktop | // 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. | // software. If it's too long, we stall the user's program when no software is running. | ||||
| #define TX_TIMEOUT_MSEC 30 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
| // too short, we risk losing data during the stalls that are common with ordinary desktop | // 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. | // software. If it's too long, we stall the user's program when no software is running. | ||||
| #define TX_TIMEOUT_MSEC 70 | #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) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600) | ||||
| #elif F_CPU == 216000000 | #elif F_CPU == 216000000 | ||||
| #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) | #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440) |
| #if F_CPU >= 20000000 && !defined(USB_DISABLED) | #if F_CPU >= 20000000 && !defined(USB_DISABLED) | ||||
| #include "core_pins.h" // for millis() | |||||
| // C language implementation | // C language implementation | ||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| extern "C" { | extern "C" { | ||||
| int usb_serial_write(const void *buffer, uint32_t size); | int usb_serial_write(const void *buffer, uint32_t size); | ||||
| int usb_serial_write_buffer_free(void); | int usb_serial_write_buffer_free(void); | ||||
| void usb_serial_flush_output(void); | void usb_serial_flush_output(void); | ||||
| void usb_serial_flush_callback(void); | |||||
| extern uint32_t usb_cdc_line_coding[2]; | extern uint32_t usb_cdc_line_coding[2]; | ||||
| extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | extern volatile uint32_t usb_cdc_line_rtsdtr_millis; | ||||
| extern volatile uint32_t systick_millis_count; | extern volatile uint32_t systick_millis_count; | ||||
| uint8_t numbits(void) { return usb_cdc_line_coding[1] >> 16; } | 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 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; } | 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 readBytes(char *buffer, size_t length) { | ||||
| size_t count=0; | size_t count=0; |
| /* 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 |
| /* 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_ |
| /* 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 |
| /* 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_ |
| // 5: Y msb | // 5: Y msb | ||||
| // 6: scan time lsb | // 6: scan time lsb | ||||
| // 7: scan time msb | // 7: scan time msb | ||||
| // 8: contact count | |||||
| // Called by the start-of-frame interrupt. | // Called by the start-of-frame interrupt. | ||||
| // | // | ||||
| void usb_touchscreen_update_callback(void) | void usb_touchscreen_update_callback(void) | ||||
| { | { | ||||
| uint8_t contact_count = 0; | |||||
| if (scan_index == 0) { | if (scan_index == 0) { | ||||
| if (usb_tx_packet_count(MULTITOUCH_ENDPOINT) > 1) { | if (usb_tx_packet_count(MULTITOUCH_ENDPOINT) > 1) { | ||||
| // wait to begin another scan if if more than | // wait to begin another scan if if more than | ||||
| } | } | ||||
| scan_timestamp = millis() * 10; | scan_timestamp = millis() * 10; | ||||
| scan_count = 0; | 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) { | while (scan_index < MULTITOUCH_FINGERS) { | ||||
| uint32_t press = pressure[scan_index]; | uint32_t press = pressure[scan_index]; | ||||
| uint32_t id = contactid[scan_index]; | uint32_t id = contactid[scan_index]; | ||||
| *(tx_packet->buf + 5) = ypos[scan_index] >> 8; | *(tx_packet->buf + 5) = ypos[scan_index] >> 8; | ||||
| *(tx_packet->buf + 6) = scan_timestamp; | *(tx_packet->buf + 6) = scan_timestamp; | ||||
| *(tx_packet->buf + 7) = scan_timestamp >> 8; | *(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); | usb_tx(MULTITOUCH_ENDPOINT, tx_packet); | ||||
| scan_index++; | scan_index++; | ||||
| return; | return; |
| #ifdef ENDPOINT_UNUSED | #ifdef ENDPOINT_UNUSED | ||||
| #undef ENDPOINT_UNUSED | #undef ENDPOINT_UNUSED | ||||
| #endif | #endif | ||||
| #ifdef ENDPOINT_TRANSIMIT_ONLY | |||||
| #undef ENDPOINT_TRANSIMIT_ONLY | |||||
| #ifdef ENDPOINT_TRANSMIT_ONLY | |||||
| #undef ENDPOINT_TRANSMIT_ONLY | |||||
| #endif | #endif | ||||
| #ifdef ENDPOINT_RECEIVE_ONLY | #ifdef ENDPOINT_RECEIVE_ONLY | ||||
| #undef ENDPOINT_RECEIVE_ONLY | #undef ENDPOINT_RECEIVE_ONLY | ||||
| #ifdef CDC_TX_SIZE | #ifdef CDC_TX_SIZE | ||||
| #undef CDC_TX_SIZE | #undef CDC_TX_SIZE | ||||
| #endif | #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 | #ifdef SEREMU_INTERFACE | ||||
| #undef SEREMU_INTERFACE | #undef SEREMU_INTERFACE | ||||
| #endif | #endif |
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <stdbool.h> | |||||
| #include "binary.h" | #include "binary.h" | ||||
| #include "core_id.h" | #include "core_id.h" | ||||
| #include "core_pins.h" | #include "core_pins.h" | ||||
| { | { | ||||
| long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max; | long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max; | ||||
| // Arduino's traditional algorithm | // 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 | // 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)) { | 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; | return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min; | ||||
| } else { | } else { | ||||
| return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | 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 | // 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> | template <class T, class A, class B, class C, class D> | ||||
| { | { | ||||
| return (x - (T)in_min) * ((T)out_max - (T)out_min) / ((T)in_max - (T)in_min) + (T)out_min; | 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> | #include <utility> | ||||
| // https://forum.pjrc.com/threads/44596-Teensyduino-1-37-Beta-2-(Arduino-1-8-3-support)?p=145150&viewfull=1#post145150 | // 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> | template<class A, class B> | ||||
| typedef bool boolean; | typedef bool boolean; | ||||
| #else | #else | ||||
| typedef uint8_t boolean; | typedef uint8_t boolean; | ||||
| #define false 0 | |||||
| #define true (!false) | |||||
| #endif | #endif | ||||
| #endif | #endif |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #include "core_pins.h" | |||||
| #include "HardwareSerial.h" | |||||
| #include "usb_serial.h" | |||||
| #include "usb_seremu.h" | |||||
| #include <Arduino.h> | |||||
| #include "EventResponder.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) __attribute__ ((weak)); | ||||
| void yield(void) | void yield(void) | ||||
| { | { | ||||
| static uint8_t running=0; | static uint8_t running=0; | ||||
| if (!yield_active_check_flags) return; // nothing to do | |||||
| if (running) return; // TODO: does this need to be atomic? | if (running) return; // TODO: does this need to be atomic? | ||||
| running = 1; | 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 | #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 | #endif | ||||
| if (yield_active_check_flags & YIELD_CHECK_HARDWARE_SERIAL) { | |||||
| HardwareSerial::processSerialEventsList(); | |||||
| } | |||||
| running = 0; | running = 0; | ||||
| EventResponder::runFromYield(); | |||||
| if (yield_active_check_flags & YIELD_CHECK_EVENT_RESPONDER) EventResponder::runFromYield(); | |||||
| }; | }; |
| // This header file is in the public domain. | |||||
| #ifndef Arduino_h | |||||
| #define Arduino_h | |||||
| #include "WProgram.h" | |||||
| #include "pins_arduino.h" | |||||
| #endif |
| /* 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"); | |||||
| } | |||||