diff --git a/IDE_Board_Manager/package_sparkfun_index.json b/IDE_Board_Manager/package_sparkfun_tiny_index.json similarity index 83% rename from IDE_Board_Manager/package_sparkfun_index.json rename to IDE_Board_Manager/package_sparkfun_tiny_index.json index 2634fe36..c5d96243 100644 --- a/IDE_Board_Manager/package_sparkfun_index.json +++ b/IDE_Board_Manager/package_sparkfun_tiny_index.json @@ -1,477 +1,562 @@ -{ - "packages":[ - { - "name":"SparkFun", - "maintainer":"SparkFun Electronics", - "websiteURL":"https://SparkFun.com", - "email":"TechSupport@SparkFun.com", - "help":{ - "online":"https://forum.sparkfun.com" - }, - "platforms":[ - { - "name":"SparkFun AVR Boards", - "architecture":"avr", - "version":"1.1.5", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfunboards.1.1.5.tar.bz2", - "archiveFileName":"sparkfunboards.1.1.5.tar.bz2", - "checksum":"SHA-256:41f9728983e0dbab597bb46ddf00b5bac6cfec7c8f3771ecd1612dae58bb0366", - "size":"1162215", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"RedBoard" }, - { "name":"MaKey MaKey" }, - { "name":"Pro Micro" }, - { "name":"Fio v3" }, - { "name":"Qduino Mini" }, - { "name":"Digital Sandbox" }, - { "name":"Mega Pro" }, - { "name":"RedBot" }, - { "name":"Serial 7-segment Display" }, - { "name":"ATmega128RFA1 Dev Board" } - ], - "toolsDependencies":[] - } - ], - "tools":[] - }, - { - "name":"SparkFun", - "maintainer":"SparkFun Electronics", - "websiteURL":"https://SparkFun.com", - "email":"TechSupport@SparkFun.com", - "help":{ - "online":"https://forum.sparkfun.com" - }, - "platforms":[ - { - "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.5)", - "architecture":"samd", - "version":"1.0.0", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.0.0.tar.bz2", - "archiveFileName":"sparkfun-samd-1.0.0.tar.bz2", - "checksum":"SHA-256:12e0be6862a3a28b6515755dcad2842757caf4e5270326554f95059512ebaab5", - "size":"268954", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"SparkFun SAMD21 Mini Breakout" }, - { "name":"SparkFun SAMD21 Dev Breakout" } - ], - "toolsDependencies":[] - }, - { - "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.5)", - "architecture":"samd", - "version":"1.1.0", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.1.0.tar.bz2", - "archiveFileName":"sparkfun-samd-1.1.0.tar.bz2", - "checksum":"SHA-256:5d71cbf8ccf5781eef9809d7b3141041daf3ed1a1272f5278762ece5a0aecf44", - "size":"279683", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"SparkFun SAMD21 Mini Breakout" }, - { "name":"SparkFun SAMD21 Dev Breakout" } - ], - "toolsDependencies":[] - }, - { - "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.5)", - "architecture":"samd", - "version":"1.2.0", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.2.0.tar.bz2", - "archiveFileName":"sparkfun-samd-1.2.0.tar.bz2", - "checksum":"SHA-256:50e055f311e07ba4d154bf00aa10579648024bef680bb3eb267401c496f791e6", - "size":"281932", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"SparkFun SAMD21 Mini Breakout" }, - { "name":"SparkFun SAMD21 Dev Breakout" } - ], - "toolsDependencies":[] - }, - { - "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.6)", - "architecture":"samd", - "version":"1.2.1", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.2.1.tar.bz2", - "archiveFileName":"sparkfun-samd-1.2.1.tar.bz2", - "checksum":"SHA-256:63b90fb26a18a89b2f51556a08286117cdade38d6cb7a16eb1eccb7d1d92422a", - "size":"280405", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"SparkFun SAMD21 Mini Breakout" }, - { "name":"SparkFun SAMD21 Dev Breakout" } - ], - "toolsDependencies":[] - }, - { - "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.8)", - "architecture":"samd", - "version":"1.2.2", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.2.2.tar.bz2", - "archiveFileName":"sparkfun-samd-1.2.2.tar.bz2", - "checksum":"SHA-256:21bc1ab1a8fd6550dca3b4953deaa2066d49ffa2583cd8e8a1e36d0c0ab00d52", - "size":"283240", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"SparkFun SAMD21 Mini Breakout" }, - { "name":"SparkFun SAMD21 Dev Breakout" } - ], - "toolsDependencies":[] - }, - { - "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.8)", - "architecture":"samd", - "version":"1.3.0", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.3.0.tar.bz2", - "archiveFileName":"sparkfun-samd-1.3.0.tar.bz2", - "checksum":"SHA-256:87695137f303000099e7e6d3fae3e87d5882ed999e4c14403c65cf51a4d6a6be", - "size":"195440", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"SparkFun SAMD21 Mini Breakout" }, - { "name":"SparkFun SAMD21 Dev Breakout" }, - { "name":"SparkFun 9DoF Razor IMU M0" } - ], - "toolsDependencies":[] - }, - { - "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.9)", - "architecture":"samd", - "version":"1.3.2", - "category":"Contributed", - "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.3.2.tar.bz2", - "archiveFileName":"sparkfun-samd-1.3.2.tar.bz2", - "checksum":"SHA-256:eb4274a3df4c6c4dbc1396600b1efc9cd9454e5be4880530ff87ba4fb3e6216a", - "size":"206253", - "help":{ - "online":"https://forums.sparkfun.com" - }, - "boards":[ - { "name":"SparkFun SAMD21 Mini Breakout" }, - { "name":"SparkFun SAMD21 Dev Breakout" }, - { "name":"SparkFun 9DoF Razor IMU M0" } - ], - "toolsDependencies":[] - } - ], - "tools":[] - }, - { - "maintainer": "SparkFun Electronics", - "help": { - "online": "http://SparkFun.com" - }, - "websiteURL": "https://github.com/sparkfun/Arduino_Boards", - "platforms": [ - { - "category": "Contributed", - "name": "SparkFun ESP8266 Boards", - "url":"https://cdn.sparkfun.com/assets/learn_tutorials/4/9/5/sparkfun-esp8266-2.1.0.tar.bz2", - "checksum":"SHA-256:FE3E0504B38A5A4C912801A3E4633380A666DC77B8D3043548187AF8675477DA", - "help":{ - "online":"https://learn.sparkfun.com" - }, - "version": "2.1.0", - "architecture": "esp8266", - "archiveFileName":"sparkfun-esp8266-2.1.0.tar.bz2", - "boards":[ - { "name":"SparkFun Blynk Board - ESP8266" }, - { "name":"SparkFun ESP8266 Thing" }, - { "name":"SparkFun ESP8266 Thing - Development Board" }, - { "name":"Generic ESP8266 Module" } - ], - "toolsDependencies": [ - { - "packager": "esp8266", - "version": "0.4.8", - "name": "esptool" - }, - { - "packager": "esp8266", - "version": "1.20.0-26-gb404fb9-2", - "name": "xtensa-lx106-elf-gcc" - }, - { - "packager": "esp8266", - "version": "0.1.2", - "name": "mkspiffs" - } - ], - "size": "5436076" - } - ], - "tools": [ - { - "version": "1.20.0-26-gb404fb9-2", - "name": "xtensa-lx106-elf-gcc", - "systems": [ - { - "url": "http://arduino.esp8266.com/win32-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "checksum": "SHA-256:10476b9c11a7a90f40883413ddfb409f505b20692e316c4e597c4c175b4be09c", - "host": "i686-mingw32", - "archiveFileName": "win32-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "size": "153527527" - }, - { - "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", - "host": "x86_64-apple-darwin", - "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "size": "35385382" - }, - { - "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", - "host": "i386-apple-darwin", - "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "size": "35385382" - }, - { - "url": "http://arduino.esp8266.com/linux64-xtensa-lx106-elf-gb404fb9.tar.gz", - "checksum": "SHA-256:46f057fbd8b320889a26167daf325038912096d09940b2a95489db92431473b7", - "host": "x86_64-pc-linux-gnu", - "archiveFileName": "linux64-xtensa-lx106-elf-gb404fb9.tar.gz", - "size": "30262903" - }, - { - "url": "http://arduino.esp8266.com/linux32-xtensa-lx106-elf.tar.gz", - "checksum": "SHA-256:b24817819f0078fb05895a640e806e0aca9aa96b47b80d2390ac8e2d9ddc955a", - "host": "i686-pc-linux-gnu", - "archiveFileName": "linux32-xtensa-lx106-elf.tar.gz", - "size": "32734156" - } - ] - }, - { - "version": "1.20.0-26-gb404fb9", - "name": "xtensa-lx106-elf-gcc", - "systems": [ - { - "url": "http://arduino.esp8266.com/win32-xtensa-lx106-elf-gb404fb9.tar.gz", - "checksum": "SHA-256:1561ec85cc58cab35cc48bfdb0d0087809f89c043112a2c36b54251a13bf781f", - "host": "i686-mingw32", - "archiveFileName": "win32-xtensa-lx106-elf-gb404fb9.tar.gz", - "size": "153807368" - }, - { - "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", - "host": "x86_64-apple-darwin", - "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "size": "35385382" - }, - { - "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", - "host": "i386-apple-darwin", - "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", - "size": "35385382" - }, - { - "url": "http://arduino.esp8266.com/linux64-xtensa-lx106-elf-gb404fb9.tar.gz", - "checksum": "SHA-256:46f057fbd8b320889a26167daf325038912096d09940b2a95489db92431473b7", - "host": "x86_64-pc-linux-gnu", - "archiveFileName": "linux64-xtensa-lx106-elf-gb404fb9.tar.gz", - "size": "30262903" - }, - { - "url": "http://arduino.esp8266.com/linux32-xtensa-lx106-elf.tar.gz", - "checksum": "SHA-256:b24817819f0078fb05895a640e806e0aca9aa96b47b80d2390ac8e2d9ddc955a", - "host": "i686-pc-linux-gnu", - "archiveFileName": "linux32-xtensa-lx106-elf.tar.gz", - "size": "32734156" - } - ] - }, - { - "version": "0.4.8", - "name": "esptool", - "systems": [ - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-win32.zip", - "checksum": "SHA-256:8d09cb0df6234c2a0562389ceedd11482b44a3f538695f9a4df80f9f10411ece", - "host": "i686-mingw32", - "archiveFileName": "esptool-0.4.8-win32.zip", - "size": "32192" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-osx.tar.gz", - "checksum": "SHA-256:2bcbf19934543fb06c505b2a595b68a76e4cab8e3d8968a4d1802195c87126cf", - "host": "x86_64-apple-darwin", - "archiveFileName": "esptool-0.4.8-osx.tar.gz", - "size": "28798" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-osx.tar.gz", - "checksum": "SHA-256:2bcbf19934543fb06c505b2a595b68a76e4cab8e3d8968a4d1802195c87126cf", - "host": "i386-apple-darwin", - "archiveFileName": "esptool-0.4.8-osx.tar.gz", - "size": "28798" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-linux64.tar.gz", - "checksum": "SHA-256:1cd9a6014bbbc37ba6dc249f4fc027f0ca9bbc6dd0e203ebc7d146dfd78a6e78", - "host": "x86_64-pc-linux-gnu", - "archiveFileName": "esptool-0.4.8-linux64.tar.gz", - "size": "15479" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-linux32.tar.gz", - "checksum": "SHA-256:b0d6e71e6f41d4ed7e167bb4b3f4f0b1b3e49d69af50ab7fbe952cbfed83f164", - "host": "i686-pc-linux-gnu", - "archiveFileName": "esptool-0.4.8-linux32.tar.gz", - "size": "15444" - } - ] - }, - { - "version": "0.4.5", - "name": "esptool", - "systems": [ - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-win32.zip", - "checksum": "SHA-256:1b0a7d254e74942d820a09281aa5dc2af1c8314ae5ee1a5abb0653d0580e531b", - "host": "i686-mingw32", - "archiveFileName": "esptool-0.4.5-win32.zip", - "size": "17408" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-osx.tar.gz", - "checksum": "SHA-256:924d31c64f4bb9f748e70806dafbabb15e5eb80afcdde33715f3ec884be1652d", - "host": "x86_64-apple-darwin", - "archiveFileName": "esptool-0.4.5-osx.tar.gz", - "size": "11359" - }, - { - "url": "http://arduino.esp8266.com/esptool-0.4.5-1-gfaa5794-osx.tar.gz", - "checksum": "SHA-256:722142071f6cf4d8c02dea42497a747e06abf583d86137a6a256b7db71dc61f6", - "host": "i386-apple-darwin", - "archiveFileName": "esptool-0.4.5-1-gfaa5794-osx.tar.gz", - "size": "20751" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-linux64.tar.gz", - "checksum": "SHA-256:4ce799e13fbd89f8a8f08a08db77dc3b1362c4486306fe1b3801dee80cfa3203", - "host": "x86_64-pc-linux-gnu", - "archiveFileName": "esptool-0.4.5-linux64.tar.gz", - "size": "12789" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-linux32.tar.gz", - "checksum": "SHA-256:a7a2c3200786d7396e8cafca1b9aefe56db8ec1dab5e9163d4a19358232a7d87", - "host": "i686-pc-linux-gnu", - "archiveFileName": "esptool-0.4.5-linux32.tar.gz", - "size": "12055" - } - ] - }, - { - "version": "0.4.6", - "name": "esptool", - "systems": [ - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-win32.zip", - "checksum": "SHA-256:0248bf78514a3195f583e29218ca7828a66e13c6e5545a078f1c1257033e4927", - "host": "i686-mingw32", - "archiveFileName": "esptool-0.4.6-win32.zip", - "size": "17481" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-osx.tar.gz", - "checksum": "SHA-256:0fe87ba7e29ee90a9fc72492aada8c0796f9e8f8a1c594b6b26cee2610d09bb3", - "host": "x86_64-apple-darwin", - "archiveFileName": "esptool-0.4.6-osx.tar.gz", - "size": "20926" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-osx.tar.gz", - "checksum": "SHA-256:0fe87ba7e29ee90a9fc72492aada8c0796f9e8f8a1c594b6b26cee2610d09bb3", - "host": "i386-apple-darwin", - "archiveFileName": "esptool-0.4.6-osx.tar.gz", - "size": "20926" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-linux64.tar.gz", - "checksum": "SHA-256:f9f456e9a42bb2597126c513cb8865f923fb978865d4838b9623d322216b74d0", - "host": "x86_64-pc-linux-gnu", - "archiveFileName": "esptool-0.4.6-linux64.tar.gz", - "size": "12885" - }, - { - "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-linux32.tar.gz", - "checksum": "SHA-256:85275ca03a82bfc456f5a84e86962ca1e470ea2e168829c38ca29ee668831d93", - "host": "i686-pc-linux-gnu", - "archiveFileName": "esptool-0.4.6-linux32.tar.gz", - "size": "13417" - } - ] - }, - { - "version": "0.1.2", - "name": "mkspiffs", - "systems": [ - { - "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-windows.zip", - "checksum": "SHA-256:0a29119b8458b61a877408f7995e4944623a712e0d313a2c2f76af9ab55cc9f2", - "host": "i686-mingw32", - "archiveFileName": "mkspiffs-0.1.2-windows.zip", - "size": "230802" - }, - { - "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-osx.tar.gz", - "checksum": "SHA-256:df656fae21a41c1269ea50cb53752dcaf6a4e1437255f3a9fb50b4025549b58e", - "host": "x86_64-apple-darwin", - "archiveFileName": "mkspiffs-0.1.2-osx.tar.gz", - "size": "115091" - }, - { - "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-osx.tar.gz", - "checksum": "SHA-256:df656fae21a41c1269ea50cb53752dcaf6a4e1437255f3a9fb50b4025549b58e", - "host": "i386-apple-darwin", - "archiveFileName": "mkspiffs-0.1.2-osx.tar.gz", - "size": "115091" - }, - { - "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-linux64.tar.gz", - "checksum": "SHA-256:1a1dd81b51daf74c382db71b42251757ca4136e8762107e69feaa8617bac315f", - "host": "x86_64-pc-linux-gnu", - "archiveFileName": "mkspiffs-0.1.2-linux64.tar.gz", - "size": "46281" - }, - { - "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-linux32.tar.gz", - "checksum": "SHA-256:e990d545dfcae308aabaac5fa9e1db734cc2b08167969e7eedac88bd0839667c", - "host": "i686-pc-linux-gnu", - "archiveFileName": "mkspiffs-0.1.2-linux32.tar.gz", - "size": "45272" - } - ] - } - ], - "email": "ivan@esp8266.com", - "name": "esp8266" - } - ] -} +{ + "packages":[ + { + "name":"SparkFun", + "maintainer":"SparkFun Electronics", + "websiteURL":"https://SparkFun.com", + "email":"TechSupport@SparkFun.com", + "help":{ + "online":"https://forum.sparkfun.com" + }, + "platforms":[ + { + "name":"SparkFun AVR Boards", + "architecture":"avr", + "version":"1.1.5", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfunboards.1.1.5.tar.bz2", + "archiveFileName":"sparkfunboards.1.1.5.tar.bz2", + "checksum":"SHA-256:41f9728983e0dbab597bb46ddf00b5bac6cfec7c8f3771ecd1612dae58bb0366", + "size":"1162215", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"RedBoard" }, + { "name":"MaKey MaKey" }, + { "name":"Pro Micro" }, + { "name":"Fio v3" }, + { "name":"Qduino Mini" }, + { "name":"Digital Sandbox" }, + { "name":"Mega Pro" }, + { "name":"RedBot" }, + { "name":"Serial 7-segment Display" }, + { "name":"ATmega128RFA1 Dev Board" } + ], + "toolsDependencies":[] + } + ], + "tools":[] + }, + { + "name":"SparkFun", + "maintainer":"SparkFun Electronics", + "websiteURL":"https://SparkFun.com", + "email":"TechSupport@SparkFun.com", + "help":{ + "online":"https://forum.sparkfun.com" + }, + "platforms":[ + { + "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.5)", + "architecture":"samd", + "version":"1.0.0", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.0.0.tar.bz2", + "archiveFileName":"sparkfun-samd-1.0.0.tar.bz2", + "checksum":"SHA-256:12e0be6862a3a28b6515755dcad2842757caf4e5270326554f95059512ebaab5", + "size":"268954", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"SparkFun SAMD21 Mini Breakout" }, + { "name":"SparkFun SAMD21 Dev Breakout" } + ], + "toolsDependencies":[] + }, + { + "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.5)", + "architecture":"samd", + "version":"1.1.0", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.1.0.tar.bz2", + "archiveFileName":"sparkfun-samd-1.1.0.tar.bz2", + "checksum":"SHA-256:5d71cbf8ccf5781eef9809d7b3141041daf3ed1a1272f5278762ece5a0aecf44", + "size":"279683", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"SparkFun SAMD21 Mini Breakout" }, + { "name":"SparkFun SAMD21 Dev Breakout" } + ], + "toolsDependencies":[] + }, + { + "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.5)", + "architecture":"samd", + "version":"1.2.0", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.2.0.tar.bz2", + "archiveFileName":"sparkfun-samd-1.2.0.tar.bz2", + "checksum":"SHA-256:50e055f311e07ba4d154bf00aa10579648024bef680bb3eb267401c496f791e6", + "size":"281932", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"SparkFun SAMD21 Mini Breakout" }, + { "name":"SparkFun SAMD21 Dev Breakout" } + ], + "toolsDependencies":[] + }, + { + "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.6)", + "architecture":"samd", + "version":"1.2.1", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.2.1.tar.bz2", + "archiveFileName":"sparkfun-samd-1.2.1.tar.bz2", + "checksum":"SHA-256:63b90fb26a18a89b2f51556a08286117cdade38d6cb7a16eb1eccb7d1d92422a", + "size":"280405", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"SparkFun SAMD21 Mini Breakout" }, + { "name":"SparkFun SAMD21 Dev Breakout" } + ], + "toolsDependencies":[] + }, + { + "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.8)", + "architecture":"samd", + "version":"1.2.2", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.2.2.tar.bz2", + "archiveFileName":"sparkfun-samd-1.2.2.tar.bz2", + "checksum":"SHA-256:21bc1ab1a8fd6550dca3b4953deaa2066d49ffa2583cd8e8a1e36d0c0ab00d52", + "size":"283240", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"SparkFun SAMD21 Mini Breakout" }, + { "name":"SparkFun SAMD21 Dev Breakout" } + ], + "toolsDependencies":[] + }, + { + "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.8)", + "architecture":"samd", + "version":"1.3.0", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.3.0.tar.bz2", + "archiveFileName":"sparkfun-samd-1.3.0.tar.bz2", + "checksum":"SHA-256:87695137f303000099e7e6d3fae3e87d5882ed999e4c14403c65cf51a4d6a6be", + "size":"195440", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"SparkFun SAMD21 Mini Breakout" }, + { "name":"SparkFun SAMD21 Dev Breakout" }, + { "name":"SparkFun 9DoF Razor IMU M0" } + ], + "toolsDependencies":[] + }, + { + "name":"SparkFun SAMD Boards (dependency: Arduino SAMD Boards 1.6.9)", + "architecture":"samd", + "version":"1.3.2", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/master/IDE_Board_Manager/sparkfun-samd-1.3.2.tar.bz2", + "archiveFileName":"sparkfun-samd-1.3.2.tar.bz2", + "checksum":"SHA-256:eb4274a3df4c6c4dbc1396600b1efc9cd9454e5be4880530ff87ba4fb3e6216a", + "size":"206253", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"SparkFun SAMD21 Mini Breakout" }, + { "name":"SparkFun SAMD21 Dev Breakout" }, + { "name":"SparkFun 9DoF Razor IMU M0" } + ], + "toolsDependencies":[] + } + ], + "tools":[] + }, + { + "maintainer": "SparkFun Electronics", + "help": { + "online": "http://SparkFun.com" + }, + "websiteURL": "https://github.com/sparkfun/Arduino_Boards", + "platforms": [ + { + "category": "Contributed", + "name": "SparkFun ESP8266 Boards", + "url":"https://cdn.sparkfun.com/assets/learn_tutorials/4/9/5/sparkfun-esp8266-2.1.0.tar.bz2", + "checksum":"SHA-256:FE3E0504B38A5A4C912801A3E4633380A666DC77B8D3043548187AF8675477DA", + "help":{ + "online":"https://learn.sparkfun.com" + }, + "version": "2.1.0", + "architecture": "esp8266", + "archiveFileName":"sparkfun-esp8266-2.1.0.tar.bz2", + "boards":[ + { "name":"SparkFun Blynk Board - ESP8266" }, + { "name":"SparkFun ESP8266 Thing" }, + { "name":"SparkFun ESP8266 Thing - Development Board" }, + { "name":"Generic ESP8266 Module" } + ], + "toolsDependencies": [ + { + "packager": "esp8266", + "version": "0.4.8", + "name": "esptool" + }, + { + "packager": "esp8266", + "version": "1.20.0-26-gb404fb9-2", + "name": "xtensa-lx106-elf-gcc" + }, + { + "packager": "esp8266", + "version": "0.1.2", + "name": "mkspiffs" + } + ], + "size": "5436076" + } + ], + "tools": [ + { + "version": "1.20.0-26-gb404fb9-2", + "name": "xtensa-lx106-elf-gcc", + "systems": [ + { + "url": "http://arduino.esp8266.com/win32-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "checksum": "SHA-256:10476b9c11a7a90f40883413ddfb409f505b20692e316c4e597c4c175b4be09c", + "host": "i686-mingw32", + "archiveFileName": "win32-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "size": "153527527" + }, + { + "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", + "host": "x86_64-apple-darwin", + "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "size": "35385382" + }, + { + "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", + "host": "i386-apple-darwin", + "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "size": "35385382" + }, + { + "url": "http://arduino.esp8266.com/linux64-xtensa-lx106-elf-gb404fb9.tar.gz", + "checksum": "SHA-256:46f057fbd8b320889a26167daf325038912096d09940b2a95489db92431473b7", + "host": "x86_64-pc-linux-gnu", + "archiveFileName": "linux64-xtensa-lx106-elf-gb404fb9.tar.gz", + "size": "30262903" + }, + { + "url": "http://arduino.esp8266.com/linux32-xtensa-lx106-elf.tar.gz", + "checksum": "SHA-256:b24817819f0078fb05895a640e806e0aca9aa96b47b80d2390ac8e2d9ddc955a", + "host": "i686-pc-linux-gnu", + "archiveFileName": "linux32-xtensa-lx106-elf.tar.gz", + "size": "32734156" + } + ] + }, + { + "version": "1.20.0-26-gb404fb9", + "name": "xtensa-lx106-elf-gcc", + "systems": [ + { + "url": "http://arduino.esp8266.com/win32-xtensa-lx106-elf-gb404fb9.tar.gz", + "checksum": "SHA-256:1561ec85cc58cab35cc48bfdb0d0087809f89c043112a2c36b54251a13bf781f", + "host": "i686-mingw32", + "archiveFileName": "win32-xtensa-lx106-elf-gb404fb9.tar.gz", + "size": "153807368" + }, + { + "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", + "host": "x86_64-apple-darwin", + "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "size": "35385382" + }, + { + "url": "http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "checksum": "SHA-256:0cf150193997bd1355e0f49d3d49711730035257bc1aee1eaaad619e56b9e4e6", + "host": "i386-apple-darwin", + "archiveFileName": "osx-xtensa-lx106-elf-gb404fb9-2.tar.gz", + "size": "35385382" + }, + { + "url": "http://arduino.esp8266.com/linux64-xtensa-lx106-elf-gb404fb9.tar.gz", + "checksum": "SHA-256:46f057fbd8b320889a26167daf325038912096d09940b2a95489db92431473b7", + "host": "x86_64-pc-linux-gnu", + "archiveFileName": "linux64-xtensa-lx106-elf-gb404fb9.tar.gz", + "size": "30262903" + }, + { + "url": "http://arduino.esp8266.com/linux32-xtensa-lx106-elf.tar.gz", + "checksum": "SHA-256:b24817819f0078fb05895a640e806e0aca9aa96b47b80d2390ac8e2d9ddc955a", + "host": "i686-pc-linux-gnu", + "archiveFileName": "linux32-xtensa-lx106-elf.tar.gz", + "size": "32734156" + } + ] + }, + { + "version": "0.4.8", + "name": "esptool", + "systems": [ + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-win32.zip", + "checksum": "SHA-256:8d09cb0df6234c2a0562389ceedd11482b44a3f538695f9a4df80f9f10411ece", + "host": "i686-mingw32", + "archiveFileName": "esptool-0.4.8-win32.zip", + "size": "32192" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-osx.tar.gz", + "checksum": "SHA-256:2bcbf19934543fb06c505b2a595b68a76e4cab8e3d8968a4d1802195c87126cf", + "host": "x86_64-apple-darwin", + "archiveFileName": "esptool-0.4.8-osx.tar.gz", + "size": "28798" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-osx.tar.gz", + "checksum": "SHA-256:2bcbf19934543fb06c505b2a595b68a76e4cab8e3d8968a4d1802195c87126cf", + "host": "i386-apple-darwin", + "archiveFileName": "esptool-0.4.8-osx.tar.gz", + "size": "28798" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-linux64.tar.gz", + "checksum": "SHA-256:1cd9a6014bbbc37ba6dc249f4fc027f0ca9bbc6dd0e203ebc7d146dfd78a6e78", + "host": "x86_64-pc-linux-gnu", + "archiveFileName": "esptool-0.4.8-linux64.tar.gz", + "size": "15479" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.8/esptool-0.4.8-linux32.tar.gz", + "checksum": "SHA-256:b0d6e71e6f41d4ed7e167bb4b3f4f0b1b3e49d69af50ab7fbe952cbfed83f164", + "host": "i686-pc-linux-gnu", + "archiveFileName": "esptool-0.4.8-linux32.tar.gz", + "size": "15444" + } + ] + }, + { + "version": "0.4.5", + "name": "esptool", + "systems": [ + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-win32.zip", + "checksum": "SHA-256:1b0a7d254e74942d820a09281aa5dc2af1c8314ae5ee1a5abb0653d0580e531b", + "host": "i686-mingw32", + "archiveFileName": "esptool-0.4.5-win32.zip", + "size": "17408" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-osx.tar.gz", + "checksum": "SHA-256:924d31c64f4bb9f748e70806dafbabb15e5eb80afcdde33715f3ec884be1652d", + "host": "x86_64-apple-darwin", + "archiveFileName": "esptool-0.4.5-osx.tar.gz", + "size": "11359" + }, + { + "url": "http://arduino.esp8266.com/esptool-0.4.5-1-gfaa5794-osx.tar.gz", + "checksum": "SHA-256:722142071f6cf4d8c02dea42497a747e06abf583d86137a6a256b7db71dc61f6", + "host": "i386-apple-darwin", + "archiveFileName": "esptool-0.4.5-1-gfaa5794-osx.tar.gz", + "size": "20751" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-linux64.tar.gz", + "checksum": "SHA-256:4ce799e13fbd89f8a8f08a08db77dc3b1362c4486306fe1b3801dee80cfa3203", + "host": "x86_64-pc-linux-gnu", + "archiveFileName": "esptool-0.4.5-linux64.tar.gz", + "size": "12789" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.5/esptool-0.4.5-linux32.tar.gz", + "checksum": "SHA-256:a7a2c3200786d7396e8cafca1b9aefe56db8ec1dab5e9163d4a19358232a7d87", + "host": "i686-pc-linux-gnu", + "archiveFileName": "esptool-0.4.5-linux32.tar.gz", + "size": "12055" + } + ] + }, + { + "version": "0.4.6", + "name": "esptool", + "systems": [ + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-win32.zip", + "checksum": "SHA-256:0248bf78514a3195f583e29218ca7828a66e13c6e5545a078f1c1257033e4927", + "host": "i686-mingw32", + "archiveFileName": "esptool-0.4.6-win32.zip", + "size": "17481" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-osx.tar.gz", + "checksum": "SHA-256:0fe87ba7e29ee90a9fc72492aada8c0796f9e8f8a1c594b6b26cee2610d09bb3", + "host": "x86_64-apple-darwin", + "archiveFileName": "esptool-0.4.6-osx.tar.gz", + "size": "20926" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-osx.tar.gz", + "checksum": "SHA-256:0fe87ba7e29ee90a9fc72492aada8c0796f9e8f8a1c594b6b26cee2610d09bb3", + "host": "i386-apple-darwin", + "archiveFileName": "esptool-0.4.6-osx.tar.gz", + "size": "20926" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-linux64.tar.gz", + "checksum": "SHA-256:f9f456e9a42bb2597126c513cb8865f923fb978865d4838b9623d322216b74d0", + "host": "x86_64-pc-linux-gnu", + "archiveFileName": "esptool-0.4.6-linux64.tar.gz", + "size": "12885" + }, + { + "url": "https://github.com/igrr/esptool-ck/releases/download/0.4.6/esptool-0.4.6-linux32.tar.gz", + "checksum": "SHA-256:85275ca03a82bfc456f5a84e86962ca1e470ea2e168829c38ca29ee668831d93", + "host": "i686-pc-linux-gnu", + "archiveFileName": "esptool-0.4.6-linux32.tar.gz", + "size": "13417" + } + ] + }, + { + "version": "0.1.2", + "name": "mkspiffs", + "systems": [ + { + "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-windows.zip", + "checksum": "SHA-256:0a29119b8458b61a877408f7995e4944623a712e0d313a2c2f76af9ab55cc9f2", + "host": "i686-mingw32", + "archiveFileName": "mkspiffs-0.1.2-windows.zip", + "size": "230802" + }, + { + "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-osx.tar.gz", + "checksum": "SHA-256:df656fae21a41c1269ea50cb53752dcaf6a4e1437255f3a9fb50b4025549b58e", + "host": "x86_64-apple-darwin", + "archiveFileName": "mkspiffs-0.1.2-osx.tar.gz", + "size": "115091" + }, + { + "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-osx.tar.gz", + "checksum": "SHA-256:df656fae21a41c1269ea50cb53752dcaf6a4e1437255f3a9fb50b4025549b58e", + "host": "i386-apple-darwin", + "archiveFileName": "mkspiffs-0.1.2-osx.tar.gz", + "size": "115091" + }, + { + "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-linux64.tar.gz", + "checksum": "SHA-256:1a1dd81b51daf74c382db71b42251757ca4136e8762107e69feaa8617bac315f", + "host": "x86_64-pc-linux-gnu", + "archiveFileName": "mkspiffs-0.1.2-linux64.tar.gz", + "size": "46281" + }, + { + "url": "https://github.com/igrr/mkspiffs/releases/download/0.1.2/mkspiffs-0.1.2-linux32.tar.gz", + "checksum": "SHA-256:e990d545dfcae308aabaac5fa9e1db734cc2b08167969e7eedac88bd0839667c", + "host": "i686-pc-linux-gnu", + "archiveFileName": "mkspiffs-0.1.2-linux32.tar.gz", + "size": "45272" + } + ] + } + ], + "email": "ivan@esp8266.com", + "name": "esp8266" + }, + { + "name":"SparkFun", + "maintainer":"SparkFun Electronics", + "websiteURL":"https://SparkFun.com", + "email":"TechSupport@SparkFun.com", + "help":{ + "online":"https://forum.sparkfun.com" + }, + "platforms":[ + { + "name":"SparkFun ATtiny Boards", + "architecture":"tiny", + "version":"0.1.6", + "category":"Contributed", + "url":"https://github.com/sparkfun/Arduino_Boards/raw/tiny/IDE_Board_Manager/sparkfun-tiny-0.1.6.tar.bz2", + "archiveFileName":"sparkfun-tiny-0.1.6.tar.bz2", + "checksum":"SHA-256:C662E7B0C8DB9ABBD5775C60AEF1F96BD35EEED59048247873273CF5B84DCC7D", + "size":"799989", + "help":{ + "online":"https://forums.sparkfun.com" + }, + "boards":[ + { "name":"Roshamglo" }, + { "name":"Atto84" } + ], + "toolsDependencies":[ + { + "packager": "SparkFun", + "name": "micronucleus", + "version": "2.03-SFE" + } + ] + } + ], + "tools":[ + { + "name": "micronucleus", + "version": "2.03-SFE", + "systems": [ + { + "host": "i686-mingw32", + "url": "https://github.com/sparkfun/Arduino_Boards/raw/tiny/sparkfun/tiny/extras/uploader/builds/windows/micronucleus-2.03-SFE-windows.tar.bz2", + "archiveFileName": "micronucleus-2.03-SFE-windows.tar.bz2", + "size": "43157", + "checksum": "SHA-256:71F027A7EF571DB44BCB771BBFD477647E794D61BBE6F6B235984F07C2C6826B" + }, + { + "host": "x86_64-apple-darwin", + "url": "https://github.com/sparkfun/Arduino_Boards/raw/tiny/sparkfun/tiny/extras/uploader/builds/osx/micronucleus-2.03-SFE-osx.tar.bz2", + "archiveFileName": "micronucleus-2.03-SFE-osx.tar.bz2", + "size": "7679", + "checksum": "SHA-256:CF95C51929EAA755F06871D2CA22A850B27105A4A08A6B85EC3550EB19B39224" + }, + { + "host": "i386-apple-darwin", + "url": "https://github.com/sparkfun/Arduino_Boards/raw/tiny/sparkfun/tiny/extras/uploader/builds/osx/micronucleus-2.03-SFE-osx.tar.bz2", + "archiveFileName": "micronucleus-2.03-SFE-osx.tar.bz2", + "size": "7679", + "checksum": "SHA-256:CF95C51929EAA755F06871D2CA22A850B27105A4A08A6B85EC3550EB19B39224" + }, + { + "host": "x86_64-pc-linux-gnu", + "url": "https://github.com/sparkfun/Arduino_Boards/raw/tiny/sparkfun/tiny/extras/uploader/builds/linux64/micronucleus-2.03-SFE-linux64.tar.bz2", + "archiveFileName": "micronucleus-2.03-SFE-linux64.tar.bz2", + "size": "20805", + "checksum": "SHA-256:5C17B30326654BA0333E1255801B70B1993842C73A94E9B46FE08826E04B8B0E" + }, + { + "host": "i686-pc-linux-gnu", + "url": "https://github.com/sparkfun/Arduino_Boards/raw/tiny/sparkfun/tiny/extras/uploader/builds/linux32/micronucleus-2.03-SFE-linux32.tar.bz2", + "archiveFileName": "micronucleus-2.03-SFE-linux32.tar.bz2", + "size": "19880", + "checksum": "SHA-256:AB44CF67A8F5C4182B0C840EFC6EEF4AAECCC9E8AC86E172B75AAAD2CD3D11E4" + }, + { + "host": "arm-linux-gnueabihf", + "url": "https://github.com/sparkfun/Arduino_Boards/raw/tiny/sparkfun/tiny/extras/uploader/builds/linuxarm/micronucleus-2.03-SFE-linuxarm.tar.bz2", + "archiveFileName": "micronucleus-2.03-SFE-linuxarm.tar.bz2", + "size": "20331", + "checksum": "SHA-256:DF2545F26B70354748B6DB5FC3C10F55C1C13005360E9CCC7C5B06E92528B3E9" + } + ] + } + ] + } + ] +} diff --git a/IDE_Board_Manager/sparkfun-tiny-0.1.0.tar.bz2 b/IDE_Board_Manager/sparkfun-tiny-0.1.0.tar.bz2 new file mode 100644 index 00000000..c765744c Binary files /dev/null and b/IDE_Board_Manager/sparkfun-tiny-0.1.0.tar.bz2 differ diff --git a/IDE_Board_Manager/sparkfun-tiny-0.1.1.tar.bz2 b/IDE_Board_Manager/sparkfun-tiny-0.1.1.tar.bz2 new file mode 100644 index 00000000..d9df397d Binary files /dev/null and b/IDE_Board_Manager/sparkfun-tiny-0.1.1.tar.bz2 differ diff --git a/IDE_Board_Manager/sparkfun-tiny-0.1.2.tar.bz2 b/IDE_Board_Manager/sparkfun-tiny-0.1.2.tar.bz2 new file mode 100644 index 00000000..25b58a7f Binary files /dev/null and b/IDE_Board_Manager/sparkfun-tiny-0.1.2.tar.bz2 differ diff --git a/IDE_Board_Manager/sparkfun-tiny-0.1.3.tar.bz2 b/IDE_Board_Manager/sparkfun-tiny-0.1.3.tar.bz2 new file mode 100644 index 00000000..090004b5 Binary files /dev/null and b/IDE_Board_Manager/sparkfun-tiny-0.1.3.tar.bz2 differ diff --git a/IDE_Board_Manager/sparkfun-tiny-0.1.4.tar.bz2 b/IDE_Board_Manager/sparkfun-tiny-0.1.4.tar.bz2 new file mode 100644 index 00000000..f9c9f10f Binary files /dev/null and b/IDE_Board_Manager/sparkfun-tiny-0.1.4.tar.bz2 differ diff --git a/IDE_Board_Manager/sparkfun-tiny-0.1.5.tar.bz2 b/IDE_Board_Manager/sparkfun-tiny-0.1.5.tar.bz2 new file mode 100644 index 00000000..268d12b2 Binary files /dev/null and b/IDE_Board_Manager/sparkfun-tiny-0.1.5.tar.bz2 differ diff --git a/IDE_Board_Manager/sparkfun-tiny-0.1.6.tar.bz2 b/IDE_Board_Manager/sparkfun-tiny-0.1.6.tar.bz2 new file mode 100644 index 00000000..fcf57ba9 Binary files /dev/null and b/IDE_Board_Manager/sparkfun-tiny-0.1.6.tar.bz2 differ diff --git a/sparkfun/tiny/boards.txt b/sparkfun/tiny/boards.txt new file mode 100644 index 00000000..b5187c42 --- /dev/null +++ b/sparkfun/tiny/boards.txt @@ -0,0 +1,61 @@ +# SparkFun AVR ATtiny boards definitions + +menu.cpu=Processor + +################################################################################ +################################## Roshamglo ################################### +################################################################################ +Roshamglo.name=Roshamglo (ATtiny84, 3.3V, 8MHz) + +#Roshamglo.vid.0=0x1B4F +#Roshamglo.pid.1=0x0014 + +#Roshamglo.upload.using=micronucleusprog +Roshamglo.upload.protocol=usb +Roshamglo.upload.tool=micronucleus +Roshamglo.upload.maximum_size=6144 + +Roshamglo.build.mcu=attiny84 +Roshamglo.build.f_cpu=8000000L +Roshamglo.build.vid=0x1B4F +Roshamglo.build.pid=0x0014 +Roshamglo.build.usb_manufacturer="SparkFun Electronics" +Roshamglo.build.usb_product="SparkFun Roshamglo" +Roshamglo.build.board=ROSHAMGLO +Roshamglo.build.core=arduino +Roshamglo.build.variant=tiny14 + +Roshamglo.bootloader.tool=arduino:avrdude +Roshamglo.bootloader.low_fuses=0xE2 +Roshamglo.bootloader.high_fuses=0xDD +Roshamglo.bootloader.extended_fuses=0xFE +Roshamglo.bootloader.file=attiny/releases/t84_roshamglo.hex + +################################################################################ +################################### Atto84 ##################################### +################################################################################ +Atto84.name=SparkX Atto84 (ATtiny84, 3.3V, 8MHz) + +#Atto84.vid.0=0x1B4F +#Atto84.pid.1=0x0014 + +#Atto84.upload.using=micronucleusprog +Atto84.upload.protocol=usb +Atto84.upload.tool=micronucleus +Atto84.upload.maximum_size=6144 + +Atto84.build.mcu=attiny84 +Atto84.build.f_cpu=8000000L +Atto84.build.vid=0x1B4F +Atto84.build.pid=0x0014 +Atto84.build.usb_manufacturer="SparkFun Electronics" +Atto84.build.usb_product="SparkX Atto84" +Atto84.build.board=ATTO84 +Atto84.build.core=tiny +Atto84.build.variant=atto84 + +Atto84.bootloader.tool=arduino:avrdude +Atto84.bootloader.low_fuses=0xE2 +Atto84.bootloader.high_fuses=0xDD +Atto84.bootloader.extended_fuses=0xFE +Atto84.bootloader.file=attiny/releases/t84_default.hex \ No newline at end of file diff --git a/sparkfun/tiny/bootloaders/attiny/Makefile b/sparkfun/tiny/bootloaders/attiny/Makefile new file mode 100644 index 00000000..828d4647 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/Makefile @@ -0,0 +1,98 @@ +# Name: Makefile +# Project: Micronucleus +# Author: Jenna Fox; portions by Christian Starkjohann, Louis Beaudoin +# Creation Date: 2007-12-10 +# Tabsize: 4 +# Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt) + +CONFIG ?= t85_default +#CONFIG ?= t85_aggressive +#CONFIG ?= t841_default +#CONFIG ?= t167_default + +############################################################################### +# Configure the following variables according to your AVR. +# Program the device with +# make fuse # to set the clock generator, boot section size etc. +# make flash # to load the boot loader into flash +# make disablereset # use external reset line for IO (CAUTION: this is not easy to enable again, see README) + +CFLAGS = +CONFIGPATH = configuration/$(CONFIG) +include $(CONFIGPATH)/Makefile.inc + +PROGRAMMER ?= -c USBasp +# PROGRAMMER contains AVRDUDE options to address your programmer + +# Tools: +AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) +CC = avr-gcc + +# Options: +CFLAGS += -I. -g2 -Os # -Wall +CFLAGS += -I$(CONFIGPATH) -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -DBOOTLOADER_ADDRESS=0x$(BOOTLOADER_ADDRESS) +CFLAGS += -nostartfiles -ffunction-sections -fdata-sections -fpack-struct -fno-inline-small-functions -fno-move-loop-invariants -fno-tree-scev-cprop + +LDFLAGS = -Wl,--relax,--section-start=.text=$(BOOTLOADER_ADDRESS),--gc-sections,-Map=main.map + +OBJECTS = crt1.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o +OBJECTS += osccalASM.o + +# symbolic targets: +all: main.hex + +.c.o: + @$(CC) $(CFLAGS) -c $< -o $@ -Wa,-ahls=$<.lst + +.S.o: + @$(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +.c.s: + @$(CC) $(CFLAGS) -S $< -o $@ + +flash: all + $(AVRDUDE) -U flash:w:main.hex:i -B 20 + +readflash: + $(AVRDUDE) -U flash:r:read.hex:i -B 20 + +fuse: + $(AVRDUDE) $(FUSEOPT) -B 20 + +disablereset: + $(AVRDUDE) $(FUSEOPT_DISABLERESET) -B 20 + +read_fuses: + $(UISP) --rd_fuses -B 20 + +clean: + @rm -f main.hex main.bin main.c.lst main.map main.raw *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s main.lss + +# file targets: +main.bin: $(OBJECTS) + @$(CC) $(CFLAGS) -o main.bin $(OBJECTS) $(LDFLAGS) + +main.hex: main.bin + @echo Building Micronucleus configuration: $(CONFIG) + @rm -f main.hex main.eep.hex + @avr-objcopy -j .text -j .data -O ihex main.bin main.hex + @echo Size of sections: + @avr-size main.bin + @echo Size of binary hexfile. Use the "data" size to calculate the bootloader address: + @avr-size main.hex + +upgrade: main.bin + avr-objcopy -O binary main.bin main.raw + avr-objcopy -I binary -O elf32-avr \ + --rename-section .data=.text \ + --redefine-sym _binary_main_raw_start=loader \ + --redefine-sym _binary_main_raw_end=loader_end \ + main.raw bootloader_linkable.o + +disasm: main.bin + @avr-objdump -d -S main.bin >main.lss diff --git a/sparkfun/tiny/bootloaders/attiny/README.md b/sparkfun/tiny/bootloaders/attiny/README.md new file mode 100644 index 00000000..60593650 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/README.md @@ -0,0 +1,145 @@ +Micronucleus V2.03 +================== + +This version of micronucleus has been copied and modified by SparkFun Electronics for the Roshamglo project. The original micronucleus can be found at https://github.com/micronucleus/micronucleus. + +Micronucleus is a bootloader designed for AVR ATtiny microcontrollers with a minimal usb interface, cross platform libusb-based program upload tool, and a strong emphasis on bootloader compactness. To the authors knowledge this is, by far, the smallest USB bootloader for AVR ATtiny + +The V2.0 release is a complete rewrite of the firmware and offers significant improvements over V1.x: + + • Support for the entire ATtiny family instead of only ATtiny85. + • Much smaller size. All configurations are below 2kb. + • Interrupt free V-USB: no patching of the user program INT-vector anymore. + • Faster uploads due to new protocol. + • Far jmp also allows using ATtinies with more than 8kb flash. + • Many robustness improvements, such as compatibility to USB hubs and + less erratic time out behavior. + +Due to the many changes, also the upload tool had to be updated. The V2.0 upload tool is backwards compatible to the V1.X tool, though. + +The last release of the V1.x can be found here: https://github.com/micronucleus/micronucleus/tree/v1.11 + + +Usage +===== + +The bootloader allows uploading of new firmware via USB. In its usual configuration it is invoked at device reset and will identify to the host computer. If no communication is initiated by the host machine within a given time, the bootloader will time out and enter the user program, if one is present. + +For proper timing, the command line tool should to be started on the host computer _before_ the bootloader is invoked. + +Windows machines will need to install the libusb drivers found in the /windows_drivers folder. Clean Micronucleus devices without uploaded userprogram will not time out and allow sufficient time for proper driver installation. Linux and OS X do not require custom drivers. + +Windows 10: Installing unsigned drivers became more difficult in Windows 10. Please use the Zadig driver installer as provided in the /windows_driver_installer folder. + +Please invoke the command line tool with "micronucleus -help" for a list of available options. + +The bootloader resides in the same memory as the user program, since the ATtiny series does not support a protected bootloader section. Therefore, special care has to be taken not to overwrite the bootloader if the user program uses the self programming features. The bootloader will patch itself into the reset vector of the user program. No other interrupt vectors are changed. + +Compiling +========= + +Micronucleus can be configured to support all devices of the ATtiny series, with the exception of the reduced core ATtiny 4/5/9/10/20/40. + +To allow maximum flexibility, micronucleus supports a configuration system. To compile micronucleus with a specific configuration, please invoke the AVR-GCC tool-chain with: + + make CONFIG= + +Output file is "main.hex," which should be uploaded to your microcontroller using a program like avrdude. It can also be copied to the /releases folder. + +Currently, the following configurations are included and tested. Please check the subfolders /firmware/configurations/ for details. Hex files can be found in /releases. + +t84_default - ATtiny84A default configuration - 1542 bytes +t84_roshamglo - ATtiny84A for Roshamglo project - 1586 bytes + +You can add your own configuration by adding a new folder to /firmware/configurations/. The folder has to contain a customized "Makefile.inc" and "bootloaderconfig.h". Feel free to supply a pull request if you added and tested a previously unsupported device. + +If changes to the configuration lead to an increase in bootloader size, it may be necessary to change the bootloader start address. Please consult "Makefile.inc" for details. + +Other make options: + + make CONFIG= fuse # Configure fuses + make CONFIG= flash # Uploade the bootloader using AVRDUDE + +There is also an option to disable the reset line and use it as an I/O. While it may seem tempting to use this feature to make an additional I/O pin available on the ATtiny85, we strongly discourage from doing so, as it led to many issues in the past. + +Please "make clean" when switching from one configuration to another. + + +Devices using Micronucleus +========================== + +Micronucleus is widely installed on thousands of open source hardware devices. Please find an incomplete list here: +https://github.com/micronucleus/micronucleus/blob/master/Devices_with_Micronucleus.md + + +License +======= + +This project is released under the GPLv2 license. Code uploaded via the bootloader is not subject to any license. + +In addition, we'd like you to consider these points if you intend to sell products using micronucleus: + + • Please make your hardware open source. At least the schematic needs to be + published according to the license inherited from V-USB. + + • Your documentation should mention Micronucleus and include a link to the + main repository (https://github.com/micronucleus/) + + • Please do not "rebrand" micronucleus by renaming the USB device. + + • Feel welcome to submit a pull request to include your product in the + "Devices using Micronucleus"-list. + + +Changes +======= + + + • v2.0b June 6th, 2015 + This pull request documents changes leading to V2.0: https://github.com/micronucleus/micronucleus/pull/43 + + • v2.01 July 26th, 2015 + This pull request documents changes leading to V2.1: https://github.com/micronucleus/micronucleus/pull/66 + - Fixes "unknown USB device" issue when devices with <16MHz CPU clock were + connected to a USB3.0 port. + - Fixes one bug that could lead to a deadlock if no USB was connected + while the bootloader was active and noise was injected into the floating D+ input. + - D- line is released before the user program is started, instead of pulling it + down. This solves various issues where Micronucleus was not recognized after a + reset depending on the duration of the reset button activation. Att: This may + lead to a "Unknown device" pop-up in Windows, if the user program does not have + USB functionality itself. + +• v2.02 August 3rd, 2015 + - Fixes timing bug with Windows 10 USB drivers. Some Win 10 drivers reduce the + delay between reset and the first data packet to 20 ms. This led to an issue + with osccalASM.S, which did not terminate correctly. + +• v2.03 February 13th, 2016 + - Added page buffer clearing if a new block transfer is initiated. This fixes a + critical, but extremely rare bug that could lead to bricking of the + device if micronucleus is restarted after an USB error. + - #74 Fixed LED_INIT macro so it only modifies the DDR register bit of the LED. + (Thanks @russdill) + +Credits +======= + +Firmware: + • Micronucleus V2.03 (c) 2016 Tim Bo"scke - cpldcpu@gmail.com + (c) 2014 Shay Green + • Original Micronucleus (c) 2012 Jenna Fox + • Based on USBaspLoader-tiny85 (c) 2012 Louis Beaudoin + • Based on USBaspLoader (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + +Commandline tool: + • Original commandline tool (c) 2012 by ihsan Kehribar + (c) 2012 Jenna Fox + • Updates for V2.x (c) 2014 T. Bo"scke + +Special Thanks: + • Aaron Stone/@sodabrew for building the OS X command line tool and various fixes. + • Objective Development's great V-USB bitbanging usb driver + • Embedded Creations' pioneering and inspiring USBaspLoader-tiny85 + • Digistump for motivation and contributing the VID/PID pair + • Numerous supporters for smaller bug fixes and improvements. \ No newline at end of file diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t167_default/Makefile.inc b/sparkfun/tiny/bootloaders/attiny/configuration/t167_default/Makefile.inc new file mode 100644 index 00000000..86103078 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t167_default/Makefile.inc @@ -0,0 +1,21 @@ +# Name: Makefile +# Project: Micronucleus +# License: GNU GPL v2 (see License.txt) +# +# Controller type: ATtiny 167 +# Configuration: Default configuration. +# Last Change: Mar 16,2014 + + +F_CPU = 16000000 +DEVICE = attiny167 + +# hexadecimal address for bootloader section to begin. To calculate the best value: +# - make clean; make main.hex; ### output will list data: 2124 (or something like that) +# - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 +# - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 +# - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 +BOOTLOADER_ADDRESS = 3A00 + +FUSEOPT = # TODO +FUSEOPT_DISABLERESET = # TODO diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t167_default/bootloaderconfig.h b/sparkfun/tiny/bootloaders/attiny/configuration/t167_default/bootloaderconfig.h new file mode 100644 index 00000000..0eab4ee1 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t167_default/bootloaderconfig.h @@ -0,0 +1,275 @@ + /* Name: bootloaderconfig.h + * Micronucleus configuration file. + * This file (together with some settings in Makefile.inc) configures the boot loader + * according to the hardware. + * + * Controller type: ATtiny 167 - 16 MHz with crystal + * Configuration: Standard configuration - Follows Digispark Pro defaults. Needs 16Mhz XTAL. + * USB D- : PB3 + * USB D+ : PB6 + * Entry : Always + * LED : Active High on PB1 + * OSCCAL : No change due to external crystal + * Note: Uses 16 MHz V-USB implementation. + * Last Change: JUn 15,2015 + * + * License: GNU GPL v2 (see License.txt + */ + +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ------------------------------------------------------------------------- */ +/* Hardware configuration. */ +/* Change this according to your CPU and USB configuration */ +/* ------------------------------------------------------------------------- */ + +#define USB_CFG_IOPORTNAME B + /* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ + +#define USB_CFG_DMINUS_BIT 3 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 6 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port, but must be configured as a pin change interrupt. + */ + +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ + +/* ------------- Set up interrupt configuration (CPU specific) -------------- */ +/* The register names change quite a bit in the ATtiny family. Pay attention */ +/* to the manual. Note that the interrupt flag system is still used even though */ +/* interrupts are disabled. So this has to be configured correctly. */ + + +// setup interrupt for Pin Change for D+ + +// This is configured for PORTB. + +#define USB_INTR_CFG PCMSK1 +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE PCICR +#define USB_INTR_ENABLE_BIT PCIE1 +#define USB_INTR_PENDING PCIFR +#define USB_INTR_PENDING_BIT PCIF1 +#define USB_INTR_VECTOR PCINT1_vect + +/* Configuration for PORTA */ +/* +#define USB_INTR_CFG PCMSK0 +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE PCICR +#define USB_INTR_ENABLE_BIT PCIE0 +#define USB_INTR_PENDING PCIFR +#define USB_INTR_PENDING_BIT PCIF0 +#define USB_INTR_VECTOR PCINT0_vect +*/ + +/* ------------------------------------------------------------------------- */ +/* Configuration relevant to the CPU the bootloader is running on */ +/* ------------------------------------------------------------------------- */ + +// how many milliseconds should host wait till it sends another erase or write? +// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms +#define MICRONUCLEUS_WRITE_SLEEP 5 + + +/* ---------------------- feature / code size options ---------------------- */ +/* Configure the behavior of the bootloader here */ +/* ------------------------------------------------------------------------- */ + +/* + * Define Bootloader entry condition + * + * If the entry condition is not met, the bootloader will not be activated and the user program + * is executed directly after a reset. If no user program has been loaded, the bootloader + * is always active. + * + * ENTRY_ALWAYS Always activate the bootloader after reset. Requires the least + * amount of code. + * + * ENTRY_WATCHDOG Activate the bootloader after a watchdog reset. This can be used + * to enter the bootloader from the user program. + * Adds 22 bytes. + * + * ENTRY_EXT_RESET Activate the bootloader after an external reset was issued by + * pulling the reset pin low. It may be necessary to add an external + * pull-up resistor to the reset pin if this entry method appears to + * behave unreliably. + * Adds 22 bytes. + * + * ENTRY_JUMPER Activate the bootloader when a specific pin is pulled low by an + * external jumper. + * Adds 34 bytes. + * + * JUMPER_PIN Pin the jumper is connected to. (e.g. PB0) + * JUMPER_PORT Port out register for the jumper (e.g. PORTB) + * JUMPER_DDR Port data direction register for the jumper (e.g. DDRB) + * JUMPER_INP Port inout register for the jumper (e.g. PINB) + * + */ + +#define ENTRYMODE ENTRY_ALWAYS + +#define JUMPER_PIN PB0 +#define JUMPER_PORT PORTB +#define JUMPER_DDR DDRB +#define JUMPER_INP PINB + +/* + Internal implementation, don't change this unless you want to add an entrymode. +*/ + +#define ENTRY_ALWAYS 1 +#define ENTRY_WATCHDOG 2 +#define ENTRY_EXT_RESET 3 +#define ENTRY_JUMPER 4 + +#if ENTRYMODE==ENTRY_ALWAYS + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() 1 +#elif ENTRYMODE==ENTRY_WATCHDOG + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(WDRF)) +#elif ENTRYMODE==ENTRY_EXT_RESET + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF)) +#elif ENTRYMODE==ENTRY_JUMPER + // Enable pull up on jumper pin and delay to stabilize input + #define bootLoaderInit() {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);} + #define bootLoaderExit() {JUMPER_PORT&=~_BV(JUMPER_PIN);} + #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN))) +#else + #error "No entry mode defined" +#endif + +/* + * Define bootloader timeout value. + * + * The bootloader will only time out if a user program was loaded. + * + * AUTO_EXIT_NO_USB_MS The bootloader will exit after this delay if no USB is connected. + * Set to 0 to disable + * Adds ~6 bytes. + * (This will wait for an USB SE0 reset from the host) + * + * AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication + * from the host tool was received. + * Set to 0 to disable + * + * All values are approx. in milliseconds + */ + +#define AUTO_EXIT_NO_USB_MS 0 +#define AUTO_EXIT_MS 6000 + + /* + * Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL) + * + * OSCCAL_RESTORE_DEFAULT Set this to '1' to revert to OSCCAL factore calibration after bootlaoder exit. + * This is 8 MHz +/-2% on most devices or 16 MHz on the ATtiny 85 with activated PLL. + * Adds ~14 bytes. + * + * OSCCAL_SAVE_CALIB Set this to '1' to save the OSCCAL calibration during program upload. + * This value will be reloaded after reset and will also be used for the user + * program unless "OSCCAL_RESTORE_DEFAULT" is active. This allows calibrate the internal + * RC oscillator to the F_CPU target frequency +/-1% from the USB timing. Please note + * that only true if the ambient temperature does not change. + * Adds ~38 bytes. + * + * OSCCAL_HAVE_XTAL Set this to '1' if you have an external crystal oscillator. In this case no attempt + * will be made to calibrate the oscillator. You should deactivate both options above + * if you use this to avoid redundant code. + * + * If both options are selected, OSCCAL_RESTORE_DEFAULT takes precedence. + * + * If no option is selected, OSCCAL will be left untouched and stays at either factory calibration or F_CPU depending + * on whether the bootloader was activated. This will take the least memory. You can use this if your program + * comes with its own OSCCAL calibration or an external clock source is used. + */ + +#define OSCCAL_RESTORE_DEFAULT 0 +#define OSCCAL_SAVE_CALIB 0 +#define OSCCAL_HAVE_XTAL 1 + +/* + * Defines handling of an indicator LED while the bootloader is active. + * + * LED_MODE Define behavior of attached LED or suppress LED code. + * + * NONE Do not generate LED code (gains 18 bytes). + * ACTIVE_HIGH LED is on when output pin is high. This will toggle bettwen 1 and 0. + * ACTIVE_LOW LED is on when output pin is low. This will toggle between Z and 0. + * + * LED_DDR,LED_PORT,LED_PIN Where is your LED connected? + * + */ + +#define LED_MODE ACTIVE_HIGH + +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PB1 + +/* + * This is the implementation of the LED code. Change the configuration above unless you want to + * change the led behavior + * + * LED_INIT Called once after bootloader entry + * LED_EXIT Called once during bootloader exit + * LED_MACRO Called in the main loop with the idle counter as parameter. + * Use to define pattern. +*/ + +#define NONE 0 +#define ACTIVE_HIGH 1 +#define ACTIVE_LOW 2 + +#if LED_MODE==ACTIVE_HIGH + #define LED_INIT(x) LED_DDR |= _BV(LED_PIN); + #define LED_EXIT(x) {LED_DDR &=~_BV(LED_PIN);LED_PORT &=~_BV(LED_PIN);} + #define LED_MACRO(x) if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);} +#elif LED_MODE==ACTIVE_LOW + #define LED_INIT(x) LED_PORT &=~_BV(LED_PIN); + #define LED_EXIT(x) LED_DDR &=~_BV(LED_PIN); + #define LED_MACRO(x) if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);} +#elif LED_MODE==NONE + #define LED_INIT(x) + #define LED_EXIT(x) + #define LED_MACRO(x) +#endif + +/* --------------------------------------------------------------------------- */ +/* Micronucleus internal configuration. Do not change anything below this line */ +/* --------------------------------------------------------------------------- */ + +// Microcontroller vectortable entries in the flash +#define RESET_VECTOR_OFFSET 0 + +// number of bytes before the boot loader vectors to store the tiny application vector table +#define TINYVECTOR_RESET_OFFSET 4 +#define TINYVECTOR_OSCCAL_OFFSET 6 + +/* ------------------------------------------------------------------------ */ +// postscript are the few bytes at the end of programmable memory which store tinyVectors +#define POSTSCRIPT_SIZE 6 +#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */ + +#endif /* __bootloader_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t45_default/Makefile.inc b/sparkfun/tiny/bootloaders/attiny/configuration/t45_default/Makefile.inc new file mode 100644 index 00000000..87c22a66 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t45_default/Makefile.inc @@ -0,0 +1,60 @@ +# Name: Makefile +# Project: Micronucleus +# License: GNU GPL v2 (see License.txt) + +# Controller type: ATtiny 45 - 16.5 MHz +# Configuration: Default +# Last Change: Oct 9,2015 + + +F_CPU = 16500000 +DEVICE = attiny45 + +# hexadecimal address for bootloader section to begin. To calculate the best value: +# - make clean; make main.hex; ### output will list data: 2124 (or something like that) +# - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 +# - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 +# - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 +BOOTLOADER_ADDRESS = 980 + +FUSEOPT = -U lfuse:w:0xe1:m -U hfuse:w:0xdd:m -U efuse:w:0xfe:m +FUSEOPT_DISABLERESET = -U lfuse:w:0xe1:m -U efuse:w:0xfe:m -U hfuse:w:0x5d:m + +#--------------------------------------------------------------------- +# ATtiny85 +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0xFE = - - - - - 1 1 0 +# ^ +# | +# +---- SELFPRGEN (enable self programming flash) +# +# Fuse high byte: +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +# Fuse high byte ("no reset": external reset disabled, can't program through SPI anymore) +# 0x5d = 0 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> disabled!) +# +# Fuse low byte: +# 0xe1 = 1 1 1 0 0 0 0 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> HF PLL) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) + +############################################################################### diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t45_default/bootloaderconfig.h b/sparkfun/tiny/bootloaders/attiny/configuration/t45_default/bootloaderconfig.h new file mode 100644 index 00000000..ecd6261d --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t45_default/bootloaderconfig.h @@ -0,0 +1,259 @@ +/* Name: bootloaderconfig.h + * Micronucleus configuration file. + * This file (together with some settings in Makefile.inc) configures the boot loader + * according to the hardware. + * + * Controller type: ATtiny 45 - 16.5 MHz + * Configuration: Default configuration + * USB D- : PB3 + * USB D+ : PB4 + * Entry : Always + * LED : None + * OSCCAL : Stays at 16 MHz + * Note: Uses 16.5 MHz V-USB implementation with PLL + * Last Change: Mar 16,2014 + * + * License: GNU GPL v2 (see License.txt + */ +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ------------------------------------------------------------------------- */ +/* Hardware configuration. */ +/* Change this according to your CPU and USB configuration */ +/* ------------------------------------------------------------------------- */ + +#define USB_CFG_IOPORTNAME B + /* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ + +#define USB_CFG_DMINUS_BIT 3 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 4 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port, but must be configured as a pin change interrupt. + */ + +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ + +/* ------------- Set up interrupt configuration (CPU specific) -------------- */ +/* The register names change quite a bit in the ATtiny family. Pay attention */ +/* to the manual. Note that the interrupt flag system is still used even though */ +/* interrupts are disabled. So this has to be configured correctly. */ + + +// setup interrupt for Pin Change for D+ +#define USB_INTR_CFG PCMSK +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE GIMSK +#define USB_INTR_ENABLE_BIT PCIE +#define USB_INTR_PENDING GIFR +#define USB_INTR_PENDING_BIT PCIF +#define USB_INTR_VECTOR PCINT0_vect + +/* ------------------------------------------------------------------------- */ +/* Configuration relevant to the CPU the bootloader is running on */ +/* ------------------------------------------------------------------------- */ + +// how many milliseconds should host wait till it sends another erase or write? +// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms +#define MICRONUCLEUS_WRITE_SLEEP 5 + + +/* ---------------------- feature / code size options ---------------------- */ +/* Configure the behavior of the bootloader here */ +/* ------------------------------------------------------------------------- */ + +/* + * Define Bootloader entry condition + * + * If the entry condition is not met, the bootloader will not be activated and the user program + * is executed directly after a reset. If no user program has been loaded, the bootloader + * is always active. + * + * ENTRY_ALWAYS Always activate the bootloader after reset. Requires the least + * amount of code. + * + * ENTRY_WATCHDOG Activate the bootloader after a watchdog reset. This can be used + * to enter the bootloader from the user program. + * Adds 22 bytes. + * + * ENTRY_EXT_RESET Activate the bootloader after an external reset was issued by + * pulling the reset pin low. It may be necessary to add an external + * pull-up resistor to the reset pin if this entry method appears to + * behave unreliably. + * Adds 22 bytes. + * + * ENTRY_JUMPER Activate the bootloader when a specific pin is pulled low by an + * external jumper. + * Adds 34 bytes. + * + * JUMPER_PIN Pin the jumper is connected to. (e.g. PB0) + * JUMPER_PORT Port out register for the jumper (e.g. PORTB) + * JUMPER_DDR Port data direction register for the jumper (e.g. DDRB) + * JUMPER_INP Port inout register for the jumper (e.g. PINB) + * + */ + +#define ENTRYMODE ENTRY_ALWAYS + +#define JUMPER_PIN PB0 +#define JUMPER_PORT PORTB +#define JUMPER_DDR DDRB +#define JUMPER_INP PINB + +/* + Internal implementation, don't change this unless you want to add an entrymode. +*/ + +#define ENTRY_ALWAYS 1 +#define ENTRY_WATCHDOG 2 +#define ENTRY_EXT_RESET 3 +#define ENTRY_JUMPER 4 + +#if ENTRYMODE==ENTRY_ALWAYS + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() 1 +#elif ENTRYMODE==ENTRY_WATCHDOG + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(WDRF)) +#elif ENTRYMODE==ENTRY_EXT_RESET + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF)) +#elif ENTRYMODE==ENTRY_JUMPER + // Enable pull up on jumper pin and delay to stabilize input + #define bootLoaderInit() {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);} + #define bootLoaderExit() {JUMPER_PORT&=~_BV(JUMPER_PIN);} + #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN))) +#else + #error "No entry mode defined" +#endif + +/* + * Define bootloader timeout value. + * + * The bootloader will only time out if a user program was loaded. + * + * AUTO_EXIT_NO_USB_MS The bootloader will exit after this delay if no USB is connected. + * Set to 0 to disable + * Adds ~6 bytes. + * (This will wait for an USB SE0 reset from the host) + * + * AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication + * from the host tool was received. + * Set to 0 to disable + * + * All values are approx. in milliseconds + */ + +#define AUTO_EXIT_NO_USB_MS 0 +#define AUTO_EXIT_MS 6000 + + /* + * Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL) + * + * OSCCAL_RESTORE_DEFAULT Set this to '1' to revert to OSCCAL factore calibration after bootlaoder exit. + * This is 8 MHz +/-2% on most devices or 16 MHz on the ATtiny 85 with activated PLL. + * Adds ~14 bytes. + * + * OSCCAL_SAVE_CALIB Set this to '1' to save the OSCCAL calibration during program upload. + * This value will be reloaded after reset and will also be used for the user + * program unless "OSCCAL_RESTORE_DEFAULT" is active. This allows calibrate the internal + * RC oscillator to the F_CPU target frequency +/-1% from the USB timing. Please note + * that only true if the ambient temperature does not change. + * Adds ~38 bytes. + * + * OSCCAL_HAVE_XTAL Set this to '1' if you have an external crystal oscillator. In this case no attempt + * will be made to calibrate the oscillator. You should deactivate both options above + * if you use this to avoid redundant code. + * + * If both options are selected, OSCCAL_RESTORE_DEFAULT takes precedence. + * + * If no option is selected, OSCCAL will be left untouched and stays at either factory calibration or F_CPU depending + * on whether the bootloader was activated. This will take the least memory. You can use this if your program + * comes with its own OSCCAL calibration or an external clock source is used. + */ + +#define OSCCAL_RESTORE_DEFAULT 0 +#define OSCCAL_SAVE_CALIB 1 +#define OSCCAL_HAVE_XTAL 0 + +/* + * Defines handling of an indicator LED while the bootloader is active. + * + * LED_MODE Define behavior of attached LED or suppress LED code. + * + * NONE Do not generate LED code (gains 18 bytes). + * ACTIVE_HIGH LED is on when output pin is high. This will toggle bettwen 1 and 0. + * ACTIVE_LOW LED is on when output pin is low. This will toggle between Z and 0. + * + * LED_DDR,LED_PORT,LED_PIN Where is your LED connected? + * + */ + +#define LED_MODE NONE + +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PB1 + +/* + * This is the implementation of the LED code. Change the configuration above unless you want to + * change the led behavior + * + * LED_INIT Called once after bootloader entry + * LED_EXIT Called once during bootloader exit + * LED_MACRO Called in the main loop with the idle counter as parameter. + * Use to define pattern. +*/ + +#define NONE 0 +#define ACTIVE_HIGH 1 +#define ACTIVE_LOW 2 + +#if LED_MODE==ACTIVE_HIGH + #define LED_INIT(x) LED_DDR = _BV(LED_PIN); + #define LED_EXIT(x) {LED_DDR &=~_BV(LED_PIN);LED_PORT &=~_BV(LED_PIN);} + #define LED_MACRO(x) if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);} +#elif LED_MODE==ACTIVE_LOW + #define LED_INIT(x) LED_PORT &=~_BV(LED_PIN); + #define LED_EXIT(x) LED_DDR &=~_BV(LED_PIN); + #define LED_MACRO(x) if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);} +#elif LED_MODE==NONE + #define LED_INIT(x) + #define LED_EXIT(x) + #define LED_MACRO(x) +#endif + +/* --------------------------------------------------------------------------- */ +/* Micronucleus internal configuration. Do not change anything below this line */ +/* --------------------------------------------------------------------------- */ + +// Microcontroller vectortable entries in the flash +#define RESET_VECTOR_OFFSET 0 + +// number of bytes before the boot loader vectors to store the tiny application vector table +#define TINYVECTOR_RESET_OFFSET 4 +#define TINYVECTOR_OSCCAL_OFFSET 6 + +/* ------------------------------------------------------------------------ */ +// postscript are the few bytes at the end of programmable memory which store tinyVectors +#define POSTSCRIPT_SIZE 6 +#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */ + +#endif /* __bootloader_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t841_default/Makefile.inc b/sparkfun/tiny/bootloaders/attiny/configuration/t841_default/Makefile.inc new file mode 100644 index 00000000..47fd7472 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t841_default/Makefile.inc @@ -0,0 +1,24 @@ +# Name: Makefile +# Project: Micronucleus +# License: GNU GPL v2 (see License.txt) +# +# Controller type: ATtiny 841 +# Configuration: Default configuration - 12 Mhz RC oscillator +# Last Change: April 27,2016 + + +F_CPU = 12000000 +DEVICE = attiny841 + +# hexadecimal address for bootloader section to begin. To calculate the best value: +# - make clean; make main.hex; ### output will list data: 2124 (or something like that) +# - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 +# - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 +# - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 +BOOTLOADER_ADDRESS = 1980 + +FUSEOPT = -U lfuse:w:0xe2:m -U hfuse:w:0xdd:m -U efuse:w:0xf4:m +FUSEOPT_DISABLERESET = # Not implemented + + + diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t841_default/bootloaderconfig.h b/sparkfun/tiny/bootloaders/attiny/configuration/t841_default/bootloaderconfig.h new file mode 100644 index 00000000..ed09e1d3 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t841_default/bootloaderconfig.h @@ -0,0 +1,267 @@ +/* Name: bootloaderconfig.h + * Micronucleus configuration file. + * This file (together with some settings in Makefile.inc) configures the boot loader + * according to the hardware. + * + * Controller type: ATtiny 841 - 12 MHz + * Configuration: Default configuration + * USB D- : PB0 + * USB D+ : PB1 + * Entry : Always + * LED : PB2, Active Low + * OSCCAL : Revert to precalibrated value (8 MHz) + * Note: can use 12 MHz V-USB without PLL due to stable RC-osc in ATTiny841 + * Flash write time may be too low. + * Last Change: Mar 16,2014 + * + * License: GNU GPL v2 (see License.txt + */ + +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ------------------------------------------------------------------------- */ +/* Hardware configuration. */ +/* Change this according to your CPU and USB configuration */ +/* ------------------------------------------------------------------------- */ + +#define USB_CFG_IOPORTNAME B + /* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ + +#define USB_CFG_DMINUS_BIT 0 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 1 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port, but must be configured as a pin change interrupt. + */ + +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ + +/* ------------- Set up interrupt configuration (CPU specific) -------------- */ +/* The register names change quite a bit in the ATtiny family. Pay attention */ +/* to the manual. Note that the interrupt flag system is still used even though */ +/* interrupts are disabled. So this has to be configured correctly. */ + + +// setup interrupt for Pin Change for D+ +#define USB_INTR_CFG PCMSK1 +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE GIMSK +#define USB_INTR_ENABLE_BIT PCIE1 +#define USB_INTR_PENDING GIFR +#define USB_INTR_PENDING_BIT PCIF1 +#define USB_INTR_VECTOR PCINT1_vect + +/* ------------------------------------------------------------------------- */ +/* Configuration relevant to the CPU the bootloader is running on */ +/* ------------------------------------------------------------------------- */ + +// how many milliseconds should host wait till it sends another erase or write? +// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms + +// Set bit 7 to reduce wait time for page erase by factor of four +#define MICRONUCLEUS_WRITE_SLEEP 128 + 5 + +// ATtiny841 does not know OSCCAL +#ifndef OSCCAL +#define OSCCAL OSCCAL0 +#endif + +/* ---------------------- feature / code size options ---------------------- */ +/* Configure the behavior of the bootloader here */ +/* ------------------------------------------------------------------------- */ + +/* + * Define Bootloader entry condition + * + * If the entry condition is not met, the bootloader will not be activated and the user program + * is executed directly after a reset. If no user program has been loaded, the bootloader + * is always active. + * + * ENTRY_ALWAYS Always activate the bootloader after reset. Requires the least + * amount of code. + * + * ENTRY_WATCHDOG Activate the bootloader after a watchdog reset. This can be used + * to enter the bootloader from the user program. + * Adds 22 bytes. + * + * ENTRY_EXT_RESET Activate the bootloader after an external reset was issued by + * pulling the reset pin low. It may be necessary to add an external + * pull-up resistor to the reset pin if this entry method appears to + * behave unreliably. + * Adds 22 bytes. + * + * ENTRY_JUMPER Activate the bootloader when a specific pin is pulled low by an + * external jumper. + * Adds 34 bytes. + * + * JUMPER_PIN Pin the jumper is connected to. (e.g. PB0) + * JUMPER_PORT Port out register for the jumper (e.g. PORTB) + * JUMPER_DDR Port data direction register for the jumper (e.g. DDRB) + * JUMPER_INP Port inout register for the jumper (e.g. PINB) + * + */ + +#define ENTRYMODE ENTRY_EXT_RESET + +#define JUMPER_PIN PB0 +#define JUMPER_PORT PORTB +#define JUMPER_DDR DDRB +#define JUMPER_INP PINB + +/* + Internal implementation, don't change this unless you want to add an entrymode. +*/ + +#define ENTRY_ALWAYS 1 +#define ENTRY_WATCHDOG 2 +#define ENTRY_EXT_RESET 3 +#define ENTRY_JUMPER 4 + +#if ENTRYMODE==ENTRY_ALWAYS + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() 1 +#elif ENTRYMODE==ENTRY_WATCHDOG + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(WDRF)) +#elif ENTRYMODE==ENTRY_EXT_RESET + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF)) +#elif ENTRYMODE==ENTRY_JUMPER + // Enable pull up on jumper pin and delay to stabilize input + #define bootLoaderInit() {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);} + #define bootLoaderExit() {JUMPER_PORT&=~_BV(JUMPER_PIN);} + #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN))) +#else + #error "No entry mode defined" +#endif + +/* + * Define bootloader timeout value. + * + * The bootloader will only time out if a user program was loaded. + * + * AUTO_EXIT_NO_USB_MS The bootloader will exit after this delay if no USB is connected. + * Set to 0 to disable + * Adds ~6 bytes. + * (This will wait for an USB SE0 reset from the host) + * + * AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication + * from the host tool was received. + * Set to 0 to disable + * + * All values are approx. in milliseconds + */ + +#define AUTO_EXIT_NO_USB_MS 0 +#define AUTO_EXIT_MS 6000 + + /* + * Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL) + * + * OSCCAL_RESTORE_DEFAULT Set this to '1' to revert to OSCCAL factore calibration after bootlaoder exit. + * This is 8 MHz +/-2% on most devices or 16 MHz on the ATtiny 85 with activated PLL. + * Adds ~14 bytes. + * + * OSCCAL_SAVE_CALIB Set this to '1' to save the OSCCAL calibration during program upload. + * This value will be reloaded after reset and will also be used for the user + * program unless "OSCCAL_RESTORE_DEFAULT" is active. This allows calibrate the internal + * RC oscillator to the F_CPU target frequency +/-1% from the USB timing. Please note + * that only true if the ambient temperature does not change. + * Adds ~38 bytes. + * + * OSCCAL_HAVE_XTAL Set this to '1' if you have an external crystal oscillator. In this case no attempt + * will be made to calibrate the oscillator. You should deactivate both options above + * if you use this to avoid redundant code. + * + * If both options are selected, OSCCAL_RESTORE_DEFAULT takes precedence. + * + * If no option is selected, OSCCAL will be left untouched and stays at either factory calibration or F_CPU depending + * on whether the bootloader was activated. This will take the least memory. You can use this if your program + * comes with its own OSCCAL calibration or an external clock source is used. + */ + +#define OSCCAL_ENTRY_ALWAYS +#define OSCCAL_SAVE_CALIB 1 +#define OSCCAL_HAVE_XTAL 0 + +/* + * Defines handling of an indicator LED while the bootloader is active. + * + * LED_MODE Define behavior of attached LED or suppress LED code. + * + * NONE Do not generate LED code (gains 18 bytes). + * ACTIVE_HIGH LED is on when output pin is high. This will toggle bettwen 1 and 0. + * ACTIVE_LOW LED is on when output pin is low. This will toggle between Z and 0. + * + * LED_DDR,LED_PORT,LED_PIN Where is your LED connected? + * + */ + +#define LED_MODE ACTIVE_LOW + +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PB2 + +/* + * This is the implementation of the LED code. Change the configuration above unless you want to + * change the led behavior + * + * LED_INIT Called once after bootloader entry + * LED_EXIT Called once during bootloader exit + * LED_MACRO Called in the main loop with the idle counter as parameter. + * Use to define pattern. +*/ + +#define NONE 0 +#define ACTIVE_HIGH 1 +#define ACTIVE_LOW 2 + +#if LED_MODE==ACTIVE_HIGH + #define LED_INIT(x) LED_DDR |= _BV(LED_PIN); + #define LED_EXIT(x) {LED_DDR &=~_BV(LED_PIN);LED_PORT &=~_BV(LED_PIN);} + #define LED_MACRO(x) if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);} +#elif LED_MODE==ACTIVE_LOW + #define LED_INIT(x) LED_PORT &=~_BV(LED_PIN); + #define LED_EXIT(x) LED_DDR &=~_BV(LED_PIN); + #define LED_MACRO(x) if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);} +#elif LED_MODE==NONE + #define LED_INIT(x) + #define LED_EXIT(x) + #define LED_MACRO(x) +#endif + +/* --------------------------------------------------------------------------- */ +/* Micronucleus internal configuration. Do not change anything below this line */ +/* --------------------------------------------------------------------------- */ + +// Microcontroller vectortable entries in the flash +#define RESET_VECTOR_OFFSET 0 + +// number of bytes before the boot loader vectors to store the tiny application vector table +#define TINYVECTOR_RESET_OFFSET 4 +#define TINYVECTOR_OSCCAL_OFFSET 6 + +/* ------------------------------------------------------------------------ */ +// postscript are the few bytes at the end of programmable memory which store tinyVectors +#define POSTSCRIPT_SIZE 6 +#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */ + +#endif /* __bootloader_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t84_default/Makefile.inc b/sparkfun/tiny/bootloaders/attiny/configuration/t84_default/Makefile.inc new file mode 100644 index 00000000..5309f79d --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t84_default/Makefile.inc @@ -0,0 +1,63 @@ +# Name: Makefile +# Project: Micronucleus +# License: GNU GPL v2 (see License.txt) +# +# Controller type: ATtiny 84 +# Configuration: Default configuration - 12 Mhz RC oscillator +# Last Change: Mar 16,2014 + + +F_CPU = 12000000 +DEVICE = attiny84 + +# hexadecimal address for bootloader section to begin. To calculate the best value: +# - make clean; make main.hex; ### output will list data: 2124 (or something like that) +# - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 +# - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 +# - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 +BOOTLOADER_ADDRESS = 1980 + +FUSEOPT = -U lfuse:w:0xe2:m -U hfuse:w:0xdd:m -U efuse:w:0xfe:m +FUSEOPT_DISABLERESET = # TODO + + +#--------------------------------------------------------------------- +# ATtiny84 +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0xFE = - - - - - 1 1 0 +# ^ +# | +# +---- SELFPRGEN (enable self programming flash) +# +# Fuse high byte: +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +# Fuse high byte ("no reset": external reset disabled, can't program through SPI anymore) +# 0x5d = 0 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> disabled!) +# +# Fuse low byte: +# 0xe1 = 1 1 1 0 0 0 1 0 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> RC Oscillator) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) + + + + diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t84_default/bootloaderconfig.h b/sparkfun/tiny/bootloaders/attiny/configuration/t84_default/bootloaderconfig.h new file mode 100644 index 00000000..05748ad0 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t84_default/bootloaderconfig.h @@ -0,0 +1,265 @@ +/* Name: bootloaderconfig.h + * Micronucleus configuration file. + * This file (together with some settings in Makefile.inc) configures the boot loader + * according to the hardware. + * + * Controller type: ATtiny 84 - 12 MHz + * Configuration: Default configuration + * USB D- : PB0 + * USB D+ : PB1 + * Entry : Always + * LED : PB2, Active Low + * OSCCAL : Revert to precalibrated value (8 MHz) + * Note: can use 12 MHz V-USB without PLL due to stable RC-osc in ATTiny84A + * Last Change: Mar 16,2014 + * + * License: GNU GPL v2 (see License.txt + */ + +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ------------------------------------------------------------------------- */ +/* Hardware configuration. */ +/* Change this according to your CPU and USB configuration */ +/* ------------------------------------------------------------------------- */ + +#define USB_CFG_IOPORTNAME B + /* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ + +#define USB_CFG_DMINUS_BIT 0 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 1 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port, but must be configured as a pin change interrupt. + */ + +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ + +/* ------------- Set up interrupt configuration (CPU specific) -------------- */ +/* The register names change quite a bit in the ATtiny family. Pay attention */ +/* to the manual. Note that the interrupt flag system is still used even though */ +/* interrupts are disabled. So this has to be configured correctly. */ + + +// setup interrupt for Pin Change for D+ +#define USB_INTR_CFG PCMSK1 +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE GIMSK +#define USB_INTR_ENABLE_BIT PCIE1 +#define USB_INTR_PENDING GIFR +#define USB_INTR_PENDING_BIT PCIF1 +#define USB_INTR_VECTOR PCINT1_vect + +/* ------------------------------------------------------------------------- */ +/* Configuration relevant to the CPU the bootloader is running on */ +/* ------------------------------------------------------------------------- */ + +// how many milliseconds should host wait till it sends another erase or write? +// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms + +#define MICRONUCLEUS_WRITE_SLEEP 5 + +// ATtiny84 does not know WDTCR +#ifndef WDTCR +#define WDTCR WDTCSR +#endif + +/* ---------------------- feature / code size options ---------------------- */ +/* Configure the behavior of the bootloader here */ +/* ------------------------------------------------------------------------- */ + +/* + * Define Bootloader entry condition + * + * If the entry condition is not met, the bootloader will not be activated and the user program + * is executed directly after a reset. If no user program has been loaded, the bootloader + * is always active. + * + * ENTRY_ALWAYS Always activate the bootloader after reset. Requires the least + * amount of code. + * + * ENTRY_WATCHDOG Activate the bootloader after a watchdog reset. This can be used + * to enter the bootloader from the user program. + * Adds 22 bytes. + * + * ENTRY_EXT_RESET Activate the bootloader after an external reset was issued by + * pulling the reset pin low. It may be necessary to add an external + * pull-up resistor to the reset pin if this entry method appears to + * behave unreliably. + * Adds 22 bytes. + * + * ENTRY_JUMPER Activate the bootloader when a specific pin is pulled low by an + * external jumper. + * Adds 34 bytes. + * + * JUMPER_PIN Pin the jumper is connected to. (e.g. PB0) + * JUMPER_PORT Port out register for the jumper (e.g. PORTB) + * JUMPER_DDR Port data direction register for the jumper (e.g. DDRB) + * JUMPER_INP Port inout register for the jumper (e.g. PINB) + * + */ + +#define ENTRYMODE ENTRY_ALWAYS + +#define JUMPER_PIN PB0 +#define JUMPER_PORT PORTB +#define JUMPER_DDR DDRB +#define JUMPER_INP PINB + +/* + Internal implementation, don't change this unless you want to add an entrymode. +*/ + +#define ENTRY_ALWAYS 1 +#define ENTRY_WATCHDOG 2 +#define ENTRY_EXT_RESET 3 +#define ENTRY_JUMPER 4 + +#if ENTRYMODE==ENTRY_ALWAYS + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() 1 +#elif ENTRYMODE==ENTRY_WATCHDOG + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(WDRF)) +#elif ENTRYMODE==ENTRY_EXT_RESET + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF)) +#elif ENTRYMODE==ENTRY_JUMPER + // Enable pull up on jumper pin and delay to stabilize input + #define bootLoaderInit() {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);} + #define bootLoaderExit() {JUMPER_PORT&=~_BV(JUMPER_PIN);} + #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN))) +#else + #error "No entry mode defined" +#endif + +/* + * Define bootloader timeout value. + * + * The bootloader will only time out if a user program was loaded. + * + * AUTO_EXIT_NO_USB_MS The bootloader will exit after this delay if no USB is connected. + * Set to 0 to disable + * Adds ~6 bytes. + * (This will wait for an USB SE0 reset from the host) + * + * AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication + * from the host tool was received. + * Set to 0 to disable + * + * All values are approx. in milliseconds + */ + +#define AUTO_EXIT_NO_USB_MS 0 +#define AUTO_EXIT_MS 6000 + + /* + * Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL) + * + * OSCCAL_RESTORE_DEFAULT Set this to '1' to revert to OSCCAL factore calibration after bootlaoder exit. + * This is 8 MHz +/-2% on most devices or 16 MHz on the ATtiny 85 with activated PLL. + * Adds ~14 bytes. + * + * OSCCAL_SAVE_CALIB Set this to '1' to save the OSCCAL calibration during program upload. + * This value will be reloaded after reset and will also be used for the user + * program unless "OSCCAL_RESTORE_DEFAULT" is active. This allows calibrate the internal + * RC oscillator to the F_CPU target frequency +/-1% from the USB timing. Please note + * that only true if the ambient temperature does not change. + * Adds ~38 bytes. + * + * OSCCAL_HAVE_XTAL Set this to '1' if you have an external crystal oscillator. In this case no attempt + * will be made to calibrate the oscillator. You should deactivate both options above + * if you use this to avoid redundant code. + * + * If both options are selected, OSCCAL_RESTORE_DEFAULT takes precedence. + * + * If no option is selected, OSCCAL will be left untouched and stays at either factory calibration or F_CPU depending + * on whether the bootloader was activated. This will take the least memory. You can use this if your program + * comes with its own OSCCAL calibration or an external clock source is used. + */ + +#define OSCCAL_RESTORE_DEFAULT 1 +#define OSCCAL_SAVE_CALIB 0 +#define OSCCAL_HAVE_XTAL 0 + +/* + * Defines handling of an indicator LED while the bootloader is active. + * + * LED_MODE Define behavior of attached LED or suppress LED code. + * + * NONE Do not generate LED code (gains 18 bytes). + * ACTIVE_HIGH LED is on when output pin is high. This will toggle bettwen 1 and 0. + * ACTIVE_LOW LED is on when output pin is low. This will toggle between Z and 0. + * + * LED_DDR,LED_PORT,LED_PIN Where is your LED connected? + * + */ + +#define LED_MODE ACTIVE_LOW + +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PB2 + +/* + * This is the implementation of the LED code. Change the configuration above unless you want to + * change the led behavior + * + * LED_INIT Called once after bootloader entry + * LED_EXIT Called once during bootloader exit + * LED_MACRO Called in the main loop with the idle counter as parameter. + * Use to define pattern. +*/ + +#define NONE 0 +#define ACTIVE_HIGH 1 +#define ACTIVE_LOW 2 + +#if LED_MODE==ACTIVE_HIGH + #define LED_INIT(x) LED_DDR = _BV(LED_PIN); + #define LED_EXIT(x) {LED_DDR &=~_BV(LED_PIN);LED_PORT &=~_BV(LED_PIN);} + #define LED_MACRO(x) if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);} +#elif LED_MODE==ACTIVE_LOW + #define LED_INIT(x) LED_PORT &=~_BV(LED_PIN); + #define LED_EXIT(x) LED_DDR &=~_BV(LED_PIN); + #define LED_MACRO(x) if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);} +#elif LED_MODE==NONE + #define LED_INIT(x) + #define LED_EXIT(x) + #define LED_MACRO(x) +#endif + +/* --------------------------------------------------------------------------- */ +/* Micronucleus internal configuration. Do not change anything below this line */ +/* --------------------------------------------------------------------------- */ + +// Microcontroller vectortable entries in the flash +#define RESET_VECTOR_OFFSET 0 + +// number of bytes before the boot loader vectors to store the tiny application vector table +#define TINYVECTOR_RESET_OFFSET 4 +#define TINYVECTOR_OSCCAL_OFFSET 6 + +/* ------------------------------------------------------------------------ */ +// postscript are the few bytes at the end of programmable memory which store tinyVectors +#define POSTSCRIPT_SIZE 6 +#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */ + +#endif /* __bootloader_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t84_roshamglo/Makefile.inc b/sparkfun/tiny/bootloaders/attiny/configuration/t84_roshamglo/Makefile.inc new file mode 100644 index 00000000..5309f79d --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t84_roshamglo/Makefile.inc @@ -0,0 +1,63 @@ +# Name: Makefile +# Project: Micronucleus +# License: GNU GPL v2 (see License.txt) +# +# Controller type: ATtiny 84 +# Configuration: Default configuration - 12 Mhz RC oscillator +# Last Change: Mar 16,2014 + + +F_CPU = 12000000 +DEVICE = attiny84 + +# hexadecimal address for bootloader section to begin. To calculate the best value: +# - make clean; make main.hex; ### output will list data: 2124 (or something like that) +# - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 +# - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 +# - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 +BOOTLOADER_ADDRESS = 1980 + +FUSEOPT = -U lfuse:w:0xe2:m -U hfuse:w:0xdd:m -U efuse:w:0xfe:m +FUSEOPT_DISABLERESET = # TODO + + +#--------------------------------------------------------------------- +# ATtiny84 +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0xFE = - - - - - 1 1 0 +# ^ +# | +# +---- SELFPRGEN (enable self programming flash) +# +# Fuse high byte: +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +# Fuse high byte ("no reset": external reset disabled, can't program through SPI anymore) +# 0x5d = 0 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> disabled!) +# +# Fuse low byte: +# 0xe1 = 1 1 1 0 0 0 1 0 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> RC Oscillator) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) + + + + diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t84_roshamglo/bootloaderconfig.h b/sparkfun/tiny/bootloaders/attiny/configuration/t84_roshamglo/bootloaderconfig.h new file mode 100644 index 00000000..e83e8531 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t84_roshamglo/bootloaderconfig.h @@ -0,0 +1,267 @@ +/* Name: bootloaderconfig.h + * Micronucleus configuration file. + * This file (together with some settings in Makefile.inc) configures the boot loader + * according to the hardware. + * + * Modified by SparkFun Electronics for Roshamglo project + * + * Controller type: ATtiny 84 - 12 MHz + * Configuration: Default configuration + * USB D- : PB0 + * USB D+ : PB1 + * Entry : Jumper - PA0 to GND + * LED : PB2, Active High + * OSCCAL : Revert to precalibrated value (8 MHz) + * Note: can use 12 MHz V-USB without PLL due to stable RC-osc in ATTiny84A + * Last Change: Feb 1, 2017 + * + * License: GNU GPL v2 (see License.txt) + */ + +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ------------------------------------------------------------------------- */ +/* Hardware configuration. */ +/* Change this according to your CPU and USB configuration */ +/* ------------------------------------------------------------------------- */ + +#define USB_CFG_IOPORTNAME B + /* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ + +#define USB_CFG_DMINUS_BIT 0 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 1 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port, but must be configured as a pin change interrupt. + */ + +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ + +/* ------------- Set up interrupt configuration (CPU specific) -------------- */ +/* The register names change quite a bit in the ATtiny family. Pay attention */ +/* to the manual. Note that the interrupt flag system is still used even though */ +/* interrupts are disabled. So this has to be configured correctly. */ + + +// setup interrupt for Pin Change for D+ +#define USB_INTR_CFG PCMSK1 +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE GIMSK +#define USB_INTR_ENABLE_BIT PCIE1 +#define USB_INTR_PENDING GIFR +#define USB_INTR_PENDING_BIT PCIF1 +#define USB_INTR_VECTOR PCINT1_vect + +/* ------------------------------------------------------------------------- */ +/* Configuration relevant to the CPU the bootloader is running on */ +/* ------------------------------------------------------------------------- */ + +// how many milliseconds should host wait till it sends another erase or write? +// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms + +#define MICRONUCLEUS_WRITE_SLEEP 5 + +// ATtiny84 does not know WDTCR +#ifndef WDTCR +#define WDTCR WDTCSR +#endif + +/* ---------------------- feature / code size options ---------------------- */ +/* Configure the behavior of the bootloader here */ +/* ------------------------------------------------------------------------- */ + +/* + * Define Bootloader entry condition + * + * If the entry condition is not met, the bootloader will not be activated and the user program + * is executed directly after a reset. If no user program has been loaded, the bootloader + * is always active. + * + * ENTRY_ALWAYS Always activate the bootloader after reset. Requires the least + * amount of code. + * + * ENTRY_WATCHDOG Activate the bootloader after a watchdog reset. This can be used + * to enter the bootloader from the user program. + * Adds 22 bytes. + * + * ENTRY_EXT_RESET Activate the bootloader after an external reset was issued by + * pulling the reset pin low. It may be necessary to add an external + * pull-up resistor to the reset pin if this entry method appears to + * behave unreliably. + * Adds 22 bytes. + * + * ENTRY_JUMPER Activate the bootloader when a specific pin is pulled low by an + * external jumper. + * Adds 34 bytes. + * + * JUMPER_PIN Pin the jumper is connected to. (e.g. PB0) + * JUMPER_PORT Port out register for the jumper (e.g. PORTB) + * JUMPER_DDR Port data direction register for the jumper (e.g. DDRB) + * JUMPER_INP Port inout register for the jumper (e.g. PINB) + * + */ + +#define ENTRYMODE ENTRY_JUMPER + +#define JUMPER_PIN PA0 +#define JUMPER_PORT PORTA +#define JUMPER_DDR DDRA +#define JUMPER_INP PINA + +/* + Internal implementation, don't change this unless you want to add an entrymode. +*/ + +#define ENTRY_ALWAYS 1 +#define ENTRY_WATCHDOG 2 +#define ENTRY_EXT_RESET 3 +#define ENTRY_JUMPER 4 + +#if ENTRYMODE==ENTRY_ALWAYS + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() 1 +#elif ENTRYMODE==ENTRY_WATCHDOG + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(WDRF)) +#elif ENTRYMODE==ENTRY_EXT_RESET + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF)) +#elif ENTRYMODE==ENTRY_JUMPER + // Enable pull up on jumper pin and delay to stabilize input + #define bootLoaderInit() {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);} + #define bootLoaderExit() {JUMPER_PORT&=~_BV(JUMPER_PIN);} + #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN))) +#else + #error "No entry mode defined" +#endif + +/* + * Define bootloader timeout value. + * + * The bootloader will only time out if a user program was loaded. + * + * AUTO_EXIT_NO_USB_MS The bootloader will exit after this delay if no USB is connected. + * Set to 0 to disable + * Adds ~6 bytes. + * (This will wait for an USB SE0 reset from the host) + * + * AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication + * from the host tool was received. + * Set to 0 to disable + * + * All values are approx. in milliseconds + */ + +#define AUTO_EXIT_NO_USB_MS 0 +#define AUTO_EXIT_MS 0 + + /* + * Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL) + * + * OSCCAL_RESTORE_DEFAULT Set this to '1' to revert to OSCCAL factore calibration after bootlaoder exit. + * This is 8 MHz +/-2% on most devices or 16 MHz on the ATtiny 85 with activated PLL. + * Adds ~14 bytes. + * + * OSCCAL_SAVE_CALIB Set this to '1' to save the OSCCAL calibration during program upload. + * This value will be reloaded after reset and will also be used for the user + * program unless "OSCCAL_RESTORE_DEFAULT" is active. This allows calibrate the internal + * RC oscillator to the F_CPU target frequency +/-1% from the USB timing. Please note + * that only true if the ambient temperature does not change. + * Adds ~38 bytes. + * + * OSCCAL_HAVE_XTAL Set this to '1' if you have an external crystal oscillator. In this case no attempt + * will be made to calibrate the oscillator. You should deactivate both options above + * if you use this to avoid redundant code. + * + * If both options are selected, OSCCAL_RESTORE_DEFAULT takes precedence. + * + * If no option is selected, OSCCAL will be left untouched and stays at either factory calibration or F_CPU depending + * on whether the bootloader was activated. This will take the least memory. You can use this if your program + * comes with its own OSCCAL calibration or an external clock source is used. + */ + +#define OSCCAL_RESTORE_DEFAULT 1 +#define OSCCAL_SAVE_CALIB 0 +#define OSCCAL_HAVE_XTAL 0 + +/* + * Defines handling of an indicator LED while the bootloader is active. + * + * LED_MODE Define behavior of attached LED or suppress LED code. + * + * NONE Do not generate LED code (gains 18 bytes). + * ACTIVE_HIGH LED is on when output pin is high. This will toggle bettwen 1 and 0. + * ACTIVE_LOW LED is on when output pin is low. This will toggle between Z and 0. + * + * LED_DDR,LED_PORT,LED_PIN Where is your LED connected? + * + */ + +#define LED_MODE ACTIVE_HIGH + +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PB2 + +/* + * This is the implementation of the LED code. Change the configuration above unless you want to + * change the led behavior + * + * LED_INIT Called once after bootloader entry + * LED_EXIT Called once during bootloader exit + * LED_MACRO Called in the main loop with the idle counter as parameter. + * Use to define pattern. +*/ + +#define NONE 0 +#define ACTIVE_HIGH 1 +#define ACTIVE_LOW 2 + +#if LED_MODE==ACTIVE_HIGH + #define LED_INIT(x) LED_DDR = _BV(LED_PIN); + #define LED_EXIT(x) {LED_DDR &=~_BV(LED_PIN);LED_PORT &=~_BV(LED_PIN);} + #define LED_MACRO(x) if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);} +#elif LED_MODE==ACTIVE_LOW + #define LED_INIT(x) LED_PORT &=~_BV(LED_PIN); + #define LED_EXIT(x) LED_DDR &=~_BV(LED_PIN); + #define LED_MACRO(x) if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);} +#elif LED_MODE==NONE + #define LED_INIT(x) + #define LED_EXIT(x) + #define LED_MACRO(x) +#endif + +/* --------------------------------------------------------------------------- */ +/* Micronucleus internal configuration. Do not change anything below this line */ +/* --------------------------------------------------------------------------- */ + +// Microcontroller vectortable entries in the flash +#define RESET_VECTOR_OFFSET 0 + +// number of bytes before the boot loader vectors to store the tiny application vector table +#define TINYVECTOR_RESET_OFFSET 4 +#define TINYVECTOR_OSCCAL_OFFSET 6 + +/* ------------------------------------------------------------------------ */ +// postscript are the few bytes at the end of programmable memory which store tinyVectors +#define POSTSCRIPT_SIZE 6 +#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */ + +#endif /* __bootloader_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t85_aggressive/Makefile.inc b/sparkfun/tiny/bootloaders/attiny/configuration/t85_aggressive/Makefile.inc new file mode 100644 index 00000000..4675ae94 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t85_aggressive/Makefile.inc @@ -0,0 +1,68 @@ +# Name: Makefile +# Project: Micronucleus +# License: GNU GPL v2 (see License.txt) + +# Controller type: ATtiny 85 +# Configuration: Size optimized. Uses 16 MHz V-USB implementation, which may be instable with some computers +# Last Change: Jan 11,2015 + +# Enable unsafe optimizions. This will disable several safety features in microncleus to save around 40 more bytes +# +# Disabled features: +# * Stack pointer and SREG initialization in CRT +# * Client side reset vector patching +# * USB collision detection. Micronucleus will not work reliability with hubs if this is disabled. + +CFLAGS += -DENABLE_UNSAFE_OPTIMIZATIONS + +F_CPU = 16000000 +DEVICE = attiny85 + +# hexadecimal address for bootloader section to begin. To calculate the best value: +# - make clean; make main.hex; ### output will list data: 2124 (or something like that) +# - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 +# - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 +# - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 +BOOTLOADER_ADDRESS = 1A40 + +FUSEOPT = -U lfuse:w:0xe1:m -U hfuse:w:0xdd:m -U efuse:w:0xfe:m +FUSEOPT_DISABLERESET = -U lfuse:w:0xe1:m -U efuse:w:0xfe:m -U hfuse:w:0x5d:m + +#--------------------------------------------------------------------- +# ATtiny85 +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0xFE = - - - - - 1 1 0 +# ^ +# | +# +---- SELFPRGEN (enable self programming flash) +# +# Fuse high byte: +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +# Fuse high byte ("no reset": external reset disabled, can't program through SPI anymore) +# 0x5d = 0 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> disabled!) +# +# Fuse low byte: +# 0xe1 = 1 1 1 0 0 0 0 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> HF PLL) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) + +############################################################################### diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t85_aggressive/bootloaderconfig.h b/sparkfun/tiny/bootloaders/attiny/configuration/t85_aggressive/bootloaderconfig.h new file mode 100644 index 00000000..0af18f53 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t85_aggressive/bootloaderconfig.h @@ -0,0 +1,262 @@ + /* Name: bootloaderconfig.h + * Micronucleus configuration file. + * This file (together with some settings in Makefile.inc) configures the boot loader + * according to the hardware. + * + * Controller type: ATtiny 85 - 16 MHz + * Configuration: Aggresively size optimized configuration + * USB D- : PB3 + * USB D+ : PB4 + * Entry : Always + * LED : None + * OSCCAL : Stays at 16 MHz + * Note: Uses 16 MHz V-USB implementation. + * Worked reliably in all tests, but is possibly less stable than 16.5M Hz Implementation with PLL + * Last Change: Jan 11,2015 + * + * License: GNU GPL v2 (see License.txt + */ + +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ------------------------------------------------------------------------- */ +/* Hardware configuration. */ +/* Change this according to your CPU and USB configuration */ +/* ------------------------------------------------------------------------- */ + +#define USB_CFG_IOPORTNAME B + /* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ + +#define USB_CFG_DMINUS_BIT 3 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 4 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port, but must be configured as a pin change interrupt. + */ + +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ + +/* ------------- Set up interrupt configuration (CPU specific) -------------- */ +/* The register names change quite a bit in the ATtiny family. Pay attention */ +/* to the manual. Note that the interrupt flag system is still used even though */ +/* interrupts are disabled. So this has to be configured correctly. */ + + +// setup interrupt for Pin Change for D+ +#define USB_INTR_CFG PCMSK +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE GIMSK +#define USB_INTR_ENABLE_BIT PCIE +#define USB_INTR_PENDING GIFR +#define USB_INTR_PENDING_BIT PCIF +#define USB_INTR_VECTOR PCINT0_vect + +/* ------------------------------------------------------------------------- */ +/* Configuration relevant to the CPU the bootloader is running on */ +/* ------------------------------------------------------------------------- */ + +// how many milliseconds should host wait till it sends another erase or write? +// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms +#define MICRONUCLEUS_WRITE_SLEEP 5 + + +/* ---------------------- feature / code size options ---------------------- */ +/* Configure the behavior of the bootloader here */ +/* ------------------------------------------------------------------------- */ + +/* + * Define Bootloader entry condition + * + * If the entry condition is not met, the bootloader will not be activated and the user program + * is executed directly after a reset. If no user program has been loaded, the bootloader + * is always active. + * + * ENTRY_ALWAYS Always activate the bootloader after reset. Requires the least + * amount of code. + * + * ENTRY_WATCHDOG Activate the bootloader after a watchdog reset. This can be used + * to enter the bootloader from the user program. + * Adds 22 bytes. + * + * ENTRY_EXT_RESET Activate the bootloader after an external reset was issued by + * pulling the reset pin low. It may be necessary to add an external + * pull-up resistor to the reset pin if this entry method appears to + * behave unreliably. + * Adds 22 bytes. + * + * ENTRY_JUMPER Activate the bootloader when a specific pin is pulled low by an + * external jumper. + * Adds 34 bytes. + * + * JUMPER_PIN Pin the jumper is connected to. (e.g. PB0) + * JUMPER_PORT Port out register for the jumper (e.g. PORTB) + * JUMPER_DDR Port data direction register for the jumper (e.g. DDRB) + * JUMPER_INP Port inout register for the jumper (e.g. PINB) + * + */ + +#define ENTRYMODE ENTRY_ALWAYS + +#define JUMPER_PIN PB0 +#define JUMPER_PORT PORTB +#define JUMPER_DDR DDRB +#define JUMPER_INP PINB + +/* + Internal implementation, don't change this unless you want to add an entrymode. +*/ + +#define ENTRY_ALWAYS 1 +#define ENTRY_WATCHDOG 2 +#define ENTRY_EXT_RESET 3 +#define ENTRY_JUMPER 4 + +#if ENTRYMODE==ENTRY_ALWAYS + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() 1 +#elif ENTRYMODE==ENTRY_WATCHDOG + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(WDRF)) +#elif ENTRYMODE==ENTRY_EXT_RESET + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF)) +#elif ENTRYMODE==ENTRY_JUMPER + // Enable pull up on jumper pin and delay to stabilize input + #define bootLoaderInit() {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);} + #define bootLoaderExit() {JUMPER_PORT&=~_BV(JUMPER_PIN);} + #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN))) +#else + #error "No entry mode defined" +#endif + +/* + * Define bootloader timeout value. + * + * The bootloader will only time out if a user program was loaded. + * + * AUTO_EXIT_NO_USB_MS The bootloader will exit after this delay if no USB is connected. + * Set to 0 to disable + * Adds ~6 bytes. + * (This will wait for an USB SE0 reset from the host) + * + * AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication + * from the host tool was received. + * Set to 0 to disable + * + * All values are approx. in milliseconds + */ + +#define AUTO_EXIT_NO_USB_MS 0 +#define AUTO_EXIT_MS 6000 + + /* + * Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL) + * + * OSCCAL_RESTORE_DEFAULT Set this to '1' to revert to OSCCAL factore calibration after bootlaoder exit. + * This is 8 MHz +/-2% on most devices or 16 MHz on the ATtiny 85 with activated PLL. + * Adds ~14 bytes. + * + * OSCCAL_SAVE_CALIB Set this to '1' to save the OSCCAL calibration during program upload. + * This value will be reloaded after reset and will also be used for the user + * program unless "OSCCAL_RESTORE_DEFAULT" is active. This allows calibrate the internal + * RC oscillator to the F_CPU target frequency +/-1% from the USB timing. Please note + * that only true if the ambient temperature does not change. + * Adds ~38 bytes. + * + * OSCCAL_HAVE_XTAL Set this to '1' if you have an external crystal oscillator. In this case no attempt + * will be made to calibrate the oscillator. You should deactivate both options above + * if you use this to avoid redundant code. + * + * If both options are selected, OSCCAL_RESTORE_DEFAULT takes precedence. + * + * If no option is selected, OSCCAL will be left untouched and stays at either factory calibration or F_CPU depending + * on whether the bootloader was activated. This will take the least memory. You can use this if your program + * comes with its own OSCCAL calibration or an external clock source is used. + */ + +#define OSCCAL_RESTORE_DEFAULT 0 +#define OSCCAL_SAVE_CALIB 0 +#define OSCCAL_HAVE_XTAL 0 + + +/* + * Defines handling of an indicator LED while the bootloader is active. + * + * LED_MODE Define behavior of attached LED or suppress LED code. + * + * NONE Do not generate LED code (gains 18 bytes). + * ACTIVE_HIGH LED is on when output pin is high. This will toggle bettwen 1 and 0. + * ACTIVE_LOW LED is on when output pin is low. This will toggle between Z and 0. + * + * LED_DDR,LED_PORT,LED_PIN Where is your LED connected? + * + */ + +#define LED_MODE NONE + +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PB1 + +/* + * This is the implementation of the LED code. Change the configuration above unless you want to + * change the led behavior + * + * LED_INIT Called once after bootloader entry + * LED_EXIT Called once during bootloader exit + * LED_MACRO Called in the main loop with the idle counter as parameter. + * Use to define pattern. +*/ + +#define NONE 0 +#define ACTIVE_HIGH 1 +#define ACTIVE_LOW 2 + +#if LED_MODE==ACTIVE_HIGH + #define LED_INIT(x) LED_DDR |= _BV(LED_PIN); + #define LED_EXIT(x) {LED_DDR &=~_BV(LED_PIN);LED_PORT &=~_BV(LED_PIN);} + #define LED_MACRO(x) if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);} +#elif LED_MODE==ACTIVE_LOW + #define LED_INIT(x) LED_PORT &=~_BV(LED_PIN); + #define LED_EXIT(x) LED_DDR &=~_BV(LED_PIN); + #define LED_MACRO(x) if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);} +#elif LED_MODE==NONE + #define LED_INIT(x) + #define LED_EXIT(x) + #define LED_MACRO(x) +#endif + +/* --------------------------------------------------------------------------- */ +/* Micronucleus internal configuration. Do not change anything below this line */ +/* --------------------------------------------------------------------------- */ + +// Microcontroller vectortable entries in the flash +#define RESET_VECTOR_OFFSET 0 + +// number of bytes before the boot loader vectors to store the tiny application vector table +#define TINYVECTOR_RESET_OFFSET 4 +#define TINYVECTOR_OSCCAL_OFFSET 6 + +/* ------------------------------------------------------------------------ */ +// postscript are the few bytes at the end of programmable memory which store tinyVectors +#define POSTSCRIPT_SIZE 6 +#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */ + +#endif /* __bootloader_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t85_default/Makefile.inc b/sparkfun/tiny/bootloaders/attiny/configuration/t85_default/Makefile.inc new file mode 100644 index 00000000..ee7252d8 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t85_default/Makefile.inc @@ -0,0 +1,60 @@ +# Name: Makefile +# Project: Micronucleus +# License: GNU GPL v2 (see License.txt) + +# Controller type: ATtiny 85 - 16.5 MHz +# Configuration: Default +# Last Change: Mar 16,2014 + + +F_CPU = 16500000 +DEVICE = attiny85 + +# hexadecimal address for bootloader section to begin. To calculate the best value: +# - make clean; make main.hex; ### output will list data: 2124 (or something like that) +# - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 +# - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 +# - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 +BOOTLOADER_ADDRESS = 1980 + +FUSEOPT = -U lfuse:w:0xe1:m -U hfuse:w:0xdd:m -U efuse:w:0xfe:m +FUSEOPT_DISABLERESET = -U lfuse:w:0xe1:m -U efuse:w:0xfe:m -U hfuse:w:0x5d:m + +#--------------------------------------------------------------------- +# ATtiny85 +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0xFE = - - - - - 1 1 0 +# ^ +# | +# +---- SELFPRGEN (enable self programming flash) +# +# Fuse high byte: +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +# Fuse high byte ("no reset": external reset disabled, can't program through SPI anymore) +# 0x5d = 0 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> disabled!) +# +# Fuse low byte: +# 0xe1 = 1 1 1 0 0 0 0 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> HF PLL) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) + +############################################################################### diff --git a/sparkfun/tiny/bootloaders/attiny/configuration/t85_default/bootloaderconfig.h b/sparkfun/tiny/bootloaders/attiny/configuration/t85_default/bootloaderconfig.h new file mode 100644 index 00000000..9b3ac638 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/configuration/t85_default/bootloaderconfig.h @@ -0,0 +1,259 @@ +/* Name: bootloaderconfig.h + * Micronucleus configuration file. + * This file (together with some settings in Makefile.inc) configures the boot loader + * according to the hardware. + * + * Controller type: ATtiny 85 - 16.5 MHz + * Configuration: Default configuration + * USB D- : PB3 + * USB D+ : PB4 + * Entry : Always + * LED : None + * OSCCAL : Stays at 16 MHz + * Note: Uses 16.5 MHz V-USB implementation with PLL + * Last Change: Mar 16,2014 + * + * License: GNU GPL v2 (see License.txt + */ +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ------------------------------------------------------------------------- */ +/* Hardware configuration. */ +/* Change this according to your CPU and USB configuration */ +/* ------------------------------------------------------------------------- */ + +#define USB_CFG_IOPORTNAME B + /* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ + +#define USB_CFG_DMINUS_BIT 3 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 4 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port, but must be configured as a pin change interrupt. + */ + +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ + +/* ------------- Set up interrupt configuration (CPU specific) -------------- */ +/* The register names change quite a bit in the ATtiny family. Pay attention */ +/* to the manual. Note that the interrupt flag system is still used even though */ +/* interrupts are disabled. So this has to be configured correctly. */ + + +// setup interrupt for Pin Change for D+ +#define USB_INTR_CFG PCMSK +#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT) +#define USB_INTR_CFG_CLR 0 +#define USB_INTR_ENABLE GIMSK +#define USB_INTR_ENABLE_BIT PCIE +#define USB_INTR_PENDING GIFR +#define USB_INTR_PENDING_BIT PCIF +#define USB_INTR_VECTOR PCINT0_vect + +/* ------------------------------------------------------------------------- */ +/* Configuration relevant to the CPU the bootloader is running on */ +/* ------------------------------------------------------------------------- */ + +// how many milliseconds should host wait till it sends another erase or write? +// needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms +#define MICRONUCLEUS_WRITE_SLEEP 5 + + +/* ---------------------- feature / code size options ---------------------- */ +/* Configure the behavior of the bootloader here */ +/* ------------------------------------------------------------------------- */ + +/* + * Define Bootloader entry condition + * + * If the entry condition is not met, the bootloader will not be activated and the user program + * is executed directly after a reset. If no user program has been loaded, the bootloader + * is always active. + * + * ENTRY_ALWAYS Always activate the bootloader after reset. Requires the least + * amount of code. + * + * ENTRY_WATCHDOG Activate the bootloader after a watchdog reset. This can be used + * to enter the bootloader from the user program. + * Adds 22 bytes. + * + * ENTRY_EXT_RESET Activate the bootloader after an external reset was issued by + * pulling the reset pin low. It may be necessary to add an external + * pull-up resistor to the reset pin if this entry method appears to + * behave unreliably. + * Adds 22 bytes. + * + * ENTRY_JUMPER Activate the bootloader when a specific pin is pulled low by an + * external jumper. + * Adds 34 bytes. + * + * JUMPER_PIN Pin the jumper is connected to. (e.g. PB0) + * JUMPER_PORT Port out register for the jumper (e.g. PORTB) + * JUMPER_DDR Port data direction register for the jumper (e.g. DDRB) + * JUMPER_INP Port inout register for the jumper (e.g. PINB) + * + */ + +#define ENTRYMODE ENTRY_ALWAYS + +#define JUMPER_PIN PB0 +#define JUMPER_PORT PORTB +#define JUMPER_DDR DDRB +#define JUMPER_INP PINB + +/* + Internal implementation, don't change this unless you want to add an entrymode. +*/ + +#define ENTRY_ALWAYS 1 +#define ENTRY_WATCHDOG 2 +#define ENTRY_EXT_RESET 3 +#define ENTRY_JUMPER 4 + +#if ENTRYMODE==ENTRY_ALWAYS + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() 1 +#elif ENTRYMODE==ENTRY_WATCHDOG + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(WDRF)) +#elif ENTRYMODE==ENTRY_EXT_RESET + #define bootLoaderInit() + #define bootLoaderExit() + #define bootLoaderStartCondition() (MCUSR&_BV(EXTRF)) +#elif ENTRYMODE==ENTRY_JUMPER + // Enable pull up on jumper pin and delay to stabilize input + #define bootLoaderInit() {JUMPER_DDR&=~_BV(JUMPER_PIN);JUMPER_PORT|=_BV(JUMPER_PIN);_delay_ms(1);} + #define bootLoaderExit() {JUMPER_PORT&=~_BV(JUMPER_PIN);} + #define bootLoaderStartCondition() (!(JUMPER_INP&_BV(JUMPER_PIN))) +#else + #error "No entry mode defined" +#endif + +/* + * Define bootloader timeout value. + * + * The bootloader will only time out if a user program was loaded. + * + * AUTO_EXIT_NO_USB_MS The bootloader will exit after this delay if no USB is connected. + * Set to 0 to disable + * Adds ~6 bytes. + * (This will wait for an USB SE0 reset from the host) + * + * AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication + * from the host tool was received. + * Set to 0 to disable + * + * All values are approx. in milliseconds + */ + +#define AUTO_EXIT_NO_USB_MS 0 +#define AUTO_EXIT_MS 6000 + + /* + * Defines the setting of the RC-oscillator calibration after quitting the bootloader. (OSCCAL) + * + * OSCCAL_RESTORE_DEFAULT Set this to '1' to revert to OSCCAL factore calibration after bootlaoder exit. + * This is 8 MHz +/-2% on most devices or 16 MHz on the ATtiny 85 with activated PLL. + * Adds ~14 bytes. + * + * OSCCAL_SAVE_CALIB Set this to '1' to save the OSCCAL calibration during program upload. + * This value will be reloaded after reset and will also be used for the user + * program unless "OSCCAL_RESTORE_DEFAULT" is active. This allows calibrate the internal + * RC oscillator to the F_CPU target frequency +/-1% from the USB timing. Please note + * that only true if the ambient temperature does not change. + * Adds ~38 bytes. + * + * OSCCAL_HAVE_XTAL Set this to '1' if you have an external crystal oscillator. In this case no attempt + * will be made to calibrate the oscillator. You should deactivate both options above + * if you use this to avoid redundant code. + * + * If both options are selected, OSCCAL_RESTORE_DEFAULT takes precedence. + * + * If no option is selected, OSCCAL will be left untouched and stays at either factory calibration or F_CPU depending + * on whether the bootloader was activated. This will take the least memory. You can use this if your program + * comes with its own OSCCAL calibration or an external clock source is used. + */ + +#define OSCCAL_RESTORE_DEFAULT 0 +#define OSCCAL_SAVE_CALIB 1 +#define OSCCAL_HAVE_XTAL 0 + +/* + * Defines handling of an indicator LED while the bootloader is active. + * + * LED_MODE Define behavior of attached LED or suppress LED code. + * + * NONE Do not generate LED code (gains 18 bytes). + * ACTIVE_HIGH LED is on when output pin is high. This will toggle bettwen 1 and 0. + * ACTIVE_LOW LED is on when output pin is low. This will toggle between Z and 0. + * + * LED_DDR,LED_PORT,LED_PIN Where is your LED connected? + * + */ + +#define LED_MODE NONE + +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PB1 + +/* + * This is the implementation of the LED code. Change the configuration above unless you want to + * change the led behavior + * + * LED_INIT Called once after bootloader entry + * LED_EXIT Called once during bootloader exit + * LED_MACRO Called in the main loop with the idle counter as parameter. + * Use to define pattern. +*/ + +#define NONE 0 +#define ACTIVE_HIGH 1 +#define ACTIVE_LOW 2 + +#if LED_MODE==ACTIVE_HIGH + #define LED_INIT(x) LED_DDR |= _BV(LED_PIN); + #define LED_EXIT(x) {LED_DDR &=~_BV(LED_PIN);LED_PORT &=~_BV(LED_PIN);} + #define LED_MACRO(x) if ( x & 0x4c ) {LED_PORT&=~_BV(LED_PIN);} else {LED_PORT|=_BV(LED_PIN);} +#elif LED_MODE==ACTIVE_LOW + #define LED_INIT(x) LED_PORT &=~_BV(LED_PIN); + #define LED_EXIT(x) LED_DDR &=~_BV(LED_PIN); + #define LED_MACRO(x) if ( x & 0x4c ) {LED_DDR&=~_BV(LED_PIN);} else {LED_DDR|=_BV(LED_PIN);} +#elif LED_MODE==NONE + #define LED_INIT(x) + #define LED_EXIT(x) + #define LED_MACRO(x) +#endif + +/* --------------------------------------------------------------------------- */ +/* Micronucleus internal configuration. Do not change anything below this line */ +/* --------------------------------------------------------------------------- */ + +// Microcontroller vectortable entries in the flash +#define RESET_VECTOR_OFFSET 0 + +// number of bytes before the boot loader vectors to store the tiny application vector table +#define TINYVECTOR_RESET_OFFSET 4 +#define TINYVECTOR_OSCCAL_OFFSET 6 + +/* ------------------------------------------------------------------------ */ +// postscript are the few bytes at the end of programmable memory which store tinyVectors +#define POSTSCRIPT_SIZE 6 +#define PROGMEM_SIZE (BOOTLOADER_ADDRESS - POSTSCRIPT_SIZE) /* max size of user program */ + +#endif /* __bootloader_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/crt1.S b/sparkfun/tiny/bootloaders/attiny/crt1.S new file mode 100644 index 00000000..1f68351b --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/crt1.S @@ -0,0 +1,112 @@ + +/* Copyright (c) 2002, Marek Michalkiewicz + Copyright (c) 2007, 2008 Eric B. Weddington + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +/* $Id$ */ + +#if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) +#error "GCC version >= 3.3 required" +#endif + +/* +#include IOSYMFILE +#include "macros.inc" +*/ +#include +//#include + +#ifdef __AVR_HAVE_JMP_CALL__ + #define XJMP jmp +#else + #define XJMP rjmp +#endif + + #define XCALL rcall + + .macro vector name + .weak \name + .set \name, __init + XJMP \name + .endm + + .section .vectors,"ax",@progbits + .global __vectors + .global __bad_interrupt + .func __vectors + +__bad_interrupt: +__vectors: + XJMP __init +; vector __vector_1 +; vector __vector_2 +; vector __vector_3 + .endfunc + + /* Handle unexpected interrupts (enabled and no handler), which + usually indicate a bug. Jump to the __vector_default function + if defined by the user, otherwise jump to the reset address. + + This must be in a different section, otherwise the assembler + will resolve "rjmp" offsets and there will be no relocs. */ + + .section .init0,"ax",@progbits + .weak __init +; .func __init +__init: + + .weak __stack + .set __stack, RAMEND + /* By default, malloc() uses the current value of the stack pointer + minus __malloc_margin as the highest available address. + + In some applications with external SRAM, the stack can be below + the data section (in the internal SRAM - faster), and __heap_end + should be set to the highest address available for malloc(). */ + .weak __heap_end + .set __heap_end, 0 + + .section .init2,"ax",@progbits + clr R1 + +#ifndef ENABLE_UNSAFE_OPTIMIZATIONS + out 0x3f,r1 + ldi r28,lo8(__stack) + ldi r29,hi8(__stack) + out 0x3d, r28 + out 0x3e, r29 +#endif + .section .init9,"ax",@progbits +; rcall main +; XJMP __vectors-2 + XJMP main + +; .endfunc + diff --git a/sparkfun/tiny/bootloaders/attiny/crt1.o b/sparkfun/tiny/bootloaders/attiny/crt1.o new file mode 100644 index 00000000..ebe56282 Binary files /dev/null and b/sparkfun/tiny/bootloaders/attiny/crt1.o differ diff --git a/sparkfun/tiny/bootloaders/attiny/main.bin b/sparkfun/tiny/bootloaders/attiny/main.bin new file mode 100644 index 00000000..5c0d99e3 Binary files /dev/null and b/sparkfun/tiny/bootloaders/attiny/main.bin differ diff --git a/sparkfun/tiny/bootloaders/attiny/main.c b/sparkfun/tiny/bootloaders/attiny/main.c new file mode 100644 index 00000000..82211058 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/main.c @@ -0,0 +1,377 @@ +/* + * Project: Micronucleus - v2.3 + * + * Micronucleus V2.3 (c) 2016 Tim Bo"scke - cpldcpu@gmail.com + * (c) 2014 Shay Green + * Original Micronucleus (c) 2012 Jenna Fox + * + * Based on USBaspLoader-tiny85 (c) 2012 Louis Beaudoin + * Based on USBaspLoader (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * + * License: GNU GPL v2 (see License.txt) + */ + +#define MICRONUCLEUS_VERSION_MAJOR 2 +#define MICRONUCLEUS_VERSION_MINOR 3 + +#include +#include +#include +#include +#include + +#include "bootloaderconfig.h" +#include "usbdrv/usbdrv.c" + +// verify the bootloader address aligns with page size +#if (defined __AVR_ATtiny841__)||(defined __AVR_ATtiny441__) + #if BOOTLOADER_ADDRESS % ( SPM_PAGESIZE * 4 ) != 0 + #error "BOOTLOADER_ADDRESS in makefile must be a multiple of chip's pagesize" + #endif +#else + #if BOOTLOADER_ADDRESS % SPM_PAGESIZE != 0 + #error "BOOTLOADER_ADDRESS in makefile must be a multiple of chip's pagesize" + #endif +#endif + +#if SPM_PAGESIZE>256 + #error "Micronucleus only supports pagesizes up to 256 bytes" +#endif + +#if ((AUTO_EXIT_MS>0) && (AUTO_EXIT_MS<1000)) + #error "Do not set AUTO_EXIT_MS to below 1s to allow Micronucleus to function properly" +#endif + +// Device configuration reply +// Length: 6 bytes +// Byte 0: User program memory size, high byte +// Byte 1: User program memory size, low byte +// Byte 2: Flash Pagesize in bytes +// Byte 3: Page write timing in ms. +// Bit 7 '0': Page erase time equals page write time +// Bit 7 '1': Page erase time equals page write time divided by 4 +// Byte 4: SIGNATURE_1 +// Byte 5: SIGNATURE_2 + +PROGMEM const uint8_t configurationReply[6] = { + (((uint16_t)PROGMEM_SIZE) >> 8) & 0xff, + ((uint16_t)PROGMEM_SIZE) & 0xff, + SPM_PAGESIZE, + MICRONUCLEUS_WRITE_SLEEP, + SIGNATURE_1, + SIGNATURE_2 +}; + + typedef union { + uint16_t w; + uint8_t b[2]; + } uint16_union_t; + +#if OSCCAL_RESTORE_DEFAULT + register uint8_t osccal_default asm("r2"); +#endif + +register uint16_union_t currentAddress asm("r4"); // r4/r5 current progmem address, used for erasing and writing +register uint16_union_t idlePolls asm("r6"); // r6/r7 idlecounter + +// command system schedules functions to run in the main loop +enum { + cmd_local_nop=0, + cmd_device_info=0, + cmd_transfer_page=1, + cmd_erase_application=2, + cmd_write_data=3, + cmd_exit=4, + cmd_write_page=64 // internal commands start at 64 +}; +register uint8_t command asm("r3"); // bind command to r3 + +// Definition of sei and cli without memory barrier keyword to prevent reloading of memory variables +#define sei() asm volatile("sei") +#define cli() asm volatile("cli") +#define nop() asm volatile("nop") +#define wdr() asm volatile("wdr") + +// Use the old delay routines without NOP padding. This saves memory. +#define __DELAY_BACKWARD_COMPATIBLE__ + +/* ------------------------------------------------------------------------ */ +static inline void eraseApplication(void); +static void writeFlashPage(void); +static void writeWordToPageBuffer(uint16_t data); +static uint8_t usbFunctionSetup(uint8_t data[8]); +static inline void leaveBootloader(void); + +// This function is never called, it is just here to suppress a compiler warning. +USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) { return 0; } + +// erase all pages until bootloader, in reverse order (so our vectors stay in place for as long as possible) +// to minimise the chance of leaving the device in a state where the bootloader wont run, if there's power failure +// during upload +static inline void eraseApplication(void) { + uint16_t ptr = BOOTLOADER_ADDRESS; + + while (ptr) { +#if (defined __AVR_ATtiny841__)||(defined __AVR_ATtiny441__) + ptr -= SPM_PAGESIZE * 4; +#else + ptr -= SPM_PAGESIZE; +#endif + boot_page_erase(ptr); + } + + // Reset address to ensure the reset vector is written first. + currentAddress.w = 0; +} + +// simply write currently stored page in to already erased flash memory +static inline void writeFlashPage(void) { + if (currentAddress.w - 2 bRequest == cmd_device_info) { // get device info + usbMsgPtr = (usbMsgPtr_t)configurationReply; + return sizeof(configurationReply); + } else if (rq->bRequest == cmd_transfer_page) { + // Set page address. Address zero always has to be written first to ensure reset vector patching. + // Mask to page boundary to prevent vulnerability to partial page write "attacks" + if ( currentAddress.w != 0 ) { + currentAddress.b[0]=rq->wIndex.bytes[0] & (~ (SPM_PAGESIZE-1)); + currentAddress.b[1]=rq->wIndex.bytes[1]; + + // clear page buffer as a precaution before filling the buffer in case + // a previous write operation failed and there is still something in the buffer. + __SPM_REG=(_BV(CTPB)|_BV(__SPM_ENABLE)); + asm volatile("spm"); + + } + } else if (rq->bRequest == cmd_write_data) { // Write data + writeWordToPageBuffer(rq->wValue.word); + writeWordToPageBuffer(rq->wIndex.word); + if ((currentAddress.b[0] % SPM_PAGESIZE) == 0) + command=cmd_write_page; // ask runloop to write our page + } else { + // Handle cmd_erase_application and cmd_exit + command=rq->bRequest&0x3f; + } + return 0; +} + +static void initHardware (void) +{ + // Disable watchdog and set timeout to maximum in case the WDT is fused on +#ifdef CCP + // New ATtinies841/441 use a different unlock sequence and renamed registers + MCUSR=0; + CCP = 0xD8; + WDTCSR = 1<0) { + idlePolls.b[1]=((AUTO_EXIT_MS-AUTO_EXIT_NO_USB_MS)/5)>>8; + } else { + idlePolls.b[1]=0; + } + + command=cmd_local_nop; + currentAddress.w = 0; + + do { + // 15 clockcycles per loop. + // adjust fastctr for 5ms timeout + + uint16_t fastctr=(uint16_t)(F_CPU/(1000.0f*15.0f/5.0f)); + uint8_t resetctr=100; + + do { + if ((USBIN & USBMASK) !=0) resetctr=100; + + if (!--resetctr) { // reset encountered + usbNewDeviceAddr = 0; // bits from the reset handling of usbpoll() + usbDeviceAddr = 0; +#if (OSCCAL_HAVE_XTAL == 0) + calibrateOscillatorASM(); +#endif + } + + if (USB_INTR_PENDING & (1<= 0){ + usbProcessRx(usbRxBuf + 1, len); // only single buffer due to in-order processing + usbRxLen = 0; /* mark rx buffer as available */ + } + + if(usbTxLen & 0x10){ /* transmit system idle */ + if(usbMsgLen != USB_NO_MSG){ /* transmit data pending? */ + usbBuildTxBlock(); + } + } + } + + idlePolls.w++; + + // Try to execute program when bootloader times out + if (AUTO_EXIT_MS&&(idlePolls.w==(AUTO_EXIT_MS/5))) { + if (pgm_read_byte(BOOTLOADER_ADDRESS - TINYVECTOR_RESET_OFFSET + 1)!=0xff) break; + } + + LED_MACRO( idlePolls.b[0] ); + + // Test whether another interrupt occurred during the processing of USBpoll and commands. + // If yes, we missed a data packet on the bus. Wait until the bus was idle for 8.8µs to + // allow synchronising to the next incoming packet. + + if (USB_INTR_PENDING & (1<>= 1; + + if (step==0) // Enter neighborhood search mode + { + step=1; + if(xl <= optimumDev){ + optimumDev = xl; + optimumValue = OSCCAL; + } + } + } + + OSCCAL = optimumValue; + asm volatile(" NOP"); +} +#endif \ No newline at end of file diff --git a/sparkfun/tiny/bootloaders/attiny/osccalASM.o b/sparkfun/tiny/bootloaders/attiny/osccalASM.o new file mode 100644 index 00000000..138c0ef4 Binary files /dev/null and b/sparkfun/tiny/bootloaders/attiny/osccalASM.o differ diff --git a/sparkfun/tiny/bootloaders/attiny/releases/t84_default.hex b/sparkfun/tiny/bootloaders/attiny/releases/t84_default.hex new file mode 100644 index 00000000..d4467bdb --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/releases/t84_default.hex @@ -0,0 +1,100 @@ +:1019800017C00403090412011001FF0000084F1BD7 +:10199000140003020000000109021200010100808E +:1019A00032090400000000000000197A4005930C81 +:1019B00011241FBECFE5D2E0CDBFDEBF10E0A0E610 +:1019C000B0E001C01D92AC38B107E1F7A2C1DC0163 +:1019D0008FEF9FEF332715C02D912827722F229567 +:1019E0002727822F269526952827239522703217A0 +:1019F00077952795822F8927972F76952795972773 +:101A00008227615048F7809590950895E0DF8D9387 +:101A10009D930895CF93CFB7CF93C395B09BE9F72C +:101A2000B09B09C0B09B07C0B09B05C0B09B03C072 +:101A3000B09B01C0A7C0DF93C0916E00DD27CA58DC +:101A4000DF4FB09B02C0DF91EBCF2F930F931F931B +:101A500006B32FEF00FB20F94F933F9316B34FEFE0 +:101A6000012700FB21F93BE031C04E7F012F16B367 +:101A7000216028C0102F4D7F2260000006B329C0CE +:101A80004B7F2460012F000016B32BC016B3477F95 +:101A900028602AC04F7E06B320612CC04F7D16B34C +:101AA00020622FC04F7B06B3206432C0422706B3AA +:101AB00049934FEF0000102710FB20F916B3137065 +:101AC000C9F1297F91F2012700FB21F906B3237F99 +:101AD00089F2315058F1102710FB22F916B3277EF6 +:101AE00079F2012700FB23F92F7C81F206B310273E +:101AF00010FB24F92F7971F200C016B3012700FB07 +:101B000025F92F7359F200C006B3102710FB26F9F0 +:101B1000223040F200C016B3012700FB27F9243021 +:101B200028F64F77206816B30000F9CF10E21ABFED +:101B300000271DC03B503195C31BD04010E21ABF97 +:101B40000881033C19F10B3409F120916C001981D3 +:101B5000110F1213EDCF093641F10D3211F0013E94 +:101B600039F7CAE01AB715FD02C0CA95D9F7009334 +:101B700074003F914F911F910F912F91DF91CAB740 +:101B8000C5FD4BCFCF91CFBFCF9108952091740069 +:101B9000222379F3109172001123E1F43430E2F042 +:101BA0003093720020936D0017C0009172000130D5 +:101BB0008CF40AE530916F0034FD10C000936F0083 +:101BC000C1E6D0E00FC02795A8F45150A9F4220F28 +:101BD0000000F9CF4AE503C042ED01C0432FC4E144 +:101BE000D0E032E017B31360C09A17BB08B320E40B +:101BF00013E05F93012756E008BB279520F451506E +:101C000021F4220FF9CF012756E000003B5A08BB10 +:101C1000D0F2279528F4515029F4220F0000F9CF73 +:101C2000012756E0279508BB20F4515021F4220FDC +:101C3000F9CF012756E02991332308BB21F60C7F09 +:101C400010917300110FC651D04008BB11F01093D2 +:101C50006C0010E21ABF016017B31C7F402F4C7F4D +:101C60005F9100C000C008BB17BB48BB82CF2FEFFD +:101C7000B0E8A0E04AE0B1BF00008EE599E0B0997D +:101C8000FECFB09BFECF0197B099FDCF97FF03C069 +:101C9000BA1B819501C0BA0FA69539F4A0E428F4C7 +:101CA000281710F031B7282FA1E0415021F731BF9C +:101CB000000008959C01F2014114510411F42FEB2E +:101CC0003CEC81E0090180935700E895112482E003 +:101CD000482E512C4E0E5F1E089514BE88E181BD22 +:101CE00087E081BDB89A88EB9BE0ECE2F1E03197A8 +:101CF000F1F70197D1F7B8988AE580936F008FEFDD +:101D00008093600080B5826080BD8BB780628BBF9E +:101D100008951F93CF93DF9381B7282EDEDFC298FB +:101D20007724332444245524C0EADFE014E686B344 +:101D300090E083709070892B09F014E6115029F41B +:101D40001092730010926C0092DF0AB605FE05C077 +:101D500061DE80E28ABF772402C0219741F7A8950F +:101D6000832D823069F4E0E8F9E1E054F04083E04B +:101D700080935700E8953097C1F74424552412C04A +:101D8000803459F4F201329729E1E038F20750F437 +:101D900085E080935700E89505C0843019F4CD2B79 +:101DA00011F4F6C0332490917200935097FDA0C0B7 +:101DB00080916D008D3209F099C0983009F096C07D +:101DC00083EC809361008AE580936F0080917700B7 +:101DD0008076909178008823A9F1992341F48AEACA +:101DE00099E1909371008093700096E074C09130F7 +:101DF00079F44114510409F46DC080917B0040ECEA +:101E0000442E482250907C0081E187BFE89562C053 +:101E10009330A1F48091790090917A004BDF80910A +:101E20007B0090917C0046DF842D90E08F73907052 +:101E3000892B09F04FC030E4332E4CC02FE3322EF3 +:101E4000392248C02091790010926A00992331F418 +:101E500010926B002AE630E092E037C0953019F41A +:101E6000209373002FC09630E9F480917A0081307E +:101E700019F486E899E104C0823041F488E999E1D7 +:101E8000909371008093700092E125C0833011F52A +:101E9000222301F582E899E190937100809370000C +:101EA00094E019C0983019F425E730E009C0993062 +:101EB00019F42093750006C09A3021F42AE630E028 +:101EC00091E003C02AE630E090E030937100209367 +:101ED000700001C090E080917E00882329F48091F9 +:101EE0007D00891708F4982F90936000109272007B +:101EF00080916F0084FF30C0809160008F3F61F15E +:101F0000182F893008F018E0811B809360008091C1 +:101F1000610098E8892780936100112381F0E091A6 +:101F20007000F0917100912FA2E6B0E084918D9342 +:101F300031969150D9F7F0937100E093700082E6EA +:101F400090E0612F63DD612F6C5F6C3019F08FEFD3 +:101F50008093600060936F00C30101963C01805B39 +:101F6000944029F4EDE7F9E1E491EF3F89F4862DFF +:101F70008C7411F0BA9801C0BA9A0AB605FED4CE94 +:101F800085E1B09B85E18150E1F780E28ABFCCCE4C +:101F9000BA98A3DE1BBE10BC21BE0000EFCCFFCF61 +:040000030000198060 +:00000001FF diff --git a/sparkfun/tiny/bootloaders/attiny/releases/t84_roshamglo.hex b/sparkfun/tiny/bootloaders/attiny/releases/t84_roshamglo.hex new file mode 100644 index 00000000..d4467bdb --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/releases/t84_roshamglo.hex @@ -0,0 +1,100 @@ +:1019800017C00403090412011001FF0000084F1BD7 +:10199000140003020000000109021200010100808E +:1019A00032090400000000000000197A4005930C81 +:1019B00011241FBECFE5D2E0CDBFDEBF10E0A0E610 +:1019C000B0E001C01D92AC38B107E1F7A2C1DC0163 +:1019D0008FEF9FEF332715C02D912827722F229567 +:1019E0002727822F269526952827239522703217A0 +:1019F00077952795822F8927972F76952795972773 +:101A00008227615048F7809590950895E0DF8D9387 +:101A10009D930895CF93CFB7CF93C395B09BE9F72C +:101A2000B09B09C0B09B07C0B09B05C0B09B03C072 +:101A3000B09B01C0A7C0DF93C0916E00DD27CA58DC +:101A4000DF4FB09B02C0DF91EBCF2F930F931F931B +:101A500006B32FEF00FB20F94F933F9316B34FEFE0 +:101A6000012700FB21F93BE031C04E7F012F16B367 +:101A7000216028C0102F4D7F2260000006B329C0CE +:101A80004B7F2460012F000016B32BC016B3477F95 +:101A900028602AC04F7E06B320612CC04F7D16B34C +:101AA00020622FC04F7B06B3206432C0422706B3AA +:101AB00049934FEF0000102710FB20F916B3137065 +:101AC000C9F1297F91F2012700FB21F906B3237F99 +:101AD00089F2315058F1102710FB22F916B3277EF6 +:101AE00079F2012700FB23F92F7C81F206B310273E +:101AF00010FB24F92F7971F200C016B3012700FB07 +:101B000025F92F7359F200C006B3102710FB26F9F0 +:101B1000223040F200C016B3012700FB27F9243021 +:101B200028F64F77206816B30000F9CF10E21ABFED +:101B300000271DC03B503195C31BD04010E21ABF97 +:101B40000881033C19F10B3409F120916C001981D3 +:101B5000110F1213EDCF093641F10D3211F0013E94 +:101B600039F7CAE01AB715FD02C0CA95D9F7009334 +:101B700074003F914F911F910F912F91DF91CAB740 +:101B8000C5FD4BCFCF91CFBFCF9108952091740069 +:101B9000222379F3109172001123E1F43430E2F042 +:101BA0003093720020936D0017C0009172000130D5 +:101BB0008CF40AE530916F0034FD10C000936F0083 +:101BC000C1E6D0E00FC02795A8F45150A9F4220F28 +:101BD0000000F9CF4AE503C042ED01C0432FC4E144 +:101BE000D0E032E017B31360C09A17BB08B320E40B +:101BF00013E05F93012756E008BB279520F451506E +:101C000021F4220FF9CF012756E000003B5A08BB10 +:101C1000D0F2279528F4515029F4220F0000F9CF73 +:101C2000012756E0279508BB20F4515021F4220FDC +:101C3000F9CF012756E02991332308BB21F60C7F09 +:101C400010917300110FC651D04008BB11F01093D2 +:101C50006C0010E21ABF016017B31C7F402F4C7F4D +:101C60005F9100C000C008BB17BB48BB82CF2FEFFD +:101C7000B0E8A0E04AE0B1BF00008EE599E0B0997D +:101C8000FECFB09BFECF0197B099FDCF97FF03C069 +:101C9000BA1B819501C0BA0FA69539F4A0E428F4C7 +:101CA000281710F031B7282FA1E0415021F731BF9C +:101CB000000008959C01F2014114510411F42FEB2E +:101CC0003CEC81E0090180935700E895112482E003 +:101CD000482E512C4E0E5F1E089514BE88E181BD22 +:101CE00087E081BDB89A88EB9BE0ECE2F1E03197A8 +:101CF000F1F70197D1F7B8988AE580936F008FEFDD +:101D00008093600080B5826080BD8BB780628BBF9E +:101D100008951F93CF93DF9381B7282EDEDFC298FB +:101D20007724332444245524C0EADFE014E686B344 +:101D300090E083709070892B09F014E6115029F41B +:101D40001092730010926C0092DF0AB605FE05C077 +:101D500061DE80E28ABF772402C0219741F7A8950F +:101D6000832D823069F4E0E8F9E1E054F04083E04B +:101D700080935700E8953097C1F74424552412C04A +:101D8000803459F4F201329729E1E038F20750F437 +:101D900085E080935700E89505C0843019F4CD2B79 +:101DA00011F4F6C0332490917200935097FDA0C0B7 +:101DB00080916D008D3209F099C0983009F096C07D +:101DC00083EC809361008AE580936F0080917700B7 +:101DD0008076909178008823A9F1992341F48AEACA +:101DE00099E1909371008093700096E074C09130F7 +:101DF00079F44114510409F46DC080917B0040ECEA +:101E0000442E482250907C0081E187BFE89562C053 +:101E10009330A1F48091790090917A004BDF80910A +:101E20007B0090917C0046DF842D90E08F73907052 +:101E3000892B09F04FC030E4332E4CC02FE3322EF3 +:101E4000392248C02091790010926A00992331F418 +:101E500010926B002AE630E092E037C0953019F41A +:101E6000209373002FC09630E9F480917A0081307E +:101E700019F486E899E104C0823041F488E999E1D7 +:101E8000909371008093700092E125C0833011F52A +:101E9000222301F582E899E190937100809370000C +:101EA00094E019C0983019F425E730E009C0993062 +:101EB00019F42093750006C09A3021F42AE630E028 +:101EC00091E003C02AE630E090E030937100209367 +:101ED000700001C090E080917E00882329F48091F9 +:101EE0007D00891708F4982F90936000109272007B +:101EF00080916F0084FF30C0809160008F3F61F15E +:101F0000182F893008F018E0811B809360008091C1 +:101F1000610098E8892780936100112381F0E091A6 +:101F20007000F0917100912FA2E6B0E084918D9342 +:101F300031969150D9F7F0937100E093700082E6EA +:101F400090E0612F63DD612F6C5F6C3019F08FEFD3 +:101F50008093600060936F00C30101963C01805B39 +:101F6000944029F4EDE7F9E1E491EF3F89F4862DFF +:101F70008C7411F0BA9801C0BA9A0AB605FED4CE94 +:101F800085E1B09B85E18150E1F780E28ABFCCCE4C +:101F9000BA98A3DE1BBE10BC21BE0000EFCCFFCF61 +:040000030000198060 +:00000001FF diff --git a/sparkfun/tiny/bootloaders/attiny/upgrade.c b/sparkfun/tiny/bootloaders/attiny/upgrade.c new file mode 100644 index 00000000..698ed28e --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/upgrade.c @@ -0,0 +1,176 @@ +// Upgrade is an in-place firmware upgrader for tiny85 chips - just fill in the +// 'bootloaderAddress' variable in bootloader_data.h, and the bootloaderData +// progmem array with the bootloader data, and you're ready to go. +// +// Upgrade will firstly rewrite the interrupt vector table to disable the bootloader, +// rewriting it to just run the upgrade app. Next it erases and writes each page of the +// bootloader in sequence, erasing over any remaining pages leaving them set to 0xFFFF +// Finally upgrader erases it's interrupt table again and fills it with RJMPs to +// bootloaderAddress, effectively bridging the interrupts in to the new bootloader's +// interrupts table. +// +// While upgrade has been written with attiny85 and micronucleus in mind, it should +// work with other bootloaders and other chips with flash self program but no hardware +// bootloader protection, where the bootloader exists at the end of flash +// +// Be very careful to not power down the AVR while upgrader is running. +// If you connect a piezo between pb0 and pb1 you'll hear a bleep when the update +// is complete. You can also connect an LED with pb0 positive and pb1 or gnd negative and +// it will blink + +#include "./utils.h" +#include +#include +#include +#include +#include +#include "./bootloader_data.c" + +void secure_interrupt_vector_table(void); +void write_new_bootloader(void); +void forward_interrupt_vector_table(void); +void beep(void); +void reboot(void); + +void load_table(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]); +void erase_page(uint16_t address); +void write_page(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]); + + +int main(void) { + pinsOff(0xFF); // pull down all pins + outputs(0xFF); // all to ground - force usb disconnect + delay(250); // milliseconds + inputs(0xFF); // let them float + delay(250); + cli(); + + secure_interrupt_vector_table(); // reset our vector table to it's original state + write_new_bootloader(); + forward_interrupt_vector_table(); + + beep(); + + reboot(); + + return 0; +} + +// erase first page, removing any interrupt table hooks the bootloader added when +// upgrade was uploaded +void secure_interrupt_vector_table(void) { + uint16_t table[SPM_PAGESIZE / 2]; + + load_table(0, table); + + // wipe out any interrupt hooks the bootloader rewrote + int i = 0; + while (i < SPM_PAGESIZE / 2) { + table[0] = 0xFFFF; + i++; + } + + erase_page(0); + write_page(0, table); +} + +// erase bootloader's section and write over it with new bootloader code +void write_new_bootloader(void) { + uint16_t outgoing_page[SPM_PAGESIZE / 2]; + int iter = 0; + while (iter < sizeof(bootloader_data)) { + + // read in one page's worth of data from progmem + int word_addr = 0; + while (word_addr < SPM_PAGESIZE) { + int subaddress = ((int) bootloader_data) + iter + word_addr; + if (subaddress >= ((int) bootloader_data) + sizeof(bootloader_data)) { + outgoing_page[word_addr / 2] = 0xFFFF; + } else { + outgoing_page[word_addr / 2] = pgm_read_word(subaddress); + } + + word_addr += 2; + } + + // erase page in destination + erase_page(bootloader_address + iter); + // write updated page + write_page(bootloader_address + iter, outgoing_page); + + iter += 64; + } +} + +// write in forwarding interrupt vector table +void forward_interrupt_vector_table(void) { + uint16_t vector_table[SPM_PAGESIZE / 2]; + + int iter = 0; + while (iter < SPM_PAGESIZE / 2) { + // rjmp to bootloader_address's interrupt table + vector_table[iter] = 0xC000 + (bootloader_address / 2) - 1; + iter++; + } + + erase_page(0); + write_page(0, vector_table); +} + +void load_table(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]) { + uint16_t subaddress = 0; + address -= address % SPM_PAGESIZE; // round down to nearest page start + + while (subaddress < SPM_PAGESIZE) { + words[subaddress / 2] = pgm_read_word(address + subaddress); + subaddress += 2; + } +} + +void erase_page(uint16_t address) { + boot_page_erase(address - (address % SPM_PAGESIZE)); + boot_spm_busy_wait(); +} + +void write_page(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]) { + // fill buffer + uint16_t iter = 0; + while (iter < SPM_PAGESIZE / 2) { + boot_page_fill(address + (iter * 2), words[iter]); + iter++; + } + + boot_page_write(address); + boot_spm_busy_wait(); // Wait until the memory is written. +} + +// beep for a quarter of a second +void beep(void) { + outputs(pin(0) | pin(1)); + pinOff(1); + + byte i = 0; + while (i < 250) { + delay(1); + pinOn(pin(0)); + delay(1); + pinOff(pin(0)); + i++; + } +} + +void reboot(void) { + void (*ptrToFunction)(); // pointer to a function + ptrToFunction = 0x0000; + (*ptrToFunction)(); // reset! +} + + +////////////// Add padding to start of program so no program code could reasonably be erased while program is running +// this never needs to be called - avr-gcc stuff happening: http://www.nongnu.org/avr-libc/user-manual/mem_sections.html +volatile void FakeISR (void) __attribute__ ((naked)) __attribute__ ((section (".init0"))); +volatile void FakeISR (void) { + // 16 nops to pad out first section of program + asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); + asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); +} diff --git a/sparkfun/tiny/bootloaders/attiny/usbconfig.h b/sparkfun/tiny/bootloaders/attiny/usbconfig.h new file mode 100644 index 00000000..738c0e74 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbconfig.h @@ -0,0 +1,350 @@ +/* Name: usbconfig.h + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2005-04-01 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbconfig.h 799 2010-07-27 17:30:13Z cs $ + * + * Modified by SparkFun Electronics to change USB VID/PID for ATtiny bootlaoder. + * Date: 2017-02-01 + */ + +#ifndef __usbconfig_h_included__ +#define __usbconfig_h_included__ + +/* YOU SHOULD NOT NEED TO MODIFY THIS FILE! All configurations are supposed + * to go into bootloaderconfig.h! + */ + +/* ---------------------------- Hardware Config ---------------------------- */ + +/* All the port and pin assignments, as well as the clock speed and CRC + setting are now in bootloaderconfig.h: */ + +#include "bootloaderconfig.h" + +/* --------------------------- Functional Range ---------------------------- */ + +#define USB_CFG_HAVE_INTRIN_ENDPOINT 0 +/* Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint (any other endpoint + * number). + */ +#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 +/* Define this to 1 if you want to compile a version with three endpoints: The + * default control endpoint 0, an interrupt-in endpoint 3 (or the number + * configured below) and a catch-all default interrupt-in endpoint as above. + * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. + */ +#define USB_CFG_EP3_NUMBER 3 +/* If the so-called endpoint 3 is used, it can now be configured to any other + * endpoint number (except 0) with this macro. Default if undefined is 3. + */ +/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */ +/* The above macro defines the startup condition for data toggling on the + * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. + * Since the token is toggled BEFORE sending any data, the first packet is + * sent with the oposite value of this configuration! + */ +#define USB_CFG_IMPLEMENT_HALT 0 +/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * it is required by the standard. We have made it a config option because it + * bloats the code considerably. + */ +#define USB_CFG_SUPPRESS_INTR_CODE 0 +/* Define this to 1 if you want to declare interrupt-in endpoints, but don't + * want to send any data over them. If this macro is defined to 1, functions + * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if + * you need the interrupt-in endpoints in order to comply to an interface + * (e.g. HID), but never want to send any data. This option saves a couple + * of bytes in flash memory and the transmit buffers in RAM. + */ +#define USB_CFG_INTR_POLL_INTERVAL 10 +/* If you compile a version with endpoint 1 (interrupt-in), this is the poll + * interval. The value is in milliseconds and must not be less than 10 ms for + * low speed devices. + */ +#ifndef USB_CFG_IS_SELF_POWERED // allow bootloaderconfig.h to override +#define USB_CFG_IS_SELF_POWERED 0 +#endif +/* Define this to 1 if the device has its own power supply. Set it to 0 if the + * device is powered from the USB bus. + */ +#ifndef USB_CFG_MAX_BUS_POWER // allow bootloaderconfig.h to override +#define USB_CFG_MAX_BUS_POWER 100 +#endif +/* Set this variable to the maximum USB bus power consumption of your device. + * The value is in milliamperes. [It will be divided by two since USB + * communicates power requirements in units of 2 mA.] + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 0 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 0 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * usbFunctionSetup(). This saves a couple of bytes. + */ +#define USB_CFG_IMPLEMENT_FN_WRITEOUT 0 +/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * interrupt/bulk data sent to any endpoint other than 0. The endpoint number + * can be found in 'usbRxToken'. + */ +#define USB_CFG_HAVE_FLOWCONTROL 0 +/* Define this to 1 if you want flowcontrol over USB data. See the definition + * of the macros usbDisableAllRequests() and usbEnableAllRequests() in + * usbdrv.h. + */ +#define USB_CFG_DRIVER_FLASH_PAGE 0 +/* If the device has more than 64 kBytes of flash, define this to the 64 k page + * where the driver's constants (descriptors) are located. Or in other words: + * Define this to 1 for boot loaders on the ATMega128. + */ +#define USB_CFG_LONG_TRANSFERS 0 +/* Define this to 1 if you want to send/receive blocks of more than 254 bytes + * in a single control-in or control-out transfer. Note that the capability + * for long transfers increases the driver size. + */ +/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */ + +// Check CRC of all received data +/* +#define USB_RX_USER_HOOK( data, len ) { \ +if ( usbCrc16( data, len + 2 ) != 0x4FFE )\ +return;\ +} +*/ +/* This macro is a hook if you want to do unconventional things. If it is + * defined, it's inserted at the beginning of received message processing. + * If you eat the received message and don't want default processing to + * proceed, do a return after doing your things. One possible application + * (besides debugging) is to flash a status LED on each packet. + */ +/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */ +/* This macro is a hook if you need to know when an USB RESET occurs. It has + * one parameter which distinguishes between the start of RESET state and its + * end. + */ +/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */ +/* This macro (if defined) is executed when a USB SET_ADDRESS request was + * received. + */ +#define USB_COUNT_SOF 0 +/* define this macro to 1 if you need the global variable "usbSofCount" which + * counts SOF packets. This feature requires that the hardware interrupt is + * connected to D- instead of D+. + */ +/* #ifdef __ASSEMBLER__ + * macro myAssemblerMacro + * in YL, TCNT0 + * sts timer0Snapshot, YL + * endm + * #endif + * #define USB_SOF_HOOK myAssemblerMacro + * This macro (if defined) is executed in the assembler module when a + * Start Of Frame condition is detected. It is recommended to define it to + * the name of an assembler macro which is defined here as well so that more + * than one assembler instruction can be used. The macro may use the register + * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages + * immediately after an SOF pulse may be lost and must be retried by the host. + * What can you do with this hook? Since the SOF signal occurs exactly every + * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in + * designs running on the internal RC oscillator. + * Please note that Start Of Frame detection works only if D- is wired to the + * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! + */ +#define USB_CFG_CHECK_DATA_TOGGLING 0 +/* define this macro to 1 if you want to filter out duplicate data packets + * sent by the host. Duplicates occur only as a consequence of communication + * errors, when the host does not receive an ACK. Please note that you need to + * implement the filtering yourself in usbFunctionWriteOut() and + * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable + * for each control- and out-endpoint to check for duplicate packets. + */ + + +#ifndef __ASSEMBLER__ + void calibrateOscillatorASM(void); +/* + #if AUTO_EXIT_NO_USB_MS>0 + extern uint16_union_t idlePolls; + #define USB_RESET_HOOK(resetStarts) if(!resetStarts){ idlePolls.b[1]=0; calibrateOscillatorASM();} + #else + #define USB_RESET_HOOK(resetStarts) if(!resetStarts){ calibrateOscillatorASM();} + #endif +*/ + #define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0 +#endif + + +/* define this macro to 1 if you want the function usbMeasureFrameLength() + * compiled in. This function can be used to calibrate the AVR's RC oscillator. + */ + + +#if USB_CFG_CLOCK_KHZ<16000 + #define USB_USE_FAST_CRC 1 +#else + #define USB_USE_FAST_CRC 0 +#endif + +/* If the CPU clock is below 16Mhz you have to use the faster CRC routines. + * otherwise time outs may occur on USB3.0 ports. This adds 20 bytes. + */ + +/* The assembler module has two implementations for the CRC algorithm. One is + * faster, the other is smaller. This CRC routine is only used for transmitted + * messages where timing is not critical. The faster routine needs 31 cycles + * per byte while the smaller one needs 61 to 69 cycles. The faster routine + * may be worth the 32 bytes bigger code size if you transmit lots of data and + * run the AVR close to its limit. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0x4F, 0x1B /* = 0x1B4F VID for SparkFun */ +#define USB_CFG_DEVICE_ID 0x14, 0x00 /* = 0x0014 PID for ATtiny bootloader */ +/* SparkFun VID and PID for ATtiny84a Roshamglo project*/ + +//#define USB_CFG_VENDOR_ID 0xD0, 0x16 /* = 0x16d0 */ +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you may use one of obdev's free + * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + */ +//#define USB_CFG_DEVICE_ID 0x53, 0x07 /* = 0x0753 = Digistump */ +/* This is the ID of the product, low byte first. It is interpreted in the + * scope of the vendor ID. If you have registered your own VID with usb.org + * or if you have licensed a PID from somebody else, define it here. Otherwise + * you may use one of obdev's free shared VID/PID pairs. See the file + * USB-IDs-for-free.txt for details! + */ +#define USB_CFG_DEVICE_VERSION MICRONUCLEUS_VERSION_MINOR, MICRONUCLEUS_VERSION_MAJOR +/* Version number of the device: Minor number first, then major number. + */ + // electric arrow - not compliant with obdev's rules but we'll have our own vid-pid soon +//#define USB_CFG_VENDOR_NAME 0x2301 +//#define USB_CFG_VENDOR_NAME_LEN 1 +//#define USB_CFG_VENDOR_NAME 'd','i','g','i','s','t','u','m','p','.','c','o','m' +//#define USB_CFG_VENDOR_NAME_LEN 13 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for + * details. + */ +//#define USB_CFG_DEVICE_NAME 0x00B5,'B' +//#define USB_CFG_DEVICE_NAME_LEN 2 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USB-IDs-for-free.txt before you assign a name if + * you use a shared VID/PID. + */ +/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ +/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * to fine tune control over USB descriptors such as the string descriptor + * for the serial number. + */ +#define USB_CFG_DEVICE_CLASS 0xff /* set to 0 if deferred to interface */ +#define USB_CFG_DEVICE_SUBCLASS 0 +//#define USB_CFG_DEVICE_CLASS 0xFE /* application specific */ +//#define USB_CFG_DEVICE_SUBCLASS 0x01 /* device firmware upgrade */ +/* See USB specification if you want to conform to an existing device class. + * Class 0xff is "vendor specific". + */ +#define USB_CFG_INTERFACE_CLASS 0 /* define class here if not at device level */ +#define USB_CFG_INTERFACE_SUBCLASS 0 +#define USB_CFG_INTERFACE_PROTOCOL 0 +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +/* #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 */ +/* Define this to the length of the HID report descriptor, if you implement + * an HID device. Otherwise don't define it or define it to 0. + * If you use this define, you must add a PROGMEM character array named + * "usbHidReportDescriptor" to your code which contains the report descriptor. + * Don't forget to keep the array and this define in sync! + */ + +#define USB_PUBLIC static +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * no properties are defined or if they are 0, the default descriptor is used. + * Possible properties are: + * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched + * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is + * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if + * you want RAM pointers. + * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found + * in static memory is in RAM, not in flash memory. + * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * USB_CFG_DESCR_PROPS_HID_REPORT + * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) + * + * Note about string descriptors: String descriptors are not just strings, they + * are Unicode strings prefixed with a 2 byte header. Example: + * int serialNumberDescriptor[] = { + * USB_STRING_DESCRIPTOR_HEADER(6), + * 'S', 'e', 'r', 'i', 'a', 'l' + * }; + */ + +#define USB_CFG_DESCR_PROPS_DEVICE 0 +#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + +#endif /* __usbconfig_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/Changelog.txt b/sparkfun/tiny/bootloaders/attiny/usbdrv/Changelog.txt new file mode 100644 index 00000000..79b52155 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/Changelog.txt @@ -0,0 +1,329 @@ +This file documents changes in the firmware-only USB driver for atmel's AVR +microcontrollers. New entries are always appended to the end of the file. +Scroll down to the bottom to see the most recent changes. + +2005-04-01: + - Implemented endpoint 1 as interrupt-in endpoint. + - Moved all configuration options to usbconfig.h which is not part of the + driver. + - Changed interface for usbVendorSetup(). + - Fixed compatibility with ATMega8 device. + - Various minor optimizations. + +2005-04-11: + - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead() + and usbFunctionWrite() now. Added configuration options to choose which + of these functions to compile in. + - Assembler module delivers receive data non-inverted now. + - Made register and bit names compatible with more AVR devices. + +2005-05-03: + - Allow address of usbRxBuf on any memory page as long as the buffer does + not cross 256 byte page boundaries. + - Better device compatibility: works with Mega88 now. + - Code optimization in debugging module. + - Documentation updates. + +2006-01-02: + - Added (free) default Vendor- and Product-IDs bought from voti.nl. + - Added USBID-License.txt file which defines the rules for using the free + shared VID/PID pair. + - Added Readme.txt to the usbdrv directory which clarifies administrative + issues. + +2006-01-25: + - Added "configured state" to become more standards compliant. + - Added "HALT" state for interrupt endpoint. + - Driver passes the "USB Command Verifier" test from usb.org now. + - Made "serial number" a configuration option. + - Minor optimizations, we now recommend compiler option "-Os" for best + results. + - Added a version number to usbdrv.h + +2006-02-03: + - New configuration variable USB_BUFFER_SECTION for the memory section where + the USB rx buffer will go. This defaults to ".bss" if not defined. Since + this buffer MUST NOT cross 256 byte pages (not even touch a page at the + end), the user may want to pass a linker option similar to + "-Wl,--section-start=.mybuffer=0x800060". + - Provide structure for usbRequest_t. + - New defines for USB constants. + - Prepared for HID implementations. + - Increased data size limit for interrupt transfers to 8 bytes. + - New macro usbInterruptIsReady() to query interrupt buffer state. + +2006-02-18: + - Ensure that the data token which is sent as an ack to an OUT transfer is + always zero sized. This fixes a bug where the host reports an error after + sending an out transfer to the device, although all data arrived at the + device. + - Updated docs in usbdrv.h to reflect changed API in usbFunctionWrite(). + +* Release 2006-02-20 + + - Give a compiler warning when compiling with debugging turned on. + - Added Oleg Semyonov's changes for IAR-cc compatibility. + - Added new (optional) functions usbDeviceConnect() and usbDeviceDisconnect() + (also thanks to Oleg!). + - Rearranged tests in usbPoll() to save a couple of instructions in the most + likely case that no actions are pending. + - We need a delay between the SET ADDRESS request until the new address + becomes active. This delay was handled in usbPoll() until now. Since the + spec says that the delay must not exceed 2ms, previous versions required + aggressive polling during the enumeration phase. We have now moved the + handling of the delay into the interrupt routine. + - We must not reply with NAK to a SETUP transaction. We can only achieve this + by making sure that the rx buffer is empty when SETUP tokens are expected. + We therefore don't pass zero sized data packets from the status phase of + a transfer to usbPoll(). This change MAY cause troubles if you rely on + receiving a less than 8 bytes long packet in usbFunctionWrite() to + identify the end of a transfer. usbFunctionWrite() will NEVER be called + with a zero length. + +* Release 2006-03-14 + + - Improved IAR C support: tiny memory model, more devices + - Added template usbconfig.h file under the name usbconfig-prototype.h + +* Release 2006-03-26 + + - Added provision for one more interrupt-in endpoint (endpoint 3). + - Added provision for one interrupt-out endpoint (endpoint 1). + - Added flowcontrol macros for USB. + - Added provision for custom configuration descriptor. + - Allow ANY two port bits for D+ and D-. + - Merged (optional) receive endpoint number into global usbRxToken variable. + - Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the + variable name from the single port letter instead of computing the address + of related ports from the output-port address. + +* Release 2006-06-26 + + - Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the + new features. + - Removed "#warning" directives because IAR does not understand them. Use + unused static variables instead to generate a warning. + - Do not include when compiling with IAR. + - Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each + USB descriptor should be handled. It is now possible to provide descriptor + data in Flash, RAM or dynamically at runtime. + - STALL is now a status in usbTxLen* instead of a message. We can now conform + to the spec and leave the stall status pending until it is cleared. + - Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the + application code to reset data toggling on interrupt pipes. + +* Release 2006-07-18 + + - Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes + an assembler error. + - usbDeviceDisconnect() takes pull-up resistor to high impedance now. + +* Release 2007-02-01 + + - Merged in some code size improvements from usbtiny (thanks to Dick + Streefland for these optimizations!) + - Special alignment requirement for usbRxBuf not required any more. Thanks + again to Dick Streefland for this hint! + - Reverted to "#warning" instead of unused static variables -- new versions + of IAR CC should handle this directive. + - Changed Open Source license to GNU GPL v2 in order to make linking against + other free libraries easier. We no longer require publication of the + circuit diagrams, but we STRONGLY encourage it. If you improve the driver + itself, PLEASE grant us a royalty free license to your changes for our + commercial license. + +* Release 2007-03-29 + + - New configuration option "USB_PUBLIC" in usbconfig.h. + - Set USB version number to 1.10 instead of 1.01. + - Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and + USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences + to USB_CFG_DESCR_PROPS_STRING_PRODUCT. + - New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver + code. + - New assembler module for 16 MHz crystal. + - usbdrvasm.S contains common code only, clock-specific parts have been moved + to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively. + +* Release 2007-06-25 + + - 16 MHz module: Do SE0 check in stuffed bits as well. + +* Release 2007-07-07 + + - Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary + for negative values. + - Added 15 MHz module contributed by V. Bosch. + - Interrupt vector name can now be configured. This is useful if somebody + wants to use a different hardware interrupt than INT0. + +* Release 2007-08-07 + + - Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is + not exceeded. + - More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN, + USB_COUNT_SOF + - USB_INTR_PENDING can now be a memory address, not just I/O + +* Release 2007-09-19 + + - Split out common parts of assembler modules into separate include file + - Made endpoint numbers configurable so that given interface definitions + can be matched. See USB_CFG_EP3_NUMBER in usbconfig-prototype.h. + - Store endpoint number for interrupt/bulk-out so that usbFunctionWriteOut() + can handle any number of endpoints. + - Define usbDeviceConnect() and usbDeviceDisconnect() even if no + USB_CFG_PULLUP_IOPORTNAME is defined. Directly set D+ and D- to 0 in this + case. + +* Release 2007-12-01 + + - Optimize usbDeviceConnect() and usbDeviceDisconnect() for less code size + when USB_CFG_PULLUP_IOPORTNAME is not defined. + +* Release 2007-12-13 + + - Renamed all include-only assembler modules from *.S to *.inc so that + people don't add them to their project sources. + - Distribute leap bits in tx loop more evenly for 16 MHz module. + - Use "macro" and "endm" instead of ".macro" and ".endm" for IAR + - Avoid compiler warnings for constant expr range by casting some values in + USB descriptors. + +* Release 2008-01-21 + + - Fixed bug in 15 and 16 MHz module where the new address set with + SET_ADDRESS was already accepted at the next NAK or ACK we send, not at + the next data packet we send. This caused problems when the host polled + too fast. Thanks to Alexander Neumann for his help and patience debugging + this issue! + +* Release 2008-02-05 + + - Fixed bug in 16.5 MHz module where a register was used in the interrupt + handler before it was pushed. This bug was introduced with version + 2007-09-19 when common parts were moved to a separate file. + - Optimized CRC routine (thanks to Reimar Doeffinger). + +* Release 2008-02-16 + + - Removed outdated IAR compatibility stuff (code sections). + - Added hook macros for USB_RESET_HOOK() and USB_SET_ADDRESS_HOOK(). + - Added optional routine usbMeasureFrameLength() for calibration of the + internal RC oscillator. + +* Release 2008-02-28 + + - USB_INITIAL_DATATOKEN defaults to USBPID_DATA1 now, which means that we + start with sending USBPID_DATA0. + - Changed defaults in usbconfig-prototype.h + - Added free USB VID/PID pair for MIDI class devices + - Restructured AVR-USB as separate package, not part of PowerSwitch any more. + +* Release 2008-04-18 + + - Restructured usbdrv.c so that it is easier to read and understand. + - Better code optimization with gcc 4. + - If a second interrupt in endpoint is enabled, also add it to config + descriptor. + - Added config option for long transfers (above 254 bytes), see + USB_CFG_LONG_TRANSFERS in usbconfig.h. + - Added 20 MHz module contributed by Jeroen Benschop. + +* Release 2008-05-13 + + - Fixed bug in libs-host/hiddata.c function usbhidGetReport(): length + was not incremented, pointer to length was incremented instead. + - Added code to command line tool(s) which claims an interface. This code + is disabled by default, but may be necessary on newer Linux kernels. + - Added usbconfig.h option "USB_CFG_CHECK_DATA_TOGGLING". + - New header "usbportability.h" prepares ports to other development + environments. + - Long transfers (above 254 bytes) did not work when usbFunctionRead() was + used to supply the data. Fixed this bug. [Thanks to Alexander Neumann!] + - In hiddata.c (example code for sending/receiving data over HID), use + USB_RECIP_DEVICE instead of USB_RECIP_INTERFACE for control transfers so + that we need not claim the interface. + - in usbPoll() loop 20 times polling for RESET state instead of 10 times. + This accounts for the higher clock rates we now support. + - Added a module for 12.8 MHz RC oscillator with PLL in receiver loop. + - Added hook to SOF code so that oscillator can be tuned to USB frame clock. + - Added timeout to waitForJ loop. Helps preventing unexpected hangs. + - Added example code for oscillator tuning to libs-device (thanks to + Henrik Haftmann for the idea to this routine). + - Implemented option USB_CFG_SUPPRESS_INTR_CODE. + +* Release 2008-10-22 + + - Fixed libs-device/osctune.h: OSCCAL is memory address on ATMega88 and + similar, not offset of 0x20 needs to be added. + - Allow distribution under GPLv3 for those who have to link against other + code distributed under GPLv3. + +* Release 2008-11-26 + + - Removed libusb-win32 dependency for hid-data example in Makefile.windows. + It was never required and confused many people. + - Added extern uchar usbRxToken to usbdrv.h. + - Integrated a module with CRC checks at 18 MHz by Lukas Schrittwieser. + +* Release 2009-03-23 + + - Hid-mouse example used settings from hid-data example, fixed that. + - Renamed project to V-USB due to a trademark issue with Atmel(r). + - Changed CommercialLicense.txt and USBID-License.txt to make the + background of USB ID registration clearer. + +* Release 2009-04-15 + + - Changed CommercialLicense.txt to reflect the new range of PIDs from + Jason Kotzin. + - Removed USBID-License.txt in favor of USB-IDs-for-free.txt and + USB-ID-FAQ.txt + - Fixed a bug in the 12.8 MHz module: End Of Packet decection was made in + the center between bit 0 and 1 of each byte. This is where the data lines + are expected to change and the sampled data may therefore be nonsense. + We therefore check EOP ONLY if bits 0 AND 1 have both been read as 0 on D-. + - Fixed a bitstuffing problem in the 16 MHz module: If bit 6 was stuffed, + the unstuffing code in the receiver routine was 1 cycle too long. If + multiple bytes had the unstuffing in bit 6, the error summed up until the + receiver was out of sync. + - Included option for faster CRC routine. + Thanks to Slawomir Fras (BoskiDialer) for this code! + - Updated bits in Configuration Descriptor's bmAttributes according to + USB 1.1 (in particular bit 7, it is a must-be-set bit now). + +* Release 2009-08-22 + + - Moved first DBG1() after odDebugInit() in all examples. + - Use vector INT0_vect instead of SIG_INTERRUPT0 if defined. This makes + V-USB compatible with the new "p" suffix devices (e.g. ATMega328p). + - USB_CFG_CLOCK_KHZ setting is now required in usbconfig.h (no default any + more). + - New option USB_CFG_DRIVER_FLASH_PAGE allows boot loaders on devices with + more than 64 kB flash. + - Built-in configuration descriptor allows custom definition for second + endpoint now. + +* Release 2010-07-15 + + - Fixed bug in usbDriverSetup() which prevented descriptor sizes above 255 + bytes. + - Avoid a compiler warning for unused parameter in usbHandleResetHook() when + compiler option -Wextra is enabled. + - Fixed wrong hex value for some IDs in USB-IDs-for-free.txt. + - Keep a define for USBATTR_BUSPOWER, although the flag does not exist + in USB 1.1 any more. Set it to 0. This is for backward compatibility. + +* Release 2012-01-09 + + - Define a separate (defined) type for usbMsgPtr so that projects using a + tiny memory model can define it to an 8 bit type in usbconfig.h. This + change also saves a couple of bytes when using a scalar 16 bit type. + - Inserted "const" keyword for all PROGMEM declarations because new GCC + requires it. + - Fixed problem with dependence of usbportability.h on usbconfig.h. This + problem occurred with IAR CC only. + - Prepared repository for github.com. + +* Release 2012-12-06 \ No newline at end of file diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/CommercialLicense.txt b/sparkfun/tiny/bootloaders/attiny/usbdrv/CommercialLicense.txt new file mode 100644 index 00000000..de1a2b09 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/CommercialLicense.txt @@ -0,0 +1,166 @@ +V-USB Driver Software License Agreement +Version 2012-07-09 + +THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN +ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING +THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT. + + +1 DEFINITIONS + +1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH, +Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA. + +1.2 "You" shall mean the Licensee. + +1.3 "V-USB" shall mean all files included in the package distributed under +the name "vusb" by OBJECTIVE DEVELOPMENT (http://www.obdev.at/vusb/) +unless otherwise noted. This includes the firmware-only USB device +implementation for Atmel AVR microcontrollers, some simple device examples +and host side software examples and libraries. + + +2 LICENSE GRANTS + +2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source +code of V-USB. + +2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the +non-exclusive right to use, copy and distribute V-USB with your hardware +product(s), restricted by the limitations in section 3 below. + +2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify +the source code and your copy of V-USB according to your needs. + +2.4 USB IDs. OBJECTIVE DEVELOPMENT furnishes you with one or two USB +Product ID(s), sent to you in e-mail. These Product IDs are reserved +exclusively for you. OBJECTIVE DEVELOPMENT has obtained USB Product ID +ranges under the Vendor ID 5824 from Wouter van Ooijen (Van Ooijen +Technische Informatica, www.voti.nl) and under the Vendor ID 8352 from +Jason Kotzin (now flirc.tv, Inc.). Both owners of the Vendor IDs have +obtained these IDs from the USB Implementers Forum, Inc. (www.usb.org). +OBJECTIVE DEVELOPMENT disclaims all liability which might arise from the +assignment of USB IDs. + +2.5 USB Certification. Although not part of this agreement, we want to make +it clear that you cannot become USB certified when you use V-USB or a USB +Product ID assigned by OBJECTIVE DEVELOPMENT. AVR microcontrollers don't +meet the electrical specifications required by the USB specification and +the USB Implementers Forum certifies only members who bought a Vendor ID of +their own. + + +3 LICENSE RESTRICTIONS + +3.1 Number of Units. Only one of the following three definitions is +applicable. Which one is determined by the amount you pay to OBJECTIVE +DEVELOPMENT, see section 4 ("Payment") below. + +Hobby License: You may use V-USB according to section 2 above in no more +than 5 hardware units. These units must not be sold for profit. + +Entry Level License: You may use V-USB according to section 2 above in no +more than 150 hardware units. + +Professional License: You may use V-USB according to section 2 above in +any number of hardware units, except for large scale production ("unlimited +fair use"). Quantities below 10,000 units are not considered large scale +production. If your reach quantities which are obviously large scale +production, you must pay a license fee of 0.10 EUR per unit for all units +above 10,000. + +3.2 Rental. You may not rent, lease, or lend V-USB or otherwise encumber +any copy of V-USB, or any of the rights granted herein. + +3.3 Transfer. You may not transfer your rights under this Agreement to +another party without OBJECTIVE DEVELOPMENT's prior written consent. If +such consent is obtained, you may permanently transfer this License to +another party. The recipient of such transfer must agree to all terms and +conditions of this Agreement. + +3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not +expressly granted. + +3.5 Non-Exclusive Rights. Your license rights under this Agreement are +non-exclusive. + +3.6 Third Party Rights. This Agreement cannot grant you rights controlled +by third parties. In particular, you are not allowed to use the USB logo or +other trademarks owned by the USB Implementers Forum, Inc. without their +consent. Since such consent depends on USB certification, it should be +noted that V-USB will not pass certification because it does not +implement checksum verification and the microcontroller ports do not meet +the electrical specifications. + + +4 PAYMENT + +The payment amount depends on the variation of this agreement (according to +section 3.1) into which you want to enter. Concrete prices are listed on +OBJECTIVE DEVELOPMENT's web site, usually at +http://www.obdev.at/vusb/license.html. You agree to pay the amount listed +there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor +or reseller. + + +5 COPYRIGHT AND OWNERSHIP + +V-USB is protected by copyright laws and international copyright +treaties, as well as other intellectual property laws and treaties. V-USB +is licensed, not sold. + + +6 TERM AND TERMINATION + +6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE +DEVELOPMENT may terminate this Agreement and revoke the granted license and +USB-IDs if you fail to comply with any of its terms and conditions. + +6.2 Survival of Terms. All provisions regarding secrecy, confidentiality +and limitation of liability shall survive termination of this agreement. + + +7 DISCLAIMER OF WARRANTY AND LIABILITY + +LIMITED WARRANTY. V-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE +DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND +NON-INFRINGEMENT, WITH REGARD TO V-USB, AND THE PROVISION OF OR FAILURE +TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL +RIGHTS. YOU MAY HAVE OTHERS, WHICH VARY FROM STATE/JURISDICTION TO +STATE/JURISDICTION. + +LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, +IN NO EVENT SHALL OBJECTIVE DEVELOPMENT OR ITS SUPPLIERS BE LIABLE FOR ANY +SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER +(INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY +LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE V-USB OR THE +PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE +DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY +CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS +AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR V-USB. + + +8 MISCELLANEOUS TERMS + +8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing +purposes that you entered into this agreement. + +8.2 Entire Agreement. This document represents the entire agreement between +OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by +an authorized representative of both, OBJECTIVE DEVELOPMENT and you. + +8.3 Severability. In case a provision of these terms and conditions should +be or become partly or entirely invalid, ineffective, or not executable, +the validity of all other provisions shall not be affected. + +8.4 Applicable Law. This agreement is governed by the laws of the Republic +of Austria. + +8.5 Responsible Courts. The responsible courts in Vienna/Austria will have +exclusive jurisdiction regarding all disputes in connection with this +agreement. + diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/License.txt b/sparkfun/tiny/bootloaders/attiny/usbdrv/License.txt new file mode 100644 index 00000000..4460cfba --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/License.txt @@ -0,0 +1,361 @@ +OBJECTIVE DEVELOPMENT GmbH's V-USB driver software is distributed under the +terms and conditions of the GNU GPL version 2 or the GNU GPL version 3. It is +your choice whether you apply the terms of version 2 or version 3. The full +text of GPLv2 is included below. In addition to the requirements in the GPL, +we STRONGLY ENCOURAGE you to do the following: + +(1) Publish your entire project on a web site and drop us a note with the URL. +Use the form at http://www.obdev.at/vusb/feedback.html for your submission. + +(2) Adhere to minimum publication standards. Please include AT LEAST: + - a circuit diagram in PDF, PNG or GIF format + - full source code for the host software + - a Readme.txt file in ASCII format which describes the purpose of the + project and what can be found in which directories and which files + - a reference to http://www.obdev.at/vusb/ + +(3) If you improve the driver firmware itself, please give us a free license +to your modifications for our commercial license offerings. + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/Readme.txt b/sparkfun/tiny/bootloaders/attiny/usbdrv/Readme.txt new file mode 100644 index 00000000..970dc66b --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/Readme.txt @@ -0,0 +1,172 @@ +This is the Readme file to Objective Development's firmware-only USB driver +for Atmel AVR microcontrollers. For more information please visit +http://www.obdev.at/vusb/ + +This directory contains the USB firmware only. Copy it as-is to your own +project and add all .c and .S files to your project (these files are marked +with an asterisk in the list below). Then copy usbconfig-prototype.h as +usbconfig.h to your project and edit it according to your configuration. + + +TECHNICAL DOCUMENTATION +======================= +The technical documentation (API) for the firmware driver is contained in the +file "usbdrv.h". Please read all of it carefully! Configuration options are +documented in "usbconfig-prototype.h". + +The driver consists of the following files: + Readme.txt ............. The file you are currently reading. + Changelog.txt .......... Release notes for all versions of the driver. + usbdrv.h ............... Driver interface definitions and technical docs. +* usbdrv.c ............... High level language part of the driver. Link this + module to your code! +* usbdrvasm.S ............ Assembler part of the driver. This module is mostly + a stub and includes one of the usbdrvasm*.S files + depending on processor clock. Link this module to + your code! + usbdrvasm*.inc ......... Assembler routines for particular clock frequencies. + Included by usbdrvasm.S, don't link it directly! + asmcommon.inc .......... Common assembler routines. Included by + usbdrvasm*.inc, don't link it directly! + usbconfig-prototype.h .. Prototype for your own usbdrv.h file. +* oddebug.c .............. Debug functions. Only used when DEBUG_LEVEL is + defined to a value greater than 0. Link this module + to your code! + oddebug.h .............. Interface definitions of the debug module. + usbportability.h ....... Header with compiler-dependent stuff. + usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this + module instead of usbdrvasm.S when you assembler + with IAR's tools. + License.txt ............ Open Source license for this driver. + CommercialLicense.txt .. Optional commercial license for this driver. + USB-ID-FAQ.txt ......... General infos about USB Product- and Vendor-IDs. + USB-IDs-for-free.txt ... List and terms of use for free shared PIDs. + +(*) ... These files should be linked to your project. + + +CPU CORE CLOCK FREQUENCY +======================== +We supply assembler modules for clock frequencies of 12 MHz, 12.8 MHz, 15 MHz, +16 MHz, 16.5 MHz 18 MHz and 20 MHz. Other clock rates are not supported. The +actual clock rate must be configured in usbconfig.h. + +12 MHz Clock +This is the traditional clock rate of V-USB because it's the lowest clock +rate where the timing constraints of the USB spec can be met. + +15 MHz Clock +Similar to 12 MHz, but some NOPs inserted. On the other hand, the higher clock +rate allows for some loops which make the resulting code size somewhat smaller +than the 12 MHz version. + +16 MHz Clock +This clock rate has been added for users of the Arduino board and other +ready-made boards which come with a fixed 16 MHz crystal. It's also an option +if you need the slightly higher clock rate for performance reasons. Since +16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code +is somewhat tricky and has to insert a leap cycle every third byte. + +12.8 MHz and 16.5 MHz Clock +The assembler modules for these clock rates differ from the other modules +because they have been built for an RC oscillator with only 1% precision. The +receiver code inserts leap cycles to compensate for clock deviations. 1% is +also the precision which can be achieved by calibrating the internal RC +oscillator of the AVR. Please note that only AVRs with internal 64 MHz PLL +oscillator can reach 16.5 MHz with the RC oscillator. This includes the very +popular ATTiny25, ATTiny45, ATTiny85 series as well as the ATTiny26. Almost +all AVRs can reach 12.8 MHz, although this is outside the specified range. + +See the EasyLogger example at http://www.obdev.at/vusb/easylogger.html for +code which calibrates the RC oscillator based on the USB frame clock. + +18 MHz Clock +This module is closer to the USB specification because it performs an on the +fly CRC check for incoming packets. Packets with invalid checksum are +discarded as required by the spec. If you also implement checks for data +PID toggling on application level (see option USB_CFG_CHECK_DATA_TOGGLING +in usbconfig.h for more info), this ensures data integrity. Due to the CRC +tables and alignment requirements, this code is bigger than modules for other +clock rates. To activate this module, you must define USB_CFG_CHECK_CRC to 1 +and USB_CFG_CLOCK_KHZ to 18000 in usbconfig.h. + +20 MHz Clock +This module is for people who won't do it with less than the maximum. Since +20 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code +uses similar tricks as the 16 MHz module to insert leap cycles. + + +USB IDENTIFIERS +=============== +Every USB device needs a vendor- and a product-identifier (VID and PID). VIDs +are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you +can assign PIDs at will. + +Since an entry level cost of 1,500 USD is too high for most small companies +and hobbyists, we provide some VID/PID pairs for free. See the file +USB-IDs-for-free.txt for details. + +Objective Development also has some license offerings which include product +IDs. See http://www.obdev.at/vusb/ for details. + + +DEVELOPMENT SYSTEM +================== +This driver has been developed and optimized for the GNU compiler version 3 +and 4. We recommend that you use the GNU compiler suite because it is freely +available. V-USB has also been ported to the IAR compiler and assembler. It +has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the +"small" and "tiny" memory model. Not every release is tested with IAR CC and +the driver may therefore fail to compile with IAR. Please note that gcc is +more efficient for usbdrv.c because this module has been deliberately +optimized for gcc. + +Gcc version 3 produces smaller code than version 4 due to new optimizing +capabilities which don't always improve things on 8 bit CPUs. The code size +generated by gcc 4 can be reduced with the compiler options +-fno-move-loop-invariants, -fno-tree-scev-cprop and +-fno-inline-small-functions in addition to -Os. On devices with more than +8k of flash memory, we also recommend the linker option --relax (written as +-Wl,--relax for gcc) to convert absolute calls into relative where possible. + +For more information about optimizing options see: + + http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html + +These optimizations are good for gcc 4.x. Version 3.x of gcc does not support +most of these options and produces good code anyway. + + +USING V-USB FOR FREE +==================== +The AVR firmware driver is published under the GNU General Public License +Version 2 (GPL2) and the GNU General Public License Version 3 (GPL3). It is +your choice whether you apply the terms of version 2 or version 3. + +If you decide for the free GPL2 or GPL3, we STRONGLY ENCOURAGE you to do the +following things IN ADDITION to the obligations from the GPL: + +(1) Publish your entire project on a web site and drop us a note with the URL. +Use the form at http://www.obdev.at/vusb/feedback.html for your submission. +If you don't have a web site, you can publish the project in obdev's +documentation wiki at +http://www.obdev.at/goto.php?t=vusb-wiki&p=hosted-projects. + +(2) Adhere to minimum publication standards. Please include AT LEAST: + - a circuit diagram in PDF, PNG or GIF format + - full source code for the host software + - a Readme.txt file in ASCII format which describes the purpose of the + project and what can be found in which directories and which files + - a reference to http://www.obdev.at/vusb/ + +(3) If you improve the driver firmware itself, please give us a free license +to your modifications for our commercial license offerings. + + +COMMERCIAL LICENSES FOR V-USB +============================= +If you don't want to publish your source code under the terms of the GPL, +you can simply pay money for V-USB. As an additional benefit you get +USB PIDs for free, reserved exclusively to you. See the file +"CommercialLicense.txt" for details. + diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/USB-ID-FAQ.txt b/sparkfun/tiny/bootloaders/attiny/usbdrv/USB-ID-FAQ.txt new file mode 100644 index 00000000..a4a6bd6e --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/USB-ID-FAQ.txt @@ -0,0 +1,149 @@ +Version 2012-07-09 + +========================== +WHY DO WE NEED THESE IDs? +========================== + +USB is more than a low level protocol for data transport. It also defines a +common set of requests which must be understood by all devices. And as part +of these common requests, the specification defines data structures, the +USB Descriptors, which are used to describe the properties of the device. + +From the perspective of an operating system, it is therefore possible to find +out basic properties of a device (such as e.g. the manufacturer and the name +of the device) without a device-specific driver. This is essential because +the operating system can choose a driver to load based on this information +(Plug-And-Play). + +Among the most important properties in the Device Descriptor are the USB +Vendor- and Product-ID. Both are 16 bit integers. The most simple form of +driver matching is based on these IDs. The driver announces the Vendor- and +Product-IDs of the devices it can handle and the operating system loads the +appropriate driver when the device is connected. + +It is obvious that this technique only works if the pair Vendor- plus +Product-ID is unique: Only devices which require the same driver can have the +same pair of IDs. + + +===================================================== +HOW DOES THE USB STANDARD ENSURE THAT IDs ARE UNIQUE? +===================================================== + +Since it is so important that USB IDs are unique, the USB Implementers Forum, +Inc. (usb.org) needs a way to enforce this legally. It is not forbidden by +law to build a device and assign it any random numbers as IDs. Usb.org +therefore needs an agreement to regulate the use of USB IDs. The agreement +binds only parties who agreed to it, of course. Everybody else is free to use +any numbers for their IDs. + +So how can usb.org ensure that every manufacturer of USB devices enters into +an agreement with them? They do it via trademark licensing. Usb.org has +registered the trademark "USB", all associated logos and related terms. If +you want to put an USB logo on your product or claim that it is USB +compliant, you must license these trademarks from usb.org. And this is where +you enter into an agreement. See the "USB-IF Trademark License Agreement and +Usage Guidelines for the USB-IF Logo" at +http://www.usb.org/developers/logo_license/. + +Licensing the USB trademarks requires that you buy a USB Vendor-ID from +usb.org (one-time fee of ca. 2,000 USD), that you become a member of usb.org +(yearly fee of ca. 4,000 USD) and that you meet all the technical +specifications from the USB spec. + +This means that most hobbyists and small companies will never be able to +become USB compliant, just because membership is so expensive. And you can't +be compliant with a driver based on V-USB anyway, because the AVR's port pins +don't meet the electrical specifications for USB. So, in principle, all +hobbyists and small companies are free to choose any random numbers for their +IDs. They have nothing to lose... + +There is one exception worth noting, though: If you use a sub-component which +implements USB, the vendor of the sub-components may guarantee USB +compliance. This might apply to some or all of FTDI's solutions. + + +======================================================================= +WHY SHOULD YOU OBTAIN USB IDs EVEN IF YOU DON'T LICENSE USB TRADEMARKS? +======================================================================= + +You have learned in the previous section that you are free to choose any +numbers for your IDs anyway. So why not do exactly this? There is still the +technical issue. If you choose IDs which are already in use by somebody else, +operating systems will load the wrong drivers and your device won't work. +Even if you choose IDs which are not currently in use, they may be in use in +the next version of the operating system or even after an automatic update. + +So what you need is a pair of Vendor- and Product-IDs for which you have the +guarantee that no USB compliant product uses them. This implies that no +operating system will ever ship with drivers responsible for these IDs. + + +============================================== +HOW DOES OBJECTIVE DEVELOPMENT HANDLE USB IDs? +============================================== + +Objective Development gives away pairs of USB-IDs with their V-USB licenses. +In order to ensure that these IDs are unique, Objective Development has an +agreement with the company/person who has bought the USB Vendor-ID from +usb.org. This agreement ensures that a range of USB Product-IDs is reserved +for assignment by Objective Development and that the owner of the Vendor-ID +won't give it to anybody else. + +This means that you have to trust three parties to ensure uniqueness of +your IDs: + + - Objective Development, that they don't give the same PID to more than + one person. + - The owner of the Vendor-ID that they don't assign PIDs from the range + assigned to Objective Development to anybody else. + - Usb.org that they don't assign the same Vendor-ID a second time. + + +================================== +WHO IS THE OWNER OF THE VENDOR-ID? +================================== + +Objective Development has obtained ranges of USB Product-IDs under two +Vendor-IDs: Under Vendor-ID 5824 from Wouter van Ooijen (Van Ooijen +Technische Informatica, www.voti.nl) and under Vendor-ID 8352 from Jason +Kotzin (now flirc.tv, Inc.). Both VID owners have received their Vendor-ID +directly from usb.org. + + +========================================================================= +CAN I USE USB-IDs FROM OBJECTIVE DEVELOPMENT WITH OTHER DRIVERS/HARDWARE? +========================================================================= + +The short answer is: Yes. All you get is a guarantee that the IDs are never +assigned to anybody else. What more do you need? + + +============================ +WHAT ABOUT SHARED ID PAIRS? +============================ + +Objective Development has reserved some PID/VID pairs for shared use. You +have no guarantee of uniqueness for them, except that no USB compliant device +uses them. In order to avoid technical problems, we must ensure that all +devices with the same pair of IDs use the same driver on kernel level. For +details, see the file USB-IDs-for-free.txt. + + +====================================================== +I HAVE HEARD THAT SUB-LICENSING OF USB-IDs IS ILLEGAL? +====================================================== + +A 16 bit integer number cannot be protected by copyright laws. It is not +sufficiently complex. And since none of the parties involved entered into the +USB-IF Trademark License Agreement, we are not bound by this agreement. So +there is no reason why it should be illegal to sub-license USB-IDs. + + +============================================= +WHO IS LIABLE IF THERE ARE INCOMPATIBILITIES? +============================================= + +Objective Development disclaims all liabilities which might arise from the +assignment of IDs. If you guarantee product features to your customers +without proper disclaimer, YOU are liable for that. diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/USB-IDs-for-free.txt b/sparkfun/tiny/bootloaders/attiny/usbdrv/USB-IDs-for-free.txt new file mode 100644 index 00000000..d46517d8 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/USB-IDs-for-free.txt @@ -0,0 +1,154 @@ +Version 2009-08-22 + +=========================== +FREE USB-IDs FOR SHARED USE +=========================== + +Objective Development has reserved a set of USB Product-IDs for use according +to the guidelines outlined below. For more information about the concept of +USB IDs please see the file USB-ID-FAQ.txt. Objective Development guarantees +that the IDs listed below are not used by any USB compliant devices. + + +==================== +MECHANISM OF SHARING +==================== + +From a technical point of view, two different devices can share the same USB +Vendor- and Product-ID if they require the same driver on operating system +level. We make use of this fact by assigning separate IDs for various device +classes. On application layer, devices must be distinguished by their textual +name or serial number. We offer separate sets of IDs for discrimination by +textual name and for serial number. + +Examples for shared use of USB IDs are included with V-USB in the "examples" +subdirectory. + + +====================================== +IDs FOR DISCRIMINATION BY TEXTUAL NAME +====================================== + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the manufacturer +and product identification. The manufacturer identification MUST be available +at least in USB language 0x0409 (English/US). + +(2) The textual manufacturer identification MUST contain either an Internet +domain name (e.g. "mycompany.com") registered and owned by you, or an e-mail +address under your control (e.g. "myname@gmx.net"). You can embed the domain +name or e-mail address in any string you like, e.g. "Objective Development +http://www.obdev.at/vusb/". + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(4) You may choose any string for the textual product identification, as long +as this string is unique within the scope of your textual manufacturer +identification. + +(5) Application side device look-up MUST be based on the textual manufacturer +and product identification in addition to VID/PID matching. The driver +matching MUST be a comparison of the entire strings, NOT a sub-string match. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +Table if IDs for discrimination by textual name: + +PID dec (hex) | VID dec (hex) | Description of use +==============+===============+============================================ +1500 (0x05dc) | 5824 (0x16c0) | For Vendor Class devices with libusb +--------------+---------------+-------------------------------------------- +1503 (0x05df) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +--------------+---------------+-------------------------------------------- +1505 (0x05e1) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +--------------+---------------+-------------------------------------------- +1508 (0x05e4) | 5824 (0x16c0) | For MIDI class devices +--------------+---------------+-------------------------------------------- + +Note that Windows caches the textual product- and vendor-description for +mice, keyboards and joysticks. Name-bsed discrimination is therefore not +recommended for these device classes. + + +======================================= +IDs FOR DISCRIMINATION BY SERIAL NUMBER +======================================= + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the serial +number, unless ONLY the operating system's default class driver is used. +The serial number string MUST be available at least in USB language 0x0409 +(English/US). + +(2) The serial number MUST start with either an Internet domain name (e.g. +"mycompany.com") registered and owned by you, or an e-mail address under your +control (e.g. "myname@gmx.net"), both terminated with a colon (":") character. +You MAY append any string you like for further discrimination of your devices. + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(5) Application side device look-up MUST be based on the serial number string +in addition to VID/PID matching. The matching must start at the first +character of the serial number string and include the colon character +terminating your domain or e-mail address. It MAY stop anywhere after that. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +(7) If ONLY the operating system's default class driver is used, e.g. for +mice, keyboards, joysticks, CDC or MIDI devices and no discrimination by an +application is needed, the serial number may be omitted. + + +Table if IDs for discrimination by serial number string: + +PID dec (hex) | VID dec (hex) | Description of use +===============+===============+=========================================== +10200 (0x27d8) | 5824 (0x16c0) | For Vendor Class devices with libusb +---------------+---------------+------------------------------------------- +10201 (0x27d9) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +---------------+---------------+------------------------------------------- +10202 (0x27da) | 5824 (0x16c0) | For USB Mice +---------------+---------------+------------------------------------------- +10203 (0x27db) | 5824 (0x16c0) | For USB Keyboards +---------------+---------------+------------------------------------------- +10204 (0x27dc) | 5824 (0x16c0) | For USB Joysticks +---------------+---------------+------------------------------------------- +10205 (0x27dd) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +---------------+---------------+------------------------------------------- +10206 (0x27de) | 5824 (0x16c0) | For MIDI class devices +---------------+---------------+------------------------------------------- + + +================= +ORIGIN OF USB-IDs +================= + +OBJECTIVE DEVELOPMENT Software GmbH has obtained all VID/PID pairs listed +here from Wouter van Ooijen (see www.voti.nl) for exclusive disposition. +Wouter van Ooijen has obtained the VID from the USB Implementers Forum, Inc. +(see www.usb.org). The VID is registered for the company name "Van Ooijen +Technische Informatica". + + +========== +DISCLAIMER +========== + +OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any +problems which are caused by the shared use of these VID/PID pairs. diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/asmcommon.inc b/sparkfun/tiny/bootloaders/attiny/usbdrv/asmcommon.inc new file mode 100644 index 00000000..5f269afc --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/asmcommon.inc @@ -0,0 +1,208 @@ +/* Name: asmcommon.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2007-11-05 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * + * Modified to an interrupt-less driver for micronucleus V2. (c) 2014 T. Bo"scke + * + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file contains assembler code which is shared among the USB driver +implementations for different CPU cocks. Since the code must be inserted +in the middle of the module, it's split out into this file and #included. + +Jump destinations called from outside: + sofError: Called when no start sequence was found. + se0: Called when a package has been successfully received. + overflow: Called when receive buffer overflows. + doReturn: Called after sending data. + +Outside jump destinations used by this module: + waitForJ: Called to receive an already arriving packet. + sendAckAndReti: + sendNakAndReti: + sendCntAndReti: + usbSendAndReti: + +The following macros must be defined before this file is included: + .macro POP_STANDARD + .endm + .macro POP_RETI + .endm +*/ + +#define token x1 + +overflow: + ldi x2, 1< 0 + +#warning "Never compile production devices with debugging enabled" + +static void uartPutc(char c) +{ + while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ + ODDBG_UDR = c; +} + +static uchar hexAscii(uchar h) +{ + h &= 0xf; + if(h >= 10) + h += 'a' - (uchar)10 - '0'; + h += '0'; + return h; +} + +static void printHex(uchar c) +{ + uartPutc(hexAscii(c >> 4)); + uartPutc(hexAscii(c)); +} + +void odDebug(uchar prefix, uchar *data, uchar len) +{ + printHex(prefix); + uartPutc(':'); + while(len--){ + uartPutc(' '); + printHex(*data++); + } + uartPutc('\r'); + uartPutc('\n'); +} + +#endif diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/oddebug.c.lst b/sparkfun/tiny/bootloaders/attiny/usbdrv/oddebug.c.lst new file mode 100644 index 00000000..b14243dc --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/oddebug.c.lst @@ -0,0 +1,236 @@ +GAS LISTING C:\Users\Nick\AppData\Local\Temp/ccUechtz.s page 1 + + + 1 .file "oddebug.c" + 2 __SREG__ = 0x3f + 3 __SP_H__ = 0x3e + 4 __SP_L__ = 0x3d + 5 __CCP__ = 0x34 + 6 __tmp_reg__ = 0 + 7 __zero_reg__ = 1 + 8 .section .debug_abbrev,"",@progbits + 9 .Ldebug_abbrev0: + 10 .section .debug_info,"",@progbits + 11 .Ldebug_info0: + 12 .section .debug_line,"",@progbits + 13 .Ldebug_line0: + 14 .text + 15 .Ltext0: + 16 .Letext0: + 17 .section .debug_info + 18 0000 6000 0000 .long 0x60 + 19 0004 0200 .word 0x2 + 20 0006 0000 0000 .long .Ldebug_abbrev0 + 21 000a 04 .byte 0x4 + 22 000b 01 .uleb128 0x1 + 23 000c 0000 0000 .long .LASF7 + 24 0010 01 .byte 0x1 + 25 0011 0000 0000 .long .LASF8 + 26 0015 0000 0000 .long .LASF9 + 27 0019 0000 0000 .long .Ltext0 + 28 001d 0000 0000 .long .Letext0 + 29 0021 0000 0000 .long .Ldebug_line0 + 30 0025 02 .uleb128 0x2 + 31 0026 01 .byte 0x1 + 32 0027 06 .byte 0x6 + 33 0028 0000 0000 .long .LASF0 + 34 002c 02 .uleb128 0x2 + 35 002d 01 .byte 0x1 + 36 002e 08 .byte 0x8 + 37 002f 0000 0000 .long .LASF1 + 38 0033 03 .uleb128 0x3 + 39 0034 02 .byte 0x2 + 40 0035 05 .byte 0x5 + 41 0036 696E 7400 .string "int" + 42 003a 02 .uleb128 0x2 + 43 003b 02 .byte 0x2 + 44 003c 07 .byte 0x7 + 45 003d 0000 0000 .long .LASF2 + 46 0041 02 .uleb128 0x2 + 47 0042 04 .byte 0x4 + 48 0043 05 .byte 0x5 + 49 0044 0000 0000 .long .LASF3 + 50 0048 02 .uleb128 0x2 + 51 0049 04 .byte 0x4 + 52 004a 07 .byte 0x7 + 53 004b 0000 0000 .long .LASF4 + 54 004f 02 .uleb128 0x2 + 55 0050 08 .byte 0x8 + 56 0051 05 .byte 0x5 + 57 0052 0000 0000 .long .LASF5 + GAS LISTING C:\Users\Nick\AppData\Local\Temp/ccUechtz.s page 2 + + + 58 0056 02 .uleb128 0x2 + 59 0057 08 .byte 0x8 + 60 0058 07 .byte 0x7 + 61 0059 0000 0000 .long .LASF6 + 62 005d 04 .uleb128 0x4 + 63 005e 01 .byte 0x1 + 64 005f 06 .byte 0x6 + 65 0060 04 .uleb128 0x4 + 66 0061 01 .byte 0x1 + 67 0062 08 .byte 0x8 + 68 0063 00 .byte 0x0 + 69 .section .debug_abbrev + 70 0000 01 .uleb128 0x1 + 71 0001 11 .uleb128 0x11 + 72 0002 01 .byte 0x1 + 73 0003 25 .uleb128 0x25 + 74 0004 0E .uleb128 0xe + 75 0005 13 .uleb128 0x13 + 76 0006 0B .uleb128 0xb + 77 0007 03 .uleb128 0x3 + 78 0008 0E .uleb128 0xe + 79 0009 1B .uleb128 0x1b + 80 000a 0E .uleb128 0xe + 81 000b 11 .uleb128 0x11 + 82 000c 01 .uleb128 0x1 + 83 000d 12 .uleb128 0x12 + 84 000e 01 .uleb128 0x1 + 85 000f 10 .uleb128 0x10 + 86 0010 06 .uleb128 0x6 + 87 0011 00 .byte 0x0 + 88 0012 00 .byte 0x0 + 89 0013 02 .uleb128 0x2 + 90 0014 24 .uleb128 0x24 + 91 0015 00 .byte 0x0 + 92 0016 0B .uleb128 0xb + 93 0017 0B .uleb128 0xb + 94 0018 3E .uleb128 0x3e + 95 0019 0B .uleb128 0xb + 96 001a 03 .uleb128 0x3 + 97 001b 0E .uleb128 0xe + 98 001c 00 .byte 0x0 + 99 001d 00 .byte 0x0 + 100 001e 03 .uleb128 0x3 + 101 001f 24 .uleb128 0x24 + 102 0020 00 .byte 0x0 + 103 0021 0B .uleb128 0xb + 104 0022 0B .uleb128 0xb + 105 0023 3E .uleb128 0x3e + 106 0024 0B .uleb128 0xb + 107 0025 03 .uleb128 0x3 + 108 0026 08 .uleb128 0x8 + 109 0027 00 .byte 0x0 + 110 0028 00 .byte 0x0 + 111 0029 04 .uleb128 0x4 + 112 002a 24 .uleb128 0x24 + 113 002b 00 .byte 0x0 + 114 002c 0B .uleb128 0xb + GAS LISTING C:\Users\Nick\AppData\Local\Temp/ccUechtz.s page 3 + + + 115 002d 0B .uleb128 0xb + 116 002e 3E .uleb128 0x3e + 117 002f 0B .uleb128 0xb + 118 0030 00 .byte 0x0 + 119 0031 00 .byte 0x0 + 120 0032 00 .byte 0x0 + 121 .section .debug_line + 122 0000 2000 0000 .long .LELT0-.LSLT0 + 123 .LSLT0: + 124 0004 0200 .word 0x2 + 125 0006 1000 0000 .long .LELTP0-.LASLTP0 + 126 .LASLTP0: + 127 000a 01 .byte 0x1 + 128 000b 01 .byte 0x1 + 129 000c F6 .byte 0xf6 + 130 000d F5 .byte 0xf5 + 131 000e 0A .byte 0xa + 132 000f 00 .byte 0x0 + 133 0010 01 .byte 0x1 + 134 0011 01 .byte 0x1 + 135 0012 01 .byte 0x1 + 136 0013 01 .byte 0x1 + 137 0014 00 .byte 0x0 + 138 0015 00 .byte 0x0 + 139 0016 00 .byte 0x0 + 140 0017 01 .byte 0x1 + 141 0018 00 .byte 0x0 + 142 0019 00 .byte 0x0 + 143 .LELTP0: + 144 001a 00 .byte 0x0 + 145 001b 05 .uleb128 0x5 + 146 001c 02 .byte 0x2 + 147 001d 0000 0000 .long .Letext0 + 148 0021 00 .byte 0x0 + 149 0022 01 .uleb128 0x1 + 150 0023 01 .byte 0x1 + 151 .LELT0: + 152 0024 1600 0000 .section .debug_str,"MS",@progbits,1 + 152 0200 1000 + 152 0000 0101 + 152 FB0E 0A00 + 152 0101 0101 + 153 .LASF2: + 154 0000 756E 7369 .string "unsigned int" + 154 676E 6564 + 154 2069 6E74 + 154 00 + 155 .LASF9: + 156 000d 433A 5C55 .ascii "C:\\Users\\Nick\\" + 156 7365 7273 + 156 5C4E 6963 + 156 6B5C + 157 001b 446F 6375 .string "Documents\\GitHub\\Arduino_Boards\\sparkfun\\tiny\\bootloaders\\attiny" + 157 6D65 6E74 + 157 735C 4769 + 157 7448 7562 + 157 5C41 7264 + GAS LISTING C:\Users\Nick\AppData\Local\Temp/ccUechtz.s page 4 + + + 158 .LASF4: + 159 005c 6C6F 6E67 .string "long unsigned int" + 159 2075 6E73 + 159 6967 6E65 + 159 6420 696E + 159 7400 + 160 .LASF8: + 161 006e 7573 6264 .string "usbdrv/oddebug.c" + 161 7276 2F6F + 161 6464 6562 + 161 7567 2E63 + 161 00 + 162 .LASF0: + 163 007f 7369 676E .string "signed char" + 163 6564 2063 + 163 6861 7200 + 164 .LASF6: + 165 008b 6C6F 6E67 .string "long long unsigned int" + 165 206C 6F6E + 165 6720 756E + 165 7369 676E + 165 6564 2069 + 166 .LASF1: + 167 00a2 756E 7369 .string "unsigned char" + 167 676E 6564 + 167 2063 6861 + 167 7200 + 168 .LASF3: + 169 00b0 6C6F 6E67 .string "long int" + 169 2069 6E74 + 169 00 + 170 .LASF7: + 171 00b9 474E 5520 .string "GNU C 4.3.3" + 171 4320 342E + 171 332E 3300 + 172 .LASF5: + 173 00c5 6C6F 6E67 .string "long long int" + 173 206C 6F6E + 173 6720 696E + 173 7400 + GAS LISTING C:\Users\Nick\AppData\Local\Temp/ccUechtz.s page 5 + + +DEFINED SYMBOLS + *ABS*:00000000 oddebug.c +C:\Users\Nick\AppData\Local\Temp/ccUechtz.s:2 *ABS*:0000003f __SREG__ +C:\Users\Nick\AppData\Local\Temp/ccUechtz.s:3 *ABS*:0000003e __SP_H__ +C:\Users\Nick\AppData\Local\Temp/ccUechtz.s:4 *ABS*:0000003d __SP_L__ +C:\Users\Nick\AppData\Local\Temp/ccUechtz.s:5 *ABS*:00000034 __CCP__ +C:\Users\Nick\AppData\Local\Temp/ccUechtz.s:6 *ABS*:00000000 __tmp_reg__ +C:\Users\Nick\AppData\Local\Temp/ccUechtz.s:7 *ABS*:00000001 __zero_reg__ + +NO UNDEFINED SYMBOLS diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/oddebug.h b/sparkfun/tiny/bootloaders/attiny/usbdrv/oddebug.h new file mode 100644 index 00000000..851f84de --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/oddebug.h @@ -0,0 +1,122 @@ +/* Name: oddebug.h + * Project: AVR library + * Author: Christian Starkjohann + * Creation Date: 2005-01-16 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#ifndef __oddebug_h_included__ +#define __oddebug_h_included__ + +/* +General Description: +This module implements a function for debug logs on the serial line of the +AVR microcontroller. Debugging can be configured with the define +'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging +calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is +2, DBG1 and DBG2 logs will be printed. + +A debug log consists of a label ('prefix') to indicate which debug log created +the output and a memory block to dump in hex ('data' and 'len'). +*/ + + +#ifndef F_CPU +# define F_CPU 12000000 /* 12 MHz */ +#endif + +/* make sure we have the UART defines: */ +#include "usbportability.h" + +#ifndef uchar +# define uchar unsigned char +#endif + +#if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */ +# warning "Debugging disabled because device has no UART" +# undef DEBUG_LEVEL +#endif + +#ifndef DEBUG_LEVEL +# define DEBUG_LEVEL 0 +#endif + +/* ------------------------------------------------------------------------- */ + +#if DEBUG_LEVEL > 0 +# define DBG1(prefix, data, len) odDebug(prefix, data, len) +#else +# define DBG1(prefix, data, len) +#endif + +#if DEBUG_LEVEL > 1 +# define DBG2(prefix, data, len) odDebug(prefix, data, len) +#else +# define DBG2(prefix, data, len) +#endif + +/* ------------------------------------------------------------------------- */ + +#if DEBUG_LEVEL > 0 +extern void odDebug(uchar prefix, uchar *data, uchar len); + +/* Try to find our control registers; ATMEL likes to rename these */ + +#if defined UBRR +# define ODDBG_UBRR UBRR +#elif defined UBRRL +# define ODDBG_UBRR UBRRL +#elif defined UBRR0 +# define ODDBG_UBRR UBRR0 +#elif defined UBRR0L +# define ODDBG_UBRR UBRR0L +#endif + +#if defined UCR +# define ODDBG_UCR UCR +#elif defined UCSRB +# define ODDBG_UCR UCSRB +#elif defined UCSR0B +# define ODDBG_UCR UCSR0B +#endif + +#if defined TXEN +# define ODDBG_TXEN TXEN +#else +# define ODDBG_TXEN TXEN0 +#endif + +#if defined USR +# define ODDBG_USR USR +#elif defined UCSRA +# define ODDBG_USR UCSRA +#elif defined UCSR0A +# define ODDBG_USR UCSR0A +#endif + +#if defined UDRE +# define ODDBG_UDRE UDRE +#else +# define ODDBG_UDRE UDRE0 +#endif + +#if defined UDR +# define ODDBG_UDR UDR +#elif defined UDR0 +# define ODDBG_UDR UDR0 +#endif + +static inline void odDebugInit(void) +{ + ODDBG_UCR |= (1<len & 0x10){ /* packet buffer was empty */ + txStatus->buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + txStatus->len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = txStatus->buffer + 1; + i = len; + do{ /* if len == 0, we still copy 1 byte, but that's no problem */ + *p++ = *data++; + }while(--i > 0); /* loop control at the end is 2 bytes shorter than at beginning */ + usbCrc16Append(&txStatus->buffer[1], len); + txStatus->len = len + 4; /* len must be given including sync byte */ + DBG2(0x21 + (((int)txStatus >> 3) & 3), txStatus->buffer, len + 3); +} + +USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) +{ + usbGenericSetInterrupt(data, len, &usbTxStatus1); +} +#endif + +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len) +{ + usbGenericSetInterrupt(data, len, &usbTxStatus3); +} +#endif +#endif /* USB_CFG_SUPPRESS_INTR_CODE */ + +/* ------------------ utilities for code following below ------------------- */ + +/* Use defines for the switch statement so that we can choose between an + * if()else if() and a switch/case based implementation. switch() is more + * efficient for a LARGE set of sequential choices, if() is better in all other + * cases. + */ +#if USB_CFG_USE_SWITCH_STATEMENT +# define SWITCH_START(cmd) switch(cmd){{ +# define SWITCH_CASE(value) }break; case (value):{ +# define SWITCH_CASE2(v1,v2) }break; case (v1): case(v2):{ +# define SWITCH_CASE3(v1,v2,v3) }break; case (v1): case(v2): case(v3):{ +# define SWITCH_DEFAULT }break; default:{ +# define SWITCH_END }} +#else +# define SWITCH_START(cmd) {uchar _cmd = cmd; if(0){ +# define SWITCH_CASE(value) }else if(_cmd == (value)){ +# define SWITCH_CASE2(v1,v2) }else if(_cmd == (v1) || _cmd == (v2)){ +# define SWITCH_CASE3(v1,v2,v3) }else if(_cmd == (v1) || _cmd == (v2) || _cmd == (v3)){ +# define SWITCH_DEFAULT }else{ +# define SWITCH_END }} +#endif + +#ifndef USB_RX_USER_HOOK +#define USB_RX_USER_HOOK(data, len) +#endif +#ifndef USB_SET_ADDRESS_HOOK +#define USB_SET_ADDRESS_HOOK() +#endif + +/* ------------------------------------------------------------------------- */ + +/* We use if() instead of #if in the macro below because #if can't be used + * in macros and the compiler optimizes constant conditions anyway. + * This may cause problems with undefined symbols if compiled without + * optimizing! + */ + + #define GET_DESCRIPTOR(cfgProp, staticName) \ + if(cfgProp){ \ + if((cfgProp) & USB_PROP_IS_RAM) \ + flags = 0; \ + if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ + len = usbFunctionDescriptor(rq); \ + }else{ \ + len = USB_PROP_LENGTH(cfgProp); \ + usbMsgPtr = (usbMsgPtr_t)(staticName); \ + } \ + } + +/* usbDriverDescriptor() is similar to usbFunctionDescriptor(), but used + * internally for all types of descriptors. + */ +static inline usbMsgLen_t usbDriverDescriptor(usbRequest_t *rq) +{ +usbMsgLen_t len = 0; +uchar flags = USB_FLG_MSGPTR_IS_ROM; + + SWITCH_START(rq->wValue.bytes[1]) + SWITCH_CASE(USBDESCR_DEVICE) /* 1 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) + SWITCH_CASE(USBDESCR_CONFIG) /* 2 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) + SWITCH_CASE(USBDESCR_STRING) /* 3 */ +#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC + if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) + flags = 0; + len = usbFunctionDescriptor(rq); +#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ + SWITCH_START(rq->wValue.bytes[0]) + SWITCH_CASE(0) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) + SWITCH_CASE(1) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) + SWITCH_CASE(2) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice) + SWITCH_CASE(3) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) + SWITCH_DEFAULT + if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + len = usbFunctionDescriptor(rq); + } + SWITCH_END +#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ +#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */ + SWITCH_CASE(USBDESCR_HID) /* 0x21 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) + SWITCH_CASE(USBDESCR_HID_REPORT)/* 0x22 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) +#endif + SWITCH_DEFAULT + if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + len = usbFunctionDescriptor(rq); + } + SWITCH_END + + flags=flags; // Make compiler shut up about unused variable +#ifndef MNHACK_ONLY_FLASH_MSGPTR + usbMsgFlags = flags; +#endif + return len; +} + +/* ------------------------------------------------------------------------- */ + +/* usbDriverSetup() is similar to usbFunctionSetup(), but it's used for + * standard requests instead of class and custom requests. + */ +static inline usbMsgLen_t usbDriverSetup(usbRequest_t *rq) +{ +usbMsgLen_t len = 0; +uchar *dataPtr = usbTxBuf + 9; /* there are 2 bytes free space at the end of the buffer */ +uchar value = rq->wValue.bytes[0]; +#if USB_CFG_IMPLEMENT_HALT +uchar index = rq->wIndex.bytes[0]; +#endif + + dataPtr[0] = 0; /* default reply common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ + SWITCH_START(rq->bRequest) + SWITCH_CASE(USBRQ_GET_STATUS) /* 0 */ + uchar recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */ + if(USB_CFG_IS_SELF_POWERED && recipient == USBRQ_RCPT_DEVICE) + dataPtr[0] = USB_CFG_IS_SELF_POWERED; +#if USB_CFG_IMPLEMENT_HALT + if(recipient == USBRQ_RCPT_ENDPOINT && index == 0x81) /* request status for endpoint 1 */ + dataPtr[0] = usbTxLen1 == USBPID_STALL; +#endif + dataPtr[1] = 0; + len = 2; +#if USB_CFG_IMPLEMENT_HALT + SWITCH_CASE2(USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE) /* 1, 3 */ + if(value == 0 && index == 0x81){ /* feature 0 == HALT for endpoint == 1 */ + usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; + usbResetDataToggling(); + } +#endif + SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */ + usbNewDeviceAddr = value; + USB_SET_ADDRESS_HOOK(); + SWITCH_CASE(USBRQ_GET_DESCRIPTOR) /* 6 */ + len = usbDriverDescriptor(rq); + goto skipMsgPtrAssignment; + SWITCH_CASE(USBRQ_GET_CONFIGURATION) /* 8 */ + dataPtr = &usbConfiguration; /* send current configuration value */ + len = 1; + SWITCH_CASE(USBRQ_SET_CONFIGURATION) /* 9 */ + usbConfiguration = value; + usbResetStall(); + SWITCH_CASE(USBRQ_GET_INTERFACE) /* 10 */ + len = 1; +#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE + SWITCH_CASE(USBRQ_SET_INTERFACE) /* 11 */ + usbResetDataToggling(); + usbResetStall(); +#endif + SWITCH_DEFAULT /* 7=SET_DESCRIPTOR, 12=SYNC_FRAME */ + /* Should we add an optional hook here? */ + SWITCH_END + usbMsgPtr = (usbMsgPtr_t)dataPtr; +skipMsgPtrAssignment: + return len; +} + +/* ------------------------------------------------------------------------- */ + +/* usbProcessRx() is called for every message received by the interrupt + * routine. It distinguishes between SETUP and DATA packets and processes + * them accordingly. + */ +static inline void usbProcessRx(uchar *data, uchar len) +{ +usbRequest_t *rq = (void *)data; + +/* usbRxToken can be: + * 0x2d 00101101 (USBPID_SETUP for setup data) + * 0xe1 11100001 (USBPID_OUT: data phase of setup transfer) + * 0...0x0f for OUT on endpoint X + */ + DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */ + USB_RX_USER_HOOK(data, len) +#if USB_CFG_IMPLEMENT_FN_WRITEOUT + if(usbRxToken < 0x10){ /* OUT to endpoint != 0: endpoint number in usbRxToken */ + usbFunctionWriteOut(data, len); + return; + } +#endif + if(usbRxToken == (uchar)USBPID_SETUP){ + if(len != 8) /* Setup size must be always 8 bytes. Ignore otherwise. */ + return; + usbMsgLen_t replyLen; + usbTxBuf[0] = USBPID_DATA0; /* initialize data toggling */ + usbTxLen = USBPID_NAK; /* abort pending transmit */ +#ifndef MNHACK_ONLY_FLASH_MSGPTR + usbMsgFlags = 0; +#endif + uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; + if(type != USBRQ_TYPE_STANDARD){ /* standard requests are handled by driver */ + replyLen = usbFunctionSetup(data); + }else{ + replyLen = usbDriverSetup(rq); + } +#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE + if(replyLen == USB_NO_MSG){ /* use user-supplied read/write function */ + /* do some conditioning on replyLen, but on IN transfers only */ + if((rq->bmRequestType & USBRQ_DIR_MASK) != USBRQ_DIR_HOST_TO_DEVICE){ + if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ + replyLen = rq->wLength.bytes[0]; + }else{ + replyLen = rq->wLength.word; + } + } + usbMsgFlags = USB_FLG_USE_USER_RW; + }else /* The 'else' prevents that we limit a replyLen of USB_NO_MSG to the maximum transfer len. */ +#endif + if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ + if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ + replyLen = rq->wLength.bytes[0]; + }else{ + if(replyLen > rq->wLength.word) /* limit length to max */ + replyLen = rq->wLength.word; + } + usbMsgLen = replyLen; + }else{ /* usbRxToken must be USBPID_OUT, which means data phase of setup (control-out) */ +#if USB_CFG_IMPLEMENT_FN_WRITE + if(usbMsgFlags & USB_FLG_USE_USER_RW){ + uchar rval = usbFunctionWrite(data, len); + if(rval == 0xff){ /* an error occurred */ + usbTxLen = USBPID_STALL; + }else if(rval != 0){ /* This was the final package */ + usbMsgLen = 0; /* answer with a zero-sized data packet */ + } + } +#endif + } +} + +/* ------------------------------------------------------------------------- */ + +/* This function is similar to usbFunctionRead(), but it's also called for + * data handled automatically by the driver (e.g. descriptor reads). + */ +static uchar usbDeviceRead(uchar *data, uchar len) +{ + if(len > 0){ /* don't bother app with 0 sized reads */ +#if USB_CFG_IMPLEMENT_FN_READ + if(usbMsgFlags & USB_FLG_USE_USER_RW){ + len = usbFunctionRead(data, len); + }else +#endif + { + uchar i = len; + usbMsgPtr_t r = usbMsgPtr; +#ifndef MNHACK_ONLY_FLASH_MSGPTR + if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */ +#endif + do{ + uchar c = USB_READ_FLASH(r); /* assign to char size variable to enforce byte ops */ + *data++ = c; + r++; + }while(--i); +#ifndef MNHACK_ONLY_FLASH_MSGPTR + }else{ // RAM data + do{ + *data++ = *((uchar *)r); + r++; + }while(--i); + } +#endif + usbMsgPtr = r; + } + } + return len; +} + +/* ------------------------------------------------------------------------- */ + +/* usbBuildTxBlock() is called when we have data to transmit and the + * interrupt routine's transmit buffer is empty. + */ +static inline void usbBuildTxBlock(void) +{ +usbMsgLen_t wantLen; +uchar len; + + wantLen = usbMsgLen; + if(wantLen > 8) + wantLen = 8; + usbMsgLen -= wantLen; + usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */ + len = usbDeviceRead(usbTxBuf + 1, wantLen); + if(len <= 8){ /* valid data packet */ + usbCrc16Append(&usbTxBuf[1], len); + len += 4; /* length including sync byte */ + if(len < 12) /* a partial package identifies end of message */ + usbMsgLen = USB_NO_MSG; + }else{ + len = USBPID_STALL; /* stall the endpoint */ + usbMsgLen = USB_NO_MSG; + } + usbTxLen = len; + DBG2(0x20, usbTxBuf, len-1); +} + +/* ------------------------------------------------------------------------- */ + +static inline void usbHandleResetHook(uchar notResetState) +{ +#ifdef USB_RESET_HOOK +static uchar wasReset; +uchar isReset = !notResetState; + + if(wasReset != isReset){ + USB_RESET_HOOK(isReset); + wasReset = isReset; + } +#else + notResetState = notResetState; // avoid compiler warning +#endif +} + +/* ------------------------------------------------------------------------- */ + +USB_PUBLIC void usbPoll(void) +{ +schar len; +uchar i; + + len = usbRxLen - 3; + if(len >= 0){ +/* We could check CRC16 here -- but ACK has already been sent anyway. If you + * need data integrity checks with this driver, check the CRC in your app + * code and report errors back to the host. Since the ACK was already sent, + * retries must be handled on application level. + * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); + */ + usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len); +#if USB_CFG_HAVE_FLOWCONTROL + if(usbRxLen > 0) /* only mark as available if not inactivated */ + usbRxLen = 0; +#else + usbRxLen = 0; /* mark rx buffer as available */ +#endif + } + if(usbTxLen & 0x10){ /* transmit system idle */ + if(usbMsgLen != USB_NO_MSG){ /* transmit data pending? */ + usbBuildTxBlock(); + } + } + for(i = 20; i > 0; i--){ + uchar usbLineStatus = USBIN & USBMASK; + if(usbLineStatus != 0) /* SE0 has ended */ + goto isNotReset; + } + /* RESET condition, called multiple times during reset */ + usbNewDeviceAddr = 0; + usbDeviceAddr = 0; + usbResetStall(); + DBG1(0xff, 0, 0); +isNotReset: + usbHandleResetHook(i); +} + +/* ------------------------------------------------------------------------- */ + +USB_PUBLIC void usbInit(void) +{ +#ifdef MNHACK_NO_DATASECTION + usbTxLen = USBPID_NAK; + usbMsgLen = USB_NO_MSG; +#endif + +#if USB_INTR_CFG_SET != 0 + USB_INTR_CFG |= USB_INTR_CFG_SET; +#endif +#if USB_INTR_CFG_CLR != 0 + USB_INTR_CFG &= ~(USB_INTR_CFG_CLR); +#endif + USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); + usbResetDataToggling(); +#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE + usbTxLen1 = USBPID_NAK; +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 + usbTxLen3 = USBPID_NAK; +#endif +#endif +} + +/* ------------------------------------------------------------------------- */ diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrv.h b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrv.h new file mode 100644 index 00000000..3fe84d5a --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrv.h @@ -0,0 +1,746 @@ +/* Name: usbdrv.h + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#ifndef __usbdrv_h_included__ +#define __usbdrv_h_included__ +#include "usbconfig.h" +#include "usbportability.h" + +/* +Hardware Prerequisites: +======================= +USB lines D+ and D- MUST be wired to the same I/O port. We recommend that D+ +triggers the interrupt (best achieved by using INT0 for D+), but it is also +possible to trigger the interrupt from D-. If D- is used, interrupts are also +triggered by SOF packets. D- requires a pull-up of 1.5k to +3.5V (and the +device must be powered at 3.5V) to identify as low-speed USB device. A +pull-down or pull-up of 1M SHOULD be connected from D+ to +3.5V to prevent +interference when no USB master is connected. If you use Zener diodes to limit +the voltage on D+ and D-, you MUST use a pull-down resistor, not a pull-up. +We use D+ as interrupt source and not D- because it does not trigger on +keep-alive and RESET states. If you want to count keep-alive events with +USB_COUNT_SOF, you MUST use D- as an interrupt source. + +As a compile time option, the 1.5k pull-up resistor on D- can be made +switchable to allow the device to disconnect at will. See the definition of +usbDeviceConnect() and usbDeviceDisconnect() further down in this file. + +Please adapt the values in usbconfig.h according to your hardware! + +The device MUST be clocked at exactly 12 MHz, 15 MHz, 16 MHz or 20 MHz +or at 12.8 MHz resp. 16.5 MHz +/- 1%. See usbconfig-prototype.h for details. + + +Limitations: +============ +Robustness with respect to communication errors: +The driver assumes error-free communication. It DOES check for errors in +the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte, +token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due +to timing constraints: We must start sending a reply within 7 bit times. +Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU +performance does not permit that. The driver does not check Data0/Data1 +toggling, but application software can implement the check. + +Input characteristics: +Since no differential receiver circuit is used, electrical interference +robustness may suffer. The driver samples only one of the data lines with +an ordinary I/O pin's input characteristics. However, since this is only a +low speed USB implementation and the specification allows for 8 times the +bit rate over the same hardware, we should be on the safe side. Even the spec +requires detection of asymmetric states at high bit rate for SE0 detection. + +Number of endpoints: +The driver supports the following endpoints: + +- Endpoint 0, the default control endpoint. +- Any number of interrupt- or bulk-out endpoints. The data is sent to + usbFunctionWriteOut() and USB_CFG_IMPLEMENT_FN_WRITEOUT must be defined + to 1 to activate this feature. The endpoint number can be found in the + global variable 'usbRxToken'. +- One default interrupt- or bulk-in endpoint. This endpoint is used for + interrupt- or bulk-in transfers which are not handled by any other endpoint. + You must define USB_CFG_HAVE_INTRIN_ENDPOINT in order to activate this + feature and call usbSetInterrupt() to send interrupt/bulk data. +- One additional interrupt- or bulk-in endpoint. This was endpoint 3 in + previous versions of this driver but can now be configured to any endpoint + number. You must define USB_CFG_HAVE_INTRIN_ENDPOINT3 in order to activate + this feature and call usbSetInterrupt3() to send interrupt/bulk data. The + endpoint number can be set with USB_CFG_EP3_NUMBER. + +Please note that the USB standard forbids bulk endpoints for low speed devices! +Most operating systems allow them anyway, but the AVR will spend 90% of the CPU +time in the USB interrupt polling for bulk data. + +Maximum data payload: +Data payload of control in and out transfers may be up to 254 bytes. In order +to accept payload data of out transfers, you need to implement +'usbFunctionWrite()'. + +USB Suspend Mode supply current: +The USB standard limits power consumption to 500uA when the bus is in suspend +mode. This is not a problem for self-powered devices since they don't need +bus power anyway. Bus-powered devices can achieve this only by putting the +CPU in sleep mode. The driver does not implement suspend handling by itself. +However, the application may implement activity monitoring and wakeup from +sleep. The host sends regular SE0 states on the bus to keep it active. These +SE0 states can be detected by using D- as the interrupt source. Define +USB_COUNT_SOF to 1 and use the global variable usbSofCount to check for bus +activity. + +Operation without an USB master: +The driver behaves neutral without connection to an USB master if D- reads +as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M) +pull-down or pull-up resistor on D+ (interrupt). If Zener diodes are used, +use a pull-down. If D- becomes statically 0, the driver may block in the +interrupt routine. + +Interrupt latency: +The application must ensure that the USB interrupt is not disabled for more +than 25 cycles (this is for 12 MHz, faster clocks allow longer latency). +This implies that all interrupt routines must either have the "ISR_NOBLOCK" +attribute set (see "avr/interrupt.h") or be written in assembler with "sei" +as the first instruction. + +Maximum interrupt duration / CPU cycle consumption: +The driver handles all USB communication during the interrupt service +routine. The routine will not return before an entire USB message is received +and the reply is sent. This may be up to ca. 1200 cycles @ 12 MHz (= 100us) if +the host conforms to the standard. The driver will consume CPU cycles for all +USB messages, even if they address another (low-speed) device on the same bus. + +*/ + +/* ------------------------------------------------------------------------- */ +/* --------------------------- Module Interface ---------------------------- */ +/* ------------------------------------------------------------------------- */ + +#define USBDRV_VERSION 20121206 +/* This define uniquely identifies a driver version. It is a decimal number + * constructed from the driver's release date in the form YYYYMMDD. If the + * driver's behavior or interface changes, you can use this constant to + * distinguish versions. If it is not defined, the driver's release date is + * older than 2006-01-25. + */ + + +#ifndef USB_PUBLIC +#define USB_PUBLIC +#endif +/* USB_PUBLIC is used as declaration attribute for all functions exported by + * the USB driver. The default is no attribute (see above). You may define it + * to static either in usbconfig.h or from the command line if you include + * usbdrv.c instead of linking against it. Including the C module of the driver + * directly in your code saves a couple of bytes in flash memory. + */ + +#ifndef __ASSEMBLER__ +#ifndef uchar +#define uchar unsigned char +#endif +#ifndef schar +#define schar signed char +#endif +/* shortcuts for well defined 8 bit integer types */ + +#if USB_CFG_LONG_TRANSFERS /* if more than 254 bytes transfer size required */ +# define usbMsgLen_t unsigned +#else +# define usbMsgLen_t uchar +#endif +/* usbMsgLen_t is the data type used for transfer lengths. By default, it is + * defined to uchar, allowing a maximum of 254 bytes (255 is reserved for + * USB_NO_MSG below). If the usbconfig.h defines USB_CFG_LONG_TRANSFERS to 1, + * a 16 bit data type is used, allowing up to 16384 bytes (the rest is used + * for flags in the descriptor configuration). + */ +#define USB_NO_MSG ((usbMsgLen_t)-1) /* constant meaning "no message" */ + +#ifndef usbMsgPtr_t +#define usbMsgPtr_t uchar * +#endif +/* Making usbMsgPtr_t a define allows the user of this library to define it to + * an 8 bit type on tiny devices. This reduces code size, especially if the + * compiler supports a tiny memory model. + * The type can be a pointer or scalar type, casts are made where necessary. + * Although it's paradoxical, Gcc 4 generates slightly better code for scalar + * types than for pointers. + */ + +struct usbRequest; /* forward declaration */ + +USB_PUBLIC void usbInit(void); +/* This function must be called before interrupts are enabled and the main + * loop is entered. We exepct that the PORT and DDR bits for D+ and D- have + * not been changed from their default status (which is 0). If you have changed + * them, set both back to 0 (configure them as input with no internal pull-up). + */ +USB_PUBLIC void usbPoll(void); +/* This function must be called at regular intervals from the main loop. + * Maximum delay between calls is somewhat less than 50ms (USB timeout for + * accepting a Setup message). Otherwise the device will not be recognized. + * Please note that debug outputs through the UART take ~ 0.5ms per byte + * at 19200 bps. + */ +extern usbMsgPtr_t usbMsgPtr; +/* This variable may be used to pass transmit data to the driver from the + * implementation of usbFunctionWrite(). It is also used internally by the + * driver for standard control requests. + */ +USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]); +/* This function is called when the driver receives a SETUP transaction from + * the host which is not answered by the driver itself (in practice: class and + * vendor requests). All control transfers start with a SETUP transaction where + * the host communicates the parameters of the following (optional) data + * transfer. The SETUP data is available in the 'data' parameter which can + * (and should) be casted to 'usbRequest_t *' for a more user-friendly access + * to parameters. + * + * If the SETUP indicates a control-in transfer, you should provide the + * requested data to the driver. There are two ways to transfer this data: + * (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data + * block and return the length of the data in 'usbFunctionSetup()'. The driver + * will handle the rest. Or (2) return USB_NO_MSG in 'usbFunctionSetup()'. The + * driver will then call 'usbFunctionRead()' when data is needed. See the + * documentation for usbFunctionRead() for details. + * + * If the SETUP indicates a control-out transfer, the only way to receive the + * data from the host is through the 'usbFunctionWrite()' call. If you + * implement this function, you must return USB_NO_MSG in 'usbFunctionSetup()' + * to indicate that 'usbFunctionWrite()' should be used. See the documentation + * of this function for more information. If you just want to ignore the data + * sent by the host, return 0 in 'usbFunctionSetup()'. + * + * Note that calls to the functions usbFunctionRead() and usbFunctionWrite() + * are only done if enabled by the configuration in usbconfig.h. + */ +USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq); +/* You need to implement this function ONLY if you provide USB descriptors at + * runtime (which is an expert feature). It is very similar to + * usbFunctionSetup() above, but it is called only to request USB descriptor + * data. See the documentation of usbFunctionSetup() above for more info. + */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT +USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len); +/* This function sets the message which will be sent during the next interrupt + * IN transfer. The message is copied to an internal buffer and must not exceed + * a length of 8 bytes. The message may be 0 bytes long just to indicate the + * interrupt status to the host. + * If you need to transfer more bytes, use a control read after the interrupt. + */ +#define usbInterruptIsReady() (usbTxLen1 & 0x10) +/* This macro indicates whether the last interrupt message has already been + * sent. If you set a new interrupt message before the old was sent, the + * message already buffered will be lost. + */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len); +#define usbInterruptIsReady3() (usbTxLen3 & 0x10) +/* Same as above for endpoint 3 */ +#endif +#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */ +#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* simplified interface for backward compatibility */ +#define usbHidReportDescriptor usbDescriptorHidReport +/* should be declared as: PROGMEM char usbHidReportDescriptor[]; */ +/* If you implement an HID device, you need to provide a report descriptor. + * The HID report descriptor syntax is a bit complex. If you understand how + * report descriptors are constructed, we recommend that you use the HID + * Descriptor Tool from usb.org, see http://www.usb.org/developers/hidpage/. + * Otherwise you should probably start with a working example. + */ +#endif /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */ +#if USB_CFG_IMPLEMENT_FN_WRITE +USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len); +/* This function is called by the driver to provide a control transfer's + * payload data (control-out). It is called in chunks of up to 8 bytes. The + * total count provided in the current control transfer can be obtained from + * the 'length' property in the setup data. If an error occurred during + * processing, return 0xff (== -1). The driver will answer the entire transfer + * with a STALL token in this case. If you have received the entire payload + * successfully, return 1. If you expect more data, return 0. If you don't + * know whether the host will send more data (you should know, the total is + * provided in the usbFunctionSetup() call!), return 1. + * NOTE: If you return 0xff for STALL, 'usbFunctionWrite()' may still be called + * for the remaining data. You must continue to return 0xff for STALL in these + * calls. + * In order to get usbFunctionWrite() called, define USB_CFG_IMPLEMENT_FN_WRITE + * to 1 in usbconfig.h and return 0xff in usbFunctionSetup().. + */ +#endif /* USB_CFG_IMPLEMENT_FN_WRITE */ +#if USB_CFG_IMPLEMENT_FN_READ +USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len); +/* This function is called by the driver to ask the application for a control + * transfer's payload data (control-in). It is called in chunks of up to 8 + * bytes each. You should copy the data to the location given by 'data' and + * return the actual number of bytes copied. If you return less than requested, + * the control-in transfer is terminated. If you return 0xff, the driver aborts + * the transfer with a STALL token. + * In order to get usbFunctionRead() called, define USB_CFG_IMPLEMENT_FN_READ + * to 1 in usbconfig.h and return 0xff in usbFunctionSetup().. + */ +#endif /* USB_CFG_IMPLEMENT_FN_READ */ + +extern uchar usbRxToken; /* may be used in usbFunctionWriteOut() below */ +#if USB_CFG_IMPLEMENT_FN_WRITEOUT +USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len); +/* This function is called by the driver when data is received on an interrupt- + * or bulk-out endpoint. The endpoint number can be found in the global + * variable usbRxToken. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT to 1 in + * usbconfig.h to get this function called. + */ +#endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */ +#ifdef USB_CFG_PULLUP_IOPORTNAME +#define usbDeviceConnect() ((USB_PULLUP_DDR |= (1<device, 1=device->host + * t ..... type: 0=standard, 1=class, 2=vendor, 3=reserved + * r ..... recipient: 0=device, 1=interface, 2=endpoint, 3=other + */ + +/* USB setup recipient values */ +#define USBRQ_RCPT_MASK 0x1f +#define USBRQ_RCPT_DEVICE 0 +#define USBRQ_RCPT_INTERFACE 1 +#define USBRQ_RCPT_ENDPOINT 2 + +/* USB request type values */ +#define USBRQ_TYPE_MASK 0x60 +#define USBRQ_TYPE_STANDARD (0<<5) +#define USBRQ_TYPE_CLASS (1<<5) +#define USBRQ_TYPE_VENDOR (2<<5) + +/* USB direction values: */ +#define USBRQ_DIR_MASK 0x80 +#define USBRQ_DIR_HOST_TO_DEVICE (0<<7) +#define USBRQ_DIR_DEVICE_TO_HOST (1<<7) + +/* USB Standard Requests */ +#define USBRQ_GET_STATUS 0 +#define USBRQ_CLEAR_FEATURE 1 +#define USBRQ_SET_FEATURE 3 +#define USBRQ_SET_ADDRESS 5 +#define USBRQ_GET_DESCRIPTOR 6 +#define USBRQ_SET_DESCRIPTOR 7 +#define USBRQ_GET_CONFIGURATION 8 +#define USBRQ_SET_CONFIGURATION 9 +#define USBRQ_GET_INTERFACE 10 +#define USBRQ_SET_INTERFACE 11 +#define USBRQ_SYNCH_FRAME 12 + +/* USB descriptor constants */ +#define USBDESCR_DEVICE 1 +#define USBDESCR_CONFIG 2 +#define USBDESCR_STRING 3 +#define USBDESCR_INTERFACE 4 +#define USBDESCR_ENDPOINT 5 +#define USBDESCR_HID 0x21 +#define USBDESCR_HID_REPORT 0x22 +#define USBDESCR_HID_PHYS 0x23 + +//#define USBATTR_BUSPOWER 0x80 // USB 1.1 does not define this value any more +#define USBATTR_BUSPOWER 0 +#define USBATTR_SELFPOWER 0x40 +#define USBATTR_REMOTEWAKE 0x20 + +/* USB HID Requests */ +#define USBRQ_HID_GET_REPORT 0x01 +#define USBRQ_HID_GET_IDLE 0x02 +#define USBRQ_HID_GET_PROTOCOL 0x03 +#define USBRQ_HID_SET_REPORT 0x09 +#define USBRQ_HID_SET_IDLE 0x0a +#define USBRQ_HID_SET_PROTOCOL 0x0b + +/* ------------------------------------------------------------------------- */ + +#endif /* __usbdrv_h_included__ */ diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.S b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.S new file mode 100644 index 00000000..d9275641 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.S @@ -0,0 +1,391 @@ +/* Name: usbdrvasm.S + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2007-06-13 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This module is the assembler part of the USB driver. This file contains +general code (preprocessor acrobatics and CRC computation) and then includes +the file appropriate for the given clock rate. +*/ + +#define __SFR_OFFSET 0 /* used by avr-libc's register definitions */ +#include "usbportability.h" +#include "usbdrv.h" /* for common defs */ + +/* register names */ +#define x1 r16 +#define x2 r17 +#define shift r18 +#define cnt r19 +#define x3 r20 +#define x4 r21 +#define x5 r22 +#define bitcnt x5 +#define phase x4 +#define leap x4 + +/* Some assembler dependent definitions and declarations: */ + +#ifdef __IAR_SYSTEMS_ASM__ + extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset + extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen + extern usbTxBuf, usbTxStatus1, usbTxStatus3 +# if USB_COUNT_SOF + extern usbSofCount +# endif + public usbCrc16 + public usbCrc16Append + + COMMON INTVEC +# ifndef USB_INTR_VECTOR + ORG INT0_vect +# else /* USB_INTR_VECTOR */ + ORG USB_INTR_VECTOR +# undef USB_INTR_VECTOR +# endif /* USB_INTR_VECTOR */ +# define USB_INTR_VECTOR usbInterruptHandler + rjmp USB_INTR_VECTOR + RSEG CODE + +#else /* __IAR_SYSTEMS_ASM__ */ + +# ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */ +# ifdef INT0_vect +# define USB_INTR_VECTOR INT0_vect // this is the "new" define for the vector +# else +# define USB_INTR_VECTOR SIG_INTERRUPT0 // this is the "old" vector +# endif +# endif + .text + .global USB_INTR_VECTOR + .type USB_INTR_VECTOR, @function + .global usbCrc16 + .global usbCrc16Append +#endif /* __IAR_SYSTEMS_ASM__ */ + + +#if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */ +# define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING +# define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg +#else /* It's a memory address, use lds and sts */ +# define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING +# define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg +#endif + +#define usbTxLen1 usbTxStatus1 +#define usbTxBuf1 (usbTxStatus1 + 1) +#define usbTxLen3 usbTxStatus3 +#define usbTxBuf3 (usbTxStatus3 + 1) + + +;---------------------------------------------------------------------------- +; Utility functions +;---------------------------------------------------------------------------- + +#ifdef __IAR_SYSTEMS_ASM__ +/* Register assignments for usbCrc16 on IAR cc */ +/* Calling conventions on IAR: + * First parameter passed in r16/r17, second in r18/r19 and so on. + * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) + * Result is passed in r16/r17 + * In case of the "tiny" memory model, pointers are only 8 bit with no + * padding. We therefore pass argument 1 as "16 bit unsigned". + */ +RTMODEL "__rt_version", "3" +/* The line above will generate an error if cc calling conventions change. + * The value "3" above is valid for IAR 4.10B/W32 + */ +# define argLen r18 /* argument 2 */ +# define argPtrL r16 /* argument 1 */ +# define argPtrH r17 /* argument 1 */ + +# define resCrcL r16 /* result */ +# define resCrcH r17 /* result */ + +# define ptrL ZL +# define ptrH ZH +# define ptr Z +# define byte r22 +# define bitCnt r19 +# define polyL r20 +# define polyH r21 +# define scratch r23 + +#else /* __IAR_SYSTEMS_ASM__ */ +/* Register assignments for usbCrc16 on gcc */ +/* Calling conventions on gcc: + * First parameter passed in r24/r25, second in r22/23 and so on. + * Callee must preserve r1-r17, r28/r29 + * Result is passed in r24/r25 + */ +# define argLen r22 /* argument 2 */ +# define argPtrL r24 /* argument 1 */ +# define argPtrH r25 /* argument 1 */ + +# define resCrcL r24 /* result */ +# define resCrcH r25 /* result */ + +# define ptrL XL +# define ptrH XH +# define ptr x +# define byte r18 +# define bitCnt r19 +# define polyL r20 +# define polyH r21 +# define scratch r23 + +#endif + + +#if USB_USE_FAST_CRC + +; This implementation is faster, but has bigger code size +; This version has been optimized in size compared to the original +; fast CRC by Shay Green, January 2014. + +; Thanks to Slawomir Fras (BoskiDialer) for the original contribution. +; It implements the following C pseudo-code: +; unsigned table(unsigned char x) +; { +; unsigned value; +; +; value = (unsigned)x << 6; +; value ^= (unsigned)x << 7; +; if(parity(x)) +; value ^= 0xc001; +; return value; +; } +; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen) +; { +; unsigned crc = 0xffff; +; +; while(argLen--) +; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc); +; return ~crc; +; } + +; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); +; argPtr r24+25 / r16+r17 +; argLen r22 / r18 +; temp variables: +; byte r18 / r22 +; scratch r23 +; resCrc r24+r25 / r16+r17 +; ptr X / Z + +usbCrc16: + movw ptrL, argPtrL + ldi resCrcL, 0xFF + ldi resCrcH, 0xFF + clr bitCnt ; zero + rjmp usbCrc16LoopTest +usbCrc16ByteLoop: + ld byte, ptr+ + eor byte, resCrcL ; scratch is now 'x' in table() + mov scratch, byte ; compute parity of 'x' + swap byte + eor byte, scratch + mov resCrcL, byte + lsr byte + lsr byte + eor byte, resCrcL + inc byte + andi byte, 2 ; byte is now parity(x) << 1 + cp bitCnt, byte ; c = (byte != 0), then put in high bit + ror scratch ; so that after xoring, shifting, and xoring, it gives + ror byte ; the desired 0xC0 with resCrcH + mov resCrcL, byte + eor resCrcL, resCrcH + mov resCrcH, scratch + lsr scratch + ror byte + eor resCrcH, scratch + eor resCrcL, byte +usbCrc16LoopTest: + subi argLen, 1 + brsh usbCrc16ByteLoop + com resCrcL + com resCrcH + ret + +#else // USB_USE_FAST_CRC + +; This implementation is slower, but has less code size +; +; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); +; argPtr r24+25 / r16+r17 +; argLen r22 / r18 +; temp variables: +; byte r18 / r22 +; bitCnt r19 +; poly r20+r21 +; scratch r23 +; resCrc r24+r25 / r16+r17 +; ptr X / Z +usbCrc16: + mov ptrL, argPtrL + mov ptrH, argPtrH + ldi resCrcL, 0 + ldi resCrcH, 0 + ldi polyL, lo8(0xa001) + ldi polyH, hi8(0xa001) + com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set + ldi bitCnt, 0 ; loop counter with starnd condition = end condition + rjmp usbCrcLoopEntry +usbCrcByteLoop: + ld byte, ptr+ + eor resCrcL, byte +usbCrcBitLoop: + ror resCrcH ; carry is always set here (see brcs jumps to here) + ror resCrcL + brcs usbCrcNoXor + eor resCrcL, polyL + eor resCrcH, polyH +usbCrcNoXor: + subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times + brcs usbCrcBitLoop +usbCrcLoopEntry: + subi argLen, -1 + brcs usbCrcByteLoop +usbCrcReady: + ret +; Thanks to Reimar Doeffinger for optimizing this CRC routine! + +#endif // USB_USE_FAST_CRC + +; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len); +usbCrc16Append: + rcall usbCrc16 + st ptr+, resCrcL + st ptr+, resCrcH + ret + +#undef argLen +#undef argPtrL +#undef argPtrH +#undef resCrcL +#undef resCrcH +#undef ptrL +#undef ptrH +#undef ptr +#undef byte +#undef bitCnt +#undef polyL +#undef polyH +#undef scratch + + +#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH +#ifdef __IAR_SYSTEMS_ASM__ +/* Register assignments for usbMeasureFrameLength on IAR cc */ +/* Calling conventions on IAR: + * First parameter passed in r16/r17, second in r18/r19 and so on. + * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) + * Result is passed in r16/r17 + * In case of the "tiny" memory model, pointers are only 8 bit with no + * padding. We therefore pass argument 1 as "16 bit unsigned". + */ +# define resL r16 +# define resH r17 +# define cnt16L r30 +# define cnt16H r31 +# define cntH r18 + +#else /* __IAR_SYSTEMS_ASM__ */ +/* Register assignments for usbMeasureFrameLength on gcc */ +/* Calling conventions on gcc: + * First parameter passed in r24/r25, second in r22/23 and so on. + * Callee must preserve r1-r17, r28/r29 + * Result is passed in r24/r25 + */ +# define resL r24 +# define resH r25 +# define cnt16L r24 +# define cnt16H r25 +# define cntH r26 +#endif +# define cnt16 cnt16L + +; extern unsigned usbMeasurePacketLength(void); +; returns time between two idle strobes in multiples of 7 CPU clocks +.global usbMeasureFrameLength +usbMeasureFrameLength: + ldi cntH, 6 ; wait ~ 10 ms for D- == 0 + clr cnt16L + clr cnt16H +usbMFTime16: + dec cntH + breq usbMFTimeout +usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe) + sbiw cnt16, 1 ;[0] [6] + breq usbMFTime16 ;[2] + sbic USBIN, USBMINUS ;[3] + rjmp usbMFWaitStrobe ;[4] +usbMFWaitIdle: ; then wait until idle again + sbis USBIN, USBMINUS ;1 wait for D- == 1 + rjmp usbMFWaitIdle ;2 + ldi cnt16L, 1 ;1 represents cycles so far + clr cnt16H ;1 +usbMFWaitLoop: + in cntH, USBIN ;[0] [7] + adiw cnt16, 1 ;[1] + breq usbMFTimeout ;[3] + andi cntH, USBMASK ;[4] + brne usbMFWaitLoop ;[5] +usbMFTimeout: +#if resL != cnt16L + mov resL, cnt16L + mov resH, cnt16H +#endif + ret + +#undef resL +#undef resH +#undef cnt16 +#undef cnt16L +#undef cnt16H +#undef cntH + +#endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */ + +;---------------------------------------------------------------------------- +; Now include the clock rate specific code +;---------------------------------------------------------------------------- + +#ifndef USB_CFG_CLOCK_KHZ +# ifdef F_CPU +# define USB_CFG_CLOCK_KHZ (F_CPU/1000) +# else +# error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!" +# endif +#endif + +#if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */ +# if USB_CFG_CLOCK_KHZ == 18000 +# include "usbdrvasm18-crc.inc" +# else +# error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!" +# endif +#else /* USB_CFG_CHECK_CRC */ +# if USB_CFG_CLOCK_KHZ == 12000 +# include "usbdrvasm12.inc" +# elif USB_CFG_CLOCK_KHZ == 12800 +# include "usbdrvasm128.inc" +# elif USB_CFG_CLOCK_KHZ == 15000 +# include "usbdrvasm15.inc" +# elif USB_CFG_CLOCK_KHZ == 16000 +# include "usbdrvasm16.inc" +# elif USB_CFG_CLOCK_KHZ == 16500 +# include "usbdrvasm165.inc" +# elif USB_CFG_CLOCK_KHZ == 20000 +# include "usbdrvasm20.inc" +# else +# error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!" +# endif +#endif /* USB_CFG_CHECK_CRC */ diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.asm b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.asm new file mode 100644 index 00000000..fb669343 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.asm @@ -0,0 +1,20 @@ +/* Name: usbdrvasm.asm + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2006-03-01 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +The IAR compiler/assembler system prefers assembler files with file extension +".asm". We simply provide this file as an alias for usbdrvasm.S. + +Thanks to Oleg Semyonov for his help with the IAR tools port! +*/ + +#include "usbdrvasm.S" + +end diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.o b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.o new file mode 100644 index 00000000..06dad446 Binary files /dev/null and b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm.o differ diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm12.inc b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm12.inc new file mode 100644 index 00000000..d3bd0567 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm12.inc @@ -0,0 +1,392 @@ +/* Name: usbdrvasm12.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 12 MHz version of the asssembler part of the USB driver. It +requires a 12 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! + + +Timing constraints according to spec (in bit times): +timing subject min max CPUcycles +--------------------------------------------------------------------------- +EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2 16 16-128 +EOP of IN to sync pattern of DATA0 (rx, then tx) 2 7.5 16-60 +DATAx (rx) to ACK/NAK/STALL (tx) 2 7.5 16-60 +*/ + +;Software-receiver engine. Strict timing! Don't change unless you can preserve timing! +;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled +;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable +;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes +;Numbers in brackets are maximum cycles since SOF. +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt + push YL ;2 [35] push only what is necessary to sync with edge ASAP + in YL, SREG ;1 [37] + push YL ;2 [39] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push YH ;2 [2] + lds YL, usbInputBufOffset;2 [4] + clr YH ;1 [5] + subi YL, lo8(-(usbRxBuf));1 [6] + sbci YH, hi8(-(usbRxBuf));1 [7] + + sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early] + rjmp haveTwoBitsK ;2 [10] + pop YH ;2 [11] undo the push from before + rjmp waitForK ;2 [13] this was not the end of sync, retry +haveTwoBitsK: +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- + push shift ;2 [16] + push x1 ;2 [12] + push x2 ;2 [14] + + in x1, USBIN ;1 [17] <-- sample bit 0 + ldi shift, 0xff ;1 [18] + bst x1, USBMINUS ;1 [19] + bld shift, 0 ;1 [20] + push x3 ;2 [22] + push cnt ;2 [24] + + in x2, USBIN ;1 [25] <-- sample bit 1 + ser x3 ;1 [26] [inserted init instruction] + eor x1, x2 ;1 [27] + bst x1, USBMINUS ;1 [28] + bld shift, 1 ;1 [29] + ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction] + rjmp rxbit2 ;2 [32] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- + +unstuff0: ;1 (branch taken) + andi x3, ~0x01 ;1 [15] + mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit + in x2, USBIN ;1 [17] <-- sample bit 1 again + ori shift, 0x01 ;1 [18] + rjmp didUnstuff0 ;2 [20] + +unstuff1: ;1 (branch taken) + mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit + andi x3, ~0x02 ;1 [22] + ori shift, 0x02 ;1 [23] + nop ;1 [24] + in x1, USBIN ;1 [25] <-- sample bit 2 again + rjmp didUnstuff1 ;2 [27] + +unstuff2: ;1 (branch taken) + andi x3, ~0x04 ;1 [29] + ori shift, 0x04 ;1 [30] + mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit + nop ;1 [32] + in x2, USBIN ;1 [33] <-- sample bit 3 + rjmp didUnstuff2 ;2 [35] + +unstuff3: ;1 (branch taken) + in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late] + andi x3, ~0x08 ;1 [35] + ori shift, 0x08 ;1 [36] + rjmp didUnstuff3 ;2 [38] + +unstuff4: ;1 (branch taken) + andi x3, ~0x10 ;1 [40] + in x1, USBIN ;1 [41] <-- sample stuffed bit 4 + ori shift, 0x10 ;1 [42] + rjmp didUnstuff4 ;2 [44] + +unstuff5: ;1 (branch taken) + andi x3, ~0x20 ;1 [48] + in x2, USBIN ;1 [49] <-- sample stuffed bit 5 + ori shift, 0x20 ;1 [50] + rjmp didUnstuff5 ;2 [52] + +unstuff6: ;1 (branch taken) + andi x3, ~0x40 ;1 [56] + in x1, USBIN ;1 [57] <-- sample stuffed bit 6 + ori shift, 0x40 ;1 [58] + rjmp didUnstuff6 ;2 [60] + +; extra jobs done during bit interval: +; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs] +; bit 1: se0 check +; bit 2: overflow check +; bit 3: recovery from delay [bit 0 tasks took too long] +; bit 4: none +; bit 5: none +; bit 6: none +; bit 7: jump, eor +rxLoop: + eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others + in x1, USBIN ;1 [1] <-- sample bit 0 + st y+, x3 ;2 [3] store data + ser x3 ;1 [4] + nop ;1 [5] + eor x2, x1 ;1 [6] + bst x2, USBMINUS;1 [7] + bld shift, 0 ;1 [8] + in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed) + andi x2, USBMASK ;1 [10] + breq se0 ;1 [11] SE0 check for bit 1 + andi shift, 0xf9 ;1 [12] +didUnstuff0: + breq unstuff0 ;1 [13] + eor x1, x2 ;1 [14] + bst x1, USBMINUS;1 [15] + bld shift, 1 ;1 [16] +rxbit2: + in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed) + andi shift, 0xf3 ;1 [18] + breq unstuff1 ;1 [19] do remaining work for bit 1 +didUnstuff1: + subi cnt, 1 ;1 [20] + brcs overflow ;1 [21] loop control + eor x2, x1 ;1 [22] + bst x2, USBMINUS;1 [23] + bld shift, 2 ;1 [24] + in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed) + andi shift, 0xe7 ;1 [26] + breq unstuff2 ;1 [27] +didUnstuff2: + eor x1, x2 ;1 [28] + bst x1, USBMINUS;1 [29] + bld shift, 3 ;1 [30] +didUnstuff3: + andi shift, 0xcf ;1 [31] + breq unstuff3 ;1 [32] + in x1, USBIN ;1 [33] <-- sample bit 4 + eor x2, x1 ;1 [34] + bst x2, USBMINUS;1 [35] + bld shift, 4 ;1 [36] +didUnstuff4: + andi shift, 0x9f ;1 [37] + breq unstuff4 ;1 [38] + nop2 ;2 [40] + in x2, USBIN ;1 [41] <-- sample bit 5 + eor x1, x2 ;1 [42] + bst x1, USBMINUS;1 [43] + bld shift, 5 ;1 [44] +didUnstuff5: + andi shift, 0x3f ;1 [45] + breq unstuff5 ;1 [46] + nop2 ;2 [48] + in x1, USBIN ;1 [49] <-- sample bit 6 + eor x2, x1 ;1 [50] + bst x2, USBMINUS;1 [51] + bld shift, 6 ;1 [52] +didUnstuff6: + cpi shift, 0x02 ;1 [53] + brlo unstuff6 ;1 [54] + nop2 ;2 [56] + in x2, USBIN ;1 [57] <-- sample bit 7 + eor x1, x2 ;1 [58] + bst x1, USBMINUS;1 [59] + bld shift, 7 ;1 [60] +didUnstuff7: + cpi shift, 0x04 ;1 [61] + brsh rxLoop ;2 [63] loop control +unstuff7: + andi x3, ~0x80 ;1 [63] + ori shift, 0x80 ;1 [64] + in x2, USBIN ;1 [65] <-- sample stuffed bit 7 + nop ;1 [66] + rjmp didUnstuff7 ;2 [68] + +macro POP_STANDARD ; 12 cycles + pop cnt + pop x3 + pop x2 + pop x1 + pop shift + pop YH + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +;---------------------------------------------------------------------------- +; Transmitting data +;---------------------------------------------------------------------------- + +txByteLoop: +txBitloop: +stuffN1Delay: ; [03] + ror shift ;[-5] [11] [59] + brcc doExorN1 ;[-4] [60] + subi x4, 1 ;[-3] + brne commonN1 ;[-2] + lsl shift ;[-1] compensate ror after rjmp stuffDelay + nop ;[00] stuffing consists of just waiting 8 cycles + rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear + +sendNakAndReti: ;0 [-19] 19 cycles until SOP + ldi x3, USBPID_NAK ;1 [-18] + rjmp usbSendX3 ;2 [-16] +sendAckAndReti: ;0 [-19] 19 cycles until SOP + ldi x3, USBPID_ACK ;1 [-18] + rjmp usbSendX3 ;2 [-16] +sendCntAndReti: ;0 [-17] 17 cycles until SOP + mov x3, cnt ;1 [-16] +usbSendX3: ;0 [-16] + ldi YL, 20 ;1 [-15] 'x3' is R20 + ldi YH, 0 ;1 [-14] + ldi cnt, 2 ;1 [-13] +; rjmp usbSendAndReti fallthrough + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 +; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 +; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte +;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt] +;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) +usbSendAndReti: + in x2, USBDDR ;[-12] 12 cycles until SOP + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + out USBDDR, x2 ;[-8] <--- acquire bus + in x1, USBOUT ;[-7] port mirror for tx loop + ldi shift, 0x40 ;[-6] sync byte is first byte sent (we enter loop after ror) + ldi x2, USBMASK ;[-5] + push x4 ;[-4] +doExorN1: + eor x1, x2 ;[-2] [06] [62] + ldi x4, 6 ;[-1] [07] [63] +commonN1: +stuffN2Delay: + out USBOUT, x1 ;[00] [08] [64] <--- set bit + ror shift ;[01] + brcc doExorN2 ;[02] + subi x4, 1 ;[03] + brne commonN2 ;[04] + lsl shift ;[05] compensate ror after rjmp stuffDelay + rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear +doExorN2: + eor x1, x2 ;[04] [12] + ldi x4, 6 ;[05] [13] +commonN2: + nop ;[06] [14] + subi cnt, 171 ;[07] [15] trick: (3 * 171) & 0xff = 1 + out USBOUT, x1 ;[08] [16] <--- set bit + brcs txBitloop ;[09] [25] [41] + +stuff6Delay: + ror shift ;[42] [50] + brcc doExor6 ;[43] + subi x4, 1 ;[44] + brne common6 ;[45] + lsl shift ;[46] compensate ror after rjmp stuffDelay + nop ;[47] stuffing consists of just waiting 8 cycles + rjmp stuff6Delay ;[48] after ror, C bit is reliably clear +doExor6: + eor x1, x2 ;[45] [53] + ldi x4, 6 ;[46] +common6: +stuff7Delay: + ror shift ;[47] [55] + out USBOUT, x1 ;[48] <--- set bit + brcc doExor7 ;[49] + subi x4, 1 ;[50] + brne common7 ;[51] + lsl shift ;[52] compensate ror after rjmp stuffDelay + rjmp stuff7Delay ;[53] after ror, C bit is reliably clear +doExor7: + eor x1, x2 ;[51] [59] + ldi x4, 6 ;[52] +common7: + ld shift, y+ ;[53] + tst cnt ;[55] + out USBOUT, x1 ;[56] <--- set bit + brne txByteLoop ;[57] + +;make SE0: + cbr x1, USBMASK ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles] + lds x2, usbNewDeviceAddr;[59] + lsl x2 ;[61] we compare with left shifted address + subi YL, 2 + 20 ;[62] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;[63] + out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[01] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 12.5625 MHz +max frequency: 69.286 cycles for 8 bit -> 12.99 MHz +nominal frequency: 12.77 MHz ( = sqrt(min * max)) + +sampling positions: (next even number in range [+/- 0.5]) +cycle index range: 0 ... 66 +bits: +.5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125 +[0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59] + +bit number: 0 1 2 3 4 5 6 7 +spare cycles 1 2 1 2 1 1 1 0 + +operations to perform: duration cycle + ---------------- + eor fix, shift 1 -> 00 + andi phase, USBMASK 1 -> 08 + breq se0 1 -> 16 (moved to 11) + st y+, data 2 -> 24, 25 + mov data, fix 1 -> 33 + ser data 1 -> 41 + subi cnt, 1 1 -> 49 + brcs overflow 1 -> 50 + +layout of samples and operations: +[##] = sample bit +<##> = sample phase +*##* = operation + +0: *00* [01] 02 03 04 <05> 06 07 +1: *08* [09] 10 11 12 <13> 14 15 *16* +2: [17] 18 19 20 <21> 22 23 +3: *24* *25* [26] 27 28 29 <30> 31 32 +4: *33* [34] 35 36 37 <38> 39 40 +5: *41* [42] 43 44 45 <46> 47 48 +6: *49* *50* [51] 52 53 54 <55> 56 57 58 +7: [59] 60 61 62 <63> 64 65 66 +*****************************************************************************/ + +/* we prefer positive expressions (do if condition) instead of negative + * (skip if condition), therefore use defines for skip instructions: + */ +#define ifioclr sbis +#define ifioset sbic +#define ifrclr sbrs +#define ifrset sbrc + +/* The registers "fix" and "data" swap their meaning during the loop. Use + * defines to keep their name constant. + */ +#define fix x2 +#define data x1 +#undef phase /* phase has a default definition to x4 */ +#define phase x3 + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0 + push YL ;2 push only what is necessary to sync with edge ASAP + in YL, SREG ;1 + push YL ;2 +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS ;[0] + rjmp foundK ;[1] +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError + +foundK: +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push YH ;[2] + lds YL, usbInputBufOffset;[4] + clr YH ;[6] + subi YL, lo8(-(usbRxBuf));[7] + sbci YH, hi8(-(usbRxBuf));[8] + + sbis USBIN, USBMINUS ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5] + rjmp haveTwoBitsK ;[10] + pop YH ;[11] undo the push from before + rjmp waitForK ;[13] this was not the end of sync, retry +haveTwoBitsK: +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +#define fix x2 +#define data x1 + + push shift ;[12] + push x1 ;[14] + push x2 ;[16] + ldi shift, 0x80 ;[18] prevent bit-unstuffing but init low bits to 0 + ifioset USBIN, USBMINUS ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5] + ori shift, 1<<0 ;[02] + push x3 ;[03] + push cnt ;[05] + push r0 ;[07] + ifioset USBIN, USBMINUS ;[09] <--- bit 1 + ori shift, 1<<1 ;[10] + ser fix ;[11] + ldi cnt, USB_BUFSIZE ;[12] + mov data, shift ;[13] + lsl shift ;[14] + nop2 ;[15] + ifioset USBIN, USBMINUS ;[17] <--- bit 2 + ori data, 3<<2 ;[18] store in bit 2 AND bit 3 + eor shift, data ;[19] do nrzi decoding + andi data, 1<<3 ;[20] + in phase, USBIN ;[21] <- phase + brne jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1 + nop ;[23] + rjmp entryAfterClr ;[24] +jumpToEntryAfterSet: + rjmp entryAfterSet ;[24] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- +#undef fix +#define fix x1 +#undef data +#define data x2 + +bit7IsSet: + ifrclr phase, USBMINUS ;[62] check phase only if D- changed + lpm ;[63] + in phase, USBIN ;[64] <- phase (one cycle too late) + ori shift, 1 << 7 ;[65] + nop ;[66] +;;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jump +bit0AfterSet: + eor fix, shift ;[00] +#undef fix +#define fix x2 +#undef data +#define data x1 /* we now have result in data, fix is reset to 0xff */ + ifioclr USBIN, USBMINUS ;[01] <--- sample 0 + rjmp bit0IsClr ;[02] + andi shift, ~(7 << 0) ;[03] + breq unstuff0s ;[04] + in phase, USBIN ;[05] <- phase + rjmp bit1AfterSet ;[06] +unstuff0s: + in phase, USBIN ;[06] <- phase (one cycle too late) + andi fix, ~(1 << 0) ;[07] + ifioclr USBIN, USBMINUS ;[00] + ifioset USBIN, USBPLUS ;[01] + rjmp bit0IsClr ;[02] executed if first expr false or second true +se0AndStore: ; executed only if both bits 0 + st y+, x1 ;[15/17] cycles after start of byte + rjmp se0 ;[17/19] + +bit0IsClr: + ifrset phase, USBMINUS ;[04] check phase only if D- changed + lpm ;[05] + in phase, USBIN ;[06] <- phase (one cycle too late) + ori shift, 1 << 0 ;[07] +bit1AfterClr: + andi phase, USBMASK ;[08] + ifioset USBIN, USBMINUS ;[09] <--- sample 1 + rjmp bit1IsSet ;[10] + breq se0AndStore ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0 + andi shift, ~(7 << 1) ;[12] + in phase, USBIN ;[13] <- phase + breq unstuff1c ;[14] + rjmp bit2AfterClr ;[15] +unstuff1c: + andi fix, ~(1 << 1) ;[16] + nop2 ;[08] + nop2 ;[10] +bit1IsSet: + ifrclr phase, USBMINUS ;[12] check phase only if D- changed + lpm ;[13] + in phase, USBIN ;[14] <- phase (one cycle too late) + ori shift, 1 << 1 ;[15] + nop ;[16] +bit2AfterSet: + ifioclr USBIN, USBMINUS ;[17] <--- sample 2 + rjmp bit2IsClr ;[18] + andi shift, ~(7 << 2) ;[19] + breq unstuff2s ;[20] + in phase, USBIN ;[21] <- phase + rjmp bit3AfterSet ;[22] +unstuff2s: + in phase, USBIN ;[22] <- phase (one cycle too late) + andi fix, ~(1 << 2) ;[23] + nop2 ;[16] + nop2 ;[18] +bit2IsClr: + ifrset phase, USBMINUS ;[20] check phase only if D- changed + lpm ;[21] + in phase, USBIN ;[22] <- phase (one cycle too late) + ori shift, 1 << 2 ;[23] +bit3AfterClr: + st y+, data ;[24] +entryAfterClr: + ifioset USBIN, USBMINUS ;[26] <--- sample 3 + rjmp bit3IsSet ;[27] + andi shift, ~(7 << 3) ;[28] + breq unstuff3c ;[29] + in phase, USBIN ;[30] <- phase + rjmp bit4AfterClr ;[31] +unstuff3c: + in phase, USBIN ;[31] <- phase (one cycle too late) + andi fix, ~(1 << 3) ;[32] + nop2 ;[25] + nop2 ;[27] +bit3IsSet: + ifrclr phase, USBMINUS ;[29] check phase only if D- changed + lpm ;[30] + in phase, USBIN ;[31] <- phase (one cycle too late) + ori shift, 1 << 3 ;[32] +bit4AfterSet: + mov data, fix ;[33] undo this move by swapping defines +#undef fix +#define fix x1 +#undef data +#define data x2 + ifioclr USBIN, USBMINUS ;[34] <--- sample 4 + rjmp bit4IsClr ;[35] + andi shift, ~(7 << 4) ;[36] + breq unstuff4s ;[37] + in phase, USBIN ;[38] <- phase + rjmp bit5AfterSet ;[39] +unstuff4s: + in phase, USBIN ;[39] <- phase (one cycle too late) + andi fix, ~(1 << 4) ;[40] + nop2 ;[33] + nop2 ;[35] +bit4IsClr: + ifrset phase, USBMINUS ;[37] check phase only if D- changed + lpm ;[38] + in phase, USBIN ;[39] <- phase (one cycle too late) + ori shift, 1 << 4 ;[40] +bit5AfterClr: + ser data ;[41] + ifioset USBIN, USBMINUS ;[42] <--- sample 5 + rjmp bit5IsSet ;[43] + andi shift, ~(7 << 5) ;[44] + breq unstuff5c ;[45] + in phase, USBIN ;[46] <- phase + rjmp bit6AfterClr ;[47] +unstuff5c: + in phase, USBIN ;[47] <- phase (one cycle too late) + andi fix, ~(1 << 5) ;[48] + nop2 ;[41] + nop2 ;[43] +bit5IsSet: + ifrclr phase, USBMINUS ;[45] check phase only if D- changed + lpm ;[46] + in phase, USBIN ;[47] <- phase (one cycle too late) + ori shift, 1 << 5 ;[48] +bit6AfterSet: + subi cnt, 1 ;[49] + brcs jumpToOverflow ;[50] + ifioclr USBIN, USBMINUS ;[51] <--- sample 6 + rjmp bit6IsClr ;[52] + andi shift, ~(3 << 6) ;[53] + cpi shift, 2 ;[54] + in phase, USBIN ;[55] <- phase + brlt unstuff6s ;[56] + rjmp bit7AfterSet ;[57] + +jumpToOverflow: + rjmp overflow + +unstuff6s: + andi fix, ~(1 << 6) ;[50] + lpm ;[51] +bit6IsClr: + ifrset phase, USBMINUS ;[54] check phase only if D- changed + lpm ;[55] + in phase, USBIN ;[56] <- phase (one cycle too late) + ori shift, 1 << 6 ;[57] + nop ;[58] +bit7AfterClr: + ifioset USBIN, USBMINUS ;[59] <--- sample 7 + rjmp bit7IsSet ;[60] + andi shift, ~(1 << 7) ;[61] + cpi shift, 4 ;[62] + in phase, USBIN ;[63] <- phase + brlt unstuff7c ;[64] + rjmp bit0AfterClr ;[65] -> [00] == [67] +unstuff7c: + andi fix, ~(1 << 7) ;[58] + nop ;[59] + rjmp bit7IsSet ;[60] + +bit7IsClr: + ifrset phase, USBMINUS ;[62] check phase only if D- changed + lpm ;[63] + in phase, USBIN ;[64] <- phase (one cycle too late) + ori shift, 1 << 7 ;[65] + nop ;[66] +;;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jump +bit0AfterClr: + eor fix, shift ;[00] +#undef fix +#define fix x2 +#undef data +#define data x1 /* we now have result in data, fix is reset to 0xff */ + ifioset USBIN, USBMINUS ;[01] <--- sample 0 + rjmp bit0IsSet ;[02] + andi shift, ~(7 << 0) ;[03] + breq unstuff0c ;[04] + in phase, USBIN ;[05] <- phase + rjmp bit1AfterClr ;[06] +unstuff0c: + in phase, USBIN ;[06] <- phase (one cycle too late) + andi fix, ~(1 << 0) ;[07] + ifioclr USBIN, USBMINUS ;[00] + ifioset USBIN, USBPLUS ;[01] + rjmp bit0IsSet ;[02] executed if first expr false or second true + rjmp se0AndStore ;[03] executed only if both bits 0 +bit0IsSet: + ifrclr phase, USBMINUS ;[04] check phase only if D- changed + lpm ;[05] + in phase, USBIN ;[06] <- phase (one cycle too late) + ori shift, 1 << 0 ;[07] +bit1AfterSet: + andi shift, ~(7 << 1) ;[08] compensated by "ori shift, 1<<1" if bit1IsClr + ifioclr USBIN, USBMINUS ;[09] <--- sample 1 + rjmp bit1IsClr ;[10] + breq unstuff1s ;[11] + nop2 ;[12] do not check for SE0 if bit 0 was 1 + in phase, USBIN ;[14] <- phase (one cycle too late) + rjmp bit2AfterSet ;[15] +unstuff1s: + in phase, USBIN ;[13] <- phase + andi fix, ~(1 << 1) ;[14] + lpm ;[07] + nop2 ;[10] +bit1IsClr: + ifrset phase, USBMINUS ;[12] check phase only if D- changed + lpm ;[13] + in phase, USBIN ;[14] <- phase (one cycle too late) + ori shift, 1 << 1 ;[15] + nop ;[16] +bit2AfterClr: + ifioset USBIN, USBMINUS ;[17] <--- sample 2 + rjmp bit2IsSet ;[18] + andi shift, ~(7 << 2) ;[19] + breq unstuff2c ;[20] + in phase, USBIN ;[21] <- phase + rjmp bit3AfterClr ;[22] +unstuff2c: + in phase, USBIN ;[22] <- phase (one cycle too late) + andi fix, ~(1 << 2) ;[23] + nop2 ;[16] + nop2 ;[18] +bit2IsSet: + ifrclr phase, USBMINUS ;[20] check phase only if D- changed + lpm ;[21] + in phase, USBIN ;[22] <- phase (one cycle too late) + ori shift, 1 << 2 ;[23] +bit3AfterSet: + st y+, data ;[24] +entryAfterSet: + ifioclr USBIN, USBMINUS ;[26] <--- sample 3 + rjmp bit3IsClr ;[27] + andi shift, ~(7 << 3) ;[28] + breq unstuff3s ;[29] + in phase, USBIN ;[30] <- phase + rjmp bit4AfterSet ;[31] +unstuff3s: + in phase, USBIN ;[31] <- phase (one cycle too late) + andi fix, ~(1 << 3) ;[32] + nop2 ;[25] + nop2 ;[27] +bit3IsClr: + ifrset phase, USBMINUS ;[29] check phase only if D- changed + lpm ;[30] + in phase, USBIN ;[31] <- phase (one cycle too late) + ori shift, 1 << 3 ;[32] +bit4AfterClr: + mov data, fix ;[33] undo this move by swapping defines +#undef fix +#define fix x1 +#undef data +#define data x2 + ifioset USBIN, USBMINUS ;[34] <--- sample 4 + rjmp bit4IsSet ;[35] + andi shift, ~(7 << 4) ;[36] + breq unstuff4c ;[37] + in phase, USBIN ;[38] <- phase + rjmp bit5AfterClr ;[39] +unstuff4c: + in phase, USBIN ;[39] <- phase (one cycle too late) + andi fix, ~(1 << 4) ;[40] + nop2 ;[33] + nop2 ;[35] +bit4IsSet: + ifrclr phase, USBMINUS ;[37] check phase only if D- changed + lpm ;[38] + in phase, USBIN ;[39] <- phase (one cycle too late) + ori shift, 1 << 4 ;[40] +bit5AfterSet: + ser data ;[41] + ifioclr USBIN, USBMINUS ;[42] <--- sample 5 + rjmp bit5IsClr ;[43] + andi shift, ~(7 << 5) ;[44] + breq unstuff5s ;[45] + in phase, USBIN ;[46] <- phase + rjmp bit6AfterSet ;[47] +unstuff5s: + in phase, USBIN ;[47] <- phase (one cycle too late) + andi fix, ~(1 << 5) ;[48] + nop2 ;[41] + nop2 ;[43] +bit5IsClr: + ifrset phase, USBMINUS ;[45] check phase only if D- changed + lpm ;[46] + in phase, USBIN ;[47] <- phase (one cycle too late) + ori shift, 1 << 5 ;[48] +bit6AfterClr: + subi cnt, 1 ;[49] + brcs overflow ;[50] + ifioset USBIN, USBMINUS ;[51] <--- sample 6 + rjmp bit6IsSet ;[52] + andi shift, ~(3 << 6) ;[53] + cpi shift, 2 ;[54] + in phase, USBIN ;[55] <- phase + brlt unstuff6c ;[56] + rjmp bit7AfterClr ;[57] +unstuff6c: + andi fix, ~(1 << 6) ;[50] + lpm ;[51] +bit6IsSet: + ifrclr phase, USBMINUS ;[54] check phase only if D- changed + lpm ;[55] + in phase, USBIN ;[56] <- phase (one cycle too late) + ori shift, 1 << 6 ;[57] +bit7AfterSet: + ifioclr USBIN, USBMINUS ;[59] <--- sample 7 + rjmp bit7IsClr ;[60] + andi shift, ~(1 << 7) ;[61] + cpi shift, 4 ;[62] + in phase, USBIN ;[63] <- phase + brlt unstuff7s ;[64] + rjmp bit0AfterSet ;[65] -> [00] == [67] +unstuff7s: + andi fix, ~(1 << 7) ;[58] + nop ;[59] + rjmp bit7IsClr ;[60] + +macro POP_STANDARD ; 14 cycles + pop r0 + pop cnt + pop x3 + pop x2 + pop x1 + pop shift + pop YH + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +;---------------------------------------------------------------------------- +; Transmitting data +;---------------------------------------------------------------------------- + +txByteLoop: +txBitloop: +stuffN1Delay: ; [03] + ror shift ;[-5] [11] [63] + brcc doExorN1 ;[-4] [64] + subi x3, 1 ;[-3] + brne commonN1 ;[-2] + lsl shift ;[-1] compensate ror after rjmp stuffDelay + nop ;[00] stuffing consists of just waiting 8 cycles + rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear + +sendNakAndReti: + ldi cnt, USBPID_NAK ;[-19] + rjmp sendCntAndReti ;[-18] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov r0, cnt ;[-16] + ldi YL, 0 ;[-15] R0 address is 0 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 +; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 +; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte +;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt] +;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) +usbSendAndReti: + in x2, USBDDR ;[-10] 10 cycles until SOP + ori x2, USBMASK ;[-9] + sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups) + out USBDDR, x2 ;[-6] <--- acquire bus + in x1, USBOUT ;[-5] port mirror for tx loop + ldi shift, 0x40 ;[-4] sync byte is first byte sent (we enter loop after ror) + ldi x2, USBMASK ;[-3] +doExorN1: + eor x1, x2 ;[-2] [06] [62] + ldi x3, 6 ;[-1] [07] [63] +commonN1: +stuffN2Delay: + out USBOUT, x1 ;[00] [08] [64] <--- set bit + ror shift ;[01] + brcc doExorN2 ;[02] + subi x3, 1 ;[03] + brne commonN2 ;[04] + lsl shift ;[05] compensate ror after rjmp stuffDelay + rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear +doExorN2: + eor x1, x2 ;[04] [12] + ldi x3, 6 ;[05] [13] +commonN2: + nop2 ;[06] [14] + subi cnt, 171 ;[08] [16] trick: (3 * 171) & 0xff = 1 + out USBOUT, x1 ;[09] [17] <--- set bit + brcs txBitloop ;[10] [27] [44] + +stuff6Delay: + ror shift ;[45] [53] + brcc doExor6 ;[46] + subi x3, 1 ;[47] + brne common6 ;[48] + lsl shift ;[49] compensate ror after rjmp stuffDelay + nop ;[50] stuffing consists of just waiting 8 cycles + rjmp stuff6Delay ;[51] after ror, C bit is reliably clear +doExor6: + eor x1, x2 ;[48] [56] + ldi x3, 6 ;[49] +common6: +stuff7Delay: + ror shift ;[50] [58] + out USBOUT, x1 ;[51] <--- set bit + brcc doExor7 ;[52] + subi x3, 1 ;[53] + brne common7 ;[54] + lsl shift ;[55] compensate ror after rjmp stuffDelay + rjmp stuff7Delay ;[56] after ror, C bit is reliably clear +doExor7: + eor x1, x2 ;[54] [62] + ldi x3, 6 ;[55] +common7: + ld shift, y+ ;[56] + nop ;[58] + tst cnt ;[59] + out USBOUT, x1 ;[60] [00]<--- set bit + brne txByteLoop ;[61] [01] +;make SE0: + cbr x1, USBMASK ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles] + lds x2, usbNewDeviceAddr;[03] + lsl x2 ;[05] we compare with left shifted address + subi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0 + sbci YH, 0 ;[07] + out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[01] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 0) + echo "$s\n"; + } +} + +function printBit($isAfterSet, $bitNum) +{ + ob_start(); + if($isAfterSet){ +?> + ifioclr USBIN, USBMINUS ;[00] <--- sample + rjmp bit#IsClr ;[01] + andi shift, ~(7 << #) ;[02] + breq unstuff#s ;[03] + in phase, USBIN ;[04] <- phase + rjmp bit@AfterSet ;[05] +unstuff#s: + in phase, USBIN ;[05] <- phase (one cycle too late) + andi fix, ~(1 << #) ;[06] + nop2 ;[-1] + nop2 ;[01] +bit#IsClr: + ifrset phase, USBMINUS ;[03] check phase only if D- changed + lpm ;[04] + in phase, USBIN ;[05] <- phase (one cycle too late) + ori shift, 1 << # ;[06] + + ifioset USBIN, USBMINUS ;[00] <--- sample + rjmp bit#IsSet ;[01] + andi shift, ~(7 << #) ;[02] + breq unstuff#c ;[03] + in phase, USBIN ;[04] <- phase + rjmp bit@AfterClr ;[05] +unstuff#c: + in phase, USBIN ;[05] <- phase (one cycle too late) + andi fix, ~(1 << #) ;[06] + nop2 ;[-1] + nop2 ;[01] +bit#IsSet: + ifrclr phase, USBMINUS ;[03] check phase only if D- changed + lpm ;[04] + in phase, USBIN ;[05] <- phase (one cycle too late) + ori shift, 1 << # ;[06] + +*****************************************************************************/ diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm15.inc b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm15.inc new file mode 100644 index 00000000..33bcf0e5 --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm15.inc @@ -0,0 +1,422 @@ +/* Name: usbdrvasm15.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: contributed by V. Bosch + * Creation Date: 2007-08-06 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 15 MHz version of the asssembler part of the USB driver. It +requires a 15 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! +*/ + +;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes +;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts + +;---------------------------------------------------------------------------- +; order of registers pushed: +; YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4 +;---------------------------------------------------------------------------- +USB_INTR_VECTOR: + push YL ;2 push only what is necessary to sync with edge ASAP + in YL, SREG ;1 + push YL ;2 +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +; +; sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +; sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +;------------------------------------------------------------------------------- +; The following code results in a sampling window of < 1/4 bit +; which meets the spec. +;------------------------------------------------------------------------------- +waitForK: ;- + sbis USBIN, USBMINUS ;1 [00] <-- sample + rjmp foundK ;2 [01] + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +;------------------------------------------------------------------------------ +; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for +; center sampling] +; we have 1 bit time for setup purposes, then sample again. +; Numbers in brackets are cycles from center of first sync (double K) +; bit after the instruction +;------------------------------------------------------------------------------ +foundK: ;- [02] + lds YL, usbInputBufOffset;2 [03+04] tx loop + push YH ;2 [05+06] + clr YH ;1 [07] + subi YL, lo8(-(usbRxBuf)) ;1 [08] [rx loop init] + sbci YH, hi8(-(usbRxBuf)) ;1 [09] [rx loop init] + push shift ;2 [10+11] + ser shift ;1 [12] + sbis USBIN, USBMINUS ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early) + rjmp haveTwoBitsK ;2 [00] [14] + pop shift ;2 [15+16] undo the push from before + pop YH ;2 [17+18] undo the push from before + rjmp waitForK ;2 [19+20] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 20 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: ;- [01] + push x1 ;2 [02+03] + push x2 ;2 [04+05] + push x3 ;2 [06+07] + push bitcnt ;2 [08+09] + in x1, USBIN ;1 [00] [10] <-- sample bit 0 + bst x1, USBMINUS ;1 [01] + bld shift, 0 ;1 [02] + push cnt ;2 [03+04] + ldi cnt, USB_BUFSIZE ;1 [05] + push x4 ;2 [06+07] tx loop + rjmp rxLoop ;2 [08] +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- +unstuff0: ;- [07] (branch taken) + andi x3, ~0x01 ;1 [08] + mov x1, x2 ;1 [09] x2 contains last sampled (stuffed) bit + in x2, USBIN ;1 [00] [10] <-- sample bit 1 again + andi x2, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 1 + ori shift, 0x01 ;1 [03] 0b00000001 + nop ;1 [04] + rjmp didUnstuff0 ;2 [05] +;----------------------------------------------------- +unstuff1: ;- [05] (branch taken) + mov x2, x1 ;1 [06] x1 contains last sampled (stuffed) bit + andi x3, ~0x02 ;1 [07] + ori shift, 0x02 ;1 [08] 0b00000010 + nop ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 2 again + andi x1, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 2 + rjmp didUnstuff1 ;2 [03] +;----------------------------------------------------- +unstuff2: ;- [05] (branch taken) + andi x3, ~0x04 ;1 [06] + ori shift, 0x04 ;1 [07] 0b00000100 + mov x1, x2 ;1 [08] x2 contains last sampled (stuffed) bit + nop ;1 [09] + in x2, USBIN ;1 [00] [10] <-- sample bit 3 + andi x2, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 3 + rjmp didUnstuff2 ;2 [03] +;----------------------------------------------------- +unstuff3: ;- [00] [10] (branch taken) + in x2, USBIN ;1 [01] [11] <-- sample stuffed bit 3 one cycle too late + andi x2, USBMASK ;1 [02] + breq se0Hop ;1 [03] SE0 check for stuffed bit 3 + andi x3, ~0x08 ;1 [04] + ori shift, 0x08 ;1 [05] 0b00001000 + rjmp didUnstuff3 ;2 [06] +;---------------------------------------------------------------------------- +; extra jobs done during bit interval: +; +; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs], +; overflow check, jump to the head of rxLoop +; bit 1: SE0 check +; bit 2: SE0 check, recovery from delay [bit 0 tasks took too long] +; bit 3: SE0 check, recovery from delay [bit 0 tasks took too long] +; bit 4: SE0 check, none +; bit 5: SE0 check, none +; bit 6: SE0 check, none +; bit 7: SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others +;---------------------------------------------------------------------------- +rxLoop: ;- [09] + in x2, USBIN ;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed) + andi x2, USBMASK ;1 [01] + brne SkipSe0Hop ;1 [02] +se0Hop: ;- [02] + rjmp se0 ;2 [03] SE0 check for bit 1 +SkipSe0Hop: ;- [03] + ser x3 ;1 [04] + andi shift, 0xf9 ;1 [05] 0b11111001 + breq unstuff0 ;1 [06] +didUnstuff0: ;- [06] + eor x1, x2 ;1 [07] + bst x1, USBMINUS ;1 [08] + bld shift, 1 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed) + andi x1, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 2 + andi shift, 0xf3 ;1 [03] 0b11110011 + breq unstuff1 ;1 [04] do remaining work for bit 1 +didUnstuff1: ;- [04] + eor x2, x1 ;1 [05] + bst x2, USBMINUS ;1 [06] + bld shift, 2 ;1 [07] + nop2 ;2 [08+09] + in x2, USBIN ;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed) + andi x2, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 3 + andi shift, 0xe7 ;1 [03] 0b11100111 + breq unstuff2 ;1 [04] +didUnstuff2: ;- [04] + eor x1, x2 ;1 [05] + bst x1, USBMINUS ;1 [06] + bld shift, 3 ;1 [07] +didUnstuff3: ;- [07] + andi shift, 0xcf ;1 [08] 0b11001111 + breq unstuff3 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 4 + andi x1, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 4 + eor x2, x1 ;1 [03] + bst x2, USBMINUS ;1 [04] + bld shift, 4 ;1 [05] +didUnstuff4: ;- [05] + andi shift, 0x9f ;1 [06] 0b10011111 + breq unstuff4 ;1 [07] + nop2 ;2 [08+09] + in x2, USBIN ;1 [00] [10] <-- sample bit 5 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for bit 5 + eor x1, x2 ;1 [03] + bst x1, USBMINUS ;1 [04] + bld shift, 5 ;1 [05] +didUnstuff5: ;- [05] + andi shift, 0x3f ;1 [06] 0b00111111 + breq unstuff5 ;1 [07] + nop2 ;2 [08+09] + in x1, USBIN ;1 [00] [10] <-- sample bit 6 + andi x1, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for bit 6 + eor x2, x1 ;1 [03] + bst x2, USBMINUS ;1 [04] + bld shift, 6 ;1 [05] +didUnstuff6: ;- [05] + cpi shift, 0x02 ;1 [06] 0b00000010 + brlo unstuff6 ;1 [07] + nop2 ;2 [08+09] + in x2, USBIN ;1 [00] [10] <-- sample bit 7 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for bit 7 + eor x1, x2 ;1 [03] + bst x1, USBMINUS ;1 [04] + bld shift, 7 ;1 [05] +didUnstuff7: ;- [05] + cpi shift, 0x04 ;1 [06] 0b00000100 + brlo unstuff7 ;1 [07] + eor x3, shift ;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others + nop ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 0 + st y+, x3 ;2 [01+02] store data + eor x2, x1 ;1 [03] + bst x2, USBMINUS ;1 [04] + bld shift, 0 ;1 [05] + subi cnt, 1 ;1 [06] + brcs overflow ;1 [07] + rjmp rxLoop ;2 [08] +;----------------------------------------------------- +unstuff4: ;- [08] + andi x3, ~0x10 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 4 + andi x1, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 4 + ori shift, 0x10 ;1 [03] + rjmp didUnstuff4 ;2 [04] +;----------------------------------------------------- +unstuff5: ;- [08] + ori shift, 0x20 ;1 [09] + in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 5 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 5 + andi x3, ~0x20 ;1 [03] + rjmp didUnstuff5 ;2 [04] +;----------------------------------------------------- +unstuff6: ;- [08] + andi x3, ~0x40 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 6 + andi x1, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 6 + ori shift, 0x40 ;1 [03] + rjmp didUnstuff6 ;2 [04] +;----------------------------------------------------- +unstuff7: ;- [08] + andi x3, ~0x80 ;1 [09] + in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 7 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 7 + ori shift, 0x80 ;1 [03] + rjmp didUnstuff7 ;2 [04] + +macro POP_STANDARD ; 16 cycles + pop x4 + pop cnt + pop bitcnt + pop x3 + pop x2 + pop x1 + pop shift + pop YH + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +;--------------------------------------------------------------------------- +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies +;--------------------------------------------------------------------------- +bitstuffN: ;- [04] + eor x1, x4 ;1 [05] + clr x2 ;1 [06] + nop ;1 [07] + rjmp didStuffN ;1 [08] +;--------------------------------------------------------------------------- +bitstuff6: ;- [04] + eor x1, x4 ;1 [05] + clr x2 ;1 [06] + rjmp didStuff6 ;1 [07] +;--------------------------------------------------------------------------- +bitstuff7: ;- [02] + eor x1, x4 ;1 [03] + clr x2 ;1 [06] + nop ;1 [05] + rjmp didStuff7 ;1 [06] +;--------------------------------------------------------------------------- +sendNakAndReti: ;- [-19] + ldi x3, USBPID_NAK ;1 [-18] + rjmp sendX3AndReti ;1 [-17] +;--------------------------------------------------------------------------- +sendAckAndReti: ;- [-17] + ldi cnt, USBPID_ACK ;1 [-16] +sendCntAndReti: ;- [-16] + mov x3, cnt ;1 [-15] +sendX3AndReti: ;- [-15] + ldi YL, 20 ;1 [-14] x3==r20 address is 20 + ldi YH, 0 ;1 [-13] + ldi cnt, 2 ;1 [-12] +; rjmp usbSendAndReti fallthrough +;--------------------------------------------------------------------------- +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, btcnt, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +;We need not to match the transfer rate exactly because the spec demands +;only 1.5% precision anyway. +usbSendAndReti: ;- [-13] 13 cycles until SOP + in x2, USBDDR ;1 [-12] + ori x2, USBMASK ;1 [-11] + sbi USBOUT, USBMINUS ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;1 [-08] port mirror for tx loop + out USBDDR, x2 ;1 [-07] <- acquire bus + ; need not init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;1 [-06] exor mask + ldi shift, 0x80 ;1 [-05] sync byte is first byte sent + ldi bitcnt, 6 ;1 [-04] +txBitLoop: ;- [-04] [06] + sbrs shift, 0 ;1 [-03] [07] + eor x1, x4 ;1 [-02] [08] + ror shift ;1 [-01] [09] +didStuffN: ;- [09] + out USBOUT, x1 ;1 [00] [10] <-- out N + ror x2 ;1 [01] + cpi x2, 0xfc ;1 [02] + brcc bitstuffN ;1 [03] + dec bitcnt ;1 [04] + brne txBitLoop ;1 [05] + sbrs shift, 0 ;1 [06] + eor x1, x4 ;1 [07] + ror shift ;1 [08] +didStuff6: ;- [08] + nop ;1 [09] + out USBOUT, x1 ;1 [00] [10] <-- out 6 + ror x2 ;1 [01] + cpi x2, 0xfc ;1 [02] + brcc bitstuff6 ;1 [03] + sbrs shift, 0 ;1 [04] + eor x1, x4 ;1 [05] + ror shift ;1 [06] + ror x2 ;1 [07] +didStuff7: ;- [07] + ldi bitcnt, 6 ;1 [08] + cpi x2, 0xfc ;1 [09] + out USBOUT, x1 ;1 [00] [10] <-- out 7 + brcc bitstuff7 ;1 [01] + ld shift, y+ ;2 [02+03] + dec cnt ;1 [04] + brne txBitLoop ;1 [05] +makeSE0: + cbr x1, USBMASK ;1 [06] prepare SE0 [spec says EOP may be 19 to 23 cycles] + lds x2, usbNewDeviceAddr;2 [07+08] + lsl x2 ;1 [09] we compare with left shifted address +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + out USBOUT, x1 ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle + subi YL, 20 + 2 ;1 [01] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;1 [02] + breq skipAddrAssign ;1 [03] + sts usbDeviceAddr, x2 ;2 [04+05] if not skipped: SE0 is one cycle longer +;---------------------------------------------------------------------------- +;end of usbDeviceAddress transfer +skipAddrAssign: ;- [03/04] + ldi x2, 1< 10.6666666 cycles per bit, 85.333333333 cycles per byte +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt + push YL ;[-25] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-23] + push YL ;[-22] + push YH ;[-20] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-15] + rjmp foundK ;[-14] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-12] +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push bitcnt ;[-12] +; [---] ;[-11] + lds YL, usbInputBufOffset;[-10] +; [---] ;[-9] + clr YH ;[-8] + subi YL, lo8(-(usbRxBuf));[-7] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init] + push shift ;[-5] +; [---] ;[-4] + ldi bitcnt, 0x55 ;[-3] [rx loop init] + sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) + rjmp haveTwoBitsK ;[-1] + pop shift ;[0] undo the push from before + pop bitcnt ;[2] undo the push from before + rjmp waitForK ;[4] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 21 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[1] + push x2 ;[3] + push x3 ;[5] + ldi shift, 0 ;[7] + ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that + push x4 ;[9] == leap + + in x1, USBIN ;[11] <-- sample bit 0 + andi x1, USBMASK ;[12] + bst x1, USBMINUS ;[13] + bld shift, 7 ;[14] + push cnt ;[15] + ldi leap, 0 ;[17] [rx loop init] + ldi cnt, USB_BUFSIZE;[18] [rx loop init] + rjmp rxbit1 ;[19] arrives at [21] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- + +; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap" +; accordingly to approximate this value in the long run. + +unstuff6: + andi x2, USBMASK ;[03] + ori x3, 1<<6 ;[04] will not be shifted any more + andi shift, ~0x80;[05] + mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6 + subi leap, -1 ;[07] total duration = 11 bits -> subtract 1/3 + rjmp didUnstuff6 ;[08] + +unstuff7: + ori x3, 1<<7 ;[09] will not be shifted any more + in x2, USBIN ;[00] [10] re-sample bit 7 + andi x2, USBMASK ;[01] + andi shift, ~0x80;[02] + subi leap, 2 ;[03] total duration = 10 bits -> add 1/3 + rjmp didUnstuff7 ;[04] + +unstuffEven: + ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0 + in x1, USBIN ;[00] [10] + andi shift, ~0x80;[01] + andi x1, USBMASK ;[02] + breq se0 ;[03] + subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 + nop2 ;[05] + rjmp didUnstuffE ;[06] + +unstuffOdd: + ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1 + in x2, USBIN ;[00] [10] + andi shift, ~0x80;[01] + andi x2, USBMASK ;[02] + breq se0 ;[03] + subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 + nop2 ;[05] + rjmp didUnstuffO ;[06] + +rxByteLoop: + andi x1, USBMASK ;[03] + eor x2, x1 ;[04] + subi leap, 1 ;[05] + brpl skipLeap ;[06] + subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte + nop ;1 +skipLeap: + subi x2, 1 ;[08] + ror shift ;[09] +didUnstuff6: + cpi shift, 0xfc ;[10] + in x2, USBIN ;[00] [11] <-- sample bit 7 + brcc unstuff6 ;[01] + andi x2, USBMASK ;[02] + eor x1, x2 ;[03] + subi x1, 1 ;[04] + ror shift ;[05] +didUnstuff7: + cpi shift, 0xfc ;[06] + brcc unstuff7 ;[07] + eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others + st y+, x3 ;[09] store data +rxBitLoop: + in x1, USBIN ;[00] [11] <-- sample bit 0/2/4 + andi x1, USBMASK ;[01] + eor x2, x1 ;[02] + andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7 + subi x2, 1 ;[04] + ror shift ;[05] + cpi shift, 0xfc ;[06] + brcc unstuffEven ;[07] +didUnstuffE: + lsr x3 ;[08] + lsr x3 ;[09] +rxbit1: + in x2, USBIN ;[00] [10] <-- sample bit 1/3/5 + andi x2, USBMASK ;[01] + breq se0 ;[02] + eor x1, x2 ;[03] + subi x1, 1 ;[04] + ror shift ;[05] + cpi shift, 0xfc ;[06] + brcc unstuffOdd ;[07] +didUnstuffO: + subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3 + brcs rxBitLoop ;[09] + + subi cnt, 1 ;[10] + in x1, USBIN ;[00] [11] <-- sample bit 6 + brcc rxByteLoop ;[01] + rjmp overflow + +macro POP_STANDARD ; 14 cycles + pop cnt + pop x4 + pop x3 + pop x2 + pop x1 + pop shift + pop bitcnt + endm +macro POP_RETI ; 7 cycles + pop YH + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies + +bitstuffN: + eor x1, x4 ;[5] + ldi x2, 0 ;[6] + nop2 ;[7] + nop ;[9] + out USBOUT, x1 ;[10] <-- out + rjmp didStuffN ;[0] + +bitstuff6: + eor x1, x4 ;[5] + ldi x2, 0 ;[6] Carry is zero due to brcc + rol shift ;[7] compensate for ror shift at branch destination + rjmp didStuff6 ;[8] + +bitstuff7: + ldi x2, 0 ;[2] Carry is zero due to brcc + rjmp didStuff7 ;[3] + + +sendNakAndReti: + ldi x3, USBPID_NAK ;[-18] + rjmp sendX3AndReti ;[-17] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov x3, cnt ;[-16] +sendX3AndReti: + ldi YL, 20 ;[-15] x3==r20 address is 20 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, btcnt, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +;We don't match the transfer rate exactly (don't insert leap cycles every third +;byte) because the spec demands only 1.5% precision anyway. +usbSendAndReti: ; 12 cycles until SOP + in x2, USBDDR ;[-12] + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;[-8] port mirror for tx loop + out USBDDR, x2 ;[-7] <- acquire bus +; need not init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;[-6] exor mask + ldi shift, 0x80 ;[-5] sync byte is first byte sent +txByteLoop: + ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101 +txBitLoop: + sbrs shift, 0 ;[-3] [7] + eor x1, x4 ;[-2] [8] + out USBOUT, x1 ;[-1] [9] <-- out N + ror shift ;[0] [10] + ror x2 ;[1] +didStuffN: + cpi x2, 0xfc ;[2] + brcc bitstuffN ;[3] + lsr bitcnt ;[4] + brcc txBitLoop ;[5] + brne txBitLoop ;[6] + + sbrs shift, 0 ;[7] + eor x1, x4 ;[8] +didStuff6: + out USBOUT, x1 ;[-1] [9] <-- out 6 + ror shift ;[0] [10] + ror x2 ;[1] + cpi x2, 0xfc ;[2] + brcc bitstuff6 ;[3] + ror shift ;[4] +didStuff7: + ror x2 ;[5] + sbrs x2, 7 ;[6] + eor x1, x4 ;[7] + nop ;[8] + cpi x2, 0xfc ;[9] + out USBOUT, x1 ;[-1][10] <-- out 7 + brcc bitstuff7 ;[0] [11] + ld shift, y+ ;[1] + dec cnt ;[3] + brne txByteLoop ;[4] +;make SE0: + cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles] + lds x2, usbNewDeviceAddr;[6] + lsl x2 ;[8] we compare with left shifted address + subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;[10] + out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[0] + sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< max 52 cycles interrupt disable +;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes +;nominal frequency: 16.5 MHz -> 11 cycles per bit +; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%) +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt + push YL ;[-23] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-21] + push YL ;[-20] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-15] + rjmp foundK ;[-14] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-12] +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push r0 ;[-12] +; [---] ;[-11] + push YH ;[-10] +; [---] ;[-9] + lds YL, usbInputBufOffset;[-8] +; [---] ;[-7] + clr YH ;[-6] + subi YL, lo8(-(usbRxBuf));[-5] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-4] [rx loop init] + mov r0, x2 ;[-3] [rx loop init] + sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) + rjmp haveTwoBitsK ;[-1] + pop YH ;[0] undo the pushes from before + pop r0 ;[2] + rjmp waitForK ;[4] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 22 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: ;[1] + push shift ;[1] + push x1 ;[3] + push x2 ;[5] + push x3 ;[7] + ldi shift, 0xff ;[9] [rx loop init] + ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag + + in x1, USBIN ;[11] <-- sample bit 0 + bst x1, USBMINUS ;[12] + bld shift, 0 ;[13] + push x4 ;[14] == phase +; [---] ;[15] + push cnt ;[16] +; [---] ;[17] + ldi phase, 0 ;[18] [rx loop init] + ldi cnt, USB_BUFSIZE;[19] [rx loop init] + rjmp rxbit1 ;[20] +; [---] ;[21] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- +/* +byte oriented operations done during loop: +bit 0: store data +bit 1: SE0 check +bit 2: overflow check +bit 3: catch up +bit 4: rjmp to achieve conditional jump range +bit 5: PLL +bit 6: catch up +bit 7: jump, fixup bitstuff +; 87 [+ 2] cycles +------------------------------------------------------------------ +*/ +continueWithBit5: + in x2, USBIN ;[055] <-- bit 5 + eor r0, x2 ;[056] + or phase, r0 ;[057] + sbrc phase, USBMINUS ;[058] + lpm ;[059] optional nop3; modifies r0 + in phase, USBIN ;[060] <-- phase + eor x1, x2 ;[061] + bst x1, USBMINUS ;[062] + bld shift, 5 ;[063] + andi shift, 0x3f ;[064] + in x1, USBIN ;[065] <-- bit 6 + breq unstuff5 ;[066] *** unstuff escape + eor phase, x1 ;[067] + eor x2, x1 ;[068] + bst x2, USBMINUS ;[069] + bld shift, 6 ;[070] +didUnstuff6: ;[ ] + in r0, USBIN ;[071] <-- phase + cpi shift, 0x02 ;[072] + brlo unstuff6 ;[073] *** unstuff escape +didUnstuff5: ;[ ] + nop2 ;[074] +; [---] ;[075] + in x2, USBIN ;[076] <-- bit 7 + eor x1, x2 ;[077] + bst x1, USBMINUS ;[078] + bld shift, 7 ;[079] +didUnstuff7: ;[ ] + eor r0, x2 ;[080] + or phase, r0 ;[081] + in r0, USBIN ;[082] <-- phase + cpi shift, 0x04 ;[083] + brsh rxLoop ;[084] +; [---] ;[085] +unstuff7: ;[ ] + andi x3, ~0x80 ;[085] + ori shift, 0x80 ;[086] + in x2, USBIN ;[087] <-- sample stuffed bit 7 + nop ;[088] + rjmp didUnstuff7 ;[089] +; [---] ;[090] + ;[080] + +unstuff5: ;[067] + eor phase, x1 ;[068] + andi x3, ~0x20 ;[069] + ori shift, 0x20 ;[070] + in r0, USBIN ;[071] <-- phase + mov x2, x1 ;[072] + nop ;[073] + nop2 ;[074] +; [---] ;[075] + in x1, USBIN ;[076] <-- bit 6 + eor r0, x1 ;[077] + or phase, r0 ;[078] + eor x2, x1 ;[079] + bst x2, USBMINUS ;[080] + bld shift, 6 ;[081] no need to check bitstuffing, we just had one + in r0, USBIN ;[082] <-- phase + rjmp didUnstuff5 ;[083] +; [---] ;[084] + ;[074] + +unstuff6: ;[074] + andi x3, ~0x40 ;[075] + in x1, USBIN ;[076] <-- bit 6 again + ori shift, 0x40 ;[077] + nop2 ;[078] +; [---] ;[079] + rjmp didUnstuff6 ;[080] +; [---] ;[081] + ;[071] + +unstuff0: ;[013] + eor r0, x2 ;[014] + or phase, r0 ;[015] + andi x2, USBMASK ;[016] check for SE0 + in r0, USBIN ;[017] <-- phase + breq didUnstuff0 ;[018] direct jump to se0 would be too long + andi x3, ~0x01 ;[019] + ori shift, 0x01 ;[020] + mov x1, x2 ;[021] mov existing sample + in x2, USBIN ;[022] <-- bit 1 again + rjmp didUnstuff0 ;[023] +; [---] ;[024] + ;[014] + +unstuff1: ;[024] + eor r0, x1 ;[025] + or phase, r0 ;[026] + andi x3, ~0x02 ;[027] + in r0, USBIN ;[028] <-- phase + ori shift, 0x02 ;[029] + mov x2, x1 ;[030] + rjmp didUnstuff1 ;[031] +; [---] ;[032] + ;[022] + +unstuff2: ;[035] + eor r0, x2 ;[036] + or phase, r0 ;[037] + andi x3, ~0x04 ;[038] + in r0, USBIN ;[039] <-- phase + ori shift, 0x04 ;[040] + mov x1, x2 ;[041] + rjmp didUnstuff2 ;[042] +; [---] ;[043] + ;[033] + +unstuff3: ;[043] + in x2, USBIN ;[044] <-- bit 3 again + eor r0, x2 ;[045] + or phase, r0 ;[046] + andi x3, ~0x08 ;[047] + ori shift, 0x08 ;[048] + nop ;[049] + in r0, USBIN ;[050] <-- phase + rjmp didUnstuff3 ;[051] +; [---] ;[052] + ;[042] + +unstuff4: ;[053] + andi x3, ~0x10 ;[054] + in x1, USBIN ;[055] <-- bit 4 again + ori shift, 0x10 ;[056] + rjmp didUnstuff4 ;[057] +; [---] ;[058] + ;[048] + +rxLoop: ;[085] + eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others + in x1, USBIN ;[000] <-- bit 0 + st y+, x3 ;[001] +; [---] ;[002] + eor r0, x1 ;[003] + or phase, r0 ;[004] + eor x2, x1 ;[005] + in r0, USBIN ;[006] <-- phase + ser x3 ;[007] + bst x2, USBMINUS ;[008] + bld shift, 0 ;[009] + andi shift, 0xf9 ;[010] +rxbit1: ;[ ] + in x2, USBIN ;[011] <-- bit 1 + breq unstuff0 ;[012] *** unstuff escape + andi x2, USBMASK ;[013] SE0 check for bit 1 +didUnstuff0: ;[ ] Z only set if we detected SE0 in bitstuff + breq se0 ;[014] + eor r0, x2 ;[015] + or phase, r0 ;[016] + in r0, USBIN ;[017] <-- phase + eor x1, x2 ;[018] + bst x1, USBMINUS ;[019] + bld shift, 1 ;[020] + andi shift, 0xf3 ;[021] +didUnstuff1: ;[ ] + in x1, USBIN ;[022] <-- bit 2 + breq unstuff1 ;[023] *** unstuff escape + eor r0, x1 ;[024] + or phase, r0 ;[025] + subi cnt, 1 ;[026] overflow check + brcs overflow ;[027] + in r0, USBIN ;[028] <-- phase + eor x2, x1 ;[029] + bst x2, USBMINUS ;[030] + bld shift, 2 ;[031] + andi shift, 0xe7 ;[032] +didUnstuff2: ;[ ] + in x2, USBIN ;[033] <-- bit 3 + breq unstuff2 ;[034] *** unstuff escape + eor r0, x2 ;[035] + or phase, r0 ;[036] + eor x1, x2 ;[037] + bst x1, USBMINUS ;[038] + in r0, USBIN ;[039] <-- phase + bld shift, 3 ;[040] + andi shift, 0xcf ;[041] +didUnstuff3: ;[ ] + breq unstuff3 ;[042] *** unstuff escape + nop ;[043] + in x1, USBIN ;[044] <-- bit 4 + eor x2, x1 ;[045] + bst x2, USBMINUS ;[046] + bld shift, 4 ;[047] +didUnstuff4: ;[ ] + eor r0, x1 ;[048] + or phase, r0 ;[049] + in r0, USBIN ;[050] <-- phase + andi shift, 0x9f ;[051] + breq unstuff4 ;[052] *** unstuff escape + rjmp continueWithBit5;[053] +; [---] ;[054] + +macro POP_STANDARD ; 16 cycles + pop cnt + pop x4 + pop x3 + pop x2 + pop x1 + pop shift + pop YH + pop r0 + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies + +bitstuff7: + eor x1, x4 ;[4] + ldi x2, 0 ;[5] + nop2 ;[6] C is zero (brcc) + rjmp didStuff7 ;[8] + +bitstuffN: + eor x1, x4 ;[5] + ldi x2, 0 ;[6] + lpm ;[7] 3 cycle NOP, modifies r0 + out USBOUT, x1 ;[10] <-- out + rjmp didStuffN ;[0] + +#define bitStatus x3 + +sendNakAndReti: + ldi cnt, USBPID_NAK ;[-19] + rjmp sendCntAndReti ;[-18] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov r0, cnt ;[-16] + ldi YL, 0 ;[-15] R0 address is 0 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +usbSendAndReti: ; 12 cycles until SOP + in x2, USBDDR ;[-12] + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;[-8] port mirror for tx loop + out USBDDR, x2 ;[-7] <- acquire bus +; need not init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;[-6] exor mask + ldi shift, 0x80 ;[-5] sync byte is first byte sent + ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes +byteloop: +bitloop: + sbrs shift, 0 ;[8] [-3] + eor x1, x4 ;[9] [-2] + out USBOUT, x1 ;[10] [-1] <-- out + ror shift ;[0] + ror x2 ;[1] +didStuffN: + cpi x2, 0xfc ;[2] + brcc bitstuffN ;[3] + nop ;[4] + subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37 + brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value + sbrs shift, 0 ;[7] + eor x1, x4 ;[8] + ror shift ;[9] +didStuff7: + out USBOUT, x1 ;[10] <-- out + ror x2 ;[0] + cpi x2, 0xfc ;[1] + brcc bitstuff7 ;[2] + ld shift, y+ ;[3] + dec cnt ;[5] + brne byteloop ;[6] +;make SE0: + cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles] + lds x2, usbNewDeviceAddr;[8] + lsl x2 ;[10] we compare with left shifted address + out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + subi YL, 2 ;[0] Only assign address on data packets, not ACK/NAK in r0 + sbci YH, 0 ;[1] + breq skipAddrAssign ;[2] + sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 12 cycles per bit +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts +;register use in receive loop to receive the data bytes: +; shift assembles the byte currently being received +; x1 holds the D+ and D- line state +; x2 holds the previous line state +; cnt holds the number of bytes left in the receive buffer +; x3 holds the higher crc byte (see algorithm below) +; x4 is used as temporary register for the crc algorithm +; x5 is used for unstuffing: when unstuffing the last received bit is inverted in shift (to prevent further +; unstuffing calls. In the same time the corresponding bit in x5 is cleared to mark the bit as beening iverted +; zl lower crc value and crc table index +; zh used for crc table accesses + +;-------------------------------------------------------------------------------------------------------------- +; CRC mods: +; table driven crc checker, Z points to table in prog space +; ZL is the lower crc byte, x3 is the higher crc byte +; x4 is used as temp register to store different results +; the initialization of the crc register is not 0xFFFF but 0xFE54. This is because during the receipt of the +; first data byte an virtual zero data byte is added to the crc register, this results in the correct initial +; value of 0xFFFF at beginning of the second data byte before the first data byte is added to the crc. +; The magic number 0xFE54 results form the crc table: At tabH[0x54] = 0xFF = crcH (required) and +; tabL[0x54] = 0x01 -> crcL = 0x01 xor 0xFE = 0xFF +; bitcnt is renamed to x5 and is used for unstuffing purposes, the unstuffing works like in the 12MHz version +;-------------------------------------------------------------------------------------------------------------- +; CRC algorithm: +; The crc register is formed by x3 (higher byte) and ZL (lower byte). The algorithm uses a 'reversed' form +; i.e. that it takes the least significant bit first and shifts to the right. So in fact the highest order +; bit seen from the polynomial devision point of view is the lsb of ZL. (If this sounds strange to you i +; propose a research on CRC :-) ) +; Each data byte received is xored to ZL, the lower crc byte. This byte now builds the crc +; table index. Next the new high byte is loaded from the table and stored in x4 until we have space in x3 +; (its destination). +; Afterwards the lower table is loaded from the table and stored in ZL (the old index is overwritten as +; we don't need it anymore. In fact this is a right shift by 8 bits.) Now the old crc high value is xored +; to ZL, this is the second shift of the old crc value. Now x4 (the temp reg) is moved to x3 and the crc +; calculation is done. +; Prior to the first byte the two CRC register have to be initialized to 0xFFFF (as defined in usb spec) +; however the crc engine also runs during the receipt of the first byte, therefore x3 and zl are initialized +; to a magic number which results in a crc value of 0xFFFF after the first complete byte. +; +; This algorithm is split into the extra cycles of the different bits: +; bit7: XOR the received byte to ZL +; bit5: load the new high byte to x4 +; bit6: load the lower xor byte from the table, xor zl and x3, store result in zl (=the new crc low value) +; move x4 (the new high byte) to x3, the crc value is ready +; + + +macro POP_STANDARD ; 18 cycles + pop ZH + pop ZL + pop cnt + pop x5 + pop x3 + pop x2 + pop x1 + pop shift + pop x4 + endm +macro POP_RETI ; 7 cycles + pop YH + pop YL + out SREG, YL + pop YL + endm + +macro CRC_CLEANUP_AND_CHECK + ; the last byte has already been xored with the lower crc byte, we have to do the table lookup and xor + ; x3 is the higher crc byte, zl the lower one + ldi ZH, hi8(usbCrcTableHigh);[+1] get the new high byte from the table + lpm x2, Z ;[+2][+3][+4] + ldi ZH, hi8(usbCrcTableLow);[+5] get the new low xor byte from the table + lpm ZL, Z ;[+6][+7][+8] + eor ZL, x3 ;[+7] xor the old high byte with the value from the table, x2:ZL now holds the crc value + cpi ZL, 0x01 ;[+8] if the crc is ok we have a fixed remainder value of 0xb001 in x2:ZL (see usb spec) + brne ignorePacket ;[+9] detected a crc fault -> paket is ignored and retransmitted by the host + cpi x2, 0xb0 ;[+10] + brne ignorePacket ;[+11] detected a crc fault -> paket is ignored and retransmitted by the host + endm + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG, YH, [sofError], x4, shift, x1, x2, x3, x5, cnt, ZL, ZH + push YL ;[-28] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-26] + push YL ;[-25] + push YH ;[-23] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-17] + rjmp foundK ;[-16] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-15] +;{3, 5} after falling D- edge, average delay: 4 cycles +;bit0 should be at 30 (2.5 bits) for center sampling. Currently at 4 so 26 cylces till bit 0 sample +;use 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push x4 ;[-14] +; [---] ;[-13] + lds YL, usbInputBufOffset;[-12] used to toggle the two usb receive buffers +; [---] ;[-11] + clr YH ;[-10] + subi YL, lo8(-(usbRxBuf));[-9] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-8] [rx loop init] + push shift ;[-7] +; [---] ;[-6] + ldi shift, 0x80 ;[-5] the last bit is the end of byte marker for the pid receiver loop + clc ;[-4] the carry has to be clear for receipt of pid bit 0 + sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) + rjmp haveTwoBitsK ;[-2] + pop shift ;[-1] undo the push from before + pop x4 ;[1] + rjmp waitForK ;[3] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 24 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[0] + push x2 ;[2] + push x3 ;[4] crc high byte + ldi x2, 1< jump back and store the byte + ori shift, 0x01 ;[11] invert the last received bit to prevent furhter unstuffing + in x2, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + andi x5, 0xFE ;[1] mark this bit as inverted (will be corrected before storing shift) + eor x1, x2 ;[2] x1 and x2 have to be different because the stuff bit is always a zero + andi x1, USBMASK ;[3] mask the interesting bits + breq stuffErr ;[4] if the stuff bit is a 1-bit something went wrong + mov x1, x2 ;[5] the next bit expects the last state to be in x1 + rjmp didunstuff0 ;[6] + ;[7] jump delay of rjmp didunstuffX + +unstuff1: ;[11] this is the jump delay of breq unstuffX + in x1, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + ori shift, 0x02 ;[1] invert the last received bit to prevent furhter unstuffing + andi x5, 0xFD ;[2] mark this bit as inverted (will be corrected before storing shift) + eor x2, x1 ;[3] x1 and x2 have to be different because the stuff bit is always a zero + andi x2, USBMASK ;[4] mask the interesting bits + breq stuffErr ;[5] if the stuff bit is a 1-bit something went wrong + mov x2, x1 ;[6] the next bit expects the last state to be in x2 + nop2 ;[7] + ;[8] + rjmp didunstuff1 ;[9] + ;[10] jump delay of rjmp didunstuffX + +unstuff2: ;[9] this is the jump delay of breq unstuffX + ori shift, 0x04 ;[10] invert the last received bit to prevent furhter unstuffing + andi x5, 0xFB ;[11] mark this bit as inverted (will be corrected before storing shift) + in x2, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + eor x1, x2 ;[1] x1 and x2 have to be different because the stuff bit is always a zero + andi x1, USBMASK ;[2] mask the interesting bits + breq stuffErr ;[3] if the stuff bit is a 1-bit something went wrong + mov x1, x2 ;[4] the next bit expects the last state to be in x1 + nop2 ;[5] + ;[6] + rjmp didunstuff2 ;[7] + ;[8] jump delay of rjmp didunstuffX + +unstuff3: ;[9] this is the jump delay of breq unstuffX + ori shift, 0x08 ;[10] invert the last received bit to prevent furhter unstuffing + andi x5, 0xF7 ;[11] mark this bit as inverted (will be corrected before storing shift) + in x1, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + eor x2, x1 ;[1] x1 and x2 have to be different because the stuff bit is always a zero + andi x2, USBMASK ;[2] mask the interesting bits + breq stuffErr ;[3] if the stuff bit is a 1-bit something went wrong + mov x2, x1 ;[4] the next bit expects the last state to be in x2 + nop2 ;[5] + ;[6] + rjmp didunstuff3 ;[7] + ;[8] jump delay of rjmp didunstuffX + + + +; the include has to be here due to branch distance restirctions +#define __USE_CRC__ +#include "asmcommon.inc" + + + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies +; 7.5 bit times is 90 cycles. ...there is plenty of time + + +sendNakAndReti: + ldi x3, USBPID_NAK ;[-18] + rjmp sendX3AndReti ;[-17] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov x3, cnt ;[-16] +sendX3AndReti: + ldi YL, 20 ;[-15] x3==r20 address is 20 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, btcnt, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent + +usbSendAndReti: ; 12 cycles until SOP + in x2, USBDDR ;[-12] + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;[-8] port mirror for tx loop + out USBDDR, x2 ;[-6] <- acquire bus + ldi x2, 0 ;[-6] init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;[-5] exor mask + ldi shift, 0x80 ;[-4] sync byte is first byte sent +txByteLoop: + ldi bitcnt, 0x40 ;[-3]=[9] binary 01000000 +txBitLoop: ; the loop sends the first 7 bits of the byte + sbrs shift, 0 ;[-2]=[10] if we have to send a 1 don't change the line state + eor x1, x4 ;[-1]=[11] + out USBOUT, x1 ;[0] + ror shift ;[1] + ror x2 ;[2] transfers the last sent bit to the stuffing history +didStuffN: + nop ;[3] + nop ;[4] + cpi x2, 0xfc ;[5] if we sent six consecutive ones + brcc bitstuffN ;[6] + lsr bitcnt ;[7] + brne txBitLoop ;[8] restart the loop while the 1 is still in the bitcount + +; transmit bit 7 + sbrs shift, 0 ;[9] + eor x1, x4 ;[10] +didStuff7: + ror shift ;[11] + out USBOUT, x1 ;[0] transfer bit 7 to the pins + ror x2 ;[1] move the bit into the stuffing history + cpi x2, 0xfc ;[2] + brcc bitstuff7 ;[3] + ld shift, y+ ;[4] get next byte to transmit + dec cnt ;[5] decrement byte counter + brne txByteLoop ;[7] if we have more bytes start next one + ;[8] branch delay + +;make SE0: + cbr x1, USBMASK ;[8] prepare SE0 [spec says EOP may be 25 to 30 cycles] + lds x2, usbNewDeviceAddr;[9] + lsl x2 ;[11] we compare with left shifted address + out USBOUT, x1 ;[0] <-- out SE0 -- from now 2 bits = 24 cycles until bus idle + subi YL, 20 + 2 ;[1] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;[2] +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[3] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< +int main (int argc, char **argv) +{ + int i, j; + for (i=0; i<512; i++){ + unsigned short crc = i & 0xff; + for(j=0; j<8; j++) crc = (crc >> 1) ^ ((crc & 1) ? 0xa001 : 0); + if((i & 7) == 0) printf("\n.byte "); + printf("0x%02x, ", (i > 0xff ? (crc >> 8) : crc) & 0xff); + if(i == 255) printf("\n"); + } + return 0; +} + +// Use the following algorithm to compute CRC values: +ushort computeCrc(uchar *msg, uchar msgLen) +{ + uchar i; + ushort crc = 0xffff; + for(i = 0; i < msgLen; i++) + crc = usbCrcTable16[lo8(crc) ^ msg[i]] ^ hi8(crc); + return crc; +} +*/ + +.balign 256 +usbCrcTableLow: +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 + +; .balign 256 +usbCrcTableHigh: +.byte 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2 +.byte 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04 +.byte 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E +.byte 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8 +.byte 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A +.byte 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC +.byte 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6 +.byte 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10 +.byte 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32 +.byte 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4 +.byte 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE +.byte 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38 +.byte 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA +.byte 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C +.byte 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26 +.byte 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0 +.byte 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62 +.byte 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4 +.byte 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE +.byte 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68 +.byte 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA +.byte 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C +.byte 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76 +.byte 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0 +.byte 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92 +.byte 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54 +.byte 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E +.byte 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98 +.byte 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A +.byte 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C +.byte 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86 +.byte 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 + diff --git a/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm20.inc b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm20.inc new file mode 100644 index 00000000..5027eddc --- /dev/null +++ b/sparkfun/tiny/bootloaders/attiny/usbdrv/usbdrvasm20.inc @@ -0,0 +1,359 @@ +/* Name: usbdrvasm20.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Jeroen Benschop + * Based on usbdrvasm16.inc from Christian Starkjohann + * Creation Date: 2008-03-05 + * Tabsize: 4 + * Copyright: (c) 2008 by Jeroen Benschop and OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 20 MHz version of the asssembler part of the USB driver. It +requires a 20 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! +*/ + +#define leap2 x3 +#ifdef __IAR_SYSTEMS_ASM__ +#define nextInst $+2 +#else +#define nextInst .+0 +#endif + +;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes +;nominal frequency: 20 MHz -> 13.333333 cycles per bit, 106.666667 cycles per byte +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts +;register use in receive loop: +; shift assembles the byte currently being received +; x1 holds the D+ and D- line state +; x2 holds the previous line state +; x4 (leap) is used to add a leap cycle once every three bytes received +; X3 (leap2) is used to add a leap cycle once every three stuff bits received +; bitcnt is used to determine when a stuff bit is due +; cnt holds the number of bytes left in the receive buffer + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt + push YL ;[-28] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-26] + push YL ;[-25] + push YH ;[-23] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-19] + rjmp foundK ;[-18] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-16] +;{3, 5} after falling D- edge, average delay: 4 cycles +;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample +;use 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push bitcnt ;[-16] +; [---] ;[-15] + lds YL, usbInputBufOffset;[-14] +; [---] ;[-13] + clr YH ;[-12] + subi YL, lo8(-(usbRxBuf));[-11] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-10] [rx loop init] + push shift ;[-9] +; [---] ;[-8] + ldi shift,0x40 ;[-7] set msb to "1" so processing bit7 can be detected + nop2 ;[-6] +; [---] ;[-5] + ldi bitcnt, 5 ;[-4] [rx loop init] + sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) + rjmp haveTwoBitsK ;[-2] + pop shift ;[-1] undo the push from before + pop bitcnt ;[1] + rjmp waitForK ;[3] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 27 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[0] + push x2 ;[2] + push x3 ;[4] (leap2) + ldi leap2, 0x55 ;[6] add leap cycle on 2nd,5th,8th,... stuff bit + push x4 ;[7] == leap + ldi leap, 0x55 ;[9] skip leap cycle on 2nd,5th,8th,... byte received + push cnt ;[10] + ldi cnt, USB_BUFSIZE ;[12] [rx loop init] + ldi x2, 1< +#ifndef __IAR_SYSTEMS_ASM__ +# include +#endif + +#define __attribute__(arg) /* not supported on IAR */ + +#ifdef __IAR_SYSTEMS_ASM__ +# define __ASSEMBLER__ /* IAR does not define standard macro for asm */ +#endif + +#ifdef __HAS_ELPM__ +# define PROGMEM __farflash +#else +# define PROGMEM __flash +#endif + +#define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) + +/* The following definitions are not needed by the driver, but may be of some + * help if you port a gcc based project to IAR. + */ +#define cli() __disable_interrupt() +#define sei() __enable_interrupt() +#define wdt_reset() __watchdog_reset() +#define _BV(x) (1 << (x)) + +/* assembler compatibility macros */ +#define nop2 rjmp $+2 /* jump to next instruction */ +#define XL r26 +#define XH r27 +#define YL r28 +#define YH r29 +#define ZL r30 +#define ZH r31 +#define lo8(x) LOW(x) +#define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */ + +/* Depending on the device you use, you may get problems with the way usbdrv.h + * handles the differences between devices. Since IAR does not use #defines + * for MCU registers, we can't check for the existence of a particular + * register with an #ifdef. If the autodetection mechanism fails, include + * definitions for the required USB_INTR_* macros in your usbconfig.h. See + * usbconfig-prototype.h and usbdrv.h for details. + */ + +/* ------------------------------------------------------------------------- */ +#elif __CODEVISIONAVR__ /* check for CodeVision AVR */ +/* ------------------------------------------------------------------------- */ +/* This port is not working (yet) */ + +/* #define F_CPU _MCU_CLOCK_FREQUENCY_ seems to be defined automatically */ + +#include +#include + +#define __attribute__(arg) /* not supported on IAR */ + +#define PROGMEM __flash +#define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) + +#ifndef __ASSEMBLER__ +static inline void cli(void) +{ + #asm("cli"); +} +static inline void sei(void) +{ + #asm("sei"); +} +#endif +#define _delay_ms(t) delay_ms(t) +#define _BV(x) (1 << (x)) +#define USB_CFG_USE_SWITCH_STATEMENT 1 /* macro for if() cascase fails for unknown reason */ + +#define macro .macro +#define endm .endmacro +#define nop2 rjmp .+0 /* jump to next instruction */ + +/* ------------------------------------------------------------------------- */ +#else /* default development environment is avr-gcc/avr-libc */ +/* ------------------------------------------------------------------------- */ + +#include +#ifdef __ASSEMBLER__ +# define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ +#else +# include +#endif + +#if USB_CFG_DRIVER_FLASH_PAGE +# define USB_READ_FLASH(addr) pgm_read_byte_far(((long)USB_CFG_DRIVER_FLASH_PAGE << 16) | (long)(addr)) +#else +# define USB_READ_FLASH(addr) pgm_read_byte(addr) +#endif + +#define macro .macro +#define endm .endm +#define nop2 rjmp .+0 /* jump to next instruction */ + +#endif /* development environment */ + +/* for conveniecne, ensure that PRG_RDB exists */ +#ifndef PRG_RDB +# define PRG_RDB(addr) USB_READ_FLASH(addr) +#endif +#endif /* __usbportability_h_INCLUDED__ */ diff --git a/sparkfun/tiny/cores/arduino/Arduino.h b/sparkfun/tiny/cores/arduino/Arduino.h new file mode 100644 index 00000000..09c14489 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Arduino.h @@ -0,0 +1,259 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Arduino_h +#define Arduino_h + +#include +#include +#include +#include + +#include +#include +#include + +#include "binary.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +void yield(void); + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 +#define EULER 2.718281828459045235360287471352 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) + #define DEFAULT 0 + #define EXTERNAL 1 + #define INTERNAL1V1 2 + #define INTERNAL INTERNAL1V1 +#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + #define DEFAULT 0 + #define EXTERNAL 4 + #define INTERNAL1V1 8 + #define INTERNAL INTERNAL1V1 + #define INTERNAL2V56 9 + #define INTERNAL2V56_EXTCAP 13 +#else +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) +#define INTERNAL1V1 2 +#define INTERNAL2V56 3 +#else +#define INTERNAL 3 +#endif +#define DEFAULT 1 +#define EXTERNAL 0 +#endif + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() sei() +#define noInterrupts() cli() + +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +// avr-libc defines _NOP() since 1.6.2 +#ifndef _NOP +#define _NOP() do { __asm__ volatile ("nop"); } while (0) +#endif + +typedef unsigned int word; + +#define bit(b) (1UL << (b)) + +typedef bool boolean; +typedef uint8_t byte; + +void init(void); +void initVariant(void); + +int atexit(void (*func)()) __attribute__((weak)); + +void pinMode(uint8_t, uint8_t); +void digitalWrite(uint8_t, uint8_t); +int digitalRead(uint8_t); +int analogRead(uint8_t); +void analogReference(uint8_t mode); +void analogWrite(uint8_t, int); + +unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t, void (*)(void), int mode); +void detachInterrupt(uint8_t); + +void setup(void); +void loop(void); + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. + +#define analogInPinToBit(P) (P) + +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; + +extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; +// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. +// +// These perform slightly better as macros compared to inline functions +// +#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) +#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +#define analogInPinToBit(P) (P) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#define NOT_AN_INTERRUPT -1 + +#ifdef ARDUINO_MAIN +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 +#endif + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER1C 5 +#define TIMER2 6 +#define TIMER2A 7 +#define TIMER2B 8 + +#define TIMER3A 9 +#define TIMER3B 10 +#define TIMER3C 11 +#define TIMER4A 12 +#define TIMER4B 13 +#define TIMER4C 14 +#define TIMER4D 15 +#define TIMER5A 16 +#define TIMER5B 17 +#define TIMER5C 18 + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#include "WCharacter.h" +#include "WString.h" +#include "HardwareSerial.h" +#include "USBAPI.h" +#if defined(HAVE_HWSERIAL0) && defined(HAVE_CDCSERIAL) +#error "Targets with both UART0 and CDC serial not supported" +#endif + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned long); +long map(long, long, long, long, long); + +#endif + +#include "pins_arduino.h" + +#endif diff --git a/sparkfun/tiny/cores/arduino/CDC.cpp b/sparkfun/tiny/cores/arduino/CDC.cpp new file mode 100644 index 00000000..0a743e1e --- /dev/null +++ b/sparkfun/tiny/cores/arduino/CDC.cpp @@ -0,0 +1,294 @@ + + +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "USBAPI.h" +#include +#include + +#if defined(USBCON) + +typedef struct +{ + u32 dwDTERate; + u8 bCharFormat; + u8 bParityType; + u8 bDataBits; + u8 lineState; +} LineInfo; + +static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; +static volatile int32_t breakValue = -1; + +bool _updatedLUFAbootloader = false; + +#define WEAK __attribute__ ((weak)) + +extern const CDCDescriptor _cdcInterface PROGMEM; +const CDCDescriptor _cdcInterface = +{ + D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1), + + // CDC communication interface + D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), + D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd) + D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) + D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported + D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40), + + // CDC data interface + D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), + D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) +}; + +int CDC_GetInterface(u8* interfaceNum) +{ + interfaceNum[0] += 2; // uses 2 + return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); +} + +bool CDC_Setup(USBSetup& setup) +{ + u8 r = setup.bRequest; + u8 requestType = setup.bmRequestType; + + if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) + { + if (CDC_GET_LINE_CODING == r) + { + USB_SendControl(0,(void*)&_usbLineInfo,7); + return true; + } + } + + if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) + { + if (CDC_SEND_BREAK == r) + { + breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; + } + + if (CDC_SET_LINE_CODING == r) + { + USB_RecvControl((void*)&_usbLineInfo,7); + } + + if (CDC_SET_CONTROL_LINE_STATE == r) + { + _usbLineInfo.lineState = setup.wValueL; + } + + if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r) + { + // auto-reset into the bootloader is triggered when the port, already + // open at 1200 bps, is closed. this is the signal to start the watchdog + // with a relatively long period so it can finish housekeeping tasks + // like servicing endpoints before the sketch ends + + uint16_t magic_key_pos = MAGIC_KEY_POS; + +// If we don't use the new RAMEND directly, check manually if we have a newer bootloader. +// This is used to keep compatible with the old leonardo bootloaders. +// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check. +#if MAGIC_KEY_POS != (RAMEND-1) + // For future boards save the key in the inproblematic RAMEND + // Which is reserved for the main() return value (which will never return) + if (_updatedLUFAbootloader) { + // horray, we got a new bootloader! + magic_key_pos = (RAMEND-1); + } +#endif + + // We check DTR state to determine if host port is open (bit 0 of lineState). + if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) + { +#if MAGIC_KEY_POS != (RAMEND-1) + // Backup ram value if its not a newer bootloader. + // This should avoid memory corruption at least a bit, not fully + if (magic_key_pos != (RAMEND-1)) { + *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos; + } +#endif + // Store boot key + *(uint16_t *)magic_key_pos = MAGIC_KEY; + wdt_enable(WDTO_120MS); + } + else + { + // Most OSs do some intermediate steps when configuring ports and DTR can + // twiggle more than once before stabilizing. + // To avoid spurious resets we set the watchdog to 250ms and eventually + // cancel if DTR goes back high. + + wdt_disable(); + wdt_reset(); +#if MAGIC_KEY_POS != (RAMEND-1) + // Restore backed up (old bootloader) magic key data + if (magic_key_pos != (RAMEND-1)) { + *(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1); + } else +#endif + { + // Clean up RAMEND key + *(uint16_t *)magic_key_pos = 0x0000; + } + } + } + return true; + } + return false; +} + + +void Serial_::begin(unsigned long /* baud_count */) +{ + peek_buffer = -1; +} + +void Serial_::begin(unsigned long /* baud_count */, byte /* config */) +{ + peek_buffer = -1; +} + +void Serial_::end(void) +{ +} + +int Serial_::available(void) +{ + if (peek_buffer >= 0) { + return 1 + USB_Available(CDC_RX); + } + return USB_Available(CDC_RX); +} + +int Serial_::peek(void) +{ + if (peek_buffer < 0) + peek_buffer = USB_Recv(CDC_RX); + return peek_buffer; +} + +int Serial_::read(void) +{ + if (peek_buffer >= 0) { + int c = peek_buffer; + peek_buffer = -1; + return c; + } + return USB_Recv(CDC_RX); +} + +int Serial_::availableForWrite(void) +{ + return USB_SendSpace(CDC_TX); +} + +void Serial_::flush(void) +{ + USB_Flush(CDC_TX); +} + +size_t Serial_::write(uint8_t c) +{ + return write(&c, 1); +} + +size_t Serial_::write(const uint8_t *buffer, size_t size) +{ + /* only try to send bytes if the high-level CDC connection itself + is open (not just the pipe) - the OS should set lineState when the port + is opened and clear lineState when the port is closed. + bytes sent before the user opens the connection or after + the connection is closed are lost - just like with a UART. */ + + // TODO - ZE - check behavior on different OSes and test what happens if an + // open connection isn't broken cleanly (cable is yanked out, host dies + // or locks up, or host virtual serial port hangs) + if (_usbLineInfo.lineState > 0) { + int r = USB_Send(CDC_TX,buffer,size); + if (r > 0) { + return r; + } else { + setWriteError(); + return 0; + } + } + setWriteError(); + return 0; +} + +// This operator is a convenient way for a sketch to check whether the +// port has actually been configured and opened by the host (as opposed +// to just being connected to the host). It can be used, for example, in +// setup() before printing to ensure that an application on the host is +// actually ready to receive and display the data. +// We add a short delay before returning to fix a bug observed by Federico +// where the port is configured (lineState != 0) but not quite opened. +Serial_::operator bool() { + bool result = false; + if (_usbLineInfo.lineState > 0) + result = true; + delay(10); + return result; +} + +unsigned long Serial_::baud() { + // Disable interrupts while reading a multi-byte value + uint32_t baudrate; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + baudrate = _usbLineInfo.dwDTERate; + } + return baudrate; +} + +uint8_t Serial_::stopbits() { + return _usbLineInfo.bCharFormat; +} + +uint8_t Serial_::paritytype() { + return _usbLineInfo.bParityType; +} + +uint8_t Serial_::numbits() { + return _usbLineInfo.bDataBits; +} + +bool Serial_::dtr() { + return _usbLineInfo.lineState & 0x1; +} + +bool Serial_::rts() { + return _usbLineInfo.lineState & 0x2; +} + +int32_t Serial_::readBreak() { + int32_t ret; + // Disable IRQs while reading and clearing breakValue to make + // sure we don't overwrite a value just set by the ISR. + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + ret = breakValue; + breakValue = -1; + } + return ret; +} + +Serial_ Serial; + +#endif /* if defined(USBCON) */ diff --git a/sparkfun/tiny/cores/arduino/Client.h b/sparkfun/tiny/cores/arduino/Client.h new file mode 100644 index 00000000..b8e5d935 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Client.h @@ -0,0 +1,45 @@ +/* + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef client_h +#define client_h +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/sparkfun/tiny/cores/arduino/HardwareSerial.cpp b/sparkfun/tiny/cores/arduino/HardwareSerial.cpp new file mode 100644 index 00000000..5cd89e5e --- /dev/null +++ b/sparkfun/tiny/cores/arduino/HardwareSerial.cpp @@ -0,0 +1,250 @@ +/* + HardwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include +#include +#include +#include +#include "Arduino.h" + +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// this next line disables the entire HardwareSerial.cpp, +// this is so I can support Attiny series and any other chip without a uart +#if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) + +// SerialEvent functions are weak, so when the user doesn't define them, +// the linker just sets their address to 0 (which is checked below). +// The Serialx_available is just a wrapper around Serialx.available(), +// but we can refer to it weakly so we don't pull in the entire +// HardwareSerial instance if the user doesn't also refer to it. +#if defined(HAVE_HWSERIAL0) + void serialEvent() __attribute__((weak)); + bool Serial0_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL1) + void serialEvent1() __attribute__((weak)); + bool Serial1_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL2) + void serialEvent2() __attribute__((weak)); + bool Serial2_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL3) + void serialEvent3() __attribute__((weak)); + bool Serial3_available() __attribute__((weak)); +#endif + +void serialEventRun(void) +{ +#if defined(HAVE_HWSERIAL0) + if (Serial0_available && serialEvent && Serial0_available()) serialEvent(); +#endif +#if defined(HAVE_HWSERIAL1) + if (Serial1_available && serialEvent1 && Serial1_available()) serialEvent1(); +#endif +#if defined(HAVE_HWSERIAL2) + if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2(); +#endif +#if defined(HAVE_HWSERIAL3) + if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3(); +#endif +} + +// Actual interrupt handlers ////////////////////////////////////////////////////////////// + +void HardwareSerial::_tx_udr_empty_irq(void) +{ + // If interrupts are enabled, there must be more data in the output + // buffer. Send the next byte + unsigned char c = _tx_buffer[_tx_buffer_tail]; + _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE; + + *_udr = c; + + // clear the TXC bit -- "can be cleared by writing a one to its bit + // location". This makes sure flush() won't return until the bytes + // actually got written + sbi(*_ucsra, TXC0); + + if (_tx_buffer_head == _tx_buffer_tail) { + // Buffer empty, so disable interrupts + cbi(*_ucsrb, UDRIE0); + } +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void HardwareSerial::begin(unsigned long baud, byte config) +{ + // Try u2x mode first + uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2; + *_ucsra = 1 << U2X0; + + // hardcoded exception for 57600 for compatibility with the bootloader + // shipped with the Duemilanove and previous boards and the firmware + // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot + // be > 4095, so switch back to non-u2x mode if the baud rate is too + // low. + if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095)) + { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + _written = false; + + //set the data bits, parity, and stop bits +#if defined(__AVR_ATmega8__) + config |= 0x80; // select UCSRC register (shared with UBRRH) +#endif + *_ucsrc = config; + + sbi(*_ucsrb, RXEN0); + sbi(*_ucsrb, TXEN0); + sbi(*_ucsrb, RXCIE0); + cbi(*_ucsrb, UDRIE0); +} + +void HardwareSerial::end() +{ + // wait for transmission of outgoing data + flush(); + + cbi(*_ucsrb, RXEN0); + cbi(*_ucsrb, TXEN0); + cbi(*_ucsrb, RXCIE0); + cbi(*_ucsrb, UDRIE0); + + // clear any received data + _rx_buffer_head = _rx_buffer_tail; +} + +int HardwareSerial::available(void) +{ + return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE; +} + +int HardwareSerial::peek(void) +{ + if (_rx_buffer_head == _rx_buffer_tail) { + return -1; + } else { + return _rx_buffer[_rx_buffer_tail]; + } +} + +int HardwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer_head == _rx_buffer_tail) { + return -1; + } else { + unsigned char c = _rx_buffer[_rx_buffer_tail]; + _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE; + return c; + } +} + +int HardwareSerial::availableForWrite(void) +{ +#if (SERIAL_TX_BUFFER_SIZE>256) + uint8_t oldSREG = SREG; + cli(); +#endif + tx_buffer_index_t head = _tx_buffer_head; + tx_buffer_index_t tail = _tx_buffer_tail; +#if (SERIAL_TX_BUFFER_SIZE>256) + SREG = oldSREG; +#endif + if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; + return tail - head - 1; +} + +void HardwareSerial::flush() +{ + // If we have never written a byte, no need to flush. This special + // case is needed since there is no way to force the TXC (transmit + // complete) bit to 1 during initialization + if (!_written) + return; + + while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) { + if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0)) + // Interrupts are globally disabled, but the DR empty + // interrupt should be enabled, so poll the DR empty flag to + // prevent deadlock + if (bit_is_set(*_ucsra, UDRE0)) + _tx_udr_empty_irq(); + } + // If we get here, nothing is queued anymore (DRIE is disabled) and + // the hardware finished tranmission (TXC is set). +} + +size_t HardwareSerial::write(uint8_t c) +{ + _written = true; + // If the buffer and the data register is empty, just write the byte + // to the data register and be done. This shortcut helps + // significantly improve the effective datarate at high (> + // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. + if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { + *_udr = c; + sbi(*_ucsra, TXC0); + return 1; + } + tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (i == _tx_buffer_tail) { + if (bit_is_clear(SREG, SREG_I)) { + // Interrupts are disabled, so we'll have to poll the data + // register empty flag ourselves. If it is set, pretend an + // interrupt has happened and call the handler to free up + // space for us. + if(bit_is_set(*_ucsra, UDRE0)) + _tx_udr_empty_irq(); + } else { + // nop, the interrupt handler will free up space for us + } + } + + _tx_buffer[_tx_buffer_head] = c; + _tx_buffer_head = i; + + sbi(*_ucsrb, UDRIE0); + + return 1; +} + +#endif // whole file diff --git a/sparkfun/tiny/cores/arduino/HardwareSerial.h b/sparkfun/tiny/cores/arduino/HardwareSerial.h new file mode 100644 index 00000000..8a5bf95e --- /dev/null +++ b/sparkfun/tiny/cores/arduino/HardwareSerial.h @@ -0,0 +1,161 @@ +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include + +#include "Stream.h" + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which head is the index of the location +// to which to write the next incoming character and tail is the index of the +// location from which to read. +// NOTE: a "power of 2" buffer size is reccomended to dramatically +// optimize all the modulo operations for ring buffers. +// WARNING: When buffer sizes are increased to > 256, the buffer index +// variables are automatically increased in size, but the extra +// atomicity guards needed for that are not implemented. This will +// often work, but occasionally a race condition can occur that makes +// Serial behave erratically. See https://github.com/arduino/Arduino/issues/2405 +#if !defined(SERIAL_TX_BUFFER_SIZE) +#if ((RAMEND - RAMSTART) < 1023) +#define SERIAL_TX_BUFFER_SIZE 16 +#else +#define SERIAL_TX_BUFFER_SIZE 64 +#endif +#endif +#if !defined(SERIAL_RX_BUFFER_SIZE) +#if ((RAMEND - RAMSTART) < 1023) +#define SERIAL_RX_BUFFER_SIZE 16 +#else +#define SERIAL_RX_BUFFER_SIZE 64 +#endif +#endif +#if (SERIAL_TX_BUFFER_SIZE>256) +typedef uint16_t tx_buffer_index_t; +#else +typedef uint8_t tx_buffer_index_t; +#endif +#if (SERIAL_RX_BUFFER_SIZE>256) +typedef uint16_t rx_buffer_index_t; +#else +typedef uint8_t rx_buffer_index_t; +#endif + +// Define config for Serial.begin(baud, config); +#define SERIAL_5N1 0x00 +#define SERIAL_6N1 0x02 +#define SERIAL_7N1 0x04 +#define SERIAL_8N1 0x06 +#define SERIAL_5N2 0x08 +#define SERIAL_6N2 0x0A +#define SERIAL_7N2 0x0C +#define SERIAL_8N2 0x0E +#define SERIAL_5E1 0x20 +#define SERIAL_6E1 0x22 +#define SERIAL_7E1 0x24 +#define SERIAL_8E1 0x26 +#define SERIAL_5E2 0x28 +#define SERIAL_6E2 0x2A +#define SERIAL_7E2 0x2C +#define SERIAL_8E2 0x2E +#define SERIAL_5O1 0x30 +#define SERIAL_6O1 0x32 +#define SERIAL_7O1 0x34 +#define SERIAL_8O1 0x36 +#define SERIAL_5O2 0x38 +#define SERIAL_6O2 0x3A +#define SERIAL_7O2 0x3C +#define SERIAL_8O2 0x3E + +class HardwareSerial : public Stream +{ + protected: + volatile uint8_t * const _ubrrh; + volatile uint8_t * const _ubrrl; + volatile uint8_t * const _ucsra; + volatile uint8_t * const _ucsrb; + volatile uint8_t * const _ucsrc; + volatile uint8_t * const _udr; + // Has any byte been written to the UART since begin() + bool _written; + + volatile rx_buffer_index_t _rx_buffer_head; + volatile rx_buffer_index_t _rx_buffer_tail; + volatile tx_buffer_index_t _tx_buffer_head; + volatile tx_buffer_index_t _tx_buffer_tail; + + // Don't put any members after these buffers, since only the first + // 32 bytes of this struct can be accessed quickly using the ldd + // instruction. + unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE]; + unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE]; + + public: + inline HardwareSerial( + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *ucsrc, volatile uint8_t *udr); + void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } + void begin(unsigned long, uint8_t); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + int availableForWrite(void); + virtual void flush(void); + virtual size_t write(uint8_t); + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool() { return true; } + + // Interrupt handlers - Not intended to be called externally + inline void _rx_complete_irq(void); + void _tx_udr_empty_irq(void); +}; + +#if defined(UBRRH) || defined(UBRR0H) + extern HardwareSerial Serial; + #define HAVE_HWSERIAL0 +#endif +#if defined(UBRR1H) + extern HardwareSerial Serial1; + #define HAVE_HWSERIAL1 +#endif +#if defined(UBRR2H) + extern HardwareSerial Serial2; + #define HAVE_HWSERIAL2 +#endif +#if defined(UBRR3H) + extern HardwareSerial Serial3; + #define HAVE_HWSERIAL3 +#endif + +extern void serialEventRun(void) __attribute__((weak)); + +#endif diff --git a/sparkfun/tiny/cores/arduino/HardwareSerial0.cpp b/sparkfun/tiny/cores/arduino/HardwareSerial0.cpp new file mode 100644 index 00000000..1146eeba --- /dev/null +++ b/sparkfun/tiny/cores/arduino/HardwareSerial0.cpp @@ -0,0 +1,79 @@ +/* + HardwareSerial0.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, sine the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL0) + +#if defined(USART_RX_vect) + ISR(USART_RX_vect) +#elif defined(USART0_RX_vect) + ISR(USART0_RX_vect) +#elif defined(USART_RXC_vect) + ISR(USART_RXC_vect) // ATmega8 +#else + #error "Don't know what the Data Received vector is called for Serial" +#endif + { + Serial._rx_complete_irq(); + } + +#if defined(UART0_UDRE_vect) +ISR(UART0_UDRE_vect) +#elif defined(UART_UDRE_vect) +ISR(UART_UDRE_vect) +#elif defined(USART0_UDRE_vect) +ISR(USART0_UDRE_vect) +#elif defined(USART_UDRE_vect) +ISR(USART_UDRE_vect) +#else + #error "Don't know what the Data Register Empty vector is called for Serial" +#endif +{ + Serial._tx_udr_empty_irq(); +} + +#if defined(UBRRH) && defined(UBRRL) + HardwareSerial Serial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); +#else + HardwareSerial Serial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0); +#endif + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial0_available() { + return Serial.available(); +} + +#endif // HAVE_HWSERIAL0 diff --git a/sparkfun/tiny/cores/arduino/HardwareSerial1.cpp b/sparkfun/tiny/cores/arduino/HardwareSerial1.cpp new file mode 100644 index 00000000..19625e23 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/HardwareSerial1.cpp @@ -0,0 +1,69 @@ +/* + HardwareSerial1.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, sine the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL1) + +#if defined(UART1_RX_vect) +ISR(UART1_RX_vect) +#elif defined(USART1_RX_vect) +ISR(USART1_RX_vect) +#else +#error "Don't know what the Data Register Empty vector is called for Serial1" +#endif +{ + Serial1._rx_complete_irq(); +} + +#if defined(UART1_UDRE_vect) +ISR(UART1_UDRE_vect) +#elif defined(USART1_UDRE_vect) +ISR(USART1_UDRE_vect) +#else +#error "Don't know what the Data Register Empty vector is called for Serial1" +#endif +{ + Serial1._tx_udr_empty_irq(); +} + +HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1); + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial1_available() { + return Serial1.available(); +} + +#endif // HAVE_HWSERIAL1 diff --git a/sparkfun/tiny/cores/arduino/HardwareSerial2.cpp b/sparkfun/tiny/cores/arduino/HardwareSerial2.cpp new file mode 100644 index 00000000..fd334ae1 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/HardwareSerial2.cpp @@ -0,0 +1,57 @@ +/* + HardwareSerial2.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, sine the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL2) + +ISR(USART2_RX_vect) +{ + Serial2._rx_complete_irq(); +} + +ISR(USART2_UDRE_vect) +{ + Serial2._tx_udr_empty_irq(); +} + +HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2); + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial2_available() { + return Serial2.available(); +} + +#endif // HAVE_HWSERIAL2 diff --git a/sparkfun/tiny/cores/arduino/HardwareSerial3.cpp b/sparkfun/tiny/cores/arduino/HardwareSerial3.cpp new file mode 100644 index 00000000..a68095b3 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/HardwareSerial3.cpp @@ -0,0 +1,57 @@ +/* + HardwareSerial3.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, sine the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL3) + +ISR(USART3_RX_vect) +{ + Serial3._rx_complete_irq(); +} + +ISR(USART3_UDRE_vect) +{ + Serial3._tx_udr_empty_irq(); +} + +HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3); + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial3_available() { + return Serial3.available(); +} + +#endif // HAVE_HWSERIAL3 diff --git a/sparkfun/tiny/cores/arduino/HardwareSerial_private.h b/sparkfun/tiny/cores/arduino/HardwareSerial_private.h new file mode 100644 index 00000000..761a5e55 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/HardwareSerial_private.h @@ -0,0 +1,123 @@ +/* + HardwareSerial_private.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus +*/ + +#include "wiring_private.h" + +// this next line disables the entire HardwareSerial.cpp, +// this is so I can support Attiny series and any other chip without a uart +#if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) + +// Ensure that the various bit positions we use are available with a 0 +// postfix, so we can always use the values for UART0 for all UARTs. The +// alternative, passing the various values for each UART to the +// HardwareSerial constructor also works, but makes the code bigger and +// slower. +#if !defined(TXC0) +#if defined(TXC) +// Some chips like ATmega8 don't have UPE, only PE. The other bits are +// named as expected. +#if !defined(UPE) && defined(PE) +#define UPE PE +#endif +// On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc. +#define TXC0 TXC +#define RXEN0 RXEN +#define TXEN0 TXEN +#define RXCIE0 RXCIE +#define UDRIE0 UDRIE +#define U2X0 U2X +#define UPE0 UPE +#define UDRE0 UDRE +#elif defined(TXC1) +// Some devices have uart1 but no uart0 +#define TXC0 TXC1 +#define RXEN0 RXEN1 +#define TXEN0 TXEN1 +#define RXCIE0 RXCIE1 +#define UDRIE0 UDRIE1 +#define U2X0 U2X1 +#define UPE0 UPE1 +#define UDRE0 UDRE1 +#else +#error No UART found in HardwareSerial.cpp +#endif +#endif // !defined TXC0 + +// Check at compiletime that it is really ok to use the bit positions of +// UART0 for the other UARTs as well, in case these values ever get +// changed for future hardware. +#if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \ + UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \ + UDRE1 != UDRE0) +#error "Not all bit positions for UART1 are the same as for UART0" +#endif +#if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \ + UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \ + UDRE2 != UDRE0) +#error "Not all bit positions for UART2 are the same as for UART0" +#endif +#if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \ + UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \ + UDRE3 != UDRE0) +#error "Not all bit positions for UART3 are the same as for UART0" +#endif + +// Constructors //////////////////////////////////////////////////////////////// + +HardwareSerial::HardwareSerial( + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *ucsrc, volatile uint8_t *udr) : + _ubrrh(ubrrh), _ubrrl(ubrrl), + _ucsra(ucsra), _ucsrb(ucsrb), _ucsrc(ucsrc), + _udr(udr), + _rx_buffer_head(0), _rx_buffer_tail(0), + _tx_buffer_head(0), _tx_buffer_tail(0) +{ +} + +// Actual interrupt handlers ////////////////////////////////////////////////////////////// + +void HardwareSerial::_rx_complete_irq(void) +{ + if (bit_is_clear(*_ucsra, UPE0)) { + // No Parity error, read byte and store it in the buffer if there is + // room + unsigned char c = *_udr; + rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != _rx_buffer_tail) { + _rx_buffer[_rx_buffer_head] = c; + _rx_buffer_head = i; + } + } else { + // Parity error, read byte but discard it + *_udr; + }; +} + +#endif // whole file diff --git a/sparkfun/tiny/cores/arduino/IPAddress.cpp b/sparkfun/tiny/cores/arduino/IPAddress.cpp new file mode 100644 index 00000000..d9fe5be1 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/IPAddress.cpp @@ -0,0 +1,114 @@ +/* + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +IPAddress::IPAddress() +{ + _address.dword = 0; +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address.bytes[0] = first_octet; + _address.bytes[1] = second_octet; + _address.bytes[2] = third_octet; + _address.bytes[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + _address.dword = address; +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +bool IPAddress::fromString(const char *address) +{ + uint16_t acc = 0; // Accumulator + uint8_t dots = 0; + + while (*address) + { + char c = *address++; + if (c >= '0' && c <= '9') + { + acc = acc * 10 + (c - '0'); + if (acc > 255) { + // Value out of [0..255] range + return false; + } + } + else if (c == '.') + { + if (dots == 3) { + // Too much dots (there must be 3 dots) + return false; + } + _address.bytes[dots++] = acc; + acc = 0; + } + else + { + // Invalid char + return false; + } + } + + if (dots != 3) { + // Too few dots (there must be 3 dots) + return false; + } + _address.bytes[3] = acc; + return true; +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + _address.dword = address; + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +size_t IPAddress::printTo(Print& p) const +{ + size_t n = 0; + for (int i =0; i < 3; i++) + { + n += p.print(_address.bytes[i], DEC); + n += p.print('.'); + } + n += p.print(_address.bytes[3], DEC); + return n; +} + diff --git a/sparkfun/tiny/cores/arduino/IPAddress.h b/sparkfun/tiny/cores/arduino/IPAddress.h new file mode 100644 index 00000000..d762f2c0 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/IPAddress.h @@ -0,0 +1,78 @@ +/* + IPAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef IPAddress_h +#define IPAddress_h + +#include +#include "Printable.h" +#include "WString.h" + +// A class to make it easier to handle and pass around IP addresses + +class IPAddress : public Printable { +private: + union { + uint8_t bytes[4]; // IPv4 address + uint32_t dword; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address.bytes; }; + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + bool fromString(const char *address); + bool fromString(const String &address) { return fromString(address.c_str()); } + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() const { return _address.dword; }; + bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; }; + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address.bytes[index]; }; + uint8_t& operator[](int index) { return _address.bytes[index]; }; + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + + virtual size_t printTo(Print& p) const; + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; +}; + +const IPAddress INADDR_NONE(0,0,0,0); + +#endif diff --git a/sparkfun/tiny/cores/arduino/PluggableUSB.cpp b/sparkfun/tiny/cores/arduino/PluggableUSB.cpp new file mode 100644 index 00000000..c489d9f1 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/PluggableUSB.cpp @@ -0,0 +1,115 @@ +/* + PluggableUSB.cpp + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "USBAPI.h" +#include "PluggableUSB.h" + +#if defined(USBCON) +#ifdef PLUGGABLE_USB_ENABLED + +extern uint8_t _initEndpoints[]; + +int PluggableUSB_::getInterface(uint8_t* interfaceCount) +{ + int sent = 0; + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int res = node->getInterface(interfaceCount); + if (res < 0) + return -1; + sent += res; + } + return sent; +} + +int PluggableUSB_::getDescriptor(USBSetup& setup) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int ret = node->getDescriptor(setup); + // ret!=0 -> request has been processed + if (ret) + return ret; + } + return 0; +} + +void PluggableUSB_::getShortName(char *iSerialNum) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + iSerialNum += node->getShortName(iSerialNum); + } + *iSerialNum = 0; +} + +bool PluggableUSB_::setup(USBSetup& setup) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + if (node->setup(setup)) { + return true; + } + } + return false; +} + +bool PluggableUSB_::plug(PluggableUSBModule *node) +{ + if ((lastEp + node->numEndpoints) > USB_ENDPOINTS) { + return false; + } + + if (!rootNode) { + rootNode = node; + } else { + PluggableUSBModule *current = rootNode; + while (current->next) { + current = current->next; + } + current->next = node; + } + + node->pluggedInterface = lastIf; + node->pluggedEndpoint = lastEp; + lastIf += node->numInterfaces; + for (uint8_t i = 0; i < node->numEndpoints; i++) { + _initEndpoints[lastEp] = node->endpointType[i]; + lastEp++; + } + return true; + // restart USB layer??? +} + +PluggableUSB_& PluggableUSB() +{ + static PluggableUSB_ obj; + return obj; +} + +PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT), + lastEp(CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT), + rootNode(NULL) +{ + // Empty +} + +#endif + +#endif /* if defined(USBCON) */ diff --git a/sparkfun/tiny/cores/arduino/PluggableUSB.h b/sparkfun/tiny/cores/arduino/PluggableUSB.h new file mode 100644 index 00000000..507f0df9 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/PluggableUSB.h @@ -0,0 +1,74 @@ +/* + PluggableUSB.h + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef PUSB_h +#define PUSB_h + +#include "USBAPI.h" +#include + +#if defined(USBCON) + +class PluggableUSBModule { +public: + PluggableUSBModule(uint8_t numEps, uint8_t numIfs, uint8_t *epType) : + numEndpoints(numEps), numInterfaces(numIfs), endpointType(epType) + { } + +protected: + virtual bool setup(USBSetup& setup) = 0; + virtual int getInterface(uint8_t* interfaceCount) = 0; + virtual int getDescriptor(USBSetup& setup) = 0; + virtual uint8_t getShortName(char *name) { name[0] = 'A'+pluggedInterface; return 1; } + + uint8_t pluggedInterface; + uint8_t pluggedEndpoint; + + const uint8_t numEndpoints; + const uint8_t numInterfaces; + const uint8_t *endpointType; + + PluggableUSBModule *next = NULL; + + friend class PluggableUSB_; +}; + +class PluggableUSB_ { +public: + PluggableUSB_(); + bool plug(PluggableUSBModule *node); + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + void getShortName(char *iSerialNum); + +private: + uint8_t lastIf; + uint8_t lastEp; + PluggableUSBModule* rootNode; +}; + +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +PluggableUSB_& PluggableUSB(); + +#endif + +#endif diff --git a/sparkfun/tiny/cores/arduino/Print.cpp b/sparkfun/tiny/cores/arduino/Print.cpp new file mode 100644 index 00000000..1e4c99a6 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Print.cpp @@ -0,0 +1,266 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 03 August 2015 by Chuck Todd + */ + +#include +#include +#include +#include +#include "Arduino.h" + +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +/* default implementation: may be overridden */ +size_t Print::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + while (size--) { + if (write(*buffer++)) n++; + else break; + } + return n; +} + +size_t Print::print(const __FlashStringHelper *ifsh) +{ + PGM_P p = reinterpret_cast(ifsh); + size_t n = 0; + while (1) { + unsigned char c = pgm_read_byte(p++); + if (c == 0) break; + if (write(c)) n++; + else break; + } + return n; +} + +size_t Print::print(const String &s) +{ + return write(s.c_str(), s.length()); +} + +size_t Print::print(const char str[]) +{ + return write(str); +} + +size_t Print::print(char c) +{ + return write(c); +} + +size_t Print::print(unsigned char b, int base) +{ + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) +{ + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) +{ + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) +{ + if (base == 0) { + return write(n); + } else if (base == 10) { + if (n < 0) { + int t = print('-'); + n = -n; + return printNumber(n, 10) + t; + } + return printNumber(n, 10); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(unsigned long n, int base) +{ + if (base == 0) return write(n); + else return printNumber(n, base); +} + +size_t Print::print(double n, int digits) +{ + return printFloat(n, digits); +} + +size_t Print::println(const __FlashStringHelper *ifsh) +{ + size_t n = print(ifsh); + n += println(); + return n; +} + +size_t Print::print(const Printable& x) +{ + return x.printTo(*this); +} + +size_t Print::println(void) +{ + return write("\r\n"); +} + +size_t Print::println(const String &s) +{ + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) +{ + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) +{ + size_t n = print(num, digits); + n += println(); + return n; +} + +size_t Print::println(const Printable& x) +{ + size_t n = print(x); + n += println(); + return n; +} + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) +{ + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if (base < 2) base = 10; + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) +{ + size_t n = 0; + + if (isnan(number)) return print("nan"); + if (isinf(number)) return print("inf"); + if (number > 4294967040.0) return print ("ovf"); // constant determined empirically + if (number <-4294967040.0) return print ("ovf"); // constant determined empirically + + // Handle negative numbers + if (number < 0.0) + { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i 0) { + n += print('.'); + } + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/sparkfun/tiny/cores/arduino/Print.h b/sparkfun/tiny/cores/arduino/Print.h new file mode 100644 index 00000000..7b53aa4d --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Print.h @@ -0,0 +1,84 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Print_h +#define Print_h + +#include +#include // for size_t + +#include "WString.h" +#include "Printable.h" + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 + +class Print +{ + private: + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + protected: + void setWriteError(int err = 1) { write_error = err; } + public: + Print() : write_error(0) {} + + int getWriteError() { return write_error; } + void clearWriteError() { setWriteError(0); } + + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); + } + + size_t print(const __FlashStringHelper *); + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + size_t print(const Printable&); + + size_t println(const __FlashStringHelper *); + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(const Printable&); + size_t println(void); +}; + +#endif diff --git a/sparkfun/tiny/cores/arduino/Printable.h b/sparkfun/tiny/cores/arduino/Printable.h new file mode 100644 index 00000000..2a1b2e9f --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Printable.h @@ -0,0 +1,40 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Printable_h +#define Printable_h + +#include + +class Print; + +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. +*/ + +class Printable +{ + public: + virtual size_t printTo(Print& p) const = 0; +}; + +#endif + diff --git a/sparkfun/tiny/cores/arduino/Server.h b/sparkfun/tiny/cores/arduino/Server.h new file mode 100644 index 00000000..69e3e39f --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Server.h @@ -0,0 +1,30 @@ +/* + Server.h - Base class that provides Server + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef server_h +#define server_h + +#include "Print.h" + +class Server : public Print { +public: + virtual void begin() =0; +}; + +#endif diff --git a/sparkfun/tiny/cores/arduino/Stream.cpp b/sparkfun/tiny/cores/arduino/Stream.cpp new file mode 100644 index 00000000..f6654653 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Stream.cpp @@ -0,0 +1,319 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + + findMulti/findUntil routines written by Jim Leonard/Xuth + */ + +#include "Arduino.h" +#include "Stream.h" + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait + +// private method to read stream with timeout +int Stream::timedRead() +{ + int c; + _startMillis = millis(); + do { + c = read(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// private method to peek stream with timeout +int Stream::timedPeek() +{ + int c; + _startMillis = millis(); + do { + c = peek(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// returns peek of the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal) +{ + int c; + while (1) { + c = timedPeek(); + + if( c < 0 || + c == '-' || + (c >= '0' && c <= '9') || + (detectDecimal && c == '.')) return c; + + switch( lookahead ){ + case SKIP_NONE: return -1; // Fail code. + case SKIP_WHITESPACE: + switch( c ){ + case ' ': + case '\t': + case '\r': + case '\n': break; + default: return -1; // Fail code. + } + case SKIP_ALL: + break; + } + read(); // discard non-numeric + } +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait +{ + _timeout = timeout; +} + + // find returns true if the target string is found +bool Stream::find(char *target) +{ + return findUntil(target, strlen(target), NULL, 0); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(char *target, char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) +{ + if (terminator == NULL) { + MultiTarget t[1] = {{target, targetLen, 0}}; + return findMulti(t, 1) == 0 ? true : false; + } else { + MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}}; + return findMulti(t, 2) == 0 ? true : false; + } +} + +// returns the first valid (long) integer value from the current position. +// lookahead determines how parseInt looks ahead in the stream. +// See LookaheadMode enumeration at the top of the file. +// Lookahead is terminated by the first character that is not a valid part of an integer. +// Once parsing commences, 'ignore' will be skipped in the stream. +long Stream::parseInt(LookaheadMode lookahead, char ignore) +{ + bool isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(lookahead, false); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == ignore) + ; // ignore this character + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || c == ignore ); + + if(isNegative) + value = -value; + return value; +} + +// as parseInt but returns a floating point value +float Stream::parseFloat(LookaheadMode lookahead, char ignore) +{ + bool isNegative = false; + bool isFraction = false; + long value = 0; + int c; + float fraction = 1.0; + + c = peekNextDigit(lookahead, true); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == ignore) + ; // ignore + else if(c == '-') + isNegative = true; + else if (c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || (c == '.' && !isFraction) || c == ignore ); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, or timeout (see setTimeout) +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +// +size_t Stream::readBytes(char *buffer, size_t length) +{ + size_t count = 0; + while (count < length) { + int c = timedRead(); + if (c < 0) break; + *buffer++ = (char)c; + count++; + } + return count; +} + + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) +{ + if (length < 1) return 0; + size_t index = 0; + while (index < length) { + int c = timedRead(); + if (c < 0 || c == terminator) break; + *buffer++ = (char)c; + index++; + } + return index; // return number of characters, not including null terminator +} + +String Stream::readString() +{ + String ret; + int c = timedRead(); + while (c >= 0) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + +String Stream::readStringUntil(char terminator) +{ + String ret; + int c = timedRead(); + while (c >= 0 && c != terminator) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + +int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) { + // any zero length target string automatically matches and would make + // a mess of the rest of the algorithm. + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + if (t->len <= 0) + return t - targets; + } + + while (1) { + int c = timedRead(); + if (c < 0) + return -1; + + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + // the simple case is if we match, deal with that first. + if (c == t->str[t->index]) { + if (++t->index == t->len) + return t - targets; + else + continue; + } + + // if not we need to walk back and see if we could have matched further + // down the stream (ie '1112' doesn't match the first position in '11112' + // but it will match the second position so we can't just reset the current + // index to 0 when we find a mismatch. + if (t->index == 0) + continue; + + int origIndex = t->index; + do { + --t->index; + // first check if current char works against the new current index + if (c != t->str[t->index]) + continue; + + // if it's the only char then we're good, nothing more to check + if (t->index == 0) { + t->index++; + break; + } + + // otherwise we need to check the rest of the found string + int diff = origIndex - t->index; + size_t i; + for (i = 0; i < t->index; ++i) { + if (t->str[i] != t->str[i + diff]) + break; + } + + // if we successfully got through the previous loop then our current + // index is good. + if (i == t->index) { + t->index++; + break; + } + + // otherwise we just try the next index + } while (t->index); + } + } + // unreachable + return -1; +} diff --git a/sparkfun/tiny/cores/arduino/Stream.h b/sparkfun/tiny/cores/arduino/Stream.h new file mode 100644 index 00000000..e4fd4338 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Stream.h @@ -0,0 +1,130 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis +*/ + +#ifndef Stream_h +#define Stream_h + +#include +#include "Print.h" + +// compatability macros for testing +/* +#define getInt() parseInt() +#define getInt(ignore) parseInt(ignore) +#define getFloat() parseFloat() +#define getFloat(ignore) parseFloat(ignore) +#define getString( pre_string, post_string, buffer, length) +readBytesBetween( pre_string, terminator, buffer, length) +*/ + +// This enumeration provides the lookahead options for parseInt(), parseFloat() +// The rules set out here are used until either the first valid character is found +// or a time out occurs due to lack of input. +enum LookaheadMode{ + SKIP_ALL, // All invalid characters are ignored. + SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid. + SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped. +}; + +#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field + +class Stream : public Print +{ + protected: + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int timedPeek(); // private method to peek stream with timeout + int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout + + public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; + + Stream() {_timeout=1000;} + +// parsing methods + + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + unsigned long getTimeout(void) { return _timeout; } + + bool find(char *target); // reads data from the stream until the target string is found + bool find(uint8_t *target) { return find ((char *)target); } + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found + bool find(uint8_t *target, size_t length) { return find ((char *)target, length); } + // returns true if target string is found, false if timed out + + bool find(char target) { return find (&target, 1); } + + bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found + bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); } + + bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found + bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } + + long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // returns the first valid (long) integer value from the current position. + // lookahead determines how parseInt looks ahead in the stream. + // See LookaheadMode enumeration at the top of the file. + // Lookahead is terminated by the first character that is not a valid part of an integer. + // Once parsing commences, 'ignore' will be skipped in the stream. + + float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // float version of parseInt + + size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer + size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character + size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); } + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + String readString(); + String readStringUntil(char terminator); + + protected: + long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); } + float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); } + // These overload exists for compatibility with any class that has derived + // Stream and used parseFloat/Int with a custom ignore character. To keep + // the public API simple, these overload remains protected. + + struct MultiTarget { + const char *str; // string you're searching for + size_t len; // length of string you're searching for + size_t index; // index used by the search routine. + }; + + // This allows you to search for an arbitrary number of strings. + // Returns index of the target that is found first or -1 if timeout occurs. + int findMulti(struct MultiTarget *targets, int tCount); +}; + +#undef NO_IGNORE_CHAR +#endif diff --git a/sparkfun/tiny/cores/arduino/Tone.cpp b/sparkfun/tiny/cores/arduino/Tone.cpp new file mode 100644 index 00000000..1bfb3e37 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Tone.cpp @@ -0,0 +1,619 @@ +/* Tone.cpp + + A Tone Generator Library + + Written by Brett Hagman + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Version Modified By Date Comments +------- ----------- -------- -------- +0001 B Hagman 09/08/02 Initial coding +0002 B Hagman 09/08/18 Multiple pins +0003 B Hagman 09/08/18 Moved initialization from constructor to begin() +0004 B Hagman 09/09/26 Fixed problems with ATmega8 +0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers + 09/11/25 Changed pin toggle method to XOR + 09/11/25 Fixed timer0 from being excluded +0006 D Mellis 09/12/29 Replaced objects with functions +0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register +0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY +0009 J Reucker 15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62) +0010 jipp 15/04/13 added additional define check #2923 +*************************************************/ + +#include +#include +#include "Arduino.h" +#include "pins_arduino.h" + +#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__) +#define TCCR2A TCCR2 +#define TCCR2B TCCR2 +#define COM2A1 COM21 +#define COM2A0 COM20 +#define OCR2A OCR2 +#define TIMSK2 TIMSK +#define OCIE2A OCIE2 +#define TIMER2_COMPA_vect TIMER2_COMP_vect +#define TIMSK1 TIMSK +#endif + +// timerx_toggle_count: +// > 0 - duration specified +// = 0 - stopped +// < 0 - infinitely (until stop() method called, or new play() called) + +#if !defined(__AVR_ATmega8__) +volatile long timer0_toggle_count; +volatile uint8_t *timer0_pin_port; +volatile uint8_t timer0_pin_mask; +#endif + +volatile long timer1_toggle_count; +volatile uint8_t *timer1_pin_port; +volatile uint8_t timer1_pin_mask; +volatile long timer2_toggle_count; +volatile uint8_t *timer2_pin_port; +volatile uint8_t timer2_pin_mask; + +#if defined(TIMSK3) +volatile long timer3_toggle_count; +volatile uint8_t *timer3_pin_port; +volatile uint8_t timer3_pin_mask; +#endif + +#if defined(TIMSK4) +volatile long timer4_toggle_count; +volatile uint8_t *timer4_pin_port; +volatile uint8_t timer4_pin_mask; +#endif + +#if defined(TIMSK5) +volatile long timer5_toggle_count; +volatile uint8_t *timer5_pin_port; +volatile uint8_t timer5_pin_mask; +#endif + + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ }; + +#elif defined(__AVR_ATmega8__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#elif defined(__AVR_ATmega32U4__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER3 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#else + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +// Leave timer 0 to last. +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ }; + +#endif + + + +static int8_t toneBegin(uint8_t _pin) +{ + int8_t _timer = -1; + + // if we're already using the pin, the timer should be configured. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + return pgm_read_byte(tone_pin_to_timer_PGM + i); + } + } + + // search for an unused timer. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == 255) { + tone_pins[i] = _pin; + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + break; + } + } + + if (_timer != -1) + { + // Set timer specific stuff + // All timers in CTC mode + // 8 bit timers will require changing prescalar values, + // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar + switch (_timer) + { + #if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01) + case 0: + // 8 bit timer + TCCR0A = 0; + TCCR0B = 0; + bitWrite(TCCR0A, WGM01, 1); + bitWrite(TCCR0B, CS00, 1); + timer0_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer0_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12) + case 1: + // 16 bit timer + TCCR1A = 0; + TCCR1B = 0; + bitWrite(TCCR1B, WGM12, 1); + bitWrite(TCCR1B, CS10, 1); + timer1_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer1_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR2A) && defined(TCCR2B) + case 2: + // 8 bit timer + TCCR2A = 0; + TCCR2B = 0; + bitWrite(TCCR2A, WGM21, 1); + bitWrite(TCCR2B, CS20, 1); + timer2_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer2_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3) + case 3: + // 16 bit timer + TCCR3A = 0; + TCCR3B = 0; + bitWrite(TCCR3B, WGM32, 1); + bitWrite(TCCR3B, CS30, 1); + timer3_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer3_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4) + case 4: + // 16 bit timer + TCCR4A = 0; + TCCR4B = 0; + #if defined(WGM42) + bitWrite(TCCR4B, WGM42, 1); + #elif defined(CS43) + // TODO this may not be correct + // atmega32u4 + bitWrite(TCCR4B, CS43, 1); + #endif + bitWrite(TCCR4B, CS40, 1); + timer4_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer4_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5) + case 5: + // 16 bit timer + TCCR5A = 0; + TCCR5B = 0; + bitWrite(TCCR5B, WGM52, 1); + bitWrite(TCCR5B, CS50, 1); + timer5_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer5_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + } + } + + return _timer; +} + + + +// frequency (in hertz) and duration (in milliseconds). + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) +{ + uint8_t prescalarbits = 0b001; + long toggle_count = 0; + uint32_t ocr = 0; + int8_t _timer; + + _timer = toneBegin(_pin); + + if (_timer >= 0) + { + // Set the pinMode as OUTPUT + pinMode(_pin, OUTPUT); + + // if we are using an 8 bit timer, scan through prescalars to find the best fit + if (_timer == 0 || _timer == 2) + { + ocr = F_CPU / frequency / 2 - 1; + prescalarbits = 0b001; // ck/1: same for both timers + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 8 - 1; + prescalarbits = 0b010; // ck/8: same for both timers + + if (_timer == 2 && ocr > 255) + { + ocr = F_CPU / frequency / 2 / 32 - 1; + prescalarbits = 0b011; + } + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalarbits = _timer == 0 ? 0b011 : 0b100; + + if (_timer == 2 && ocr > 255) + { + ocr = F_CPU / frequency / 2 / 128 - 1; + prescalarbits = 0b101; + } + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 256 - 1; + prescalarbits = _timer == 0 ? 0b100 : 0b110; + if (ocr > 255) + { + // can't do any better than /1024 + ocr = F_CPU / frequency / 2 / 1024 - 1; + prescalarbits = _timer == 0 ? 0b101 : 0b111; + } + } + } + } + +#if defined(TCCR0B) + if (_timer == 0) + { + TCCR0B = (TCCR0B & 0b11111000) | prescalarbits; + } + else +#endif +#if defined(TCCR2B) + { + TCCR2B = (TCCR2B & 0b11111000) | prescalarbits; + } +#else + { + // dummy place holder to make the above ifdefs work + } +#endif + } + else + { + // two choices for the 16 bit timers: ck/1 or ck/64 + ocr = F_CPU / frequency / 2 - 1; + + prescalarbits = 0b001; + if (ocr > 0xffff) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalarbits = 0b011; + } + + if (_timer == 1) + { +#if defined(TCCR1B) + TCCR1B = (TCCR1B & 0b11111000) | prescalarbits; +#endif + } +#if defined(TCCR3B) + else if (_timer == 3) + TCCR3B = (TCCR3B & 0b11111000) | prescalarbits; +#endif +#if defined(TCCR4B) + else if (_timer == 4) + TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; +#endif +#if defined(TCCR5B) + else if (_timer == 5) + TCCR5B = (TCCR5B & 0b11111000) | prescalarbits; +#endif + + } + + + // Calculate the toggle count + if (duration > 0) + { + toggle_count = 2 * frequency * duration / 1000; + } + else + { + toggle_count = -1; + } + + // Set the OCR for the given timer, + // set the toggle count, + // then turn on the interrupts + switch (_timer) + { + +#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A) + case 0: + OCR0A = ocr; + timer0_toggle_count = toggle_count; + bitWrite(TIMSK0, OCIE0A, 1); + break; +#endif + + case 1: +#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A) + OCR1A = ocr; + timer1_toggle_count = toggle_count; + bitWrite(TIMSK1, OCIE1A, 1); +#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A) + // this combination is for at least the ATmega32 + OCR1A = ocr; + timer1_toggle_count = toggle_count; + bitWrite(TIMSK, OCIE1A, 1); +#endif + break; + +#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A) + case 2: + OCR2A = ocr; + timer2_toggle_count = toggle_count; + bitWrite(TIMSK2, OCIE2A, 1); + break; +#endif + +#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A) + case 3: + OCR3A = ocr; + timer3_toggle_count = toggle_count; + bitWrite(TIMSK3, OCIE3A, 1); + break; +#endif + +#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A) + case 4: + OCR4A = ocr; + timer4_toggle_count = toggle_count; + bitWrite(TIMSK4, OCIE4A, 1); + break; +#endif + +#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A) + case 5: + OCR5A = ocr; + timer5_toggle_count = toggle_count; + bitWrite(TIMSK5, OCIE5A, 1); + break; +#endif + + } + } +} + + +// XXX: this function only works properly for timer 2 (the only one we use +// currently). for the others, it should end the tone, but won't restore +// proper PWM functionality for the timer. +void disableTimer(uint8_t _timer) +{ + switch (_timer) + { + case 0: + #if defined(TIMSK0) + TIMSK0 = 0; + #elif defined(TIMSK) + TIMSK = 0; // atmega32 + #endif + break; + +#if defined(TIMSK1) && defined(OCIE1A) + case 1: + bitWrite(TIMSK1, OCIE1A, 0); + break; +#endif + + case 2: + #if defined(TIMSK2) && defined(OCIE2A) + bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt + #endif + #if defined(TCCR2A) && defined(WGM20) + TCCR2A = (1 << WGM20); + #endif + #if defined(TCCR2B) && defined(CS22) + TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); + #endif + #if defined(OCR2A) + OCR2A = 0; + #endif + break; + +#if defined(TIMSK3) && defined(OCIE3A) + case 3: + bitWrite(TIMSK3, OCIE3A, 0); + break; +#endif + +#if defined(TIMSK4) && defined(OCIE4A) + case 4: + bitWrite(TIMSK4, OCIE4A, 0); + break; +#endif + +#if defined(TIMSK5) && defined(OCIE5A) + case 5: + bitWrite(TIMSK5, OCIE5A, 0); + break; +#endif + } +} + + +void noTone(uint8_t _pin) +{ + int8_t _timer = -1; + + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + tone_pins[i] = 255; + break; + } + } + + disableTimer(_timer); + + digitalWrite(_pin, 0); +} + +#ifdef USE_TIMER0 +ISR(TIMER0_COMPA_vect) +{ + if (timer0_toggle_count != 0) + { + // toggle the pin + *timer0_pin_port ^= timer0_pin_mask; + + if (timer0_toggle_count > 0) + timer0_toggle_count--; + } + else + { + disableTimer(0); + *timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER1 +ISR(TIMER1_COMPA_vect) +{ + if (timer1_toggle_count != 0) + { + // toggle the pin + *timer1_pin_port ^= timer1_pin_mask; + + if (timer1_toggle_count > 0) + timer1_toggle_count--; + } + else + { + disableTimer(1); + *timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER2 +ISR(TIMER2_COMPA_vect) +{ + + if (timer2_toggle_count != 0) + { + // toggle the pin + *timer2_pin_port ^= timer2_pin_mask; + + if (timer2_toggle_count > 0) + timer2_toggle_count--; + } + else + { + // need to call noTone() so that the tone_pins[] entry is reset, so the + // timer gets initialized next time we call tone(). + // XXX: this assumes timer 2 is always the first one used. + noTone(tone_pins[0]); +// disableTimer(2); +// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER3 +ISR(TIMER3_COMPA_vect) +{ + if (timer3_toggle_count != 0) + { + // toggle the pin + *timer3_pin_port ^= timer3_pin_mask; + + if (timer3_toggle_count > 0) + timer3_toggle_count--; + } + else + { + disableTimer(3); + *timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER4 +ISR(TIMER4_COMPA_vect) +{ + if (timer4_toggle_count != 0) + { + // toggle the pin + *timer4_pin_port ^= timer4_pin_mask; + + if (timer4_toggle_count > 0) + timer4_toggle_count--; + } + else + { + disableTimer(4); + *timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER5 +ISR(TIMER5_COMPA_vect) +{ + if (timer5_toggle_count != 0) + { + // toggle the pin + *timer5_pin_port ^= timer5_pin_mask; + + if (timer5_toggle_count > 0) + timer5_toggle_count--; + } + else + { + disableTimer(5); + *timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop + } +} +#endif diff --git a/sparkfun/tiny/cores/arduino/USBAPI.h b/sparkfun/tiny/cores/arduino/USBAPI.h new file mode 100644 index 00000000..358444ed --- /dev/null +++ b/sparkfun/tiny/cores/arduino/USBAPI.h @@ -0,0 +1,207 @@ +/* + USBAPI.h + Copyright (c) 2005-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __USBAPI__ +#define __USBAPI__ + +#include +#include +#include +#include +#include + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +#include "Arduino.h" + +// This definitions is usefull if you want to reduce the EP_SIZE to 16 +// at the moment only 64 and 16 as EP_SIZE for all EPs are supported except the control endpoint +#ifndef USB_EP_SIZE +#define USB_EP_SIZE 64 +#endif + +#if defined(USBCON) + +#include "USBDesc.h" +#include "USBCore.h" + +//================================================================================ +//================================================================================ +// USB + +#define EP_TYPE_CONTROL (0x00) +#define EP_TYPE_BULK_IN ((1<256) +#error Please lower the CDC Buffer size +#endif + +class Serial_ : public Stream +{ +private: + int peek_buffer; +public: + Serial_() { peek_buffer = -1; }; + void begin(unsigned long); + void begin(unsigned long, uint8_t); + void end(void); + + virtual int available(void); + virtual int peek(void); + virtual int read(void); + int availableForWrite(void); + virtual void flush(void); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t*, size_t); + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool(); + + volatile uint8_t _rx_buffer_head; + volatile uint8_t _rx_buffer_tail; + unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; + + // This method allows processing "SEND_BREAK" requests sent by + // the USB host. Those requests indicate that the host wants to + // send a BREAK signal and are accompanied by a single uint16_t + // value, specifying the duration of the break. The value 0 + // means to end any current break, while the value 0xffff means + // to start an indefinite break. + // readBreak() will return the value of the most recent break + // request, but will return it at most once, returning -1 when + // readBreak() is called again (until another break request is + // received, which is again returned once). + // This also mean that if two break requests are received + // without readBreak() being called in between, the value of the + // first request is lost. + // Note that the value returned is a long, so it can return + // 0-0xffff as well as -1. + int32_t readBreak(); + + // These return the settings specified by the USB host for the + // serial port. These aren't really used, but are offered here + // in case a sketch wants to act on these settings. + uint32_t baud(); + uint8_t stopbits(); + uint8_t paritytype(); + uint8_t numbits(); + bool dtr(); + bool rts(); + enum { + ONE_STOP_BIT = 0, + ONE_AND_HALF_STOP_BIT = 1, + TWO_STOP_BITS = 2, + }; + enum { + NO_PARITY = 0, + ODD_PARITY = 1, + EVEN_PARITY = 2, + MARK_PARITY = 3, + SPACE_PARITY = 4, + }; + +}; +extern Serial_ Serial; + +#define HAVE_CDCSERIAL + +//================================================================================ +//================================================================================ +// Low level API + +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint16_t wIndex; + uint16_t wLength; +} USBSetup; + +//================================================================================ +//================================================================================ +// MSC 'Driver' + +int MSC_GetInterface(uint8_t* interfaceNum); +int MSC_GetDescriptor(int i); +bool MSC_Setup(USBSetup& setup); +bool MSC_Data(uint8_t rx,uint8_t tx); + +//================================================================================ +//================================================================================ +// CSC 'Driver' + +int CDC_GetInterface(uint8_t* interfaceNum); +int CDC_GetDescriptor(int i); +bool CDC_Setup(USBSetup& setup); + +//================================================================================ +//================================================================================ + +#define TRANSFER_PGM 0x80 +#define TRANSFER_RELEASE 0x40 +#define TRANSFER_ZERO 0x20 + +int USB_SendControl(uint8_t flags, const void* d, int len); +int USB_RecvControl(void* d, int len); +int USB_RecvControlLong(void* d, int len); + +uint8_t USB_Available(uint8_t ep); +uint8_t USB_SendSpace(uint8_t ep); +int USB_Send(uint8_t ep, const void* data, int len); // blocking +int USB_Recv(uint8_t ep, void* data, int len); // non-blocking +int USB_Recv(uint8_t ep); // non-blocking +void USB_Flush(uint8_t ep); + +#endif + +#endif /* if defined(USBCON) */ diff --git a/sparkfun/tiny/cores/arduino/USBCore.cpp b/sparkfun/tiny/cores/arduino/USBCore.cpp new file mode 100644 index 00000000..723edb3c --- /dev/null +++ b/sparkfun/tiny/cores/arduino/USBCore.cpp @@ -0,0 +1,861 @@ + + +/* Copyright (c) 2010, Peter Barrett +** Sleep/Wakeup support added by Michael Dreher +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "USBAPI.h" +#include "PluggableUSB.h" +#include + +#if defined(USBCON) + +/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ +#define TX_RX_LED_PULSE_MS 100 +volatile u8 TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ +volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ + +//================================================================== +//================================================================== + +extern const u16 STRING_LANGUAGE[] PROGMEM; +extern const u8 STRING_PRODUCT[] PROGMEM; +extern const u8 STRING_MANUFACTURER[] PROGMEM; +extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM; +extern const DeviceDescriptor USB_DeviceDescriptorB PROGMEM; +extern bool _updatedLUFAbootloader; + +const u16 STRING_LANGUAGE[2] = { + (3<<8) | (2+2), + 0x0409 // English +}; + +#ifndef USB_PRODUCT +// If no product is provided, use USB IO Board +#define USB_PRODUCT "USB IO Board" +#endif + +const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT; + +#if USB_VID == 0x2341 +# if defined(USB_MANUFACTURER) +# undef USB_MANUFACTURER +# endif +# define USB_MANUFACTURER "Arduino LLC" +#elif USB_VID == 0x1b4f +# if defined(USB_MANUFACTURER) +# undef USB_MANUFACTURER +# endif +# define USB_MANUFACTURER "SparkFun" +#elif !defined(USB_MANUFACTURER) +// Fall through to unknown if no manufacturer name was provided in a macro +# define USB_MANUFACTURER "Unknown" +#endif + +const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER; + + +#define DEVICE_CLASS 0x02 + +// DEVICE DESCRIPTOR +const DeviceDescriptor USB_DeviceDescriptor = + D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1); + +const DeviceDescriptor USB_DeviceDescriptorB = + D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1); + +//================================================================== +//================================================================== + +volatile u8 _usbConfiguration = 0; +volatile u8 _usbCurrentStatus = 0; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device +volatile u8 _usbSuspendState = 0; // copy of UDINT to check SUSPI and WAKEUPI bits + +static inline void WaitIN(void) +{ + while (!(UEINTX & (1< len) + n = len; + { + LockEP lock(ep); + // Frame may have been released by the SOF interrupt handler + if (!ReadWriteAllowed()) + continue; + len -= n; + if (ep & TRANSFER_ZERO) + { + while (n--) + Send8(0); + } + else if (ep & TRANSFER_PGM) + { + while (n--) + Send8(pgm_read_byte(data++)); + } + else + { + while (n--) + Send8(*data++); + } + if (!ReadWriteAllowed() || ((len == 0) && (ep & TRANSFER_RELEASE))) // Release full buffer + ReleaseTX(); + } + } + TXLED1; // light the TX LED + TxLEDPulse = TX_RX_LED_PULSE_MS; + return r; +} + +u8 _initEndpoints[USB_ENDPOINTS] = +{ + 0, // Control Endpoint + + EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM + EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT + EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN + + // Following endpoints are automatically initialized to 0 +}; + +#define EP_SINGLE_64 0x32 // EP0 +#define EP_DOUBLE_64 0x36 // Other endpoints +#define EP_SINGLE_16 0x12 + +static +void InitEP(u8 index, u8 type, u8 size) +{ + UENUM = index; + UECONX = (1< 64){ + recvLength = 64; + } + + // Write data to fit to the end (not the beginning) of the array + WaitOUT(); + Recv((u8*)d + len - length, recvLength); + ClearOUT(); + length -= recvLength; + } + return len; +} + +static u8 SendInterfaces() +{ + u8 interfaces = 0; + + CDC_GetInterface(&interfaces); + +#ifdef PLUGGABLE_USB_ENABLED + PluggableUSB().getInterface(&interfaces); +#endif + + return interfaces; +} + +// Construct a dynamic configuration descriptor +// This really needs dynamic endpoint allocation etc +// TODO +static +bool SendConfiguration(int maxlen) +{ + // Count and measure interfaces + InitControl(0); + u8 interfaces = SendInterfaces(); + ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); + + // Now send them + InitControl(maxlen); + USB_SendControl(0,&config,sizeof(ConfigDescriptor)); + SendInterfaces(); + return true; +} + +static u8 _cdcComposite = 0; + +static +bool SendDescriptor(USBSetup& setup) +{ + int ret; + u8 t = setup.wValueH; + if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) + return SendConfiguration(setup.wLength); + + InitControl(setup.wLength); +#ifdef PLUGGABLE_USB_ENABLED + ret = PluggableUSB().getDescriptor(setup); + if (ret != 0) { + return (ret > 0 ? true : false); + } +#endif + + const u8* desc_addr = 0; + if (USB_DEVICE_DESCRIPTOR_TYPE == t) + { + if (setup.wLength == 8) + _cdcComposite = 1; + desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorB : (const u8*)&USB_DeviceDescriptor; + } + else if (USB_STRING_DESCRIPTOR_TYPE == t) + { + if (setup.wValueL == 0) { + desc_addr = (const u8*)&STRING_LANGUAGE; + } + else if (setup.wValueL == IPRODUCT) { + return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT), TRANSFER_PGM); + } + else if (setup.wValueL == IMANUFACTURER) { + return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER), TRANSFER_PGM); + } + else if (setup.wValueL == ISERIAL) { +#ifdef PLUGGABLE_USB_ENABLED + char name[ISERIAL_MAX_LEN]; + PluggableUSB().getShortName(name); + return USB_SendStringDescriptor((uint8_t*)name, strlen(name), 0); +#endif + } + else + return false; + } + + if (desc_addr == 0) + return false; + u8 desc_length = pgm_read_byte(desc_addr); + + USB_SendControl(TRANSFER_PGM,desc_addr,desc_length); + return true; +} + +// Endpoint 0 interrupt +ISR(USB_COM_vect) +{ + SetEP(0); + if (!ReceivedSetupInt()) + return; + + USBSetup setup; + Recv((u8*)&setup,8); + ClearSetupInt(); + + u8 requestType = setup.bmRequestType; + if (requestType & REQUEST_DEVICETOHOST) + WaitIN(); + else + ClearIN(); + + bool ok = true; + if (REQUEST_STANDARD == (requestType & REQUEST_TYPE)) + { + // Standard Requests + u8 r = setup.bRequest; + u16 wValue = setup.wValueL | (setup.wValueH << 8); + if (GET_STATUS == r) + { + if (requestType == (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_DEVICE)) + { + Send8(_usbCurrentStatus); + Send8(0); + } + else + { + // TODO: handle the HALT state of an endpoint here + // see "Figure 9-6. Information Returned by a GetStatus() Request to an Endpoint" in usb_20.pdf for more information + Send8(0); + Send8(0); + } + } + else if (CLEAR_FEATURE == r) + { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus &= ~FEATURE_REMOTE_WAKEUP_ENABLED; + } + } + else if (SET_FEATURE == r) + { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus |= FEATURE_REMOTE_WAKEUP_ENABLED; + } + } + else if (SET_ADDRESS == r) + { + WaitIN(); + UDADDR = setup.wValueL | (1<> 8) & 0xFF) + +#define CDC_V1_10 0x0110 +#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 + +#define CDC_CALL_MANAGEMENT 0x01 +#define CDC_ABSTRACT_CONTROL_MODEL 0x02 +#define CDC_HEADER 0x00 +#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 +#define CDC_UNION 0x06 +#define CDC_CS_INTERFACE 0x24 +#define CDC_CS_ENDPOINT 0x25 +#define CDC_DATA_INTERFACE_CLASS 0x0A + +#define MSC_SUBCLASS_SCSI 0x06 +#define MSC_PROTOCOL_BULK_ONLY 0x50 + +#ifndef USB_VERSION +#define USB_VERSION 0x200 +#endif + +// Device +typedef struct { + u8 len; // 18 + u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE + u16 usbVersion; // 0x200 or 0x210 + u8 deviceClass; + u8 deviceSubClass; + u8 deviceProtocol; + u8 packetSize0; // Packet 0 + u16 idVendor; + u16 idProduct; + u16 deviceVersion; // 0x100 + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; +} DeviceDescriptor; + +// Config +typedef struct { + u8 len; // 9 + u8 dtype; // 2 + u16 clen; // total length + u8 numInterfaces; + u8 config; + u8 iconfig; + u8 attributes; + u8 maxPower; +} ConfigDescriptor; + +// String + +// Interface +typedef struct +{ + u8 len; // 9 + u8 dtype; // 4 + u8 number; + u8 alternate; + u8 numEndpoints; + u8 interfaceClass; + u8 interfaceSubClass; + u8 protocol; + u8 iInterface; +} InterfaceDescriptor; + +// Endpoint +typedef struct +{ + u8 len; // 7 + u8 dtype; // 5 + u8 addr; + u8 attr; + u16 packetSize; + u8 interval; +} EndpointDescriptor; + +// Interface Association Descriptor +// Used to bind 2 interfaces together in CDC compostite device +typedef struct +{ + u8 len; // 8 + u8 dtype; // 11 + u8 firstInterface; + u8 interfaceCount; + u8 functionClass; + u8 funtionSubClass; + u8 functionProtocol; + u8 iInterface; +} IADDescriptor; + +// CDC CS interface descriptor +typedef struct +{ + u8 len; // 5 + u8 dtype; // 0x24 + u8 subtype; + u8 d0; + u8 d1; +} CDCCSInterfaceDescriptor; + +typedef struct +{ + u8 len; // 4 + u8 dtype; // 0x24 + u8 subtype; + u8 d0; +} CDCCSInterfaceDescriptor4; + +typedef struct +{ + u8 len; + u8 dtype; // 0x24 + u8 subtype; // 1 + u8 bmCapabilities; + u8 bDataInterface; +} CMFunctionalDescriptor; + +typedef struct +{ + u8 len; + u8 dtype; // 0x24 + u8 subtype; // 1 + u8 bmCapabilities; +} ACMFunctionalDescriptor; + +typedef struct +{ + // IAD + IADDescriptor iad; // Only needed on compound device + + // Control + InterfaceDescriptor cif; // + CDCCSInterfaceDescriptor header; + CMFunctionalDescriptor callManagement; // Call Management + ACMFunctionalDescriptor controlManagement; // ACM + CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION + EndpointDescriptor cifin; + + // Data + InterfaceDescriptor dif; + EndpointDescriptor in; + EndpointDescriptor out; +} CDCDescriptor; + +typedef struct +{ + InterfaceDescriptor msc; + EndpointDescriptor in; + EndpointDescriptor out; +} MSCDescriptor; + + +#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ + { 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } + +#define D_CONFIG(_totalLength,_interfaces) \ + { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) } + +#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ + { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } + +#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ + { 7, 5, _addr,_attr,_packetSize, _interval } + +#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ + { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } + +#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } +#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } + +// Bootloader related fields +// Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten +// by the running sketch before to actual reboot). +// Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both +// the usafe and the safe location. Check once (in USBCore.cpp) if the bootloader in new, then set the global +// _updatedLUFAbootloader variable to true/false and place the magic key consequently +#ifndef MAGIC_KEY +#define MAGIC_KEY 0x7777 +#endif + +#ifndef MAGIC_KEY_POS +#define MAGIC_KEY_POS 0x0800 +#endif + +#ifndef NEW_LUFA_SIGNATURE +#define NEW_LUFA_SIGNATURE 0xDCFB +#endif + +#endif diff --git a/sparkfun/tiny/cores/arduino/USBDesc.h b/sparkfun/tiny/cores/arduino/USBDesc.h new file mode 100644 index 00000000..c0dce079 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/USBDesc.h @@ -0,0 +1,46 @@ +/* + Copyright (c) 2011, Peter Barrett + Copyright (c) 2015, Arduino LLC + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#define PLUGGABLE_USB_ENABLED + +#if defined(EPRST6) +#define USB_ENDPOINTS 7 // AtMegaxxU4 +#else +#define USB_ENDPOINTS 5 // AtMegaxxU2 +#endif + +#define ISERIAL_MAX_LEN 20 + +#define CDC_INTERFACE_COUNT 2 +#define CDC_ENPOINT_COUNT 3 + +#define CDC_ACM_INTERFACE 0 // CDC ACM +#define CDC_DATA_INTERFACE 1 // CDC Data +#define CDC_FIRST_ENDPOINT 1 +#define CDC_ENDPOINT_ACM (CDC_FIRST_ENDPOINT) // CDC First +#define CDC_ENDPOINT_OUT (CDC_FIRST_ENDPOINT+1) +#define CDC_ENDPOINT_IN (CDC_FIRST_ENDPOINT+2) + +#define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT) + +#define CDC_RX CDC_ENDPOINT_OUT +#define CDC_TX CDC_ENDPOINT_IN + +#define IMANUFACTURER 1 +#define IPRODUCT 2 +#define ISERIAL 3 \ No newline at end of file diff --git a/sparkfun/tiny/cores/arduino/Udp.h b/sparkfun/tiny/cores/arduino/Udp.h new file mode 100644 index 00000000..dc5644b9 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/Udp.h @@ -0,0 +1,88 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/sparkfun/tiny/cores/arduino/WCharacter.h b/sparkfun/tiny/cores/arduino/WCharacter.h new file mode 100644 index 00000000..79733b50 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/WCharacter.h @@ -0,0 +1,168 @@ +/* + WCharacter.h - Character utility functions for Wiring & Arduino + Copyright (c) 2010 Hernando Barragan. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Character_h +#define Character_h + +#include + +// WCharacter.h prototypes +inline boolean isAlphaNumeric(int c) __attribute__((always_inline)); +inline boolean isAlpha(int c) __attribute__((always_inline)); +inline boolean isAscii(int c) __attribute__((always_inline)); +inline boolean isWhitespace(int c) __attribute__((always_inline)); +inline boolean isControl(int c) __attribute__((always_inline)); +inline boolean isDigit(int c) __attribute__((always_inline)); +inline boolean isGraph(int c) __attribute__((always_inline)); +inline boolean isLowerCase(int c) __attribute__((always_inline)); +inline boolean isPrintable(int c) __attribute__((always_inline)); +inline boolean isPunct(int c) __attribute__((always_inline)); +inline boolean isSpace(int c) __attribute__((always_inline)); +inline boolean isUpperCase(int c) __attribute__((always_inline)); +inline boolean isHexadecimalDigit(int c) __attribute__((always_inline)); +inline int toAscii(int c) __attribute__((always_inline)); +inline int toLowerCase(int c) __attribute__((always_inline)); +inline int toUpperCase(int c)__attribute__((always_inline)); + + +// Checks for an alphanumeric character. +// It is equivalent to (isalpha(c) || isdigit(c)). +inline boolean isAlphaNumeric(int c) +{ + return ( isalnum(c) == 0 ? false : true); +} + + +// Checks for an alphabetic character. +// It is equivalent to (isupper(c) || islower(c)). +inline boolean isAlpha(int c) +{ + return ( isalpha(c) == 0 ? false : true); +} + + +// Checks whether c is a 7-bit unsigned char value +// that fits into the ASCII character set. +inline boolean isAscii(int c) +{ + return ( isascii (c) == 0 ? false : true); +} + + +// Checks for a blank character, that is, a space or a tab. +inline boolean isWhitespace(int c) +{ + return ( isblank (c) == 0 ? false : true); +} + + +// Checks for a control character. +inline boolean isControl(int c) +{ + return ( iscntrl (c) == 0 ? false : true); +} + + +// Checks for a digit (0 through 9). +inline boolean isDigit(int c) +{ + return ( isdigit (c) == 0 ? false : true); +} + + +// Checks for any printable character except space. +inline boolean isGraph(int c) +{ + return ( isgraph (c) == 0 ? false : true); +} + + +// Checks for a lower-case character. +inline boolean isLowerCase(int c) +{ + return (islower (c) == 0 ? false : true); +} + + +// Checks for any printable character including space. +inline boolean isPrintable(int c) +{ + return ( isprint (c) == 0 ? false : true); +} + + +// Checks for any printable character which is not a space +// or an alphanumeric character. +inline boolean isPunct(int c) +{ + return ( ispunct (c) == 0 ? false : true); +} + + +// Checks for white-space characters. For the avr-libc library, +// these are: space, formfeed ('\f'), newline ('\n'), carriage +// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). +inline boolean isSpace(int c) +{ + return ( isspace (c) == 0 ? false : true); +} + + +// Checks for an uppercase letter. +inline boolean isUpperCase(int c) +{ + return ( isupper (c) == 0 ? false : true); +} + + +// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7 +// 8 9 a b c d e f A B C D E F. +inline boolean isHexadecimalDigit(int c) +{ + return ( isxdigit (c) == 0 ? false : true); +} + + +// Converts c to a 7-bit unsigned char value that fits into the +// ASCII character set, by clearing the high-order bits. +inline int toAscii(int c) +{ + return toascii (c); +} + + +// Warning: +// Many people will be unhappy if you use this function. +// This function will convert accented letters into random +// characters. + +// Converts the letter c to lower case, if possible. +inline int toLowerCase(int c) +{ + return tolower (c); +} + + +// Converts the letter c to upper case, if possible. +inline int toUpperCase(int c) +{ + return toupper (c); +} + +#endif \ No newline at end of file diff --git a/sparkfun/tiny/cores/arduino/WInterrupts.c b/sparkfun/tiny/cores/arduino/WInterrupts.c new file mode 100644 index 00000000..cef1106e --- /dev/null +++ b/sparkfun/tiny/cores/arduino/WInterrupts.c @@ -0,0 +1,324 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.uniandes.edu.co + + Copyright (c) 2004-05 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 24 November 2006 by David A. Mellis + Modified 1 August 2010 by Mark Sproul +*/ + +#include +#include +#include +#include +#include + +#include "wiring_private.h" + +static void nothing(void) { +} + +static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = { +#if EXTERNAL_NUM_INTERRUPTS > 8 + #warning There are more than 8 external interrupts. Some callbacks may not be initialized. + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 7 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 6 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 5 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 4 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 3 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 2 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 1 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 0 + nothing, +#endif +}; +// volatile static voidFuncPtr twiIntFunc; + +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { + if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { + intFunc[interruptNum] = userFunc; + + // Configure the interrupt mode (trigger on low input, any change, rising + // edge, or falling edge). The mode constants were chosen to correspond + // to the configuration bits in the hardware register, so we simply shift + // the mode into place. + + // Enable the interrupt. + + switch (interruptNum) { +#if defined(__AVR_ATmega32U4__) + // I hate doing this, but the register assignment differs between the 1280/2560 + // and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't + // even present on the 32U4 this is the only way to distinguish between them. + case 0: + EICRA = (EICRA & ~((1<= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return random(diff) + howsmall; +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +unsigned int makeWord(unsigned int w) { return w; } +unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } diff --git a/sparkfun/tiny/cores/arduino/WString.cpp b/sparkfun/tiny/cores/arduino/WString.cpp new file mode 100644 index 00000000..f2572d60 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/WString.cpp @@ -0,0 +1,750 @@ +/* + WString.cpp - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WString.h" + +/*********************************************/ +/* Constructors */ +/*********************************************/ + +String::String(const char *cstr) +{ + init(); + if (cstr) copy(cstr, strlen(cstr)); +} + +String::String(const String &value) +{ + init(); + *this = value; +} + +String::String(const __FlashStringHelper *pstr) +{ + init(); + *this = pstr; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +String::String(String &&rval) +{ + init(); + move(rval); +} +String::String(StringSumHelper &&rval) +{ + init(); + move(rval); +} +#endif + +String::String(char c) +{ + init(); + char buf[2]; + buf[0] = c; + buf[1] = 0; + *this = buf; +} + +String::String(unsigned char value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned char)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(int value, unsigned char base) +{ + init(); + char buf[2 + 8 * sizeof(int)]; + itoa(value, buf, base); + *this = buf; +} + +String::String(unsigned int value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned int)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(long value, unsigned char base) +{ + init(); + char buf[2 + 8 * sizeof(long)]; + ltoa(value, buf, base); + *this = buf; +} + +String::String(unsigned long value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned long)]; + ultoa(value, buf, base); + *this = buf; +} + +String::String(float value, unsigned char decimalPlaces) +{ + init(); + char buf[33]; + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); +} + +String::String(double value, unsigned char decimalPlaces) +{ + init(); + char buf[33]; + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); +} + +String::~String() +{ + free(buffer); +} + +/*********************************************/ +/* Memory Management */ +/*********************************************/ + +inline void String::init(void) +{ + buffer = NULL; + capacity = 0; + len = 0; +} + +void String::invalidate(void) +{ + if (buffer) free(buffer); + buffer = NULL; + capacity = len = 0; +} + +unsigned char String::reserve(unsigned int size) +{ + if (buffer && capacity >= size) return 1; + if (changeBuffer(size)) { + if (len == 0) buffer[0] = 0; + return 1; + } + return 0; +} + +unsigned char String::changeBuffer(unsigned int maxStrLen) +{ + char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); + if (newbuffer) { + buffer = newbuffer; + capacity = maxStrLen; + return 1; + } + return 0; +} + +/*********************************************/ +/* Copy and Move */ +/*********************************************/ + +String & String::copy(const char *cstr, unsigned int length) +{ + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + strcpy(buffer, cstr); + return *this; +} + +String & String::copy(const __FlashStringHelper *pstr, unsigned int length) +{ + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + strcpy_P(buffer, (PGM_P)pstr); + return *this; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +void String::move(String &rhs) +{ + if (buffer) { + if (rhs && capacity >= rhs.len) { + strcpy(buffer, rhs.buffer); + len = rhs.len; + rhs.len = 0; + return; + } else { + free(buffer); + } + } + buffer = rhs.buffer; + capacity = rhs.capacity; + len = rhs.len; + rhs.buffer = NULL; + rhs.capacity = 0; + rhs.len = 0; +} +#endif + +String & String::operator = (const String &rhs) +{ + if (this == &rhs) return *this; + + if (rhs.buffer) copy(rhs.buffer, rhs.len); + else invalidate(); + + return *this; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +String & String::operator = (String &&rval) +{ + if (this != &rval) move(rval); + return *this; +} + +String & String::operator = (StringSumHelper &&rval) +{ + if (this != &rval) move(rval); + return *this; +} +#endif + +String & String::operator = (const char *cstr) +{ + if (cstr) copy(cstr, strlen(cstr)); + else invalidate(); + + return *this; +} + +String & String::operator = (const __FlashStringHelper *pstr) +{ + if (pstr) copy(pstr, strlen_P((PGM_P)pstr)); + else invalidate(); + + return *this; +} + +/*********************************************/ +/* concat */ +/*********************************************/ + +unsigned char String::concat(const String &s) +{ + return concat(s.buffer, s.len); +} + +unsigned char String::concat(const char *cstr, unsigned int length) +{ + unsigned int newlen = len + length; + if (!cstr) return 0; + if (length == 0) return 1; + if (!reserve(newlen)) return 0; + strcpy(buffer + len, cstr); + len = newlen; + return 1; +} + +unsigned char String::concat(const char *cstr) +{ + if (!cstr) return 0; + return concat(cstr, strlen(cstr)); +} + +unsigned char String::concat(char c) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + return concat(buf, 1); +} + +unsigned char String::concat(unsigned char num) +{ + char buf[1 + 3 * sizeof(unsigned char)]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(int num) +{ + char buf[2 + 3 * sizeof(int)]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned int num) +{ + char buf[1 + 3 * sizeof(unsigned int)]; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(long num) +{ + char buf[2 + 3 * sizeof(long)]; + ltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned long num) +{ + char buf[1 + 3 * sizeof(unsigned long)]; + ultoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(float num) +{ + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +unsigned char String::concat(double num) +{ + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +unsigned char String::concat(const __FlashStringHelper * str) +{ + if (!str) return 0; + int length = strlen_P((const char *) str); + if (length == 0) return 1; + unsigned int newlen = len + length; + if (!reserve(newlen)) return 0; + strcpy_P(buffer + len, (const char *) str); + len = newlen; + return 1; +} + +/*********************************************/ +/* Concatenate */ +/*********************************************/ + +StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs.buffer, rhs.len)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) +{ + StringSumHelper &a = const_cast(lhs); + if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, char c) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(c)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, float num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, double num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs)) a.invalidate(); + return a; +} + +/*********************************************/ +/* Comparison */ +/*********************************************/ + +int String::compareTo(const String &s) const +{ + if (!buffer || !s.buffer) { + if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer; + if (buffer && len > 0) return *(unsigned char *)buffer; + return 0; + } + return strcmp(buffer, s.buffer); +} + +unsigned char String::equals(const String &s2) const +{ + return (len == s2.len && compareTo(s2) == 0); +} + +unsigned char String::equals(const char *cstr) const +{ + if (len == 0) return (cstr == NULL || *cstr == 0); + if (cstr == NULL) return buffer[0] == 0; + return strcmp(buffer, cstr) == 0; +} + +unsigned char String::operator<(const String &rhs) const +{ + return compareTo(rhs) < 0; +} + +unsigned char String::operator>(const String &rhs) const +{ + return compareTo(rhs) > 0; +} + +unsigned char String::operator<=(const String &rhs) const +{ + return compareTo(rhs) <= 0; +} + +unsigned char String::operator>=(const String &rhs) const +{ + return compareTo(rhs) >= 0; +} + +unsigned char String::equalsIgnoreCase( const String &s2 ) const +{ + if (this == &s2) return 1; + if (len != s2.len) return 0; + if (len == 0) return 1; + const char *p1 = buffer; + const char *p2 = s2.buffer; + while (*p1) { + if (tolower(*p1++) != tolower(*p2++)) return 0; + } + return 1; +} + +unsigned char String::startsWith( const String &s2 ) const +{ + if (len < s2.len) return 0; + return startsWith(s2, 0); +} + +unsigned char String::startsWith( const String &s2, unsigned int offset ) const +{ + if (offset > len - s2.len || !buffer || !s2.buffer) return 0; + return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; +} + +unsigned char String::endsWith( const String &s2 ) const +{ + if ( len < s2.len || !buffer || !s2.buffer) return 0; + return strcmp(&buffer[len - s2.len], s2.buffer) == 0; +} + +/*********************************************/ +/* Character Access */ +/*********************************************/ + +char String::charAt(unsigned int loc) const +{ + return operator[](loc); +} + +void String::setCharAt(unsigned int loc, char c) +{ + if (loc < len) buffer[loc] = c; +} + +char & String::operator[](unsigned int index) +{ + static char dummy_writable_char; + if (index >= len || !buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return buffer[index]; +} + +char String::operator[]( unsigned int index ) const +{ + if (index >= len || !buffer) return 0; + return buffer[index]; +} + +void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const +{ + if (!bufsize || !buf) return; + if (index >= len) { + buf[0] = 0; + return; + } + unsigned int n = bufsize - 1; + if (n > len - index) n = len - index; + strncpy((char *)buf, buffer + index, n); + buf[n] = 0; +} + +/*********************************************/ +/* Search */ +/*********************************************/ + +int String::indexOf(char c) const +{ + return indexOf(c, 0); +} + +int String::indexOf( char ch, unsigned int fromIndex ) const +{ + if (fromIndex >= len) return -1; + const char* temp = strchr(buffer + fromIndex, ch); + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::indexOf(const String &s2) const +{ + return indexOf(s2, 0); +} + +int String::indexOf(const String &s2, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + const char *found = strstr(buffer + fromIndex, s2.buffer); + if (found == NULL) return -1; + return found - buffer; +} + +int String::lastIndexOf( char theChar ) const +{ + return lastIndexOf(theChar, len - 1); +} + +int String::lastIndexOf(char ch, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + char tempchar = buffer[fromIndex + 1]; + buffer[fromIndex + 1] = '\0'; + char* temp = strrchr( buffer, ch ); + buffer[fromIndex + 1] = tempchar; + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::lastIndexOf(const String &s2) const +{ + return lastIndexOf(s2, len - s2.len); +} + +int String::lastIndexOf(const String &s2, unsigned int fromIndex) const +{ + if (s2.len == 0 || len == 0 || s2.len > len) return -1; + if (fromIndex >= len) fromIndex = len - 1; + int found = -1; + for (char *p = buffer; p <= buffer + fromIndex; p++) { + p = strstr(p, s2.buffer); + if (!p) break; + if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer; + } + return found; +} + +String String::substring(unsigned int left, unsigned int right) const +{ + if (left > right) { + unsigned int temp = right; + right = left; + left = temp; + } + String out; + if (left >= len) return out; + if (right > len) right = len; + char temp = buffer[right]; // save the replaced character + buffer[right] = '\0'; + out = buffer + left; // pointer arithmetic + buffer[right] = temp; //restore character + return out; +} + +/*********************************************/ +/* Modification */ +/*********************************************/ + +void String::replace(char find, char replace) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + if (*p == find) *p = replace; + } +} + +void String::replace(const String& find, const String& replace) +{ + if (len == 0 || find.len == 0) return; + int diff = replace.len - find.len; + char *readFrom = buffer; + char *foundAt; + if (diff == 0) { + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + memcpy(foundAt, replace.buffer, replace.len); + readFrom = foundAt + replace.len; + } + } else if (diff < 0) { + char *writeTo = buffer; + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + unsigned int n = foundAt - readFrom; + memcpy(writeTo, readFrom, n); + writeTo += n; + memcpy(writeTo, replace.buffer, replace.len); + writeTo += replace.len; + readFrom = foundAt + find.len; + len += diff; + } + strcpy(writeTo, readFrom); + } else { + unsigned int size = len; // compute size needed for result + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + readFrom = foundAt + find.len; + size += diff; + } + if (size == len) return; + if (size > capacity && !changeBuffer(size)) return; // XXX: tell user! + int index = len - 1; + while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { + readFrom = buffer + index + find.len; + memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); + len += diff; + buffer[len] = 0; + memcpy(buffer + index, replace.buffer, replace.len); + index--; + } + } +} + +void String::remove(unsigned int index){ + // Pass the biggest integer as the count. The remove method + // below will take care of truncating it at the end of the + // string. + remove(index, (unsigned int)-1); +} + +void String::remove(unsigned int index, unsigned int count){ + if (index >= len) { return; } + if (count <= 0) { return; } + if (count > len - index) { count = len - index; } + char *writeTo = buffer + index; + len = len - count; + strncpy(writeTo, buffer + index + count,len - index); + buffer[len] = 0; +} + +void String::toLowerCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = tolower(*p); + } +} + +void String::toUpperCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = toupper(*p); + } +} + +void String::trim(void) +{ + if (!buffer || len == 0) return; + char *begin = buffer; + while (isspace(*begin)) begin++; + char *end = buffer + len - 1; + while (isspace(*end) && end >= begin) end--; + len = end + 1 - begin; + if (begin > buffer) memcpy(buffer, begin, len); + buffer[len] = 0; +} + +/*********************************************/ +/* Parsing / Conversion */ +/*********************************************/ + +long String::toInt(void) const +{ + if (buffer) return atol(buffer); + return 0; +} + +float String::toFloat(void) const +{ + return float(toDouble()); +} + +double String::toDouble(void) const +{ + if (buffer) return atof(buffer); + return 0; +} diff --git a/sparkfun/tiny/cores/arduino/WString.h b/sparkfun/tiny/cores/arduino/WString.h new file mode 100644 index 00000000..77709c3b --- /dev/null +++ b/sparkfun/tiny/cores/arduino/WString.h @@ -0,0 +1,229 @@ +/* + WString.h - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All right reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef String_class_h +#define String_class_h +#ifdef __cplusplus + +#include +#include +#include +#include + +// When compiling programs with this class, the following gcc parameters +// dramatically increase performance and memory (RAM) efficiency, typically +// with little or no increase in code size. +// -felide-constructors +// -std=c++0x + +class __FlashStringHelper; +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) + +// An inherited class for holding the result of a concatenation. These +// result objects are assumed to be writable by subsequent concatenations. +class StringSumHelper; + +// The string class +class String +{ + // use a function pointer to allow for "if (s)" without the + // complications of an operator bool(). for more information, see: + // http://www.artima.com/cppsource/safebool.html + typedef void (String::*StringIfHelperType)() const; + void StringIfHelper() const {} + +public: + // constructors + // creates a copy of the initial value. + // if the initial value is null or invalid, or if memory allocation + // fails, the string will be marked as invalid (i.e. "if (s)" will + // be false). + String(const char *cstr = ""); + String(const String &str); + String(const __FlashStringHelper *str); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + String(String &&rval); + String(StringSumHelper &&rval); + #endif + explicit String(char c); + explicit String(unsigned char, unsigned char base=10); + explicit String(int, unsigned char base=10); + explicit String(unsigned int, unsigned char base=10); + explicit String(long, unsigned char base=10); + explicit String(unsigned long, unsigned char base=10); + explicit String(float, unsigned char decimalPlaces=2); + explicit String(double, unsigned char decimalPlaces=2); + ~String(void); + + // memory management + // return true on success, false on failure (in which case, the string + // is left unchanged). reserve(0), if successful, will validate an + // invalid string (i.e., "if (s)" will be true afterwards) + unsigned char reserve(unsigned int size); + inline unsigned int length(void) const {return len;} + + // creates a copy of the assigned value. if the value is null or + // invalid, or if the memory allocation fails, the string will be + // marked as invalid ("if (s)" will be false). + String & operator = (const String &rhs); + String & operator = (const char *cstr); + String & operator = (const __FlashStringHelper *str); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + String & operator = (String &&rval); + String & operator = (StringSumHelper &&rval); + #endif + + // concatenate (works w/ built-in types) + + // returns true on success, false on failure (in which case, the string + // is left unchanged). if the argument is null or invalid, the + // concatenation is considered unsucessful. + unsigned char concat(const String &str); + unsigned char concat(const char *cstr); + unsigned char concat(char c); + unsigned char concat(unsigned char c); + unsigned char concat(int num); + unsigned char concat(unsigned int num); + unsigned char concat(long num); + unsigned char concat(unsigned long num); + unsigned char concat(float num); + unsigned char concat(double num); + unsigned char concat(const __FlashStringHelper * str); + + // if there's not enough memory for the concatenated value, the string + // will be left unchanged (but this isn't signalled in any way) + String & operator += (const String &rhs) {concat(rhs); return (*this);} + String & operator += (const char *cstr) {concat(cstr); return (*this);} + String & operator += (char c) {concat(c); return (*this);} + String & operator += (unsigned char num) {concat(num); return (*this);} + String & operator += (int num) {concat(num); return (*this);} + String & operator += (unsigned int num) {concat(num); return (*this);} + String & operator += (long num) {concat(num); return (*this);} + String & operator += (unsigned long num) {concat(num); return (*this);} + String & operator += (float num) {concat(num); return (*this);} + String & operator += (double num) {concat(num); return (*this);} + String & operator += (const __FlashStringHelper *str){concat(str); return (*this);} + + friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, float num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, double num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs); + + // comparison (only works w/ Strings and "strings") + operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } + int compareTo(const String &s) const; + unsigned char equals(const String &s) const; + unsigned char equals(const char *cstr) const; + unsigned char operator == (const String &rhs) const {return equals(rhs);} + unsigned char operator == (const char *cstr) const {return equals(cstr);} + unsigned char operator != (const String &rhs) const {return !equals(rhs);} + unsigned char operator != (const char *cstr) const {return !equals(cstr);} + unsigned char operator < (const String &rhs) const; + unsigned char operator > (const String &rhs) const; + unsigned char operator <= (const String &rhs) const; + unsigned char operator >= (const String &rhs) const; + unsigned char equalsIgnoreCase(const String &s) const; + unsigned char startsWith( const String &prefix) const; + unsigned char startsWith(const String &prefix, unsigned int offset) const; + unsigned char endsWith(const String &suffix) const; + + // character acccess + char charAt(unsigned int index) const; + void setCharAt(unsigned int index, char c); + char operator [] (unsigned int index) const; + char& operator [] (unsigned int index); + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; + void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const + { getBytes((unsigned char *)buf, bufsize, index); } + const char* c_str() const { return buffer; } + char* begin() { return buffer; } + char* end() { return buffer + length(); } + const char* begin() const { return c_str(); } + const char* end() const { return c_str() + length(); } + + // search + int indexOf( char ch ) const; + int indexOf( char ch, unsigned int fromIndex ) const; + int indexOf( const String &str ) const; + int indexOf( const String &str, unsigned int fromIndex ) const; + int lastIndexOf( char ch ) const; + int lastIndexOf( char ch, unsigned int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, unsigned int fromIndex ) const; + String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); }; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + + // modification + void replace(char find, char replace); + void replace(const String& find, const String& replace); + void remove(unsigned int index); + void remove(unsigned int index, unsigned int count); + void toLowerCase(void); + void toUpperCase(void); + void trim(void); + + // parsing/conversion + long toInt(void) const; + float toFloat(void) const; + double toDouble(void) const; + +protected: + char *buffer; // the actual char array + unsigned int capacity; // the array length minus one (for the '\0') + unsigned int len; // the String length (not counting the '\0') +protected: + void init(void); + void invalidate(void); + unsigned char changeBuffer(unsigned int maxStrLen); + unsigned char concat(const char *cstr, unsigned int length); + + // copy and move + String & copy(const char *cstr, unsigned int length); + String & copy(const __FlashStringHelper *pstr, unsigned int length); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + void move(String &rhs); + #endif +}; + +class StringSumHelper : public String +{ +public: + StringSumHelper(const String &s) : String(s) {} + StringSumHelper(const char *p) : String(p) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(unsigned char num) : String(num) {} + StringSumHelper(int num) : String(num) {} + StringSumHelper(unsigned int num) : String(num) {} + StringSumHelper(long num) : String(num) {} + StringSumHelper(unsigned long num) : String(num) {} + StringSumHelper(float num) : String(num) {} + StringSumHelper(double num) : String(num) {} +}; + +#endif // __cplusplus +#endif // String_class_h diff --git a/sparkfun/tiny/cores/arduino/abi.cpp b/sparkfun/tiny/cores/arduino/abi.cpp new file mode 100644 index 00000000..8d719b8e --- /dev/null +++ b/sparkfun/tiny/cores/arduino/abi.cpp @@ -0,0 +1,35 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__)); +extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__)); + +void __cxa_pure_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + +void __cxa_deleted_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + diff --git a/sparkfun/tiny/cores/arduino/binary.h b/sparkfun/tiny/cores/arduino/binary.h new file mode 100644 index 00000000..aec4c733 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/binary.h @@ -0,0 +1,534 @@ +/* + binary.h - Definitions for binary constants + Copyright (c) 2006 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Binary_h +#define Binary_h + +#define B0 0 +#define B00 0 +#define B000 0 +#define B0000 0 +#define B00000 0 +#define B000000 0 +#define B0000000 0 +#define B00000000 0 +#define B1 1 +#define B01 1 +#define B001 1 +#define B0001 1 +#define B00001 1 +#define B000001 1 +#define B0000001 1 +#define B00000001 1 +#define B10 2 +#define B010 2 +#define B0010 2 +#define B00010 2 +#define B000010 2 +#define B0000010 2 +#define B00000010 2 +#define B11 3 +#define B011 3 +#define B0011 3 +#define B00011 3 +#define B000011 3 +#define B0000011 3 +#define B00000011 3 +#define B100 4 +#define B0100 4 +#define B00100 4 +#define B000100 4 +#define B0000100 4 +#define B00000100 4 +#define B101 5 +#define B0101 5 +#define B00101 5 +#define B000101 5 +#define B0000101 5 +#define B00000101 5 +#define B110 6 +#define B0110 6 +#define B00110 6 +#define B000110 6 +#define B0000110 6 +#define B00000110 6 +#define B111 7 +#define B0111 7 +#define B00111 7 +#define B000111 7 +#define B0000111 7 +#define B00000111 7 +#define B1000 8 +#define B01000 8 +#define B001000 8 +#define B0001000 8 +#define B00001000 8 +#define B1001 9 +#define B01001 9 +#define B001001 9 +#define B0001001 9 +#define B00001001 9 +#define B1010 10 +#define B01010 10 +#define B001010 10 +#define B0001010 10 +#define B00001010 10 +#define B1011 11 +#define B01011 11 +#define B001011 11 +#define B0001011 11 +#define B00001011 11 +#define B1100 12 +#define B01100 12 +#define B001100 12 +#define B0001100 12 +#define B00001100 12 +#define B1101 13 +#define B01101 13 +#define B001101 13 +#define B0001101 13 +#define B00001101 13 +#define B1110 14 +#define B01110 14 +#define B001110 14 +#define B0001110 14 +#define B00001110 14 +#define B1111 15 +#define B01111 15 +#define B001111 15 +#define B0001111 15 +#define B00001111 15 +#define B10000 16 +#define B010000 16 +#define B0010000 16 +#define B00010000 16 +#define B10001 17 +#define B010001 17 +#define B0010001 17 +#define B00010001 17 +#define B10010 18 +#define B010010 18 +#define B0010010 18 +#define B00010010 18 +#define B10011 19 +#define B010011 19 +#define B0010011 19 +#define B00010011 19 +#define B10100 20 +#define B010100 20 +#define B0010100 20 +#define B00010100 20 +#define B10101 21 +#define B010101 21 +#define B0010101 21 +#define B00010101 21 +#define B10110 22 +#define B010110 22 +#define B0010110 22 +#define B00010110 22 +#define B10111 23 +#define B010111 23 +#define B0010111 23 +#define B00010111 23 +#define B11000 24 +#define B011000 24 +#define B0011000 24 +#define B00011000 24 +#define B11001 25 +#define B011001 25 +#define B0011001 25 +#define B00011001 25 +#define B11010 26 +#define B011010 26 +#define B0011010 26 +#define B00011010 26 +#define B11011 27 +#define B011011 27 +#define B0011011 27 +#define B00011011 27 +#define B11100 28 +#define B011100 28 +#define B0011100 28 +#define B00011100 28 +#define B11101 29 +#define B011101 29 +#define B0011101 29 +#define B00011101 29 +#define B11110 30 +#define B011110 30 +#define B0011110 30 +#define B00011110 30 +#define B11111 31 +#define B011111 31 +#define B0011111 31 +#define B00011111 31 +#define B100000 32 +#define B0100000 32 +#define B00100000 32 +#define B100001 33 +#define B0100001 33 +#define B00100001 33 +#define B100010 34 +#define B0100010 34 +#define B00100010 34 +#define B100011 35 +#define B0100011 35 +#define B00100011 35 +#define B100100 36 +#define B0100100 36 +#define B00100100 36 +#define B100101 37 +#define B0100101 37 +#define B00100101 37 +#define B100110 38 +#define B0100110 38 +#define B00100110 38 +#define B100111 39 +#define B0100111 39 +#define B00100111 39 +#define B101000 40 +#define B0101000 40 +#define B00101000 40 +#define B101001 41 +#define B0101001 41 +#define B00101001 41 +#define B101010 42 +#define B0101010 42 +#define B00101010 42 +#define B101011 43 +#define B0101011 43 +#define B00101011 43 +#define B101100 44 +#define B0101100 44 +#define B00101100 44 +#define B101101 45 +#define B0101101 45 +#define B00101101 45 +#define B101110 46 +#define B0101110 46 +#define B00101110 46 +#define B101111 47 +#define B0101111 47 +#define B00101111 47 +#define B110000 48 +#define B0110000 48 +#define B00110000 48 +#define B110001 49 +#define B0110001 49 +#define B00110001 49 +#define B110010 50 +#define B0110010 50 +#define B00110010 50 +#define B110011 51 +#define B0110011 51 +#define B00110011 51 +#define B110100 52 +#define B0110100 52 +#define B00110100 52 +#define B110101 53 +#define B0110101 53 +#define B00110101 53 +#define B110110 54 +#define B0110110 54 +#define B00110110 54 +#define B110111 55 +#define B0110111 55 +#define B00110111 55 +#define B111000 56 +#define B0111000 56 +#define B00111000 56 +#define B111001 57 +#define B0111001 57 +#define B00111001 57 +#define B111010 58 +#define B0111010 58 +#define B00111010 58 +#define B111011 59 +#define B0111011 59 +#define B00111011 59 +#define B111100 60 +#define B0111100 60 +#define B00111100 60 +#define B111101 61 +#define B0111101 61 +#define B00111101 61 +#define B111110 62 +#define B0111110 62 +#define B00111110 62 +#define B111111 63 +#define B0111111 63 +#define B00111111 63 +#define B1000000 64 +#define B01000000 64 +#define B1000001 65 +#define B01000001 65 +#define B1000010 66 +#define B01000010 66 +#define B1000011 67 +#define B01000011 67 +#define B1000100 68 +#define B01000100 68 +#define B1000101 69 +#define B01000101 69 +#define B1000110 70 +#define B01000110 70 +#define B1000111 71 +#define B01000111 71 +#define B1001000 72 +#define B01001000 72 +#define B1001001 73 +#define B01001001 73 +#define B1001010 74 +#define B01001010 74 +#define B1001011 75 +#define B01001011 75 +#define B1001100 76 +#define B01001100 76 +#define B1001101 77 +#define B01001101 77 +#define B1001110 78 +#define B01001110 78 +#define B1001111 79 +#define B01001111 79 +#define B1010000 80 +#define B01010000 80 +#define B1010001 81 +#define B01010001 81 +#define B1010010 82 +#define B01010010 82 +#define B1010011 83 +#define B01010011 83 +#define B1010100 84 +#define B01010100 84 +#define B1010101 85 +#define B01010101 85 +#define B1010110 86 +#define B01010110 86 +#define B1010111 87 +#define B01010111 87 +#define B1011000 88 +#define B01011000 88 +#define B1011001 89 +#define B01011001 89 +#define B1011010 90 +#define B01011010 90 +#define B1011011 91 +#define B01011011 91 +#define B1011100 92 +#define B01011100 92 +#define B1011101 93 +#define B01011101 93 +#define B1011110 94 +#define B01011110 94 +#define B1011111 95 +#define B01011111 95 +#define B1100000 96 +#define B01100000 96 +#define B1100001 97 +#define B01100001 97 +#define B1100010 98 +#define B01100010 98 +#define B1100011 99 +#define B01100011 99 +#define B1100100 100 +#define B01100100 100 +#define B1100101 101 +#define B01100101 101 +#define B1100110 102 +#define B01100110 102 +#define B1100111 103 +#define B01100111 103 +#define B1101000 104 +#define B01101000 104 +#define B1101001 105 +#define B01101001 105 +#define B1101010 106 +#define B01101010 106 +#define B1101011 107 +#define B01101011 107 +#define B1101100 108 +#define B01101100 108 +#define B1101101 109 +#define B01101101 109 +#define B1101110 110 +#define B01101110 110 +#define B1101111 111 +#define B01101111 111 +#define B1110000 112 +#define B01110000 112 +#define B1110001 113 +#define B01110001 113 +#define B1110010 114 +#define B01110010 114 +#define B1110011 115 +#define B01110011 115 +#define B1110100 116 +#define B01110100 116 +#define B1110101 117 +#define B01110101 117 +#define B1110110 118 +#define B01110110 118 +#define B1110111 119 +#define B01110111 119 +#define B1111000 120 +#define B01111000 120 +#define B1111001 121 +#define B01111001 121 +#define B1111010 122 +#define B01111010 122 +#define B1111011 123 +#define B01111011 123 +#define B1111100 124 +#define B01111100 124 +#define B1111101 125 +#define B01111101 125 +#define B1111110 126 +#define B01111110 126 +#define B1111111 127 +#define B01111111 127 +#define B10000000 128 +#define B10000001 129 +#define B10000010 130 +#define B10000011 131 +#define B10000100 132 +#define B10000101 133 +#define B10000110 134 +#define B10000111 135 +#define B10001000 136 +#define B10001001 137 +#define B10001010 138 +#define B10001011 139 +#define B10001100 140 +#define B10001101 141 +#define B10001110 142 +#define B10001111 143 +#define B10010000 144 +#define B10010001 145 +#define B10010010 146 +#define B10010011 147 +#define B10010100 148 +#define B10010101 149 +#define B10010110 150 +#define B10010111 151 +#define B10011000 152 +#define B10011001 153 +#define B10011010 154 +#define B10011011 155 +#define B10011100 156 +#define B10011101 157 +#define B10011110 158 +#define B10011111 159 +#define B10100000 160 +#define B10100001 161 +#define B10100010 162 +#define B10100011 163 +#define B10100100 164 +#define B10100101 165 +#define B10100110 166 +#define B10100111 167 +#define B10101000 168 +#define B10101001 169 +#define B10101010 170 +#define B10101011 171 +#define B10101100 172 +#define B10101101 173 +#define B10101110 174 +#define B10101111 175 +#define B10110000 176 +#define B10110001 177 +#define B10110010 178 +#define B10110011 179 +#define B10110100 180 +#define B10110101 181 +#define B10110110 182 +#define B10110111 183 +#define B10111000 184 +#define B10111001 185 +#define B10111010 186 +#define B10111011 187 +#define B10111100 188 +#define B10111101 189 +#define B10111110 190 +#define B10111111 191 +#define B11000000 192 +#define B11000001 193 +#define B11000010 194 +#define B11000011 195 +#define B11000100 196 +#define B11000101 197 +#define B11000110 198 +#define B11000111 199 +#define B11001000 200 +#define B11001001 201 +#define B11001010 202 +#define B11001011 203 +#define B11001100 204 +#define B11001101 205 +#define B11001110 206 +#define B11001111 207 +#define B11010000 208 +#define B11010001 209 +#define B11010010 210 +#define B11010011 211 +#define B11010100 212 +#define B11010101 213 +#define B11010110 214 +#define B11010111 215 +#define B11011000 216 +#define B11011001 217 +#define B11011010 218 +#define B11011011 219 +#define B11011100 220 +#define B11011101 221 +#define B11011110 222 +#define B11011111 223 +#define B11100000 224 +#define B11100001 225 +#define B11100010 226 +#define B11100011 227 +#define B11100100 228 +#define B11100101 229 +#define B11100110 230 +#define B11100111 231 +#define B11101000 232 +#define B11101001 233 +#define B11101010 234 +#define B11101011 235 +#define B11101100 236 +#define B11101101 237 +#define B11101110 238 +#define B11101111 239 +#define B11110000 240 +#define B11110001 241 +#define B11110010 242 +#define B11110011 243 +#define B11110100 244 +#define B11110101 245 +#define B11110110 246 +#define B11110111 247 +#define B11111000 248 +#define B11111001 249 +#define B11111010 250 +#define B11111011 251 +#define B11111100 252 +#define B11111101 253 +#define B11111110 254 +#define B11111111 255 + +#endif diff --git a/sparkfun/tiny/cores/arduino/hooks.c b/sparkfun/tiny/cores/arduino/hooks.c new file mode 100644 index 00000000..641eabc7 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/hooks.c @@ -0,0 +1,31 @@ +/* + Copyright (c) 2012 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * Empty yield() hook. + * + * This function is intended to be used by library writers to build + * libraries or sketches that supports cooperative threads. + * + * Its defined as a weak symbol and it can be redefined to implement a + * real cooperative scheduler. + */ +static void __empty() { + // Empty +} +void yield(void) __attribute__ ((weak, alias("__empty"))); diff --git a/sparkfun/tiny/cores/arduino/main.cpp b/sparkfun/tiny/cores/arduino/main.cpp new file mode 100644 index 00000000..434cd403 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/main.cpp @@ -0,0 +1,52 @@ +/* + main.cpp - Main loop for Arduino sketches + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +// Declared weak in Arduino.h to allow user redefinitions. +int atexit(void (* /*func*/ )()) { return 0; } + +// Weak empty variant initialization function. +// May be redefined by variant files. +void initVariant() __attribute__((weak)); +void initVariant() { } + +void setupUSB() __attribute__((weak)); +void setupUSB() { } + +int main(void) +{ + init(); + + initVariant(); + +#if defined(USBCON) + USBDevice.attach(); +#endif + + setup(); + + for (;;) { + loop(); + if (serialEventRun) serialEventRun(); + } + + return 0; +} + diff --git a/sparkfun/tiny/cores/arduino/new.cpp b/sparkfun/tiny/cores/arduino/new.cpp new file mode 100644 index 00000000..cf6f89c1 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/new.cpp @@ -0,0 +1,36 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +void *operator new(size_t size) { + return malloc(size); +} + +void *operator new[](size_t size) { + return malloc(size); +} + +void operator delete(void * ptr) { + free(ptr); +} + +void operator delete[](void * ptr) { + free(ptr); +} + diff --git a/sparkfun/tiny/cores/arduino/new.h b/sparkfun/tiny/cores/arduino/new.h new file mode 100644 index 00000000..6e1b68f0 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/new.h @@ -0,0 +1,30 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef NEW_H +#define NEW_H + +#include + +void * operator new(size_t size); +void * operator new[](size_t size); +void operator delete(void * ptr); +void operator delete[](void * ptr); + +#endif + diff --git a/sparkfun/tiny/cores/arduino/wiring.c b/sparkfun/tiny/cores/arduino/wiring.c new file mode 100644 index 00000000..b956f787 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/wiring.c @@ -0,0 +1,392 @@ +/* + wiring.c - Partial implementation of the Wiring API for the ATmega8. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "wiring_private.h" + +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +// the whole number of milliseconds per timer0 overflow +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) + +// the fractional number of milliseconds per timer0 overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +volatile unsigned long timer0_overflow_count = 0; +volatile unsigned long timer0_millis = 0; +static unsigned char timer0_fract = 0; + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) +ISR(TIM0_OVF_vect) +#else +ISR(TIMER0_OVF_vect) +#endif +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} + +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read timer0_millis or we might get an + // inconsistent value (e.g. in the middle of a write to timer0_millis) + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; +} + +unsigned long micros() { + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = timer0_overflow_count; +#if defined(TCNT0) + t = TCNT0; +#elif defined(TCNT0L) + t = TCNT0L; +#else + #error TIMER 0 not defined +#endif + +#ifdef TIFR0 + if ((TIFR0 & _BV(TOV0)) && (t < 255)) + m++; +#else + if ((TIFR & _BV(TOV0)) && (t < 255)) + m++; +#endif + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + +void delay(unsigned long ms) +{ + uint32_t start = micros(); + + while (ms > 0) { + yield(); + while ( ms > 0 && (micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable) + + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); +#if F_CPU >= 24000000L + // for the 24 MHz clock for the aventurous ones, trying to overclock + + // zero delay fix + if (!us) return; // = 3 cycles, (4 when true) + + // the following loop takes a 1/6 of a microsecond (4 cycles) + // per iteration, so execute it six times for each microsecond of + // delay requested. + us *= 6; // x6 us, = 7 cycles + + // account for the time taken in the preceeding commands. + // we just burned 22 (24) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //=2 cycles + +#elif F_CPU >= 20000000L + // for the 20 MHz clock on rare Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call takes 18 (20) cycles, which is 1us + __asm__ __volatile__ ( + "nop" "\n\t" + "nop" "\n\t" + "nop" "\n\t" + "nop"); //just waiting 4 cycles + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes a 1/5 of a microsecond (4 cycles) + // per iteration, so execute it five times for each microsecond of + // delay requested. + us = (us << 2) + us; // x5 us, = 7 cycles + + // account for the time taken in the preceeding commands. + // we just burned 26 (28) cycles above, remove 7, (7*4=28) + // us is at least 10 so we can substract 7 + us -= 7; // 2 cycles + +#elif F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 1us + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/4 of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; // x4 us, = 4 cycles + + // account for the time taken in the preceeding commands. + // we just burned 19 (21) cycles above, remove 5, (5*4=20) + // us is at least 8 so we can substract 5 + us -= 5; // = 2 cycles, + +#elif F_CPU >= 12000000L + // for the 12 MHz clock if somebody is working with USB + + // for a 1 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 1.5us + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/3 of a microsecond (4 cycles) + // per iteration, so execute it three times for each microsecond of + // delay requested. + us = (us << 1) + us; // x3 us, = 5 cycles + + // account for the time taken in the preceeding commands. + // we just burned 20 (22) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //2 cycles + +#elif F_CPU >= 8000000L + // for the 8 MHz internal clock + + // for a 1 and 2 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 2us + if (us <= 2) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/2 of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; //x2 us, = 2 cycles + + // account for the time taken in the preceeding commands. + // we just burned 17 (19) cycles above, remove 4, (4*4=16) + // us is at least 6 so we can substract 4 + us -= 4; // = 2 cycles + +#else + // for the 1 MHz internal clock (default settings for common Atmega microcontrollers) + + // the overhead of the function calls is 14 (16) cycles + if (us <= 16) return; //= 3 cycles, (4 when true) + if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22) + + // compensate for the time taken by the preceeding and next commands (about 22 cycles) + us -= 22; // = 2 cycles + // the following loop takes 4 microseconds (4 cycles) + // per iteration, so execute it us/4 times + // us is at least 4, divided by 4 gives us 1 (no zero delay bug) + us >>= 2; // us div 4, = 4 cycles + + +#endif + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); + // return = 4 cycles +} + +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + sei(); + + // on the ATmega168, timer 0 is also used for fast hardware pwm + // (using phase-correct PWM would mean that timer 0 overflowed half as often + // resulting in different millis() behavior on the ATmega8 and ATmega168) +#if defined(TCCR0A) && defined(WGM01) + sbi(TCCR0A, WGM01); + sbi(TCCR0A, WGM00); +#endif + + // set timer 0 prescale factor to 64 +#if defined(__AVR_ATmega128__) + // CPU specific: different values for the ATmega128 + sbi(TCCR0, CS02); +#elif defined(TCCR0) && defined(CS01) && defined(CS00) + // this combination is for the standard atmega8 + sbi(TCCR0, CS01); + sbi(TCCR0, CS00); +#elif defined(TCCR0B) && defined(CS01) && defined(CS00) + // this combination is for the standard 168/328/1280/2560 + sbi(TCCR0B, CS01); + sbi(TCCR0B, CS00); +#elif defined(TCCR0A) && defined(CS01) && defined(CS00) + // this combination is for the __AVR_ATmega645__ series + sbi(TCCR0A, CS01); + sbi(TCCR0A, CS00); +#else + #error Timer 0 prescale factor 64 not set correctly +#endif + + // enable timer 0 overflow interrupt +#if defined(TIMSK) && defined(TOIE0) + sbi(TIMSK, TOIE0); +#elif defined(TIMSK0) && defined(TOIE0) + sbi(TIMSK0, TOIE0); +#else + #error Timer 0 overflow interrupt not set correctly +#endif + + // timers 1 and 2 are used for phase-correct hardware pwm + // this is better for motors as it ensures an even waveform + // note, however, that fast pwm mode can achieve a frequency of up + // 8 MHz (with a 16 MHz clock) at 50% duty cycle + +#if defined(TCCR1B) && defined(CS11) && defined(CS10) + TCCR1B = 0; + + // set timer 1 prescale factor to 64 + sbi(TCCR1B, CS11); +#if F_CPU >= 8000000L + sbi(TCCR1B, CS10); +#endif +#elif defined(TCCR1) && defined(CS11) && defined(CS10) + sbi(TCCR1, CS11); +#if F_CPU >= 8000000L + sbi(TCCR1, CS10); +#endif +#endif + // put timer 1 in 8-bit phase correct pwm mode +#if defined(TCCR1A) && defined(WGM10) + sbi(TCCR1A, WGM10); +#endif + + // set timer 2 prescale factor to 64 +#if defined(TCCR2) && defined(CS22) + sbi(TCCR2, CS22); +#elif defined(TCCR2B) && defined(CS22) + sbi(TCCR2B, CS22); +//#else + // Timer 2 not finished (may not be present on this CPU) +#endif + + // configure timer 2 for phase correct pwm (8-bit) +#if defined(TCCR2) && defined(WGM20) + sbi(TCCR2, WGM20); +#elif defined(TCCR2A) && defined(WGM20) + sbi(TCCR2A, WGM20); +//#else + // Timer 2 not finished (may not be present on this CPU) +#endif + +#if defined(TCCR3B) && defined(CS31) && defined(WGM30) + sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64 + sbi(TCCR3B, CS30); + sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode +#endif + +#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */ + sbi(TCCR4B, CS42); // set timer4 prescale factor to 64 + sbi(TCCR4B, CS41); + sbi(TCCR4B, CS40); + sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode + sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A + sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D +#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */ +#if defined(TCCR4B) && defined(CS41) && defined(WGM40) + sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64 + sbi(TCCR4B, CS40); + sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode +#endif +#endif /* end timer4 block for ATMEGA1280/2560 and similar */ + +#if defined(TCCR5B) && defined(CS51) && defined(WGM50) + sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64 + sbi(TCCR5B, CS50); + sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode +#endif + +#if defined(ADCSRA) + // set a2d prescaler so we are inside the desired 50-200 KHz range. + #if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + cbi(ADCSRA, ADPS0); + #elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz + sbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz + sbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + cbi(ADCSRA, ADPS0); + #elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz + cbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2 + cbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #endif + // enable a2d conversions + sbi(ADCSRA, ADEN); +#endif + + // the bootloader connects pins 0 and 1 to the USART; disconnect them + // here so they can be used as normal digital i/o; they will be + // reconnected in Serial.begin() +#if defined(UCSRB) + UCSRB = 0; +#elif defined(UCSR0B) + UCSR0B = 0; +#endif +} diff --git a/sparkfun/tiny/cores/arduino/wiring_analog.c b/sparkfun/tiny/cores/arduino/wiring_analog.c new file mode 100644 index 00000000..967c2b97 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/wiring_analog.c @@ -0,0 +1,294 @@ +/* + wiring_analog.c - analog input and output + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 28 September 2010 by Mark Sproul +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +uint8_t analog_reference = DEFAULT; + +void analogReference(uint8_t mode) +{ + // can't actually set the register here because the default setting + // will connect AVCC and the AREF pin, which would cause a short if + // there's something connected to AREF. + analog_reference = mode; +} + +int analogRead(uint8_t pin) +{ + uint8_t low, high; + +#if defined(analogPinToChannel) +#if defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers +#endif + pin = analogPinToChannel(pin); +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + if (pin >= 54) pin -= 54; // allow for channel or pin numbers +#elif defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers +#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) + if (pin >= 24) pin -= 24; // allow for channel or pin numbers +#else + if (pin >= 14) pin -= 14; // allow for channel or pin numbers +#endif + +#if defined(ADCSRB) && defined(MUX5) + // the MUX5 bit of ADCSRB selects whether we're reading from channels + // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). + ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); +#endif + + // set the analog reference (high two bits of ADMUX) and select the + // channel (low 4 bits). this also sets ADLAR (left-adjust result) + // to 0 (the default). +#if defined(ADMUX) +#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + ADMUX = (analog_reference << 4) | (pin & 0x07); +#else + ADMUX = (analog_reference << 6) | (pin & 0x07); +#endif +#endif + + // without a delay, we seem to read from the wrong channel + //delay(1); + +#if defined(ADCSRA) && defined(ADCL) + // start the conversion + sbi(ADCSRA, ADSC); + + // ADSC is cleared when the conversion finishes + while (bit_is_set(ADCSRA, ADSC)); + + // we have to read ADCL first; doing so locks both ADCL + // and ADCH until ADCH is read. reading ADCL second would + // cause the results of each conversion to be discarded, + // as ADCL and ADCH would be locked when it completed. + low = ADCL; + high = ADCH; +#else + // we dont have an ADC, return 0 + low = 0; + high = 0; +#endif + + // combine the two bytes + return (high << 8) | low; +} + +// Right now, PWM output only works on the pins with +// hardware support. These are defined in the appropriate +// pins_*.c file. For the rest of the pins, we default +// to digital output. +void analogWrite(uint8_t pin, int val) +{ + // We need to make sure the PWM output is enabled for those pins + // that support it, as we turn it off when digitally reading or + // writing with them. Also, make sure the pin is in output mode + // for consistenty with Wiring, which doesn't require a pinMode + // call for the analog output pins. + pinMode(pin, OUTPUT); + if (val == 0) + { + digitalWrite(pin, LOW); + } + else if (val == 255) + { + digitalWrite(pin, HIGH); + } + else + { + switch(digitalPinToTimer(pin)) + { + // XXX fix needed for atmega8 + #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) + case TIMER0A: + // connect pwm to pin on timer 0 + sbi(TCCR0, COM00); + OCR0 = val; // set pwm duty + break; + #endif + + #if defined(TCCR0A) && defined(COM0A1) + case TIMER0A: + // connect pwm to pin on timer 0, channel A + sbi(TCCR0A, COM0A1); + OCR0A = val; // set pwm duty + break; + #endif + + #if defined(TCCR0A) && defined(COM0B1) + case TIMER0B: + // connect pwm to pin on timer 0, channel B + sbi(TCCR0A, COM0B1); + OCR0B = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1A1) + case TIMER1A: + // connect pwm to pin on timer 1, channel A + sbi(TCCR1A, COM1A1); + OCR1A = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1B1) + case TIMER1B: + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1B1); + OCR1B = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1C1) + case TIMER1C: + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1C1); + OCR1C = val; // set pwm duty + break; + #endif + + #if defined(TCCR2) && defined(COM21) + case TIMER2: + // connect pwm to pin on timer 2 + sbi(TCCR2, COM21); + OCR2 = val; // set pwm duty + break; + #endif + + #if defined(TCCR2A) && defined(COM2A1) + case TIMER2A: + // connect pwm to pin on timer 2, channel A + sbi(TCCR2A, COM2A1); + OCR2A = val; // set pwm duty + break; + #endif + + #if defined(TCCR2A) && defined(COM2B1) + case TIMER2B: + // connect pwm to pin on timer 2, channel B + sbi(TCCR2A, COM2B1); + OCR2B = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3A1) + case TIMER3A: + // connect pwm to pin on timer 3, channel A + sbi(TCCR3A, COM3A1); + OCR3A = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3B1) + case TIMER3B: + // connect pwm to pin on timer 3, channel B + sbi(TCCR3A, COM3B1); + OCR3B = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3C1) + case TIMER3C: + // connect pwm to pin on timer 3, channel C + sbi(TCCR3A, COM3C1); + OCR3C = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) + case TIMER4A: + //connect pwm to pin on timer 4, channel A + sbi(TCCR4A, COM4A1); + #if defined(COM4A0) // only used on 32U4 + cbi(TCCR4A, COM4A0); + #endif + OCR4A = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) && defined(COM4B1) + case TIMER4B: + // connect pwm to pin on timer 4, channel B + sbi(TCCR4A, COM4B1); + OCR4B = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) && defined(COM4C1) + case TIMER4C: + // connect pwm to pin on timer 4, channel C + sbi(TCCR4A, COM4C1); + OCR4C = val; // set pwm duty + break; + #endif + + #if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: + // connect pwm to pin on timer 4, channel D + sbi(TCCR4C, COM4D1); + #if defined(COM4D0) // only used on 32U4 + cbi(TCCR4C, COM4D0); + #endif + OCR4D = val; // set pwm duty + break; + #endif + + + #if defined(TCCR5A) && defined(COM5A1) + case TIMER5A: + // connect pwm to pin on timer 5, channel A + sbi(TCCR5A, COM5A1); + OCR5A = val; // set pwm duty + break; + #endif + + #if defined(TCCR5A) && defined(COM5B1) + case TIMER5B: + // connect pwm to pin on timer 5, channel B + sbi(TCCR5A, COM5B1); + OCR5B = val; // set pwm duty + break; + #endif + + #if defined(TCCR5A) && defined(COM5C1) + case TIMER5C: + // connect pwm to pin on timer 5, channel C + sbi(TCCR5A, COM5C1); + OCR5C = val; // set pwm duty + break; + #endif + + case NOT_ON_TIMER: + default: + if (val < 128) { + digitalWrite(pin, LOW); + } else { + digitalWrite(pin, HIGH); + } + } + } +} + diff --git a/sparkfun/tiny/cores/arduino/wiring_digital.c b/sparkfun/tiny/cores/arduino/wiring_digital.c new file mode 100644 index 00000000..27a62fc6 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/wiring_digital.c @@ -0,0 +1,179 @@ +/* + wiring_digital.c - digital input and output functions + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 28 September 2010 by Mark Sproul +*/ + +#define ARDUINO_MAIN +#include "wiring_private.h" +#include "pins_arduino.h" + +void pinMode(uint8_t pin, uint8_t mode) +{ + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *reg, *out; + + if (port == NOT_A_PIN) return; + + // JWS: can I let the optimizer do this? + reg = portModeRegister(port); + out = portOutputRegister(port); + + if (mode == INPUT) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out &= ~bit; + SREG = oldSREG; + } else if (mode == INPUT_PULLUP) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out |= bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *reg |= bit; + SREG = oldSREG; + } +} + +// Forcing this inline keeps the callers from having to push their own stuff +// on the stack. It is a good performance win and only takes 1 more byte per +// user than calling. (It will take more bytes on the 168.) +// +// But shouldn't this be moved into pinMode? Seems silly to check and do on +// each digitalread or write. +// +// Mark Sproul: +// - Removed inline. Save 170 bytes on atmega1280 +// - changed to a switch statment; added 32 bytes but much easier to read and maintain. +// - Added more #ifdefs, now compiles for atmega645 +// +//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); +//static inline void turnOffPWM(uint8_t timer) +static void turnOffPWM(uint8_t timer) +{ + switch (timer) + { + #if defined(TCCR1A) && defined(COM1A1) + case TIMER1A: cbi(TCCR1A, COM1A1); break; + #endif + #if defined(TCCR1A) && defined(COM1B1) + case TIMER1B: cbi(TCCR1A, COM1B1); break; + #endif + #if defined(TCCR1A) && defined(COM1C1) + case TIMER1C: cbi(TCCR1A, COM1C1); break; + #endif + + #if defined(TCCR2) && defined(COM21) + case TIMER2: cbi(TCCR2, COM21); break; + #endif + + #if defined(TCCR0A) && defined(COM0A1) + case TIMER0A: cbi(TCCR0A, COM0A1); break; + #endif + + #if defined(TCCR0A) && defined(COM0B1) + case TIMER0B: cbi(TCCR0A, COM0B1); break; + #endif + #if defined(TCCR2A) && defined(COM2A1) + case TIMER2A: cbi(TCCR2A, COM2A1); break; + #endif + #if defined(TCCR2A) && defined(COM2B1) + case TIMER2B: cbi(TCCR2A, COM2B1); break; + #endif + + #if defined(TCCR3A) && defined(COM3A1) + case TIMER3A: cbi(TCCR3A, COM3A1); break; + #endif + #if defined(TCCR3A) && defined(COM3B1) + case TIMER3B: cbi(TCCR3A, COM3B1); break; + #endif + #if defined(TCCR3A) && defined(COM3C1) + case TIMER3C: cbi(TCCR3A, COM3C1); break; + #endif + + #if defined(TCCR4A) && defined(COM4A1) + case TIMER4A: cbi(TCCR4A, COM4A1); break; + #endif + #if defined(TCCR4A) && defined(COM4B1) + case TIMER4B: cbi(TCCR4A, COM4B1); break; + #endif + #if defined(TCCR4A) && defined(COM4C1) + case TIMER4C: cbi(TCCR4A, COM4C1); break; + #endif + #if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: cbi(TCCR4C, COM4D1); break; + #endif + + #if defined(TCCR5A) + case TIMER5A: cbi(TCCR5A, COM5A1); break; + case TIMER5B: cbi(TCCR5A, COM5B1); break; + case TIMER5C: cbi(TCCR5A, COM5C1); break; + #endif + } +} + +void digitalWrite(uint8_t pin, uint8_t val) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *out; + + if (port == NOT_A_PIN) return; + + // If the pin that support PWM output, we need to turn it off + // before doing a digital write. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + out = portOutputRegister(port); + + uint8_t oldSREG = SREG; + cli(); + + if (val == LOW) { + *out &= ~bit; + } else { + *out |= bit; + } + + SREG = oldSREG; +} + +int digitalRead(uint8_t pin) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + + if (port == NOT_A_PIN) return LOW; + + // If the pin that support PWM output, we need to turn it off + // before getting a digital reading. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + if (*portInputRegister(port) & bit) return HIGH; + return LOW; +} diff --git a/sparkfun/tiny/cores/arduino/wiring_private.h b/sparkfun/tiny/cores/arduino/wiring_private.h new file mode 100644 index 00000000..a277b148 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/wiring_private.h @@ -0,0 +1,72 @@ +/* + wiring_private.h - Internal header file. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#ifndef WiringPrivate_h +#define WiringPrivate_h + +#include +#include +#include +#include + +#include "Arduino.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops); + +#define EXTERNAL_INT_0 0 +#define EXTERNAL_INT_1 1 +#define EXTERNAL_INT_2 2 +#define EXTERNAL_INT_3 3 +#define EXTERNAL_INT_4 4 +#define EXTERNAL_INT_5 5 +#define EXTERNAL_INT_6 6 +#define EXTERNAL_INT_7 7 + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__) || \ + defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) +#define EXTERNAL_NUM_INTERRUPTS 8 +#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) +#define EXTERNAL_NUM_INTERRUPTS 3 +#elif defined(__AVR_ATmega32U4__) +#define EXTERNAL_NUM_INTERRUPTS 5 +#else +#define EXTERNAL_NUM_INTERRUPTS 2 +#endif + +typedef void (*voidFuncPtr)(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/sparkfun/tiny/cores/arduino/wiring_pulse.S b/sparkfun/tiny/cores/arduino/wiring_pulse.S new file mode 100644 index 00000000..1dd22e62 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/wiring_pulse.S @@ -0,0 +1,178 @@ +/* + wiring_pulse.s - pulseInASM() function in different flavours + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2014 Martino Facchin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +/* + * The following routine was generated by avr-gcc 4.8.3 with the following parameters + * -gstabs -Wa,-ahlmsd=output.lst -dp -fverbose-asm -O2 + * on the original C function + * + * unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops) + * { + * unsigned long width = 0; + * // wait for any previous pulse to end + * while ((*port & bit) == stateMask) + * if (--maxloops == 0) + * return 0; + * + * // wait for the pulse to start + * while ((*port & bit) != stateMask) + * if (--maxloops == 0) + * return 0; + * + * // wait for the pulse to stop + * while ((*port & bit) == stateMask) { + * if (++width == maxloops) + * return 0; + * } + * return width; + * } + * + * some compiler outputs were removed but the rest of the code is untouched + */ + +#include + +.section .text + +.global countPulseASM + +countPulseASM: + +.LM0: +.LFBB1: + push r12 ; ; 130 pushqi1/1 [length = 1] + push r13 ; ; 131 pushqi1/1 [length = 1] + push r14 ; ; 132 pushqi1/1 [length = 1] + push r15 ; ; 133 pushqi1/1 [length = 1] + push r16 ; ; 134 pushqi1/1 [length = 1] + push r17 ; ; 135 pushqi1/1 [length = 1] +/* prologue: function */ +/* frame size = 0 */ +/* stack size = 6 */ +.L__stack_usage = 6 + mov r30,r24 ; port, port ; 2 *movhi/1 [length = 2] + mov r31,r25 ; port, port +/* unsigned long width = 0; +*** // wait for any previous pulse to end +*** while ((*port & bit) == stateMask) +*/ +.LM1: + rjmp .L2 ; ; 181 jump [length = 1] +.L4: +/* if (--maxloops == 0) */ +.LM2: + subi r16,1 ; maxloops, ; 17 addsi3/2 [length = 4] + sbc r17, r1 ; maxloops + sbc r18, r1 ; maxloops + sbc r19, r1 ; maxloops + breq .L13 ; , ; 19 branch [length = 1] +.L2: +/* if (--maxloops == 0) */ +.LM3: + ld r25,Z ; D.1554, *port_7(D) ; 22 movqi_insn/4 [length = 1] + and r25,r22 ; D.1554, bit ; 24 andqi3/1 [length = 1] + cp r25,r20 ; D.1554, stateMask ; 25 *cmpqi/2 [length = 1] + breq .L4 ; , ; 26 branch [length = 1] + rjmp .L6 ; ; 184 jump [length = 1] +.L7: +/* return 0; +*** +*** // wait for the pulse to start +*** while ((*port & bit) != stateMask) +*** if (--maxloops == 0) +*/ +.LM4: + subi r16,1 ; maxloops, ; 31 addsi3/2 [length = 4] + sbc r17, r1 ; maxloops + sbc r18, r1 ; maxloops + sbc r19, r1 ; maxloops + breq .L13 ; , ; 33 branch [length = 1] +.L6: +/* if (--maxloops == 0) */ +.LM5: + ld r25,Z ; D.1554, *port_7(D) ; 41 movqi_insn/4 [length = 1] + and r25,r22 ; D.1554, bit ; 43 andqi3/1 [length = 1] + cpse r25,r20 ; D.1554, stateMask ; 44 enable_interrupt-3 [length = 1] + rjmp .L7 ; + mov r12, r1 ; width ; 7 *movsi/2 [length = 4] + mov r13, r1 ; width + mov r14, r1 ; width + mov r15, r1 ; width + rjmp .L9 ; ; 186 jump [length = 1] +.L10: +/* return 0; +*** +*** // wait for the pulse to stop +*** while ((*port & bit) == stateMask) { +*** if (++width == maxloops) +*/ +.LM6: + ldi r24,-1 ; , ; 50 addsi3/3 [length = 5] + sub r12,r24 ; width, + sbc r13,r24 ; width, + sbc r14,r24 ; width, + sbc r15,r24 ; width, + cp r16,r12 ; maxloops, width ; 51 *cmpsi/2 [length = 4] + cpc r17,r13 ; maxloops, width + cpc r18,r14 ; maxloops, width + cpc r19,r15 ; maxloops, width + breq .L13 ; , ; 52 branch [length = 1] +.L9: +/* if (++width == maxloops) */ +.LM7: + ld r24,Z ; D.1554, *port_7(D) ; 60 movqi_insn/4 [length = 1] + and r24,r22 ; D.1554, bit ; 62 andqi3/1 [length = 1] + cp r24,r20 ; D.1554, stateMask ; 63 *cmpqi/2 [length = 1] + breq .L10 ; , ; 64 branch [length = 1] +/* return 0; +*** } +*** return width; +*/ +.LM8: + mov r22,r12 ; D.1553, width ; 108 movqi_insn/1 [length = 1] + mov r23,r13 ; D.1553, width ; 109 movqi_insn/1 [length = 1] + mov r24,r14 ; D.1553, width ; 110 movqi_insn/1 [length = 1] + mov r25,r15 ; D.1553, width ; 111 movqi_insn/1 [length = 1] +/* epilogue start */ +.LM9: + pop r17 ; ; 171 popqi [length = 1] + pop r16 ; ; 172 popqi [length = 1] + pop r15 ; ; 173 popqi [length = 1] + pop r14 ; ; 174 popqi [length = 1] + pop r13 ; ; 175 popqi [length = 1] + pop r12 ; ; 176 popqi [length = 1] + ret ; 177 return_from_epilogue [length = 1] +.L13: +.LM10: + ldi r22,0 ; D.1553 ; 120 movqi_insn/1 [length = 1] + ldi r23,0 ; D.1553 ; 121 movqi_insn/1 [length = 1] + ldi r24,0 ; D.1553 ; 122 movqi_insn/1 [length = 1] + ldi r25,0 ; D.1553 ; 123 movqi_insn/1 [length = 1] +/* epilogue start */ +.LM11: + pop r17 ; ; 138 popqi [length = 1] + pop r16 ; ; 139 popqi [length = 1] + pop r15 ; ; 140 popqi [length = 1] + pop r14 ; ; 141 popqi [length = 1] + pop r13 ; ; 142 popqi [length = 1] + pop r12 ; ; 143 popqi [length = 1] + ret ; 144 return_from_epilogue [length = 1] diff --git a/sparkfun/tiny/cores/arduino/wiring_pulse.c b/sparkfun/tiny/cores/arduino/wiring_pulse.c new file mode 100644 index 00000000..d6e04347 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/wiring_pulse.c @@ -0,0 +1,93 @@ +/* + wiring_pulse.c - pulseIn() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. + * + * This function performs better with short pulses in noInterrupt() context + */ +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + + // convert the timeout from microseconds to a number of times through + // the initial loop; it takes approximately 16 clock cycles per iteration + unsigned long maxloops = microsecondsToClockCycles(timeout)/16; + + unsigned long width = countPulseASM(portInputRegister(port), bit, stateMask, maxloops); + + // prevent clockCyclesToMicroseconds to return bogus values if countPulseASM timed out + if (width) + return clockCyclesToMicroseconds(width * 16 + 16); + else + return 0; +} + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. + * + * ATTENTION: + * this function relies on micros() so cannot be used in noInterrupt() context + */ +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + + unsigned long startMicros = micros(); + + // wait for any previous pulse to end + while ((*portInputRegister(port) & bit) == stateMask) { + if (micros() - startMicros > timeout) + return 0; + } + + // wait for the pulse to start + while ((*portInputRegister(port) & bit) != stateMask) { + if (micros() - startMicros > timeout) + return 0; + } + + unsigned long start = micros(); + // wait for the pulse to stop + while ((*portInputRegister(port) & bit) == stateMask) { + if (micros() - startMicros > timeout) + return 0; + } + return micros() - start; +} diff --git a/sparkfun/tiny/cores/arduino/wiring_shift.c b/sparkfun/tiny/cores/arduino/wiring_shift.c new file mode 100644 index 00000000..2b6f7a81 --- /dev/null +++ b/sparkfun/tiny/cores/arduino/wiring_shift.c @@ -0,0 +1,53 @@ +/* + wiring_shift.c - shiftOut() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "wiring_private.h" + +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { + uint8_t value = 0; + uint8_t i; + + for (i = 0; i < 8; ++i) { + digitalWrite(clockPin, HIGH); + if (bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + digitalWrite(clockPin, LOW); + } + return value; +} + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} diff --git a/sparkfun/tiny/cores/tiny/Arduino.h b/sparkfun/tiny/cores/tiny/Arduino.h new file mode 100644 index 00000000..2ab7ed1d --- /dev/null +++ b/sparkfun/tiny/cores/tiny/Arduino.h @@ -0,0 +1,276 @@ +#ifndef Arduino_h +#define Arduino_h + +#include +#include +#include + +#include +#include +#include + +#include "binary.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#define ATTINY_CORE 1 + +void yield(void); + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#define NOT_AN_INTERRUPT -1 + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() sei() +#define noInterrupts() cli() + +#if F_CPU < 1000000L +//Prevent a divide by 0 is +#warning Clocks per microsecond < 1. To prevent divide by 0, it is rounded up to 1. +//static inline unsigned long clockCyclesPerMicrosecond() __attribute__ ((always_inline)); +//static inline unsigned long clockCyclesPerMicrosecond() +//{// +//Inline function will be optimised out. +// return 1; +//} + //WTF were they thinking?! +#define clockCyclesPerMicrosecond() 1L +#else +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#endif + +#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) ) +#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + + +typedef unsigned int word; + +#define bit(b) (1UL << (b)) + +typedef uint8_t boolean; +typedef uint8_t byte; + +void initToneTimer(void); +void init(void); + +void pinMode(uint8_t, uint8_t); +void digitalWrite(uint8_t, uint8_t); +int digitalRead(uint8_t); +int analogRead(uint8_t); +void analogReference(uint8_t mode); +void analogWrite(uint8_t, int); + +unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t, void (*)(void), int mode); +void detachInterrupt(uint8_t); + +void setup(void); +void loop(void); + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. + +#define analogInPinToBit(P) (P) + +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; + +extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. +// +// These perform slightly better as macros compared to inline functions +// +#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) +#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +#define analogInPinToBit(P) (P) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER1D 5 + +#include "pins_arduino.h" + +#ifndef USE_SOFTWARE_SERIAL +//Default to hardware serial. +#define USE_SOFTWARE_SERIAL 0 +#endif + +/*============================================================================= + Allow the ADC to be optional for low-power applications +=============================================================================*/ + +#ifndef TIMER_TO_USE_FOR_MILLIS +#define TIMER_TO_USE_FOR_MILLIS 0 +#endif +/* + Tone goes on whichever timer was not used for millis. +*/ +#if TIMER_TO_USE_FOR_MILLIS == 1 +#define TIMER_TO_USE_FOR_TONE 0 +#else +#define TIMER_TO_USE_FOR_TONE 1 +#endif + +#if NUM_ANALOG_INPUTS > 0 + #define HAVE_ADC 1 + #ifndef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER + #define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 1 + #endif +#else + #define HAVE_ADC 0 + #if defined(INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER) + #undef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER + #endif + #define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 0 +#endif + +#if !HAVE_ADC + #undef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER + #define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 0 +#else + #ifndef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER + #define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 1 + #endif +#endif + +/*============================================================================= + Allow the "secondary timers" to be optional for low-power applications +=============================================================================*/ + +#ifndef INITIALIZE_SECONDARY_TIMERS + #define INITIALIZE_SECONDARY_TIMERS 1 +#endif + + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#include "WCharacter.h" +#include "WString.h" +#include "HardwareSerial.h" +#include "TinySoftwareSerial.h" + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin = 255); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned int); +long map(long, long, long, long, long); + +#endif + +/*============================================================================= + Aliases for the interrupt service routine vector numbers so the code + doesn't have to be riddled with #ifdefs. +=============================================================================*/ + +#if defined( TIM0_COMPA_vect ) && ! defined( TIMER0_COMPA_vect ) +#define TIMER0_COMPA_vect TIM0_COMPA_vect +#endif + +#if defined( TIM0_COMPB_vect ) && ! defined( TIMER0_COMPB_vect ) +#define TIMER0_COMPB_vect TIM0_COMPB_vect +#endif + +#if defined( TIM0_OVF_vect ) && ! defined( TIMER0_OVF_vect ) +#define TIMER0_OVF_vect TIM0_OVF_vect +#endif + +#if defined( TIM1_COMPA_vect ) && ! defined( TIMER1_COMPA_vect ) +#define TIMER1_COMPA_vect TIM1_COMPA_vect +#endif + +#if defined( TIM1_COMPB_vect ) && ! defined( TIMER1_COMPB_vect ) +#define TIMER1_COMPB_vect TIM1_COMPB_vect +#endif + +#if defined( TIM1_OVF_vect ) && ! defined( TIMER1_OVF_vect ) +#define TIMER1_OVF_vect TIM1_OVF_vect +#endif + +#endif diff --git a/sparkfun/tiny/cores/tiny/HardwareSerial.cpp b/sparkfun/tiny/cores/tiny/HardwareSerial.cpp new file mode 100644 index 00000000..f6af462f --- /dev/null +++ b/sparkfun/tiny/cores/tiny/HardwareSerial.cpp @@ -0,0 +1,409 @@ +/* + HardwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul +*/ + +#include +#include +#include +#include + +#include "Arduino.h" +#include "wiring_private.h" + +// this next line disables the entire HardwareSerial.cpp, +// this is so I can support Attiny series and any other chip without a uart +#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL + +#include "HardwareSerial.h" + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which rx_buffer_head is the index of the +// location to which to write the next incoming character and rx_buffer_tail +// is the index of the location from which to read. +#if (RAMEND < 1000) + #define SERIAL_BUFFER_SIZE 16 +#else + #define SERIAL_BUFFER_SIZE 64 +#endif + +struct ring_buffer +{ + unsigned char buffer[SERIAL_BUFFER_SIZE]; + byte head; + byte tail; +}; + +#if defined(UBRRH) || defined(UBRR0H) || defined(LINCR) + ring_buffer rx_buffer = { { 0 }, 0, 0 }; + ring_buffer tx_buffer = { { 0 }, 0, 0 }; +#endif +#if defined(UBRR1H) + ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer1 = { { 0 }, 0, 0 }; +#endif + +inline void store_char(unsigned char c, ring_buffer *buffer) +{ + byte i = (buffer->head + 1) % SERIAL_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != buffer->tail) { + buffer->buffer[buffer->head] = c; + buffer->head = i; + } +} + +#if defined(USART_RX_vect) + ISR(USART_RX_vect) + { + #if defined(UDR) + unsigned char c = UDR; + #elif defined(UDR0) + unsigned char c = UDR0; // atmega8535 + #else + #error UDR not defined + #endif + store_char(c, &rx_buffer); + } +#elif defined(USART0_RX_vect) + ISR(USART0_RX_vect) + { + #if defined(UDR) + unsigned char c = UDR; + #elif defined(UDR0) + unsigned char c = UDR0; // atmega8535 + #else + #error UDR not defined + #endif + store_char(c, &rx_buffer); + } +#elif defined(UART_RX_vect) + ISR(UART_RX_vect) + { + #if defined(UDR) + unsigned char c = UDR; + #elif defined(UDR0) + unsigned char c = UDR0; // atmega8535 + #else + #error UDR not defined + #endif + store_char(c, &rx_buffer); + } +#elif defined(UART0_RX_vect) + ISR(UART0_RX_vect) + { + #if defined(UDR) + unsigned char c = UDR; + #elif defined(UDR0) + unsigned char c = UDR0; // atmega8535 + #else + #error UDR not defined + #endif + store_char(c, &rx_buffer); + } +#elif defined(LIN_TC_vect) + // this is for attinyX7 + ISR(LIN_TC_vect) + { + if(LINSIR & _BV(LRXOK)) { + unsigned char c = LINDAT; + store_char(c, &rx_buffer); + } + if(LINSIR & _BV(LTXOK)){ + //PINA |= _BV(PINA5); //debug + if (tx_buffer.head == tx_buffer.tail) { + // Buffer empty, so disable interrupts + cbi(LINENIR,LENTXOK); + } else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer.buffer[tx_buffer.tail]; + tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; + + LINDAT = c; + } + } + } +#else + #error No interrupt handler for usart 0 +#endif + +//#if defined(SIG_USART1_RECV) +#if defined(USART1_RX_vect) + ISR(USART1_RX_vect) + { + unsigned char c = UDR1; + store_char(c, &rx_buffer1); + } +#elif defined(USART1_RXC_vect) + ISR(USART1_RXC_vect ) + { + unsigned char c = UDR1; + store_char(c, &rx_buffer1); + } +#else + //no UART1 +#endif + +#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect) && !defined(LIN_TC_vect) + #error "Don't know what the Data Register Empty vector is called for the first UART" +#else +#if defined(UART0_UDRE_vect) +ISR(UART0_UDRE_vect) +#elif defined(UART_UDRE_vect) +ISR(UART_UDRE_vect) +#elif defined(USART0_UDRE_vect) +ISR(USART0_UDRE_vect) +#elif defined(USART_UDRE_vect) +ISR(USART_UDRE_vect) +#endif +#if !defined(LIN_TC_vect) +{ + if (tx_buffer.head == tx_buffer.tail) { + // Buffer empty, so disable interrupts +#if defined(UCSR0B) + cbi(UCSR0B, UDRIE0); +#else + cbi(UCSRB, UDRIE); +#endif + } else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer.buffer[tx_buffer.tail]; + tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; + + #if defined(UDR) + UDR = c; + #elif defined(UDR0) + UDR0 = c; + #else + #error UDR not defined + #endif + } +} +#endif +#endif + +#ifdef USART1_UDRE_vect +ISR(USART1_UDRE_vect) +{ + if (tx_buffer1.head == tx_buffer1.tail) { + // Buffer empty, so disable interrupts + cbi(UCSR1B, UDRIE1); + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer1.buffer[tx_buffer1.tail]; + tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR1 = c; + } +} +#endif + + +// Constructors //////////////////////////////////////////////////////////////// + +HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer +#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H)) + ,volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x) +{ + _rx_buffer = rx_buffer; + _tx_buffer = tx_buffer; + _ubrrh = ubrrh; + _ubrrl = ubrrl; + _ucsra = ucsra; + _ucsrb = ucsrb; + _udr = udr; + _rxen = rxen; + _txen = txen; + _rxcie = rxcie; + _udrie = udrie; + _u2x = u2x; +} +#else +) +{ + _rx_buffer = rx_buffer; + _tx_buffer = tx_buffer; +} +#endif + + +// Public Methods ////////////////////////////////////////////////////////////// + +void HardwareSerial::begin(long baud) +{ +#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H)) + uint16_t baud_setting; + bool use_u2x = true; + +#if F_CPU == 16000000UL + // hardcoded exception for compatibility with the bootloader shipped + // with the Duemilanove and previous boards and the firmware on the 8U2 + // on the Uno and Mega 2560. + if (baud == 57600) { + use_u2x = false; + } +#endif + +try_again: + + if (use_u2x) { + *_ucsra = 1 << _u2x; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + if ((baud_setting > 4095) && use_u2x) + { + use_u2x = false; + goto try_again; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + sbi(*_ucsrb, _rxen); + sbi(*_ucsrb, _txen); + sbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); +#else + LINCR = (1 << LSWRES); + LINBRR = (((F_CPU * 10L / 16L / baud) + 5L) / 10L) - 1; + LINBTR = (1 << LDISR) | (16 << LBT0); + LINCR = _BV(LENA) | _BV(LCMD2) | _BV(LCMD1) | _BV(LCMD0); + sbi(LINENIR,LENRXOK); +#endif + +} + +void HardwareSerial::end() +{ + while (_tx_buffer->head != _tx_buffer->tail) + ; +#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H)) + cbi(*_ucsrb, _rxen); + cbi(*_ucsrb, _txen); + cbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); +#else + cbi(LINENIR,LENTXOK); + cbi(LINENIR,LENRXOK); + cbi(LINCR,LENA); + cbi(LINCR,LCMD0); + cbi(LINCR,LCMD1); + cbi(LINCR,LCMD2); +#endif + + _rx_buffer->head = _rx_buffer->tail; +} + +int HardwareSerial::available(void) +{ + return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE; +} + +int HardwareSerial::peek(void) +{ + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + return _rx_buffer->buffer[_rx_buffer->tail]; + } +} + +int HardwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; + _rx_buffer->tail = (_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE; + return c; + } +} + +void HardwareSerial::flush() +{ + while (_tx_buffer->head != _tx_buffer->tail) + ; +} + +size_t HardwareSerial::write(uint8_t c) +{ + byte i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + // ???: return 0 here instead? + while (i == _tx_buffer->tail) + ; + + _tx_buffer->buffer[_tx_buffer->head] = c; + _tx_buffer->head = i; + + #if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) ) + sbi(*_ucsrb, _udrie); + #else + if(!(LINENIR & _BV(LENTXOK))){ + //The buffer was previously empty, so enable TX Complete interrupt and load first byte. + sbi(LINENIR,LENTXOK); + unsigned char c = tx_buffer.buffer[tx_buffer.tail]; + tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; + LINDAT = c; + } + #endif + + + return 1; +} + +HardwareSerial::operator bool() { + return true; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +#if defined(UBRRH) && defined(UBRRL) + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X); +#elif defined(UBRR0H) && defined(UBRR0L) + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0); +#elif defined(LINBRRH) + HardwareSerial Serial(&rx_buffer, &tx_buffer); +#endif + + +#if defined(UBRR1H) + HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1); +#endif + +#elif !USE_SOFTWARE_SERIAL +#warning There is no Hardware UART, and Sofware Serial is not enabled. There will be no serial port. +#endif // whole file diff --git a/sparkfun/tiny/cores/tiny/HardwareSerial.h b/sparkfun/tiny/cores/tiny/HardwareSerial.h new file mode 100644 index 00000000..03862492 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/HardwareSerial.h @@ -0,0 +1,78 @@ +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL + +#include + +#include "Stream.h" + +struct ring_buffer; + +class HardwareSerial : public Stream +{ + private: + volatile ring_buffer *_rx_buffer; + volatile ring_buffer *_tx_buffer; + volatile uint8_t *_ubrrh; + volatile uint8_t *_ubrrl; + volatile uint8_t *_ucsra; + volatile uint8_t *_ucsrb; + volatile uint8_t *_udr; + uint8_t _rxen; + uint8_t _txen; + uint8_t _rxcie; + uint8_t _udrie; + uint8_t _u2x; + public: + HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer + #if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H)) + , + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x); + #else + ); + #endif + void begin(long); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t); + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool(); +}; + +#endif + +#if (defined(UBRRH) || defined(UBRR0H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL + extern HardwareSerial Serial; +#endif +#if defined(UBRR1H) + extern HardwareSerial Serial1; +#endif + +#endif diff --git a/sparkfun/tiny/cores/tiny/Print.cpp b/sparkfun/tiny/cores/tiny/Print.cpp new file mode 100644 index 00000000..cd4c88d8 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/Print.cpp @@ -0,0 +1,286 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + */ + +#include +#include +#include +#include + +#include "Arduino.h" +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +/* default implementation: may be overridden */ +size_t Print::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + while (size--) { + n += write(*buffer++); + } + return n; +} + +size_t Print::print(const String &s) +{ + size_t n = 0; + for (uint16_t i = 0; i < s.length(); i++) { + n += write(s[i]); + } + return n; +} + +size_t Print::print(const char str[]) +{ + return write(str); +} + +size_t Print::print(char c) +{ + return write(c); +} + +size_t Print::print(unsigned char b, int base) +{ + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) +{ + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) +{ + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) +{ + if (base == 0) { + return write(n); + } else if (base == 10) { + int t = 0; + if (n < 0) { + t = print('-'); + n = -n; + } + return printNumber(n, 10) + t; + } else { + return printNumber(n, base); + } +} + +size_t Print::print(unsigned long n, int base) +{ + if (base == 0) return write(n); + else return printNumber(n, base); +} + +size_t Print::print(double n, int digits) +{ + return printFloat(n, digits); +} + +size_t Print::print( fstr_t* s ) +{ + size_t n = 0; + char ch; + + ch = pgm_read_byte( s ); + while ( ch != 0 ) + { + write( ch ); + ++s; + ++n; + ch = pgm_read_byte( s ); + } + return( n ); +} + +size_t Print::println(void) +{ + size_t n = print('\r'); + n += print('\n'); + return n; +} + +size_t Print::println(const String &s) +{ + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) +{ + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) +{ + size_t n = print(num, digits); + n += println(); + return n; +} + +size_t Print::println( fstr_t* s ) +{ + size_t n = print( s ); + n += println(); + return( n ); +} + +#ifdef FLASHSTRING_SUPPORT + +size_t Print::print(const __FlashStringHelper *ifsh) +{ + PGM_P p = reinterpret_cast(ifsh); + size_t n = 0; + while (1) { + unsigned char c = pgm_read_byte(p++); + if (c == 0) break; + if (write(c)) n++; + else break; + } + return n; +} + +size_t Print::println(const __FlashStringHelper *ifsh) +{ + size_t n = print(ifsh); + n += println(); + return n; +} + +#endif + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if (base < 2) base = 10; + + do { + unsigned long m = n; + n /= base; + char c = m - base * n; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) +{ + size_t n = 0; + + // Handle negative numbers + if (number < 0.0) + { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i 0) { + n += print("."); + } + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + int toPrint = int(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/sparkfun/tiny/cores/tiny/Print.h b/sparkfun/tiny/cores/tiny/Print.h new file mode 100644 index 00000000..66e2d7e6 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/Print.h @@ -0,0 +1,115 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 20-11-2010 by B.Cook ... + + http://arduiniana.org/libraries/flash/ + Printable support thanks to Mikal Hart +*/ + +#ifndef Print_h +#define Print_h + +#include +#include // for size_t + +#include "WString.h" + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#ifdef BIN +#define ABIN BIN +//One of the ATtiny84 registers has a bit called BIN, so rename it to avoid compiler warnings. +#undef BIN +#endif +#define BIN 2 + +#define ARDUINO_CORE_PRINTABLE_SUPPORT + +#define FLASHSTRING_SUPPORT + +class Print; + +/* Printable...*/ + +class _Printable +{ +public: + virtual void print(Print &stream) const = 0; +}; + +/* ...Printable */ + +typedef struct +{ + char c; +} +fstr_t; + + +class Print +{ + private: + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + protected: + void setWriteError(int err = 1) { write_error = err; } + public: + Print() : write_error(0) {} + + int getWriteError() { return write_error; } + void clearWriteError() { setWriteError(0); } + + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); } + virtual size_t write(const uint8_t *buffer, size_t size); + + size_t print(fstr_t*); + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(long long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(fstr_t*); + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(long long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); + + #ifdef FLASHSTRING_SUPPORT + size_t print(const __FlashStringHelper *ifsh); + size_t println(const __FlashStringHelper *ifsh); + #endif +}; + +#endif diff --git a/sparkfun/tiny/cores/tiny/Printable.h b/sparkfun/tiny/cores/tiny/Printable.h new file mode 100644 index 00000000..2a1b2e9f --- /dev/null +++ b/sparkfun/tiny/cores/tiny/Printable.h @@ -0,0 +1,40 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Printable_h +#define Printable_h + +#include + +class Print; + +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. +*/ + +class Printable +{ + public: + virtual size_t printTo(Print& p) const = 0; +}; + +#endif + diff --git a/sparkfun/tiny/cores/tiny/Stream.cpp b/sparkfun/tiny/cores/tiny/Stream.cpp new file mode 100644 index 00000000..f6654653 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/Stream.cpp @@ -0,0 +1,319 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + + findMulti/findUntil routines written by Jim Leonard/Xuth + */ + +#include "Arduino.h" +#include "Stream.h" + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait + +// private method to read stream with timeout +int Stream::timedRead() +{ + int c; + _startMillis = millis(); + do { + c = read(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// private method to peek stream with timeout +int Stream::timedPeek() +{ + int c; + _startMillis = millis(); + do { + c = peek(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// returns peek of the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal) +{ + int c; + while (1) { + c = timedPeek(); + + if( c < 0 || + c == '-' || + (c >= '0' && c <= '9') || + (detectDecimal && c == '.')) return c; + + switch( lookahead ){ + case SKIP_NONE: return -1; // Fail code. + case SKIP_WHITESPACE: + switch( c ){ + case ' ': + case '\t': + case '\r': + case '\n': break; + default: return -1; // Fail code. + } + case SKIP_ALL: + break; + } + read(); // discard non-numeric + } +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait +{ + _timeout = timeout; +} + + // find returns true if the target string is found +bool Stream::find(char *target) +{ + return findUntil(target, strlen(target), NULL, 0); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(char *target, char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) +{ + if (terminator == NULL) { + MultiTarget t[1] = {{target, targetLen, 0}}; + return findMulti(t, 1) == 0 ? true : false; + } else { + MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}}; + return findMulti(t, 2) == 0 ? true : false; + } +} + +// returns the first valid (long) integer value from the current position. +// lookahead determines how parseInt looks ahead in the stream. +// See LookaheadMode enumeration at the top of the file. +// Lookahead is terminated by the first character that is not a valid part of an integer. +// Once parsing commences, 'ignore' will be skipped in the stream. +long Stream::parseInt(LookaheadMode lookahead, char ignore) +{ + bool isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(lookahead, false); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == ignore) + ; // ignore this character + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || c == ignore ); + + if(isNegative) + value = -value; + return value; +} + +// as parseInt but returns a floating point value +float Stream::parseFloat(LookaheadMode lookahead, char ignore) +{ + bool isNegative = false; + bool isFraction = false; + long value = 0; + int c; + float fraction = 1.0; + + c = peekNextDigit(lookahead, true); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == ignore) + ; // ignore + else if(c == '-') + isNegative = true; + else if (c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || (c == '.' && !isFraction) || c == ignore ); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, or timeout (see setTimeout) +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +// +size_t Stream::readBytes(char *buffer, size_t length) +{ + size_t count = 0; + while (count < length) { + int c = timedRead(); + if (c < 0) break; + *buffer++ = (char)c; + count++; + } + return count; +} + + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) +{ + if (length < 1) return 0; + size_t index = 0; + while (index < length) { + int c = timedRead(); + if (c < 0 || c == terminator) break; + *buffer++ = (char)c; + index++; + } + return index; // return number of characters, not including null terminator +} + +String Stream::readString() +{ + String ret; + int c = timedRead(); + while (c >= 0) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + +String Stream::readStringUntil(char terminator) +{ + String ret; + int c = timedRead(); + while (c >= 0 && c != terminator) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + +int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) { + // any zero length target string automatically matches and would make + // a mess of the rest of the algorithm. + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + if (t->len <= 0) + return t - targets; + } + + while (1) { + int c = timedRead(); + if (c < 0) + return -1; + + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + // the simple case is if we match, deal with that first. + if (c == t->str[t->index]) { + if (++t->index == t->len) + return t - targets; + else + continue; + } + + // if not we need to walk back and see if we could have matched further + // down the stream (ie '1112' doesn't match the first position in '11112' + // but it will match the second position so we can't just reset the current + // index to 0 when we find a mismatch. + if (t->index == 0) + continue; + + int origIndex = t->index; + do { + --t->index; + // first check if current char works against the new current index + if (c != t->str[t->index]) + continue; + + // if it's the only char then we're good, nothing more to check + if (t->index == 0) { + t->index++; + break; + } + + // otherwise we need to check the rest of the found string + int diff = origIndex - t->index; + size_t i; + for (i = 0; i < t->index; ++i) { + if (t->str[i] != t->str[i + diff]) + break; + } + + // if we successfully got through the previous loop then our current + // index is good. + if (i == t->index) { + t->index++; + break; + } + + // otherwise we just try the next index + } while (t->index); + } + } + // unreachable + return -1; +} diff --git a/sparkfun/tiny/cores/tiny/Stream.h b/sparkfun/tiny/cores/tiny/Stream.h new file mode 100644 index 00000000..e4fd4338 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/Stream.h @@ -0,0 +1,130 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis +*/ + +#ifndef Stream_h +#define Stream_h + +#include +#include "Print.h" + +// compatability macros for testing +/* +#define getInt() parseInt() +#define getInt(ignore) parseInt(ignore) +#define getFloat() parseFloat() +#define getFloat(ignore) parseFloat(ignore) +#define getString( pre_string, post_string, buffer, length) +readBytesBetween( pre_string, terminator, buffer, length) +*/ + +// This enumeration provides the lookahead options for parseInt(), parseFloat() +// The rules set out here are used until either the first valid character is found +// or a time out occurs due to lack of input. +enum LookaheadMode{ + SKIP_ALL, // All invalid characters are ignored. + SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid. + SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped. +}; + +#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field + +class Stream : public Print +{ + protected: + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int timedPeek(); // private method to peek stream with timeout + int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout + + public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; + + Stream() {_timeout=1000;} + +// parsing methods + + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + unsigned long getTimeout(void) { return _timeout; } + + bool find(char *target); // reads data from the stream until the target string is found + bool find(uint8_t *target) { return find ((char *)target); } + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found + bool find(uint8_t *target, size_t length) { return find ((char *)target, length); } + // returns true if target string is found, false if timed out + + bool find(char target) { return find (&target, 1); } + + bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found + bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); } + + bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found + bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } + + long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // returns the first valid (long) integer value from the current position. + // lookahead determines how parseInt looks ahead in the stream. + // See LookaheadMode enumeration at the top of the file. + // Lookahead is terminated by the first character that is not a valid part of an integer. + // Once parsing commences, 'ignore' will be skipped in the stream. + + float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // float version of parseInt + + size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer + size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character + size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); } + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + String readString(); + String readStringUntil(char terminator); + + protected: + long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); } + float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); } + // These overload exists for compatibility with any class that has derived + // Stream and used parseFloat/Int with a custom ignore character. To keep + // the public API simple, these overload remains protected. + + struct MultiTarget { + const char *str; // string you're searching for + size_t len; // length of string you're searching for + size_t index; // index used by the search routine. + }; + + // This allows you to search for an arbitrary number of strings. + // Returns index of the target that is found first or -1 if timeout occurs. + int findMulti(struct MultiTarget *targets, int tCount); +}; + +#undef NO_IGNORE_CHAR +#endif diff --git a/sparkfun/tiny/cores/tiny/TinySoftwareSerial.cpp b/sparkfun/tiny/cores/tiny/TinySoftwareSerial.cpp new file mode 100644 index 00000000..93c96c9c --- /dev/null +++ b/sparkfun/tiny/cores/tiny/TinySoftwareSerial.cpp @@ -0,0 +1,266 @@ +/* + TinySoftwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul +*/ + +#include +#include +#include +#include + +#include "Arduino.h" +#include "wiring_private.h" + +#if USE_SOFTWARE_SERIAL +#include "TinySoftwareSerial.h" + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which rx_buffer_head is the index of the +// location to which to write the next incoming character and rx_buffer_tail +// is the index of the location from which to read. + +extern "C"{ +uint8_t getch() { + uint8_t ch = 0; + __asm__ __volatile__ ( + " rcall uartDelay\n" // Get to 0.25 of start bit (our baud is too fast, so give room to correct) + "1: rcall uartDelay\n" // Wait 0.25 bit period + " rcall uartDelay\n" // Wait 0.25 bit period + " rcall uartDelay\n" // Wait 0.25 bit period + " rcall uartDelay\n" // Wait 0.25 bit period + " clc\n" + " in r23,%[pin]\n" + " and r23, %[mask]\n" + " breq 2f\n" + " sec\n" + "2: ror %0\n" + " dec %[count]\n" + " breq 3f\n" + " rjmp 1b\n" + "3: rcall uartDelay\n" // Wait 0.25 bit period + " rcall uartDelay\n" // Wait 0.25 bit period + : + "=r" (ch) + : + "0" ((uint8_t)0), + [count] "r" ((uint8_t)8), + [pin] "I" (_SFR_IO_ADDR(ANALOG_COMP_PIN)), + [mask] "r" (Serial._rxmask) + : + "r23", + "r24", + "r25" + ); + return ch; +} + +void uartDelay() { + __asm__ __volatile__ ( + "mov r25,%[count]\n" + "1:dec r25\n" + "brne 1b\n" + "ret\n" + ::[count] "r" ((uint8_t)Serial._delayCount) + ); +} + +#if !defined (ANALOG_COMP_vect) && defined(ANA_COMP_vect) +//rename the vector so we can use it. + #define ANALOG_COMP_vect ANA_COMP_vect +#elif !defined (ANALOG_COMP_vect) + #error Tiny Software Serial cant find the Analog comparator interrupt vector! +#endif +ISR(ANALOG_COMP_vect){ + char ch = getch(); //read in the character softwarily - I know its not a word, but it sounded cool, so you know what: #define softwarily 1 + store_char(ch, Serial._rx_buffer); + sbi(ACSR,ACI); //clear the flag. +} + +} +soft_ring_buffer rx_buffer = { { 0 }, 0, 0 }; + +// Constructor //////////////////////////////////////////////////////////////// + +TinySoftwareSerial::TinySoftwareSerial(soft_ring_buffer *rx_buffer, uint8_t txBit, uint8_t rxBit) +{ + _rx_buffer = rx_buffer; + + _rxmask = _BV(rxBit); + _txmask = _BV(txBit); + _txunmask = ~_txmask; + + _delayCount = 0; +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void TinySoftwareSerial::begin(long baud) +{ + long tempDelay = (((F_CPU/baud)-39)/12); + if ((tempDelay > 255) || (tempDelay <= 0)){ + end(); //Cannot start as it would screw up uartDelay(). + } + _delayCount = (uint8_t)tempDelay; + cbi(ACSR,ACIE); //turn off the comparator interrupt to allow change of ACD +#ifdef ACBG + sbi(ACSR,ACBG); //enable the internal bandgap reference - used instead of AIN0 to allow it to be used for TX. +#endif + cbi(ACSR,ACD); //turn on the comparator for RX +#ifdef ACIC + cbi(ACSR,ACIC); //prevent the comparator from affecting timer1 - just to be safe. +#endif + sbi(ACSR,ACIS1); //interrupt on rising edge (this means RX has gone from Mark state to Start bit state). + sbi(ACSR,ACIS0); + //Setup the pins in case someone messed with them. + ANALOG_COMP_DDR &= ~_rxmask; //set RX to an input + ANALOG_COMP_PORT |= _rxmask; //enable pullup on RX pin - to prevent accidental interrupt triggers. + ANALOG_COMP_DDR |= _txmask; //set TX to an output. + ANALOG_COMP_PORT |= _txmask; //set TX pin high + sbi(ACSR,ACI); //clear the flag. + sbi(ACSR,ACIE); //turn on the comparator interrupt to allow us to use it for RX +#ifdef ACSRB + ACSRB = 0; //Use AIN0 as +, AIN1 as -, no hysteresis - just like ones without this register. +#endif +} + +void TinySoftwareSerial::end() +{ + sbi(ACSR,ACI); //clear the flag. + cbi(ACSR,ACIE); //turn off the comparator interrupt to allow change of ACD, and because it needs to be turned off now too! +#ifdef ACBG + cbi(ACSR,ACBG); //disable the bandgap reference +#endif + sbi(ACSR,ACD); //turn off the comparator to save power + _delayCount = 0; + _rx_buffer->head = _rx_buffer->tail; +} + +int TinySoftwareSerial::available(void) +{ + return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE; +} + +void store_char(unsigned char c, soft_ring_buffer *buffer) +{ + int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != buffer->tail) { + buffer->buffer[buffer->head] = c; + buffer->head = i; + } +} + +int TinySoftwareSerial::peek(void) +{ + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + return _rx_buffer->buffer[_rx_buffer->tail]; + } +} + +int TinySoftwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; + _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE; + return c; + } +} + +size_t TinySoftwareSerial::write(uint8_t ch) +{ + uint8_t oldSREG = SREG; + cli(); //Prevent interrupts from breaking the transmission. Note: TinySoftwareSerial is half duplex. + //it can either recieve or send, not both (because recieving requires an interrupt and would stall transmission + __asm__ __volatile__ ( + " com %[ch]\n" // ones complement, carry set + " sec\n" + "1: brcc 2f\n" + " in r23,%[uartPort] \n" + " and r23,%[uartUnmask]\n" + " out %[uartPort],r23 \n" + " rjmp 3f\n" + "2: in r23,%[uartPort] \n" + " or r23,%[uartMask]\n" + " out %[uartPort],r23 \n" + " nop\n" + "3: rcall uartDelay\n" + " rcall uartDelay\n" + " rcall uartDelay\n" + " rcall uartDelay\n" + " lsr %[ch]\n" + " dec %[count]\n" + " brne 1b\n" + : + : + [ch] "r" (ch), + [count] "r" ((uint8_t)10), + [uartPort] "I" (_SFR_IO_ADDR(ANALOG_COMP_PORT)), + [uartMask] "r" (_txmask), + [uartUnmask] "r" (_txunmask) + : "r23", + "r24", + "r25" + ); + SREG = oldSREG; + return 1; +} + +void TinySoftwareSerial::flush() +{ + +} + +TinySoftwareSerial::operator bool() { + return true; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// +#ifndef ANALOG_COMP_DDR +#error Please define ANALOG_COMP_DDR in the pins_arduino.h file! +#endif + +#ifndef ANALOG_COMP_PORT +#error Please define ANALOG_COMP_PORT in the pins_arduino.h file! +#endif + +#ifndef ANALOG_COMP_PIN +#error Please define ANALOG_COMP_PIN in the pins_arduino.h file! +#endif + +#ifndef ANALOG_COMP_AIN0_BIT +#error Please define ANALOG_COMP_AIN0_BIT in the pins_arduino.h file! +#endif + +#ifndef ANALOG_COMP_AIN1_BIT +#error Please define ANALOG_COMP_AIN1_BIT in the pins_arduino.h file! +#endif + +TinySoftwareSerial Serial(&rx_buffer, ANALOG_COMP_AIN0_BIT, ANALOG_COMP_AIN1_BIT); + +#endif // whole file diff --git a/sparkfun/tiny/cores/tiny/TinySoftwareSerial.h b/sparkfun/tiny/cores/tiny/TinySoftwareSerial.h new file mode 100644 index 00000000..9d56f512 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/TinySoftwareSerial.h @@ -0,0 +1,61 @@ + +#if USE_SOFTWARE_SERIAL +#ifndef TinySoftwareSerial_h +#define TinySoftwareSerial_h +#include +#include "Stream.h" + +#if !defined(ACSR) && defined(ACSRA) +#define ACSR ACSRA +#endif + +#if (RAMEND < 250) + #define SERIAL_BUFFER_SIZE 8 +#elif (RAMEND < 500) + #define SERIAL_BUFFER_SIZE 16 +#elif (RAMEND < 1000) + #define SERIAL_BUFFER_SIZE 32 +#else + #define SERIAL_BUFFER_SIZE 128 +#endif +struct soft_ring_buffer +{ + unsigned char buffer[SERIAL_BUFFER_SIZE]; + int head; + int tail; +}; + +extern "C"{ + void uartDelay() __attribute__ ((naked,used)); //used attribute needed to prevent LTO from throwing it out. + uint8_t getch(); + void store_char(unsigned char c, soft_ring_buffer *buffer); +} + +class TinySoftwareSerial : public Stream +{ + public: //should be private but needed by extern "C" {} functions. + uint8_t _rxmask; + uint8_t _txmask; + uint8_t _txunmask; + soft_ring_buffer *_rx_buffer; + uint8_t _delayCount; + public: + TinySoftwareSerial(soft_ring_buffer *rx_buffer, uint8_t txBit, uint8_t rxBit); + void begin(long); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t); + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool(); +}; + +#if (!defined(UBRRH) && !defined(UBRR0H)) || USE_SOFTWARE_SERIAL + extern TinySoftwareSerial Serial; +#endif + +//extern void putch(uint8_t); +#endif +#endif diff --git a/sparkfun/tiny/cores/tiny/Tone.cpp b/sparkfun/tiny/cores/tiny/Tone.cpp new file mode 100644 index 00000000..9f249357 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/Tone.cpp @@ -0,0 +1,558 @@ +/* Tone.cpp + + A Tone Generator Library + + Written by Brett Hagman + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Version Modified By Date Comments +------- ----------- -------- -------- +0001 B Hagman 09/08/02 Initial coding +0002 B Hagman 09/08/18 Multiple pins +0003 B Hagman 09/08/18 Moved initialization from constructor to begin() +0004 B Hagman 09/09/26 Fixed problems with ATmega8 +0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers + 09/11/25 Changed pin toggle method to XOR + 09/11/25 Fixed timer0 from being excluded +0006 D Mellis 09/12/29 Replaced objects with functions +0007 B Cook 10/05/03 Rewritten to only work with Timer1 and support direct hardware output +0008 B Cook 10/05/03 Rewritten so the timer can be selected at compile time +0009 T Carpenter 12/08/06 Rewritten to remove requirement for all the wierd timer name creation macros. + +*************************************************/ + +#include +#include "Arduino.h" +#include "wiring_private.h" +#include "pins_arduino.h" + +// timerx_toggle_count: +// > 0 - duration specified +// = 0 - stopped +// < 0 - infinitely (until stop() method called, or new play() called) + +static volatile long tone_timer_toggle_count; +static volatile uint8_t *tone_timer_pin_register; +static volatile uint8_t tone_timer_pin_mask; + +static uint8_t tone_pin = 255; + + +void tone( uint8_t _pin, unsigned int frequency, unsigned long duration ) +{ + + if ( tone_pin == 255 ) + { + /* Set the timer to power-up conditions so we start from a known state */ + // Ensure the timer is in the same state as power-up + #if (TIMER_TO_USE_FOR_TONE == 0) + TCCR0B = (0< 0 ) + { + /* Determine which prescaler to use */ + /* Set the Output Compare Register (rounding up) */ + + #if TIMER_TO_USE_FOR_TONE == 1 + #ifdef PLLTIMER1 + uint16_t ocr = 64000000UL / frequency / 2; + #else + #ifdef LOWPLLTIMER1 + uint16_t ocr = 32000000UL / frequency / 2; + #else + uint16_t ocr = F_CPU / frequency / 2; + #endif + #endif + #if defined(TCCR1E) + uint8_t prescalarbits = 0b0001; + if (ocr > 256) + { + ocr >>= 3; //divide by 8 + prescalarbits = 0b0100; // ck/8 + if (ocr > 256) + { + ocr >>= 3; //divide by a further 8 + prescalarbits = 0b0111; //ck/64 + if (ocr > 256) + { + ocr >>= 2; //divide by a further 4 + prescalarbits = 0b1001; //ck/256 + if (ocr > 256) + { + // can't do any better than /1024 + ocr >>= 2; //divide by a further 4 + prescalarbits = 0b1011; //ck/1024 + } + } + } + } + #else + #if defined(TCCR1) //Start FANCY ATtiny85 code + uint8_t prescalarbits = 0b0001; + while (ocr > 0xff && prescalarbits < 15) { + prescalarbits++; + ocr>>=1; + + } + OCR1C=ocr-1; + #else + uint8_t prescalarbits = 0b001; + if (ocr > 0xffff) + { + ocr /= 64; + prescalarbits = 0b011; + } + #endif + ocr -= 1; //Note we are doing the subtraction of 1 here to save repeatedly calculating ocr from just the frequency in the if tree above + + OCR1A = ocr; + #endif + #elif TIMER_TO_USE_FOR_TONE == 0 + uint16_t ocr = F_CPU / frequency / 2; + uint8_t prescalarbits = 0b001; // ck/1 + if (ocr > 256) + { + ocr >>= 3; //divide by 8 + prescalarbits = 0b010; // ck/8 + if (ocr > 256) + { + ocr >>= 3; //divide by a further 8 + prescalarbits = 0b011; //ck/64 + if (ocr > 256) + { + ocr >>= 2; //divide by a further 4 + prescalarbits = 0b100; //ck/256 + if (ocr > 256) + { + // can't do any better than /1024 + ocr >>= 2; //divide by a further 4 + prescalarbits = 0b101; //ck/1024 + } + } + } + } + ocr -= 1; //Note we are doing the subtraction of 1 here to save repeatedly calculating ocr from just the frequency in the if tree above + OCR0A = ocr; + + #endif + + /* Does the caller want a specific duration? */ + if ( duration > 0 ) + { + /* Determine how many times the value toggles */ + tone_timer_toggle_count = (2 * frequency * duration) / 1000; + /* Output Compare A Match Interrupt Enable */ + #if (TIMER_TO_USE_FOR_TONE == 1) + #if defined (TIMSK) + TIMSK |= (1< 0 ) + { + --tone_timer_toggle_count; + + if ( tone_timer_toggle_count == 0 ) + { + // Shutdown the hardware + noTone( 255 ); + + // Skip the rest. We're finished. + return; + } + } + *tone_timer_pin_register ^= tone_timer_pin_mask; + } + else + { + // Shutdown the hardware + noTone( 255 ); + } +} diff --git a/sparkfun/tiny/cores/tiny/WCharacter.h b/sparkfun/tiny/cores/tiny/WCharacter.h new file mode 100644 index 00000000..79733b50 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/WCharacter.h @@ -0,0 +1,168 @@ +/* + WCharacter.h - Character utility functions for Wiring & Arduino + Copyright (c) 2010 Hernando Barragan. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Character_h +#define Character_h + +#include + +// WCharacter.h prototypes +inline boolean isAlphaNumeric(int c) __attribute__((always_inline)); +inline boolean isAlpha(int c) __attribute__((always_inline)); +inline boolean isAscii(int c) __attribute__((always_inline)); +inline boolean isWhitespace(int c) __attribute__((always_inline)); +inline boolean isControl(int c) __attribute__((always_inline)); +inline boolean isDigit(int c) __attribute__((always_inline)); +inline boolean isGraph(int c) __attribute__((always_inline)); +inline boolean isLowerCase(int c) __attribute__((always_inline)); +inline boolean isPrintable(int c) __attribute__((always_inline)); +inline boolean isPunct(int c) __attribute__((always_inline)); +inline boolean isSpace(int c) __attribute__((always_inline)); +inline boolean isUpperCase(int c) __attribute__((always_inline)); +inline boolean isHexadecimalDigit(int c) __attribute__((always_inline)); +inline int toAscii(int c) __attribute__((always_inline)); +inline int toLowerCase(int c) __attribute__((always_inline)); +inline int toUpperCase(int c)__attribute__((always_inline)); + + +// Checks for an alphanumeric character. +// It is equivalent to (isalpha(c) || isdigit(c)). +inline boolean isAlphaNumeric(int c) +{ + return ( isalnum(c) == 0 ? false : true); +} + + +// Checks for an alphabetic character. +// It is equivalent to (isupper(c) || islower(c)). +inline boolean isAlpha(int c) +{ + return ( isalpha(c) == 0 ? false : true); +} + + +// Checks whether c is a 7-bit unsigned char value +// that fits into the ASCII character set. +inline boolean isAscii(int c) +{ + return ( isascii (c) == 0 ? false : true); +} + + +// Checks for a blank character, that is, a space or a tab. +inline boolean isWhitespace(int c) +{ + return ( isblank (c) == 0 ? false : true); +} + + +// Checks for a control character. +inline boolean isControl(int c) +{ + return ( iscntrl (c) == 0 ? false : true); +} + + +// Checks for a digit (0 through 9). +inline boolean isDigit(int c) +{ + return ( isdigit (c) == 0 ? false : true); +} + + +// Checks for any printable character except space. +inline boolean isGraph(int c) +{ + return ( isgraph (c) == 0 ? false : true); +} + + +// Checks for a lower-case character. +inline boolean isLowerCase(int c) +{ + return (islower (c) == 0 ? false : true); +} + + +// Checks for any printable character including space. +inline boolean isPrintable(int c) +{ + return ( isprint (c) == 0 ? false : true); +} + + +// Checks for any printable character which is not a space +// or an alphanumeric character. +inline boolean isPunct(int c) +{ + return ( ispunct (c) == 0 ? false : true); +} + + +// Checks for white-space characters. For the avr-libc library, +// these are: space, formfeed ('\f'), newline ('\n'), carriage +// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). +inline boolean isSpace(int c) +{ + return ( isspace (c) == 0 ? false : true); +} + + +// Checks for an uppercase letter. +inline boolean isUpperCase(int c) +{ + return ( isupper (c) == 0 ? false : true); +} + + +// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7 +// 8 9 a b c d e f A B C D E F. +inline boolean isHexadecimalDigit(int c) +{ + return ( isxdigit (c) == 0 ? false : true); +} + + +// Converts c to a 7-bit unsigned char value that fits into the +// ASCII character set, by clearing the high-order bits. +inline int toAscii(int c) +{ + return toascii (c); +} + + +// Warning: +// Many people will be unhappy if you use this function. +// This function will convert accented letters into random +// characters. + +// Converts the letter c to lower case, if possible. +inline int toLowerCase(int c) +{ + return tolower (c); +} + + +// Converts the letter c to upper case, if possible. +inline int toUpperCase(int c) +{ + return toupper (c); +} + +#endif \ No newline at end of file diff --git a/sparkfun/tiny/cores/tiny/WInterrupts.c b/sparkfun/tiny/cores/tiny/WInterrupts.c new file mode 100644 index 00000000..823d7738 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/WInterrupts.c @@ -0,0 +1,155 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.uniandes.edu.co + + Copyright (c) 2004-05 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 24 November 2006 by David A. Mellis + + Modified 28-08-2009 for attiny84 R.Wiersma + Modified 09-10-2009 for attiny45 A.Saporetti + Modified 20-11-2010 - B.Cook - Correct a minor bug in attachInterrupt +*/ + +#include +#include +#include +#include +#include + +#include "wiring_private.h" + +static volatile voidFuncPtr intFunc[NUMBER_EXTERNAL_INTERRUPTS]; + +#if defined( MCUCR ) && ! defined( EICRA ) + #define EICRA MCUCR +#endif + +#if defined( GIMSK ) && ! defined( EIMSK ) + #define EIMSK GIMSK +#endif + +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) +{ + if ( interruptNum < NUMBER_EXTERNAL_INTERRUPTS ) + { + /* + If attachInterrupt is called in succession for the same + interruptNum but a different userFunc then the following line + is not safe. Changing intFunc is not atomic. + intFunc[interruptNum] = userFunc; + */ + { + // save interrupt flag + uint8_t SaveSREG = SREG; + // disable interrupts + cli(); + // access the shared data + intFunc[interruptNum] = userFunc; + // restore the interrupt flag + SREG = SaveSREG; + } + + // Configure the interrupt mode (trigger on low input, any change, rising + // edge, or falling edge). The mode constants were chosen to correspond + // to the configuration bits in the hardware register, so we simply shift + // the mode into place. + + // Enable the interrupt. + + switch ( interruptNum ) + { + #if NUMBER_EXTERNAL_INTERRUPTS >= 1 + case EXTERNAL_INTERRUPT_0: + EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + EIMSK |= (1 << INT0); + break; + #endif + + #if NUMBER_EXTERNAL_INTERRUPTS >= 2 && !defined(ISC11) + //For ATtiny861, but interrupts share the same vector. + case EXTERNAL_INTERRUPT_1: + EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + EIMSK |= (1 << INT1); + break; + #endif + + #if NUMBER_EXTERNAL_INTERRUPTS >= 2 && defined(ISC11) + case EXTERNAL_INTERRUPT_1: + EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); + EIMSK |= (1 << INT1); + break; + #endif + + #if NUMBER_EXTERNAL_INTERRUPTS > 2 + #error Add handlers for the additional interrupts. + #endif + } + } +} + +void detachInterrupt(uint8_t interruptNum) +{ + if ( interruptNum < NUMBER_EXTERNAL_INTERRUPTS ) + { + // Disable the interrupt. (We can't assume that interruptNum is equal + // to the number of the EIMSK bit to clear, as this isn't true on the + // ATmega8. There, INT0 is 6 and INT1 is 7.) + + switch (interruptNum) + { + #if NUMBER_EXTERNAL_INTERRUPTS >= 1 + case EXTERNAL_INTERRUPT_0: + EIMSK &= ~(1 << INT0); + break;; + #endif + + #if NUMBER_EXTERNAL_INTERRUPTS >= 2 + case EXTERNAL_INTERRUPT_1: + EIMSK &= ~(1 << INT1); + break;; + #endif + + #if NUMBER_EXTERNAL_INTERRUPTS > 2 + #error Add handlers for the additional interrupts. + #endif + } + intFunc[interruptNum] = 0; + } +} + +#if NUMBER_EXTERNAL_INTERRUPTS >= 1 +ISR(EXTERNAL_INTERRUPT_0_vect) +{ + if(intFunc[EXTERNAL_INTERRUPT_0]) + intFunc[EXTERNAL_INTERRUPT_0](); +} +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 2 +ISR(EXTERNAL_INTERRUPT_1_vect) +{ + if(intFunc[EXTERNAL_INTERRUPT_1]) + intFunc[EXTERNAL_INTERRUPT_1](); +} +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS > 2 +#error Add handlers for the additional interrupts. +#endif diff --git a/sparkfun/tiny/cores/tiny/WMath.cpp b/sparkfun/tiny/cores/tiny/WMath.cpp new file mode 100644 index 00000000..2120c4cc --- /dev/null +++ b/sparkfun/tiny/cores/tiny/WMath.cpp @@ -0,0 +1,60 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + Copyright (c) 2004-06 Hernando Barragan + Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ +*/ + +extern "C" { + #include "stdlib.h" +} + +void randomSeed(unsigned int seed) +{ + if (seed != 0) { + srandom(seed); + } +} + +long random(long howbig) +{ + if (howbig == 0) { + return 0; + } + return random() % howbig; +} + +long random(long howsmall, long howbig) +{ + if (howsmall >= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return random(diff) + howsmall; +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +unsigned int makeWord(unsigned int w) { return w; } +unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } \ No newline at end of file diff --git a/sparkfun/tiny/cores/tiny/WProgram.h b/sparkfun/tiny/cores/tiny/WProgram.h new file mode 100644 index 00000000..3a14eb5e --- /dev/null +++ b/sparkfun/tiny/cores/tiny/WProgram.h @@ -0,0 +1,2 @@ +//For compatibility with older programs +#include "Arduino.h" \ No newline at end of file diff --git a/sparkfun/tiny/cores/tiny/WString.cpp b/sparkfun/tiny/cores/tiny/WString.cpp new file mode 100644 index 00000000..f2572d60 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/WString.cpp @@ -0,0 +1,750 @@ +/* + WString.cpp - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WString.h" + +/*********************************************/ +/* Constructors */ +/*********************************************/ + +String::String(const char *cstr) +{ + init(); + if (cstr) copy(cstr, strlen(cstr)); +} + +String::String(const String &value) +{ + init(); + *this = value; +} + +String::String(const __FlashStringHelper *pstr) +{ + init(); + *this = pstr; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +String::String(String &&rval) +{ + init(); + move(rval); +} +String::String(StringSumHelper &&rval) +{ + init(); + move(rval); +} +#endif + +String::String(char c) +{ + init(); + char buf[2]; + buf[0] = c; + buf[1] = 0; + *this = buf; +} + +String::String(unsigned char value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned char)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(int value, unsigned char base) +{ + init(); + char buf[2 + 8 * sizeof(int)]; + itoa(value, buf, base); + *this = buf; +} + +String::String(unsigned int value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned int)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(long value, unsigned char base) +{ + init(); + char buf[2 + 8 * sizeof(long)]; + ltoa(value, buf, base); + *this = buf; +} + +String::String(unsigned long value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned long)]; + ultoa(value, buf, base); + *this = buf; +} + +String::String(float value, unsigned char decimalPlaces) +{ + init(); + char buf[33]; + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); +} + +String::String(double value, unsigned char decimalPlaces) +{ + init(); + char buf[33]; + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); +} + +String::~String() +{ + free(buffer); +} + +/*********************************************/ +/* Memory Management */ +/*********************************************/ + +inline void String::init(void) +{ + buffer = NULL; + capacity = 0; + len = 0; +} + +void String::invalidate(void) +{ + if (buffer) free(buffer); + buffer = NULL; + capacity = len = 0; +} + +unsigned char String::reserve(unsigned int size) +{ + if (buffer && capacity >= size) return 1; + if (changeBuffer(size)) { + if (len == 0) buffer[0] = 0; + return 1; + } + return 0; +} + +unsigned char String::changeBuffer(unsigned int maxStrLen) +{ + char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); + if (newbuffer) { + buffer = newbuffer; + capacity = maxStrLen; + return 1; + } + return 0; +} + +/*********************************************/ +/* Copy and Move */ +/*********************************************/ + +String & String::copy(const char *cstr, unsigned int length) +{ + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + strcpy(buffer, cstr); + return *this; +} + +String & String::copy(const __FlashStringHelper *pstr, unsigned int length) +{ + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + strcpy_P(buffer, (PGM_P)pstr); + return *this; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +void String::move(String &rhs) +{ + if (buffer) { + if (rhs && capacity >= rhs.len) { + strcpy(buffer, rhs.buffer); + len = rhs.len; + rhs.len = 0; + return; + } else { + free(buffer); + } + } + buffer = rhs.buffer; + capacity = rhs.capacity; + len = rhs.len; + rhs.buffer = NULL; + rhs.capacity = 0; + rhs.len = 0; +} +#endif + +String & String::operator = (const String &rhs) +{ + if (this == &rhs) return *this; + + if (rhs.buffer) copy(rhs.buffer, rhs.len); + else invalidate(); + + return *this; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +String & String::operator = (String &&rval) +{ + if (this != &rval) move(rval); + return *this; +} + +String & String::operator = (StringSumHelper &&rval) +{ + if (this != &rval) move(rval); + return *this; +} +#endif + +String & String::operator = (const char *cstr) +{ + if (cstr) copy(cstr, strlen(cstr)); + else invalidate(); + + return *this; +} + +String & String::operator = (const __FlashStringHelper *pstr) +{ + if (pstr) copy(pstr, strlen_P((PGM_P)pstr)); + else invalidate(); + + return *this; +} + +/*********************************************/ +/* concat */ +/*********************************************/ + +unsigned char String::concat(const String &s) +{ + return concat(s.buffer, s.len); +} + +unsigned char String::concat(const char *cstr, unsigned int length) +{ + unsigned int newlen = len + length; + if (!cstr) return 0; + if (length == 0) return 1; + if (!reserve(newlen)) return 0; + strcpy(buffer + len, cstr); + len = newlen; + return 1; +} + +unsigned char String::concat(const char *cstr) +{ + if (!cstr) return 0; + return concat(cstr, strlen(cstr)); +} + +unsigned char String::concat(char c) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + return concat(buf, 1); +} + +unsigned char String::concat(unsigned char num) +{ + char buf[1 + 3 * sizeof(unsigned char)]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(int num) +{ + char buf[2 + 3 * sizeof(int)]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned int num) +{ + char buf[1 + 3 * sizeof(unsigned int)]; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(long num) +{ + char buf[2 + 3 * sizeof(long)]; + ltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned long num) +{ + char buf[1 + 3 * sizeof(unsigned long)]; + ultoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(float num) +{ + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +unsigned char String::concat(double num) +{ + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +unsigned char String::concat(const __FlashStringHelper * str) +{ + if (!str) return 0; + int length = strlen_P((const char *) str); + if (length == 0) return 1; + unsigned int newlen = len + length; + if (!reserve(newlen)) return 0; + strcpy_P(buffer + len, (const char *) str); + len = newlen; + return 1; +} + +/*********************************************/ +/* Concatenate */ +/*********************************************/ + +StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs.buffer, rhs.len)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) +{ + StringSumHelper &a = const_cast(lhs); + if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, char c) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(c)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, float num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, double num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs)) a.invalidate(); + return a; +} + +/*********************************************/ +/* Comparison */ +/*********************************************/ + +int String::compareTo(const String &s) const +{ + if (!buffer || !s.buffer) { + if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer; + if (buffer && len > 0) return *(unsigned char *)buffer; + return 0; + } + return strcmp(buffer, s.buffer); +} + +unsigned char String::equals(const String &s2) const +{ + return (len == s2.len && compareTo(s2) == 0); +} + +unsigned char String::equals(const char *cstr) const +{ + if (len == 0) return (cstr == NULL || *cstr == 0); + if (cstr == NULL) return buffer[0] == 0; + return strcmp(buffer, cstr) == 0; +} + +unsigned char String::operator<(const String &rhs) const +{ + return compareTo(rhs) < 0; +} + +unsigned char String::operator>(const String &rhs) const +{ + return compareTo(rhs) > 0; +} + +unsigned char String::operator<=(const String &rhs) const +{ + return compareTo(rhs) <= 0; +} + +unsigned char String::operator>=(const String &rhs) const +{ + return compareTo(rhs) >= 0; +} + +unsigned char String::equalsIgnoreCase( const String &s2 ) const +{ + if (this == &s2) return 1; + if (len != s2.len) return 0; + if (len == 0) return 1; + const char *p1 = buffer; + const char *p2 = s2.buffer; + while (*p1) { + if (tolower(*p1++) != tolower(*p2++)) return 0; + } + return 1; +} + +unsigned char String::startsWith( const String &s2 ) const +{ + if (len < s2.len) return 0; + return startsWith(s2, 0); +} + +unsigned char String::startsWith( const String &s2, unsigned int offset ) const +{ + if (offset > len - s2.len || !buffer || !s2.buffer) return 0; + return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; +} + +unsigned char String::endsWith( const String &s2 ) const +{ + if ( len < s2.len || !buffer || !s2.buffer) return 0; + return strcmp(&buffer[len - s2.len], s2.buffer) == 0; +} + +/*********************************************/ +/* Character Access */ +/*********************************************/ + +char String::charAt(unsigned int loc) const +{ + return operator[](loc); +} + +void String::setCharAt(unsigned int loc, char c) +{ + if (loc < len) buffer[loc] = c; +} + +char & String::operator[](unsigned int index) +{ + static char dummy_writable_char; + if (index >= len || !buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return buffer[index]; +} + +char String::operator[]( unsigned int index ) const +{ + if (index >= len || !buffer) return 0; + return buffer[index]; +} + +void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const +{ + if (!bufsize || !buf) return; + if (index >= len) { + buf[0] = 0; + return; + } + unsigned int n = bufsize - 1; + if (n > len - index) n = len - index; + strncpy((char *)buf, buffer + index, n); + buf[n] = 0; +} + +/*********************************************/ +/* Search */ +/*********************************************/ + +int String::indexOf(char c) const +{ + return indexOf(c, 0); +} + +int String::indexOf( char ch, unsigned int fromIndex ) const +{ + if (fromIndex >= len) return -1; + const char* temp = strchr(buffer + fromIndex, ch); + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::indexOf(const String &s2) const +{ + return indexOf(s2, 0); +} + +int String::indexOf(const String &s2, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + const char *found = strstr(buffer + fromIndex, s2.buffer); + if (found == NULL) return -1; + return found - buffer; +} + +int String::lastIndexOf( char theChar ) const +{ + return lastIndexOf(theChar, len - 1); +} + +int String::lastIndexOf(char ch, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + char tempchar = buffer[fromIndex + 1]; + buffer[fromIndex + 1] = '\0'; + char* temp = strrchr( buffer, ch ); + buffer[fromIndex + 1] = tempchar; + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::lastIndexOf(const String &s2) const +{ + return lastIndexOf(s2, len - s2.len); +} + +int String::lastIndexOf(const String &s2, unsigned int fromIndex) const +{ + if (s2.len == 0 || len == 0 || s2.len > len) return -1; + if (fromIndex >= len) fromIndex = len - 1; + int found = -1; + for (char *p = buffer; p <= buffer + fromIndex; p++) { + p = strstr(p, s2.buffer); + if (!p) break; + if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer; + } + return found; +} + +String String::substring(unsigned int left, unsigned int right) const +{ + if (left > right) { + unsigned int temp = right; + right = left; + left = temp; + } + String out; + if (left >= len) return out; + if (right > len) right = len; + char temp = buffer[right]; // save the replaced character + buffer[right] = '\0'; + out = buffer + left; // pointer arithmetic + buffer[right] = temp; //restore character + return out; +} + +/*********************************************/ +/* Modification */ +/*********************************************/ + +void String::replace(char find, char replace) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + if (*p == find) *p = replace; + } +} + +void String::replace(const String& find, const String& replace) +{ + if (len == 0 || find.len == 0) return; + int diff = replace.len - find.len; + char *readFrom = buffer; + char *foundAt; + if (diff == 0) { + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + memcpy(foundAt, replace.buffer, replace.len); + readFrom = foundAt + replace.len; + } + } else if (diff < 0) { + char *writeTo = buffer; + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + unsigned int n = foundAt - readFrom; + memcpy(writeTo, readFrom, n); + writeTo += n; + memcpy(writeTo, replace.buffer, replace.len); + writeTo += replace.len; + readFrom = foundAt + find.len; + len += diff; + } + strcpy(writeTo, readFrom); + } else { + unsigned int size = len; // compute size needed for result + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + readFrom = foundAt + find.len; + size += diff; + } + if (size == len) return; + if (size > capacity && !changeBuffer(size)) return; // XXX: tell user! + int index = len - 1; + while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { + readFrom = buffer + index + find.len; + memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); + len += diff; + buffer[len] = 0; + memcpy(buffer + index, replace.buffer, replace.len); + index--; + } + } +} + +void String::remove(unsigned int index){ + // Pass the biggest integer as the count. The remove method + // below will take care of truncating it at the end of the + // string. + remove(index, (unsigned int)-1); +} + +void String::remove(unsigned int index, unsigned int count){ + if (index >= len) { return; } + if (count <= 0) { return; } + if (count > len - index) { count = len - index; } + char *writeTo = buffer + index; + len = len - count; + strncpy(writeTo, buffer + index + count,len - index); + buffer[len] = 0; +} + +void String::toLowerCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = tolower(*p); + } +} + +void String::toUpperCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = toupper(*p); + } +} + +void String::trim(void) +{ + if (!buffer || len == 0) return; + char *begin = buffer; + while (isspace(*begin)) begin++; + char *end = buffer + len - 1; + while (isspace(*end) && end >= begin) end--; + len = end + 1 - begin; + if (begin > buffer) memcpy(buffer, begin, len); + buffer[len] = 0; +} + +/*********************************************/ +/* Parsing / Conversion */ +/*********************************************/ + +long String::toInt(void) const +{ + if (buffer) return atol(buffer); + return 0; +} + +float String::toFloat(void) const +{ + return float(toDouble()); +} + +double String::toDouble(void) const +{ + if (buffer) return atof(buffer); + return 0; +} diff --git a/sparkfun/tiny/cores/tiny/WString.h b/sparkfun/tiny/cores/tiny/WString.h new file mode 100644 index 00000000..77709c3b --- /dev/null +++ b/sparkfun/tiny/cores/tiny/WString.h @@ -0,0 +1,229 @@ +/* + WString.h - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All right reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef String_class_h +#define String_class_h +#ifdef __cplusplus + +#include +#include +#include +#include + +// When compiling programs with this class, the following gcc parameters +// dramatically increase performance and memory (RAM) efficiency, typically +// with little or no increase in code size. +// -felide-constructors +// -std=c++0x + +class __FlashStringHelper; +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) + +// An inherited class for holding the result of a concatenation. These +// result objects are assumed to be writable by subsequent concatenations. +class StringSumHelper; + +// The string class +class String +{ + // use a function pointer to allow for "if (s)" without the + // complications of an operator bool(). for more information, see: + // http://www.artima.com/cppsource/safebool.html + typedef void (String::*StringIfHelperType)() const; + void StringIfHelper() const {} + +public: + // constructors + // creates a copy of the initial value. + // if the initial value is null or invalid, or if memory allocation + // fails, the string will be marked as invalid (i.e. "if (s)" will + // be false). + String(const char *cstr = ""); + String(const String &str); + String(const __FlashStringHelper *str); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + String(String &&rval); + String(StringSumHelper &&rval); + #endif + explicit String(char c); + explicit String(unsigned char, unsigned char base=10); + explicit String(int, unsigned char base=10); + explicit String(unsigned int, unsigned char base=10); + explicit String(long, unsigned char base=10); + explicit String(unsigned long, unsigned char base=10); + explicit String(float, unsigned char decimalPlaces=2); + explicit String(double, unsigned char decimalPlaces=2); + ~String(void); + + // memory management + // return true on success, false on failure (in which case, the string + // is left unchanged). reserve(0), if successful, will validate an + // invalid string (i.e., "if (s)" will be true afterwards) + unsigned char reserve(unsigned int size); + inline unsigned int length(void) const {return len;} + + // creates a copy of the assigned value. if the value is null or + // invalid, or if the memory allocation fails, the string will be + // marked as invalid ("if (s)" will be false). + String & operator = (const String &rhs); + String & operator = (const char *cstr); + String & operator = (const __FlashStringHelper *str); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + String & operator = (String &&rval); + String & operator = (StringSumHelper &&rval); + #endif + + // concatenate (works w/ built-in types) + + // returns true on success, false on failure (in which case, the string + // is left unchanged). if the argument is null or invalid, the + // concatenation is considered unsucessful. + unsigned char concat(const String &str); + unsigned char concat(const char *cstr); + unsigned char concat(char c); + unsigned char concat(unsigned char c); + unsigned char concat(int num); + unsigned char concat(unsigned int num); + unsigned char concat(long num); + unsigned char concat(unsigned long num); + unsigned char concat(float num); + unsigned char concat(double num); + unsigned char concat(const __FlashStringHelper * str); + + // if there's not enough memory for the concatenated value, the string + // will be left unchanged (but this isn't signalled in any way) + String & operator += (const String &rhs) {concat(rhs); return (*this);} + String & operator += (const char *cstr) {concat(cstr); return (*this);} + String & operator += (char c) {concat(c); return (*this);} + String & operator += (unsigned char num) {concat(num); return (*this);} + String & operator += (int num) {concat(num); return (*this);} + String & operator += (unsigned int num) {concat(num); return (*this);} + String & operator += (long num) {concat(num); return (*this);} + String & operator += (unsigned long num) {concat(num); return (*this);} + String & operator += (float num) {concat(num); return (*this);} + String & operator += (double num) {concat(num); return (*this);} + String & operator += (const __FlashStringHelper *str){concat(str); return (*this);} + + friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, float num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, double num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs); + + // comparison (only works w/ Strings and "strings") + operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } + int compareTo(const String &s) const; + unsigned char equals(const String &s) const; + unsigned char equals(const char *cstr) const; + unsigned char operator == (const String &rhs) const {return equals(rhs);} + unsigned char operator == (const char *cstr) const {return equals(cstr);} + unsigned char operator != (const String &rhs) const {return !equals(rhs);} + unsigned char operator != (const char *cstr) const {return !equals(cstr);} + unsigned char operator < (const String &rhs) const; + unsigned char operator > (const String &rhs) const; + unsigned char operator <= (const String &rhs) const; + unsigned char operator >= (const String &rhs) const; + unsigned char equalsIgnoreCase(const String &s) const; + unsigned char startsWith( const String &prefix) const; + unsigned char startsWith(const String &prefix, unsigned int offset) const; + unsigned char endsWith(const String &suffix) const; + + // character acccess + char charAt(unsigned int index) const; + void setCharAt(unsigned int index, char c); + char operator [] (unsigned int index) const; + char& operator [] (unsigned int index); + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; + void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const + { getBytes((unsigned char *)buf, bufsize, index); } + const char* c_str() const { return buffer; } + char* begin() { return buffer; } + char* end() { return buffer + length(); } + const char* begin() const { return c_str(); } + const char* end() const { return c_str() + length(); } + + // search + int indexOf( char ch ) const; + int indexOf( char ch, unsigned int fromIndex ) const; + int indexOf( const String &str ) const; + int indexOf( const String &str, unsigned int fromIndex ) const; + int lastIndexOf( char ch ) const; + int lastIndexOf( char ch, unsigned int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, unsigned int fromIndex ) const; + String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); }; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + + // modification + void replace(char find, char replace); + void replace(const String& find, const String& replace); + void remove(unsigned int index); + void remove(unsigned int index, unsigned int count); + void toLowerCase(void); + void toUpperCase(void); + void trim(void); + + // parsing/conversion + long toInt(void) const; + float toFloat(void) const; + double toDouble(void) const; + +protected: + char *buffer; // the actual char array + unsigned int capacity; // the array length minus one (for the '\0') + unsigned int len; // the String length (not counting the '\0') +protected: + void init(void); + void invalidate(void); + unsigned char changeBuffer(unsigned int maxStrLen); + unsigned char concat(const char *cstr, unsigned int length); + + // copy and move + String & copy(const char *cstr, unsigned int length); + String & copy(const __FlashStringHelper *pstr, unsigned int length); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + void move(String &rhs); + #endif +}; + +class StringSumHelper : public String +{ +public: + StringSumHelper(const String &s) : String(s) {} + StringSumHelper(const char *p) : String(p) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(unsigned char num) : String(num) {} + StringSumHelper(int num) : String(num) {} + StringSumHelper(unsigned int num) : String(num) {} + StringSumHelper(long num) : String(num) {} + StringSumHelper(unsigned long num) : String(num) {} + StringSumHelper(float num) : String(num) {} + StringSumHelper(double num) : String(num) {} +}; + +#endif // __cplusplus +#endif // String_class_h diff --git a/sparkfun/tiny/cores/tiny/abi.cpp b/sparkfun/tiny/cores/tiny/abi.cpp new file mode 100644 index 00000000..57dc98d8 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/abi.cpp @@ -0,0 +1,35 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +extern "C" void __cxa_pure_virtual(void) __attribute__ ((weak, __noreturn__)); +extern "C" void __cxa_deleted_virtual(void) __attribute__ ((weak, __noreturn__)); + +void __cxa_pure_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + +void __cxa_deleted_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + diff --git a/sparkfun/tiny/cores/tiny/binary.h b/sparkfun/tiny/cores/tiny/binary.h new file mode 100644 index 00000000..af149803 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/binary.h @@ -0,0 +1,515 @@ +#ifndef Binary_h +#define Binary_h + +#define B0 0 +#define B00 0 +#define B000 0 +#define B0000 0 +#define B00000 0 +#define B000000 0 +#define B0000000 0 +#define B00000000 0 +#define B1 1 +#define B01 1 +#define B001 1 +#define B0001 1 +#define B00001 1 +#define B000001 1 +#define B0000001 1 +#define B00000001 1 +#define B10 2 +#define B010 2 +#define B0010 2 +#define B00010 2 +#define B000010 2 +#define B0000010 2 +#define B00000010 2 +#define B11 3 +#define B011 3 +#define B0011 3 +#define B00011 3 +#define B000011 3 +#define B0000011 3 +#define B00000011 3 +#define B100 4 +#define B0100 4 +#define B00100 4 +#define B000100 4 +#define B0000100 4 +#define B00000100 4 +#define B101 5 +#define B0101 5 +#define B00101 5 +#define B000101 5 +#define B0000101 5 +#define B00000101 5 +#define B110 6 +#define B0110 6 +#define B00110 6 +#define B000110 6 +#define B0000110 6 +#define B00000110 6 +#define B111 7 +#define B0111 7 +#define B00111 7 +#define B000111 7 +#define B0000111 7 +#define B00000111 7 +#define B1000 8 +#define B01000 8 +#define B001000 8 +#define B0001000 8 +#define B00001000 8 +#define B1001 9 +#define B01001 9 +#define B001001 9 +#define B0001001 9 +#define B00001001 9 +#define B1010 10 +#define B01010 10 +#define B001010 10 +#define B0001010 10 +#define B00001010 10 +#define B1011 11 +#define B01011 11 +#define B001011 11 +#define B0001011 11 +#define B00001011 11 +#define B1100 12 +#define B01100 12 +#define B001100 12 +#define B0001100 12 +#define B00001100 12 +#define B1101 13 +#define B01101 13 +#define B001101 13 +#define B0001101 13 +#define B00001101 13 +#define B1110 14 +#define B01110 14 +#define B001110 14 +#define B0001110 14 +#define B00001110 14 +#define B1111 15 +#define B01111 15 +#define B001111 15 +#define B0001111 15 +#define B00001111 15 +#define B10000 16 +#define B010000 16 +#define B0010000 16 +#define B00010000 16 +#define B10001 17 +#define B010001 17 +#define B0010001 17 +#define B00010001 17 +#define B10010 18 +#define B010010 18 +#define B0010010 18 +#define B00010010 18 +#define B10011 19 +#define B010011 19 +#define B0010011 19 +#define B00010011 19 +#define B10100 20 +#define B010100 20 +#define B0010100 20 +#define B00010100 20 +#define B10101 21 +#define B010101 21 +#define B0010101 21 +#define B00010101 21 +#define B10110 22 +#define B010110 22 +#define B0010110 22 +#define B00010110 22 +#define B10111 23 +#define B010111 23 +#define B0010111 23 +#define B00010111 23 +#define B11000 24 +#define B011000 24 +#define B0011000 24 +#define B00011000 24 +#define B11001 25 +#define B011001 25 +#define B0011001 25 +#define B00011001 25 +#define B11010 26 +#define B011010 26 +#define B0011010 26 +#define B00011010 26 +#define B11011 27 +#define B011011 27 +#define B0011011 27 +#define B00011011 27 +#define B11100 28 +#define B011100 28 +#define B0011100 28 +#define B00011100 28 +#define B11101 29 +#define B011101 29 +#define B0011101 29 +#define B00011101 29 +#define B11110 30 +#define B011110 30 +#define B0011110 30 +#define B00011110 30 +#define B11111 31 +#define B011111 31 +#define B0011111 31 +#define B00011111 31 +#define B100000 32 +#define B0100000 32 +#define B00100000 32 +#define B100001 33 +#define B0100001 33 +#define B00100001 33 +#define B100010 34 +#define B0100010 34 +#define B00100010 34 +#define B100011 35 +#define B0100011 35 +#define B00100011 35 +#define B100100 36 +#define B0100100 36 +#define B00100100 36 +#define B100101 37 +#define B0100101 37 +#define B00100101 37 +#define B100110 38 +#define B0100110 38 +#define B00100110 38 +#define B100111 39 +#define B0100111 39 +#define B00100111 39 +#define B101000 40 +#define B0101000 40 +#define B00101000 40 +#define B101001 41 +#define B0101001 41 +#define B00101001 41 +#define B101010 42 +#define B0101010 42 +#define B00101010 42 +#define B101011 43 +#define B0101011 43 +#define B00101011 43 +#define B101100 44 +#define B0101100 44 +#define B00101100 44 +#define B101101 45 +#define B0101101 45 +#define B00101101 45 +#define B101110 46 +#define B0101110 46 +#define B00101110 46 +#define B101111 47 +#define B0101111 47 +#define B00101111 47 +#define B110000 48 +#define B0110000 48 +#define B00110000 48 +#define B110001 49 +#define B0110001 49 +#define B00110001 49 +#define B110010 50 +#define B0110010 50 +#define B00110010 50 +#define B110011 51 +#define B0110011 51 +#define B00110011 51 +#define B110100 52 +#define B0110100 52 +#define B00110100 52 +#define B110101 53 +#define B0110101 53 +#define B00110101 53 +#define B110110 54 +#define B0110110 54 +#define B00110110 54 +#define B110111 55 +#define B0110111 55 +#define B00110111 55 +#define B111000 56 +#define B0111000 56 +#define B00111000 56 +#define B111001 57 +#define B0111001 57 +#define B00111001 57 +#define B111010 58 +#define B0111010 58 +#define B00111010 58 +#define B111011 59 +#define B0111011 59 +#define B00111011 59 +#define B111100 60 +#define B0111100 60 +#define B00111100 60 +#define B111101 61 +#define B0111101 61 +#define B00111101 61 +#define B111110 62 +#define B0111110 62 +#define B00111110 62 +#define B111111 63 +#define B0111111 63 +#define B00111111 63 +#define B1000000 64 +#define B01000000 64 +#define B1000001 65 +#define B01000001 65 +#define B1000010 66 +#define B01000010 66 +#define B1000011 67 +#define B01000011 67 +#define B1000100 68 +#define B01000100 68 +#define B1000101 69 +#define B01000101 69 +#define B1000110 70 +#define B01000110 70 +#define B1000111 71 +#define B01000111 71 +#define B1001000 72 +#define B01001000 72 +#define B1001001 73 +#define B01001001 73 +#define B1001010 74 +#define B01001010 74 +#define B1001011 75 +#define B01001011 75 +#define B1001100 76 +#define B01001100 76 +#define B1001101 77 +#define B01001101 77 +#define B1001110 78 +#define B01001110 78 +#define B1001111 79 +#define B01001111 79 +#define B1010000 80 +#define B01010000 80 +#define B1010001 81 +#define B01010001 81 +#define B1010010 82 +#define B01010010 82 +#define B1010011 83 +#define B01010011 83 +#define B1010100 84 +#define B01010100 84 +#define B1010101 85 +#define B01010101 85 +#define B1010110 86 +#define B01010110 86 +#define B1010111 87 +#define B01010111 87 +#define B1011000 88 +#define B01011000 88 +#define B1011001 89 +#define B01011001 89 +#define B1011010 90 +#define B01011010 90 +#define B1011011 91 +#define B01011011 91 +#define B1011100 92 +#define B01011100 92 +#define B1011101 93 +#define B01011101 93 +#define B1011110 94 +#define B01011110 94 +#define B1011111 95 +#define B01011111 95 +#define B1100000 96 +#define B01100000 96 +#define B1100001 97 +#define B01100001 97 +#define B1100010 98 +#define B01100010 98 +#define B1100011 99 +#define B01100011 99 +#define B1100100 100 +#define B01100100 100 +#define B1100101 101 +#define B01100101 101 +#define B1100110 102 +#define B01100110 102 +#define B1100111 103 +#define B01100111 103 +#define B1101000 104 +#define B01101000 104 +#define B1101001 105 +#define B01101001 105 +#define B1101010 106 +#define B01101010 106 +#define B1101011 107 +#define B01101011 107 +#define B1101100 108 +#define B01101100 108 +#define B1101101 109 +#define B01101101 109 +#define B1101110 110 +#define B01101110 110 +#define B1101111 111 +#define B01101111 111 +#define B1110000 112 +#define B01110000 112 +#define B1110001 113 +#define B01110001 113 +#define B1110010 114 +#define B01110010 114 +#define B1110011 115 +#define B01110011 115 +#define B1110100 116 +#define B01110100 116 +#define B1110101 117 +#define B01110101 117 +#define B1110110 118 +#define B01110110 118 +#define B1110111 119 +#define B01110111 119 +#define B1111000 120 +#define B01111000 120 +#define B1111001 121 +#define B01111001 121 +#define B1111010 122 +#define B01111010 122 +#define B1111011 123 +#define B01111011 123 +#define B1111100 124 +#define B01111100 124 +#define B1111101 125 +#define B01111101 125 +#define B1111110 126 +#define B01111110 126 +#define B1111111 127 +#define B01111111 127 +#define B10000000 128 +#define B10000001 129 +#define B10000010 130 +#define B10000011 131 +#define B10000100 132 +#define B10000101 133 +#define B10000110 134 +#define B10000111 135 +#define B10001000 136 +#define B10001001 137 +#define B10001010 138 +#define B10001011 139 +#define B10001100 140 +#define B10001101 141 +#define B10001110 142 +#define B10001111 143 +#define B10010000 144 +#define B10010001 145 +#define B10010010 146 +#define B10010011 147 +#define B10010100 148 +#define B10010101 149 +#define B10010110 150 +#define B10010111 151 +#define B10011000 152 +#define B10011001 153 +#define B10011010 154 +#define B10011011 155 +#define B10011100 156 +#define B10011101 157 +#define B10011110 158 +#define B10011111 159 +#define B10100000 160 +#define B10100001 161 +#define B10100010 162 +#define B10100011 163 +#define B10100100 164 +#define B10100101 165 +#define B10100110 166 +#define B10100111 167 +#define B10101000 168 +#define B10101001 169 +#define B10101010 170 +#define B10101011 171 +#define B10101100 172 +#define B10101101 173 +#define B10101110 174 +#define B10101111 175 +#define B10110000 176 +#define B10110001 177 +#define B10110010 178 +#define B10110011 179 +#define B10110100 180 +#define B10110101 181 +#define B10110110 182 +#define B10110111 183 +#define B10111000 184 +#define B10111001 185 +#define B10111010 186 +#define B10111011 187 +#define B10111100 188 +#define B10111101 189 +#define B10111110 190 +#define B10111111 191 +#define B11000000 192 +#define B11000001 193 +#define B11000010 194 +#define B11000011 195 +#define B11000100 196 +#define B11000101 197 +#define B11000110 198 +#define B11000111 199 +#define B11001000 200 +#define B11001001 201 +#define B11001010 202 +#define B11001011 203 +#define B11001100 204 +#define B11001101 205 +#define B11001110 206 +#define B11001111 207 +#define B11010000 208 +#define B11010001 209 +#define B11010010 210 +#define B11010011 211 +#define B11010100 212 +#define B11010101 213 +#define B11010110 214 +#define B11010111 215 +#define B11011000 216 +#define B11011001 217 +#define B11011010 218 +#define B11011011 219 +#define B11011100 220 +#define B11011101 221 +#define B11011110 222 +#define B11011111 223 +#define B11100000 224 +#define B11100001 225 +#define B11100010 226 +#define B11100011 227 +#define B11100100 228 +#define B11100101 229 +#define B11100110 230 +#define B11100111 231 +#define B11101000 232 +#define B11101001 233 +#define B11101010 234 +#define B11101011 235 +#define B11101100 236 +#define B11101101 237 +#define B11101110 238 +#define B11101111 239 +#define B11110000 240 +#define B11110001 241 +#define B11110010 242 +#define B11110011 243 +#define B11110100 244 +#define B11110101 245 +#define B11110110 246 +#define B11110111 247 +#define B11111000 248 +#define B11111001 249 +#define B11111010 250 +#define B11111011 251 +#define B11111100 252 +#define B11111101 253 +#define B11111110 254 +#define B11111111 255 + +#endif diff --git a/sparkfun/tiny/cores/tiny/main.cpp b/sparkfun/tiny/cores/tiny/main.cpp new file mode 100644 index 00000000..d14d1ffa --- /dev/null +++ b/sparkfun/tiny/cores/tiny/main.cpp @@ -0,0 +1,17 @@ +#include + +int main(void) +{ + #ifdef TUNED_OSCCAL_VALUE + OSCCAL = TUNED_OSCCAL_VALUE; //set the oscillator calibration value based on the pins_arduino.h file. If this is not set, it will be optimised away + #endif + init(); + + setup(); + + for (;;) + loop(); + + return 0; +} + diff --git a/sparkfun/tiny/cores/tiny/new.cpp b/sparkfun/tiny/cores/tiny/new.cpp new file mode 100644 index 00000000..7a6f416c --- /dev/null +++ b/sparkfun/tiny/cores/tiny/new.cpp @@ -0,0 +1,35 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +void *operator new(size_t size) { + return malloc(size); +} + +void *operator new[](size_t size) { + return malloc(size); +} + +void operator delete(void * ptr) { + free(ptr); +} + +void operator delete[](void * ptr) { + free(ptr); +} diff --git a/sparkfun/tiny/cores/tiny/new.h b/sparkfun/tiny/cores/tiny/new.h new file mode 100644 index 00000000..3a4facb2 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/new.h @@ -0,0 +1,29 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef NEW_H +#define NEW_H + +#include + +void * operator new(size_t size); +void * operator new[](size_t size); +void operator delete(void * ptr); +void operator delete[](void * ptr); + +#endif diff --git a/sparkfun/tiny/cores/tiny/wiring.c b/sparkfun/tiny/cores/tiny/wiring.c new file mode 100644 index 00000000..a68a0cfe --- /dev/null +++ b/sparkfun/tiny/cores/tiny/wiring.c @@ -0,0 +1,805 @@ +/* + wiring.c - Partial implementation of the Wiring API for the ATmega8. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 970 2010-05-25 20:16:15Z dmellis $ + + Modified 28-08-2009 for attiny84 R.Wiersma + Modified 14-10-2009 for attiny45 Saposoft + Modified 20-11-2010 - B.Cook - Rewritten to use the various Veneers. +*/ + +#include "wiring_private.h" + +#if F_CPU >= 3000000L + +#if !defined(__AVR_ATtiny167__) && !defined(__AVR_ATtiny87__) +#define timer0Prescaler 0b011 +#else +#define timer0Prescaler 0b100 +#endif + +//Timers with TCCR1 are slightly different. +#if defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 1) + #define MillisTimer_Prescale_Index (0b0111) + #define ToneTimer_Prescale_Index (timer0Prescaler) +#elif defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 0) + #define MillisTimer_Prescale_Index (timer0Prescaler) + #define ToneTimer_Prescale_Index (0b0111) +#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 1) + #define MillisTimer_Prescale_Index (0b0111) + #define ToneTimer_Prescale_Index (timer0Prescaler) +#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 0) + #define MillisTimer_Prescale_Index (timer0Prescaler) + #define ToneTimer_Prescale_Index (0b0111) +#elif (TIMER_TO_USE_FOR_MILLIS == 1) + #define MillisTimer_Prescale_Index (0b011) + #define ToneTimer_Prescale_Index (timer0Prescaler) +#else + #define MillisTimer_Prescale_Index (timer0Prescaler) + #define ToneTimer_Prescale_Index (0b011) +#endif + + #define MillisTimer_Prescale_Value (64) + #define ToneTimer_Prescale_Value (64) + +#else + +#if defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 1) + #define MillisTimer_Prescale_Index (0b0100) + #define ToneTimer_Prescale_Index (0b010) +#elif defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 0) + #define MillisTimer_Prescale_Index (0b010) + #define ToneTimer_Prescale_Index (0b0100) +#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 1) + #define MillisTimer_Prescale_Index (0b0100) + #define ToneTimer_Prescale_Index (0b010) +#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 0) + #define MillisTimer_Prescale_Index (0b010) + #define ToneTimer_Prescale_Index (0b0100) +#else + #define MillisTimer_Prescale_Index (0b010) + #define ToneTimer_Prescale_Index (0b010) +#endif + + #define MillisTimer_Prescale_Value (8) + #define ToneTimer_Prescale_Value (8) + +#endif + +// the prescaler is set so that the millis timer ticks every MillisTimer_Prescale_Value (64) clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_MILLIS_OVERFLOW (clockCyclesToMicroseconds(MillisTimer_Prescale_Value * 256)) + +// the whole number of milliseconds per millis timer overflow +#define MILLIS_INC (MICROSECONDS_PER_MILLIS_OVERFLOW / 1000) + +// the fractional number of milliseconds per millis timer overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_MILLIS_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +volatile unsigned long millis_timer_overflow_count = 0; +volatile unsigned long millis_timer_millis = 0; +static unsigned char millis_timer_fract = 0; +#if (TIMER_TO_USE_FOR_MILLIS == 0) + +#if defined(TIMER0_OVF_vect) +SIGNAL(TIMER0_OVF_vect) +#elif defined(TIM0_OVF_vect) +SIGNAL(TIM0_OVF_vect) +#else +#error cannot find Millis() timer overflow vector +#endif + +#elif (TIMER_TO_USE_FOR_MILLIS == 1) + +#if defined(TIMER1_OVF_vect) +SIGNAL(TIMER1_OVF_vect) +#elif defined(TIM1_OVF_vect) +SIGNAL(TIM1_OVF_vect) +#else +#error cannot find Millis() timer overflow vector +#endif + +#else + +#error Millis() timer not defined! + +#endif +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = millis_timer_millis; + unsigned char f = millis_timer_fract; + +/* rmv: The code below generates considerably less code (emtpy Sketch is 326 versus 304)... + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; + } +...rmv */ + + f += FRACT_INC; + + if (f >= FRACT_MAX) + { + f -= FRACT_MAX; + m += 1; + m += MILLIS_INC; + } + else + { + m += MILLIS_INC; + } + + millis_timer_fract = f; + millis_timer_millis = m; + millis_timer_overflow_count++; + + +//MICROSECONDS_PER_MILLIS_OVERFLOW=2048 +//MILLIS_INC=2 +//FRACT_INC=6 +//FRACT_MAX=125 +} + +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read millis_timer_millis or we might get an + // inconsistent value (e.g. in the middle of a write to millis_timer_millis) + cli(); + m = millis_timer_millis; + SREG = oldSREG; + + return m; +} + +unsigned long micros() +{ + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = millis_timer_overflow_count; +#if defined(TCNT0) && (TIMER_TO_USE_FOR_MILLIS == 0) && !defined(TCW0) + t = TCNT0; +#elif defined(TCNT0L) && (TIMER_TO_USE_FOR_MILLIS == 0) + t = TCNT0L; +#elif defined(TCNT1) && (TIMER_TO_USE_FOR_MILLIS == 1) + t = TCNT1; +#elif defined(TCNT1L) && (TIMER_TO_USE_FOR_MILLIS == 1) + t = TCNT1L; +#else + #error Millis()/Micros() timer not defined +#endif + +#if defined(TIFR0) && (TIMER_TO_USE_FOR_MILLIS == 0) + if ((TIFR0 & _BV(TOV0)) && (t < 255)) + m++; +#elif defined(TIFR) && (TIMER_TO_USE_FOR_MILLIS == 0) + if ((TIFR & _BV(TOV0)) && (t < 255)) + m++; +#elif defined(TIFR1) && (TIMER_TO_USE_FOR_MILLIS == 1) + if ((TIFR1 & _BV(TOV1)) && (t < 255)) + m++; +#elif defined(TIFR) && (TIMER_TO_USE_FOR_MILLIS == 1) + if ((TIFR & _BV(TOV1)) && (t < 255)) + m++; +#endif + + SREG = oldSREG; + + +#if F_CPU < 1000000L +return ((m << 8) + t) * MillisTimer_Prescale_Value * (1000000L/F_CPU); +#else +#if (MillisTimer_Prescale_Value % clockCyclesPerMicrosecond() == 0 ) //Can we just do it the naive way? If so great! + return ((m << 8) + t) * (MillisTimer_Prescale_Value / clockCyclesPerMicrosecond()); +//Otherwise we have a problem. +#elif (MillisTimer_Prescale_Value == 64 && clockCyclesPerMicrosecond() == 11) // 5.75 vs real value 5.818 (11mhz) 5.78 (11.059) + m=(m << 8) + t; + return m+(m<<2)+(m>>1)+(m>>2); +#elif (MillisTimer_Prescale_Value == 64 && clockCyclesPerMicrosecond() == 12) // 5.3125 vs real value 5.333 + m=(m << 8) + t; + return m+(m<<2)+(m>>2)+(m>>4); +#elif (MillisTimer_Prescale_Value == 64 && clockCyclesPerMicrosecond() == 20) // 3.187 vs real value 3.2 + m=(m << 8) + t; + return m+(m<<1)+(m>>2)-(m>>4); +#elif (MillisTimer_Prescale_Value == 64 && F_CPU == 18432000L) // 3.5 vs real value 3.47 + m=(m << 8) + t; + return m+(m<<1)+(m>>1) +#elif (MillisTimer_Prescale_Value == 64 && F_CPU==14745600L) //4.375 vs real value 4.34 + m=(m << 8) + t; + return (m<<2)+(m>>1)-(m>>3); +#elif (MillisTimer_Prescale_Value == 64 && clockCyclesPerMicrosecond() == 14) //4.5 - actual 4.57 for 14.0mhz, 4.47 for the 14.3 crystals scrappable from everything + m=(m << 8) + t; + return (m<<2)+(m>>1) +#elif (MillisTimer_Prescale_Value == 64 && F_CPU==7372800L) //8.625, vs real value 8.68 + m=(m << 8) + t; + return (m<<3)+(m>>2)+(m>>3); +#elif (MillisTimer_Prescale_Value == 64 && F_CPU==6000000L) //10.625, vs real value 10.67 + m=(m << 8) + t; + return (m<<3)+(m<<1)+(m>>2)+(m>>3); +#elif (MillisTimer_Prescale_Value == 64 && clockCyclesPerMicrosecond() == 9) //for 9mhz, this is a little off, but for 9.21, it's very close! + return ((m << 8) + t) * (MillisTimer_Prescale_Value / clockCyclesPerMicrosecond()); +#else + //return ((m << 8) + t) * (MillisTimer_Prescale_Value / clockCyclesPerMicrosecond()); + //return ((m << 8) + t) * MillisTimer_Prescale_Value / clockCyclesPerMicrosecond(); + //Integer division precludes the above technique. + //so we have to get a bit more creative. + //We can't just remove the parens, because then it will overflow (MillisTimer_Prescale_Value) times more often than unsigned longs should, so overflows would break everything. + //So what we do here is: + //the high part gets divided by cCPuS then multiplied by the prescaler. Then take the low 8 bits plus the high part modulo-cCPuS to correct for the division, then multiply that by the prescaler value first before dividing by cCPuS, and finally add the two together. + //return ((m << 8 )/clockCyclesPerMicrosecond()* MillisTimer_Prescale_Value) + ((t+(((m<<8)%clockCyclesPerMicrosecond())) * MillisTimer_Prescale_Value / clockCyclesPerMicrosecond())); + return ((m << 8 )/clockCyclesPerMicrosecond()* MillisTimer_Prescale_Value) + (t * MillisTimer_Prescale_Value / clockCyclesPerMicrosecond()); + + //This doesn't work, and I don't know why: + //return ((m*(unsigned long)MillisTimer_Prescale_Value / (unsigned long)clockCyclesPerMicrosecond())<<8)+(((unsigned long)t+((m%11)<<8)) * (unsigned long)MillisTimer_Prescale_Value / (unsigned long)clockCyclesPerMicrosecond()); + //This works without the loss of precision, but eats an extra 380 bytes of flash + //return (((long long)((m << 8) + t)) * MillisTimer_Prescale_Value / clockCyclesPerMicrosecond()); //very disappointing fix, eats an extra 380 bytes of flash because of long long +#endif + #endif +} + + + +static void __empty() { + // Empty +} +void yield(void) __attribute__ ((weak, alias("__empty"))); + +void delay(unsigned long ms) +{ + uint16_t start = (uint16_t)micros(); + + while (ms > 0) { + yield(); + while (((uint16_t)micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable) + + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); +#if F_CPU >= 24000000L + // for the 24 MHz clock for the aventurous ones, trying to overclock + + // zero delay fix + if (!us) return; // = 3 cycles, (4 when true) + + // the following loop takes a 1/6 of a microsecond (4 cycles) + // per iteration, so execute it six times for each microsecond of + // delay requested. + us *= 6; // x6 us, = 7 cycles + + // account for the time taken in the preceeding commands. + // we just burned 22 (24) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //=2 cycles + +#elif F_CPU >= 20000000L + // for the 20 MHz clock on rare Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call takes 18 (20) cycles, which is 1us + __asm__ __volatile__ ( + "nop" "\n\t" + "nop" "\n\t" + "nop" "\n\t" + "nop"); //just waiting 4 cycles + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes a 1/5 of a microsecond (4 cycles) + // per iteration, so execute it five times for each microsecond of + // delay requested. + us = (us << 2) + us; // x5 us, = 7 cycles + + // account for the time taken in the preceeding commands. + // we just burned 26 (28) cycles above, remove 7, (7*4=28) + // us is at least 10 so we can substract 7 + us -= 7; // 2 cycles + +#elif F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 1us + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/4 of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; // x4 us, = 4 cycles + + // account for the time taken in the preceeding commands. + // we just burned 19 (21) cycles above, remove 5, (5*4=20) + // us is at least 8 so we can substract 5 + us -= 5; // = 2 cycles, + +#elif F_CPU >= 12000000L + // for the 12 MHz clock if somebody is working with USB + + // for a 1 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 1.5us + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/3 of a microsecond (4 cycles) + // per iteration, so execute it three times for each microsecond of + // delay requested. + us = (us << 1) + us; // x3 us, = 5 cycles + + // account for the time taken in the preceeding commands. + // we just burned 20 (22) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //2 cycles + +#elif F_CPU >= 8000000L + // for the 8 MHz internal clock + + // for a 1 and 2 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 2us + if (us <= 2) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/2 of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; //x2 us, = 2 cycles + + // account for the time taken in the preceeding commands. + // we just burned 17 (19) cycles above, remove 4, (4*4=16) + // us is at least 6 so we can substract 4 + us -= 4; // = 2 cycles +#elif F_CPU >= 6000000L + // for that unusual 6mhz clock... + + // for a 1 and 2 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 2us + if (us <= 2) return; // = 3 cycles, (4 when true) + + // the following loop takes 2/3rd microsecond (4 cycles) + // per iteration, so we want to add it to half of itself + us +=us>>1; + us -= 2; // = 2 cycles + +#elif F_CPU >= 4000000L + // for that unusual 4mhz clock... + + // for a 1 and 2 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 2us + if (us <= 2) return; // = 3 cycles, (4 when true) + + // the following loop takes 1 microsecond (4 cycles) + // per iteration, so nothing to do here! \o/ + + us -= 2; // = 2 cycles + + +#else + // for the 1 MHz internal clock (default settings for common AVR microcontrollers) + + // the overhead of the function calls is 14 (16) cycles + if (us <= 16) return; //= 3 cycles, (4 when true) + if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22) + + // compensate for the time taken by the preceeding and next commands (about 22 cycles) + us -= 22; // = 2 cycles + // the following loop takes 4 microseconds (4 cycles) + // per iteration, so execute it us/4 times + // us is at least 4, divided by 4 gives us 1 (no zero delay bug) + us >>= 2; // us div 4, = 4 cycles + + +#endif + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); + // return = 4 cycles +} + +#if INITIALIZE_SECONDARY_TIMERS +static void initToneTimerInternal(void) +{ + // Timer is processor clock divided by ToneTimer_Prescale_Index + #if (TIMER_TO_USE_FOR_TONE == 0) + TCCR0B &= ~((1< 12000000L + // above 12mhz, prescale by 128, the highest prescaler available + #define ADC_ARDUINO_PRESCALER B111 +#elif F_CPU >= 6000000L + // 12 MHz / 64 ~= 188 KHz + // 8 MHz / 64 = 125 KHz + #define ADC_ARDUINO_PRESCALER B110 +#elif F_CPU >= 3000000L + // 4 MHz / 32 = 125 KHz + #define ADC_ARDUINO_PRESCALER B101 +#elif F_CPU >= 1500000L + // 2 MHz / 16 = 125 KHz + #define ADC_ARDUINO_PRESCALER B100 +#elif F_CPU >= 750000L + // 1 MHz / 8 = 125 KHz + #define ADC_ARDUINO_PRESCALER B011 +#elif F_CPU < 400000L + // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2 + #define ADC_ARDUINO_PRESCALER B000 +#else //speed between 400khz and 750khz + #define ADC_ARDUINO_PRESCALER B010 //prescaler of 4 +#endif + +void init(void) +{ + + // In case the bootloader left our millis timer in a bad way + #if defined( HAVE_BOOTLOADER ) && HAVE_BOOTLOADER + // Ensure the timer is in the same state as power-up + #if (TIMER_TO_USE_FOR_MILLIS == 0) && defined(WGM01) + #ifdef TCCR0B + TCCR0B = 0; + TCCR0A = 0; + #else + TCCR0A = 0; + #endif + // Reset the count to zero + TCNT0 = 0; + // Set the output compare registers to zero + OCR0A = 0; + #ifdef OCR0B + OCR0B = 0; + #endif + #if defined(TIMSK) + // Disable all Timer0 interrupts + TIMSK = 0; //safer - the bootloader may have made a mess of this. + // TIMSK &= ~((1<> 2) << REFS2); //some have an extra reference bit in a weird position. + #endif + #endif + + #if defined(HAVE_ADC) && HAVE_ADC + sbi(ADCSRA, ADSC); //Start conversion + + while(ADCSRA & (1<= 255) + { + digitalWrite(pin, HIGH); + } + else + { + uint8_t timer = digitalPinToTimer(pin); + #if defined(TCCR0A) && defined(COM0A1) + if( timer == TIMER0A){ + // connect pwm to pin on timer 0, channel A + sbi(TCCR0A, COM0A1); + cbi(TCCR0A, COM0A0); + OCR0A = val; // set pwm duty + } else + #endif + + #if defined(TCCR0A) && defined(COM0B1) + if( timer == TIMER0B){ + // connect pwm to pin on timer 0, channel B + sbi(TCCR0A, COM0B1); + cbi(TCCR0A, COM0B0); + OCR0B = val; // set pwm duty + } else + #endif + + #if defined(TCCR1A) && defined(COM1A1) && !defined(TCCR1E) + if( timer == TIMER1A){ + // connect pwm to pin on timer 1, channel A + sbi(TCCR1A, COM1A1); + cbi(TCCR1A, COM1A0); + #ifdef OC1AX + cbi(TCCR1D, OC1AV); + cbi(TCCR1D, OC1AU); + cbi(TCCR1D, OC1AW); + sbi(TCCR1D, OC1AX); + #endif + OCR1A = val; // set pwm duty + } else + #endif + + #if defined(TCCR1E) + if( timer == TIMER1A){ + // connect pwm to pin on timer 1, channel A + cbi(TCCR1C,COM1A1S); + sbi(TCCR1C,COM1A0S); + OCR1A = val; // set pwm duty + } else if (timer == TIMER1B){ + // connect pwm to pin on timer 1, channel A + cbi(TCCR1C,COM1B1S); + sbi(TCCR1C,COM1B0S); + OCR1B = val; // set pwm duty + } else if (timer == TIMER1D){ + // connect pwm to pin on timer 1, channel A + cbi(TCCR1C,COM1D1); + sbi(TCCR1C,COM1D0); + OCR1D = val; // set pwm duty + } else + #endif + + #if defined(TCCR1) && defined(COM1A1) + if(timer == TIMER1A){ + // connect pwm to pin on timer 1, channel A + sbi(TCCR1, COM1A1); + cbi(TCCR1, COM1A0); + OCR1A = val; // set pwm duty + } else + #endif + + #if defined(TCCR1A) && defined(COM1B1) && !defined(TCCR1E) + if( timer == TIMER1B){ + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1B1); + cbi(TCCR1A, COM1B0); + #ifdef OC1BV + sbi(TCCR1D, OC1BV); + cbi(TCCR1D, OC1BU); + cbi(TCCR1D, OC1BW); + cbi(TCCR1D, OC1BX); + #endif + OCR1B = val; // set pwm duty + } else + #endif + + #if defined(TCCR1) && defined(COM1B1) + if( timer == TIMER1B){ + // connect pwm to pin on timer 1, channel B + sbi(GTCCR, COM1B1); + cbi(GTCCR, COM1B0); + OCR1B = val; // set pwm duty + } else + #endif + + { + if (val < 128) + { + digitalWrite(pin, LOW); + } + else + { + digitalWrite(pin, HIGH); + } + } + + } +} diff --git a/sparkfun/tiny/cores/tiny/wiring_digital.c b/sparkfun/tiny/cores/tiny/wiring_digital.c new file mode 100644 index 00000000..cfbd9b21 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/wiring_digital.c @@ -0,0 +1,163 @@ +/* + wiring_digital.c - digital input and output functions + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ + + Modified 28-08-2009 for attiny84 R.Wiersma + Modified 14-10-2009 for attiny45 Saposoft +*/ + +#define ARDUINO_MAIN +#include "wiring_private.h" +#include "pins_arduino.h" + +void pinMode(uint8_t pin, uint8_t mode) +{ + if (pin&128) {pin=analogInputToDigitalPin(pin&127);} + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *reg, *out; + + if (port == NOT_A_PIN) return; + + reg = portModeRegister(port); + out = portOutputRegister(port); + + if (mode == INPUT) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out &= ~bit; + SREG = oldSREG; + } else if (mode == INPUT_PULLUP) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out |= bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *reg |= bit; + SREG = oldSREG; + } +} + +static void turnOffPWM(uint8_t timer) +{ + #if defined(TCCR0A) && defined(COM0A1) + if( timer == TIMER0A){ + cbi(TCCR0A, COM0A1); + cbi(TCCR0A, COM0A0); + } else + #endif + + #if defined(TCCR0A) && defined(COM0B1) + if( timer == TIMER0B){ + cbi(TCCR0A, COM0B1); + cbi(TCCR0A, COM0B0); + } else + #endif + + #if defined(TCCR1A) && defined(COM1A1) + if( timer == TIMER1A){ + cbi(TCCR1A, COM1A1); + cbi(TCCR1A, COM1A0); + } else + #endif + + #if defined(TCCR1) && defined(COM1A1) + if(timer == TIMER1A){ + cbi(TCCR1, COM1A1); + cbi(TCCR1, COM1A0); + #ifdef OC1AX + cbi(TCCR1D, OC1AX); + #endif + } else + #endif + + #if defined(TCCR1A) && defined(COM1B1) + if( timer == TIMER1B){ + cbi(TCCR1A, COM1B1); + cbi(TCCR1A, COM1B0); + #ifdef OC1BV + cbi(TCCR1D, OC1BV); + #endif + } else + #endif + + #if defined(TCCR1) && defined(COM1B1) + if( timer == TIMER1B){ + cbi(GTCCR, COM1B1); + cbi(GTCCR, COM1B0); + } else + #endif + + { + } + +} + +void digitalWrite(uint8_t pin, uint8_t val) +{ + if (pin&128) {pin=analogInputToDigitalPin(pin&127);} + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *out; + + if (port == NOT_A_PIN) return; + + // If the pin that support PWM output, we need to turn it off + // before doing a digital write. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + out = portOutputRegister(port); + + if (val == LOW) { + uint8_t oldSREG = SREG; + cli(); + *out &= ~bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *out |= bit; + SREG = oldSREG; + } +} + +int digitalRead(uint8_t pin) +{ + if (pin&128) {pin=analogInputToDigitalPin(pin&127);} + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + + if (port == NOT_A_PIN) return LOW; + + // If the pin that support PWM output, we need to turn it off + // before getting a digital reading. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + if (*portInputRegister(port) & bit) return HIGH; + return LOW; +} diff --git a/sparkfun/tiny/cores/tiny/wiring_private.h b/sparkfun/tiny/cores/tiny/wiring_private.h new file mode 100644 index 00000000..776ac287 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/wiring_private.h @@ -0,0 +1,178 @@ +/* + wiring_private.h - Internal header file. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 239 2007-01-12 17:58:39Z mellis $ + + Modified 28-08-2009 for attiny84 R.Wiersma +*/ + +#ifndef WiringPrivate_h +#define WiringPrivate_h + +#include +#include +#include +#include + +#include "Arduino.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#if defined( EXT_INT0_vect ) + #define EXTERNAL_INTERRUPT_0_vect EXT_INT0_vect +#elif defined( INT0_vect ) + #define EXTERNAL_INTERRUPT_0_vect INT0_vect +#endif + +#if defined( EXT_INT1_vect ) + #define EXTERNAL_INTERRUPT_1_vect EXT_INT1_vect +#elif defined( INT1_vect ) + #define EXTERNAL_INTERRUPT_1_vect INT1_vect +#endif + +#if defined( EXT_INT2_vect ) + #define EXTERNAL_INTERRUPT_2_vect EXT_INT2_vect +#elif defined( INT2_vect ) + #define EXTERNAL_INTERRUPT_2_vect INT2_vect +#endif + +#if defined( EXT_INT3_vect ) + #define EXTERNAL_INTERRUPT_3_vect EXT_INT3_vect +#elif defined( INT3_vect ) + #define EXTERNAL_INTERRUPT_3_vect INT3_vect +#endif + +#if defined( EXT_INT4_vect ) + #define EXTERNAL_INTERRUPT_4_vect EXT_INT4_vect +#elif defined( INT4_vect ) + #define EXTERNAL_INTERRUPT_4_vect INT4_vect +#endif + +#if defined( EXT_INT5_vect ) + #define EXTERNAL_INTERRUPT_5_vect EXT_INT5_vect +#elif defined( INT5_vect ) + #define EXTERNAL_INTERRUPT_5_vect INT5_vect +#endif + +#if defined( EXT_INT6_vect ) + #define EXTERNAL_INTERRUPT_6_vect EXT_INT6_vect +#elif defined( INT6_vect ) + #define EXTERNAL_INTERRUPT_6_vect INT6_vect +#endif + +#if defined( EXT_INT7_vect ) + #define EXTERNAL_INTERRUPT_7_vect EXT_INT7_vect +#elif defined( INT7_vect ) + #define EXTERNAL_INTERRUPT_7_vect INT7_vect +#endif + +#if defined( EXT_INT8_vect ) + #define EXTERNAL_INTERRUPT_8_vect EXT_INT8_vect +#elif defined( INT8_vect ) + #define EXTERNAL_INTERRUPT_8_vect INT8_vect +#endif + +#if defined( EXT_INT9_vect ) + #define EXTERNAL_INTERRUPT_9_vect EXT_INT9_vect +#elif defined( INT9_vect ) + #define EXTERNAL_INTERRUPT_9_vect INT9_vect +#endif + +#if defined( EXTERNAL_INTERRUPT_9_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (10) +#elif defined( EXTERNAL_INTERRUPT_8_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (9) +#elif defined( EXTERNAL_INTERRUPT_7_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (8) +#elif defined( EXTERNAL_INTERRUPT_6_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (7) +#elif defined( EXTERNAL_INTERRUPT_5_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (6) +#elif defined( EXTERNAL_INTERRUPT_4_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (5) +#elif defined( EXTERNAL_INTERRUPT_3_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (4) +#elif defined( EXTERNAL_INTERRUPT_2_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (3) +#elif defined( EXTERNAL_INTERRUPT_1_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (2) +#elif defined( EXTERNAL_INTERRUPT_0_vect ) + #define NUMBER_EXTERNAL_INTERRUPTS (1) +#else + #define NUMBER_EXTERNAL_INTERRUPTS (0) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 1 + #define EXTERNAL_INTERRUPT_0 (0) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 2 + #define EXTERNAL_INTERRUPT_1 (1) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 3 + #define EXTERNAL_INTERRUPT_2 (2) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 4 + #define EXTERNAL_INTERRUPT_3 (3) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 5 + #define EXTERNAL_INTERRUPT_4 (4) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 6 + #define EXTERNAL_INTERRUPT_5 (5) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 7 + #define EXTERNAL_INTERRUPT_6 (6) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 8 + #define EXTERNAL_INTERRUPT_7 (7) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 9 + #define EXTERNAL_INTERRUPT_8 (8) +#endif + +#if NUMBER_EXTERNAL_INTERRUPTS >= 10 + #define EXTERNAL_INTERRUPT_9 (9) +#endif + +typedef void (*voidFuncPtr)(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/sparkfun/tiny/cores/tiny/wiring_pulse.c b/sparkfun/tiny/cores/tiny/wiring_pulse.c new file mode 100644 index 00000000..0d968865 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/wiring_pulse.c @@ -0,0 +1,69 @@ +/* + wiring_pulse.c - pulseIn() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. */ +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + unsigned long width = 0; // keep initialization out of time critical area + + // convert the timeout from microseconds to a number of times through + // the initial loop; it takes 16 clock cycles per iteration. + unsigned long numloops = 0; + unsigned long maxloops = microsecondsToClockCycles(timeout) / 16; + + // wait for any previous pulse to end + while ((*portInputRegister(port) & bit) == stateMask) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to start + while ((*portInputRegister(port) & bit) != stateMask) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to stop + while ((*portInputRegister(port) & bit) == stateMask) { + if (numloops++ == maxloops) + return 0; + width++; + } + + // convert the reading to microseconds. The loop has been determined + // to be 20 clock cycles long and have about 16 clocks between the edge + // and the start of the loop. There will be some error introduced by + // the interrupt handlers. + return clockCyclesToMicroseconds(width * 21 + 16); +} diff --git a/sparkfun/tiny/cores/tiny/wiring_shift.c b/sparkfun/tiny/cores/tiny/wiring_shift.c new file mode 100644 index 00000000..cfe78675 --- /dev/null +++ b/sparkfun/tiny/cores/tiny/wiring_shift.c @@ -0,0 +1,55 @@ +/* + wiring_shift.c - shiftOut() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" + +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { + uint8_t value = 0; + uint8_t i; + + for (i = 0; i < 8; ++i) { + digitalWrite(clockPin, HIGH); + if (bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + digitalWrite(clockPin, LOW); + } + return value; +} + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} diff --git a/sparkfun/tiny/driver/amd64/libusb0.dll b/sparkfun/tiny/driver/amd64/libusb0.dll new file mode 100644 index 00000000..f916b089 Binary files /dev/null and b/sparkfun/tiny/driver/amd64/libusb0.dll differ diff --git a/sparkfun/tiny/driver/amd64/libusb0.sys b/sparkfun/tiny/driver/amd64/libusb0.sys new file mode 100644 index 00000000..0718dfb7 Binary files /dev/null and b/sparkfun/tiny/driver/amd64/libusb0.sys differ diff --git a/sparkfun/tiny/driver/ia64/libusb0.dll b/sparkfun/tiny/driver/ia64/libusb0.dll new file mode 100644 index 00000000..f0ea8448 Binary files /dev/null and b/sparkfun/tiny/driver/ia64/libusb0.dll differ diff --git a/sparkfun/tiny/driver/ia64/libusb0.sys b/sparkfun/tiny/driver/ia64/libusb0.sys new file mode 100644 index 00000000..7f781a69 Binary files /dev/null and b/sparkfun/tiny/driver/ia64/libusb0.sys differ diff --git a/sparkfun/tiny/driver/license/libusb0/installer_license.txt b/sparkfun/tiny/driver/license/libusb0/installer_license.txt new file mode 100644 index 00000000..56bb2cda --- /dev/null +++ b/sparkfun/tiny/driver/license/libusb0/installer_license.txt @@ -0,0 +1,851 @@ +Copyright (c) 2002-2004 Stephan Meyer, +Copyright (c) 2000-2004 Johannes Erdfelt, +Copyright (c) 2000-2004 Thomas Sailer, +Copyright (c) 2010 Travis Robinson, + +This software is distributed under the following licenses: +Driver: GNU General Public License (GPL) +Library, Test Files, Installer: GNU Lesser General Public License (LGPL) + +*********************************************************************** + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/sparkfun/tiny/driver/sparkfun_attiny_bootloader.cat b/sparkfun/tiny/driver/sparkfun_attiny_bootloader.cat new file mode 100644 index 00000000..cd8ad45a Binary files /dev/null and b/sparkfun/tiny/driver/sparkfun_attiny_bootloader.cat differ diff --git a/sparkfun/tiny/driver/sparkfun_attiny_bootloader.inf b/sparkfun/tiny/driver/sparkfun_attiny_bootloader.inf new file mode 100644 index 00000000..7ad6083a Binary files /dev/null and b/sparkfun/tiny/driver/sparkfun_attiny_bootloader.inf differ diff --git a/sparkfun/tiny/driver/x86/libusb0.sys b/sparkfun/tiny/driver/x86/libusb0.sys new file mode 100644 index 00000000..5322e5b9 Binary files /dev/null and b/sparkfun/tiny/driver/x86/libusb0.sys differ diff --git a/sparkfun/tiny/driver/x86/libusb0_x86.dll b/sparkfun/tiny/driver/x86/libusb0_x86.dll new file mode 100644 index 00000000..f80d7136 Binary files /dev/null and b/sparkfun/tiny/driver/x86/libusb0_x86.dll differ diff --git a/sparkfun/tiny/extras/uploader/49-micronucleus.rules b/sparkfun/tiny/extras/uploader/49-micronucleus.rules new file mode 100644 index 00000000..bed33d64 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/49-micronucleus.rules @@ -0,0 +1,16 @@ +# UDEV Rules for Micronucleus boards including the Digispark. +# This file must be placed at: +# +# /etc/udev/rules.d/49-micronucleus.rules (preferred location) +# or +# /lib/udev/rules.d/49-micronucleus.rules (req'd on some broken systems) +# +# After this file is copied, physically unplug and reconnect the board. +# +SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666" +KERNEL=="ttyACM*", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1" +# +# If you share your linux system with other users, or just don't like the +# idea of write permission for everybody, you can replace MODE:="0666" with +# OWNER:="yourusername" to create the device owned by you, or with +# GROUP:="somegroupname" and mange access using standard unix groups. diff --git a/sparkfun/tiny/extras/uploader/Makefile b/sparkfun/tiny/extras/uploader/Makefile new file mode 100644 index 00000000..65e7469d --- /dev/null +++ b/sparkfun/tiny/extras/uploader/Makefile @@ -0,0 +1,62 @@ +# Makefile initially writen for Little-Wire by Omer Kilic +# Later on modified by ihsan Kehribar for Micronucleus bootloader application. + +CC=gcc + +ifeq ($(shell uname), Linux) + USBFLAGS=$(shell libusb-config --cflags) + USBLIBS=$(shell libusb-config --libs) + EXE_SUFFIX = + OSFLAG = -D LINUX +else ifeq ($(shell uname), Darwin) + USBFLAGS=$(shell libusb-config --cflags || libusb-legacy-config --cflags) + USBLIBS=$(shell libusb-config --libs || libusb-legacy-config --libs) + EXE_SUFFIX = + OSFLAG = -D MAC_OS + # Uncomment these to create a static binary: + # USBLIBS = /opt/local/lib/libusb-legacy/libusb-legacy.a + # USBLIBS += -mmacosx-version-min=10.5 + # USBLIBS += -framework CoreFoundation + # USBLIBS += -framework IOKit + # Uncomment these to create a dual architecture binary: + # OSFLAG += -arch x86_64 -arch i386 +else ifeq ($(shell uname), OpenBSD) + USBFLAGS=$(shell libusb-config --cflags || libusb-legacy-config --cflags) + USBLIBS=$(shell libusb-config --libs || libusb-legacy-config --libs) + EXE_SUFFIX = + OSFLAG = -D OPENBSD +else + #USBFLAGS = -I C:\MinGW\include + #USBLIBS = -L C:\MinGW\lib -lusb + USBFLAGS = -I library\libusb-win32\include + USBLIBS = -L library\libusb-win32\lib\gcc -lusb + EXE_SUFFIX = .exe + OSFLAG = -D WIN +endif + +LIBS = $(USBLIBS) +INCLUDE = library +CFLAGS = $(USBFLAGS) $(LIBS) -I$(INCLUDE) -O -g $(OSFLAG) + +LWLIBS = micronucleus_lib littleWire_util +EXAMPLES = micronucleus + +.PHONY: clean library + +all: library $(EXAMPLES) + +library: $(LWLIBS) + +$(LWLIBS): + @echo Building library: $@... + $(CC) $(CFLAGS) -c library/$@.c + +$(EXAMPLES): $(addsuffix .o, $(LWLIBS)) + @echo Building command line tool: $@... + $(CC) $(CFLAGS) -o $@$(EXE_SUFFIX) $@.c $^ $(LIBS) + +clean: + rm -f $(EXAMPLES)$(EXE_SUFFIX) *.o *.exe + +install: all + cp micronucleus /usr/local/bin diff --git a/sparkfun/tiny/extras/uploader/Readme b/sparkfun/tiny/extras/uploader/Readme new file mode 100644 index 00000000..5eec6b98 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/Readme @@ -0,0 +1,55 @@ +This commandline application for the Micronucleus bootloader is written by +ihsan Kehribar and Bluebie + +Modified by SparkFun Electronics, 2017. + +It's been tested casually on Mac, Windows, and Linux, and aught to work on all +three. To make and install, do the regular 'make; sudo make install' on unixes. +On windows just 'make' with mingw and do whatever people do with windows exes. + +Usage on Ubuntu: + sudo micronucleus --run name_of_the_file.hex +Usage on Mac: + micronucleus --run name_of_the_file.hex +Usage on Windows + micronucleus.exe --run name_of_the_file.hex + +Raw binary file writing hasn't been tested as much as hex files. + +Every now and then the program fails once it reaches the Writing stage - this is +a known bug - but if you simply rerun the micronucleus command immediately, it +will succeed the second time usually. Most of the time this issue is not present. + +To linux users: sudo is used above because the default configuration under most +modern linux distributions is to not allow userspace apps to communicate +directly to unknown USB devices. You can fix this by installing some config +files, or you can just use sudo. Either way you're going to need root. To +configure your system to allow micronucleus access from non-root users, copy +49-micronucleus.rules from this folder to /etc/udev/rules.d/ + +To Build +-------- + +You might want to re-compile the micronucleus uploader tool if you plan to use +different USB VID/PID identifiers. To start, change the MICRONUCLEUS_VENDOR_ID +and MICRONUCLEUS_PRODUCT_ID constants in library/micronucleus_lib.h to your +VID/PID pair. Then compile for your operating system: + +Ubuntu: + sudo apt-get install libusb-dev + make + cp micronucleus builds/linux64 + make clean +Mac: + brew install libusb-compat --universal + make + cp micronucleus builds/osx + make clean +Windows: + Install MinGW and MSYS. Navigate to this directory and enter "make". Copy + micronucleus.exe to wherever you need it and enter "make clean" to remove + +To zip the tool for Arduino, move to the directory with your build (e.g. +builds/windows), create a version directory (e.g. 2.03-SFE), copy the +executable to that directory, and enter: + tar -cvjSf micronucleus-2.03-SFE-windows.tar.bz2 2.03-SFE/ diff --git a/sparkfun/tiny/extras/uploader/builds/linux32/2.03-SFE/micronucleus b/sparkfun/tiny/extras/uploader/builds/linux32/2.03-SFE/micronucleus new file mode 100755 index 00000000..f86e1fe1 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/linux32/2.03-SFE/micronucleus differ diff --git a/sparkfun/tiny/extras/uploader/builds/linux32/micronucleus-2.03-SFE-linux32.tar.bz2 b/sparkfun/tiny/extras/uploader/builds/linux32/micronucleus-2.03-SFE-linux32.tar.bz2 new file mode 100644 index 00000000..7edf43cf Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/linux32/micronucleus-2.03-SFE-linux32.tar.bz2 differ diff --git a/sparkfun/tiny/extras/uploader/builds/linux64/2.03-SFE/micronucleus b/sparkfun/tiny/extras/uploader/builds/linux64/2.03-SFE/micronucleus new file mode 100755 index 00000000..56af9ec7 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/linux64/2.03-SFE/micronucleus differ diff --git a/sparkfun/tiny/extras/uploader/builds/linux64/micronucleus-2.03-SFE-linux64.tar.bz2 b/sparkfun/tiny/extras/uploader/builds/linux64/micronucleus-2.03-SFE-linux64.tar.bz2 new file mode 100644 index 00000000..27628969 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/linux64/micronucleus-2.03-SFE-linux64.tar.bz2 differ diff --git a/sparkfun/tiny/extras/uploader/builds/linuxarm/2.03-SFE/micronucleus b/sparkfun/tiny/extras/uploader/builds/linuxarm/2.03-SFE/micronucleus new file mode 100755 index 00000000..8d35adb6 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/linuxarm/2.03-SFE/micronucleus differ diff --git a/sparkfun/tiny/extras/uploader/builds/linuxarm/micronucleus-2.03-SFE-linuxarm.tar.bz2 b/sparkfun/tiny/extras/uploader/builds/linuxarm/micronucleus-2.03-SFE-linuxarm.tar.bz2 new file mode 100644 index 00000000..864b44d3 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/linuxarm/micronucleus-2.03-SFE-linuxarm.tar.bz2 differ diff --git a/sparkfun/tiny/extras/uploader/builds/osx/2.03-SFE/micronucleus b/sparkfun/tiny/extras/uploader/builds/osx/2.03-SFE/micronucleus new file mode 100644 index 00000000..01ed5893 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/osx/2.03-SFE/micronucleus differ diff --git a/sparkfun/tiny/extras/uploader/builds/osx/micronucleus-2.03-SFE-osx.tar.bz2 b/sparkfun/tiny/extras/uploader/builds/osx/micronucleus-2.03-SFE-osx.tar.bz2 new file mode 100644 index 00000000..a39cbe59 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/osx/micronucleus-2.03-SFE-osx.tar.bz2 differ diff --git a/sparkfun/tiny/extras/uploader/builds/windows/2.03-SFE/micronucleus.exe b/sparkfun/tiny/extras/uploader/builds/windows/2.03-SFE/micronucleus.exe new file mode 100644 index 00000000..b7a12162 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/windows/2.03-SFE/micronucleus.exe differ diff --git a/sparkfun/tiny/extras/uploader/builds/windows/micronucleus-2.03-SFE-windows.tar.bz2 b/sparkfun/tiny/extras/uploader/builds/windows/micronucleus-2.03-SFE-windows.tar.bz2 new file mode 100644 index 00000000..567c7846 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/builds/windows/micronucleus-2.03-SFE-windows.tar.bz2 differ diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/AUTHORS.txt b/sparkfun/tiny/extras/uploader/library/libusb-win32/AUTHORS.txt new file mode 100644 index 00000000..375ec6c2 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/AUTHORS.txt @@ -0,0 +1,16 @@ + +Library, Test Programs: + +Stephan Meyer, +Johannes Erdfelt, +Thomas Sailer, + +Drivers, Installer: + +Stephan Meyer, +Travis Robinson, + +Testing, Technical support: + +Xiaofan Chen, + diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/COPYING_GPL.txt b/sparkfun/tiny/extras/uploader/library/libusb-win32/COPYING_GPL.txt new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/COPYING_GPL.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/COPYING_LGPL.txt b/sparkfun/tiny/extras/uploader/library/libusb-win32/COPYING_LGPL.txt new file mode 100644 index 00000000..65c5ca88 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/COPYING_LGPL.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/README.txt b/sparkfun/tiny/extras/uploader/library/libusb-win32/README.txt new file mode 100644 index 00000000..0dc3ac09 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/README.txt @@ -0,0 +1,12 @@ + +This is libusb-win32 (http://libusb-win32.sourceforge.net) version 1.2.6.0. +Libusb-win32 is a library that allows userspace application to access USB +devices on Windows operation systems (Win2k, WinXP, Vista, Win7). +It is derived from and fully API compatible to libusb available at +http://libusb.sourceforge.net. + +For more information visit the project's web site at: + +http://libusb-win32.sourceforge.net +http://sourceforge.net/projects/libusb-win32 + diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/include/lusb0_usb.h b/sparkfun/tiny/extras/uploader/library/libusb-win32/include/lusb0_usb.h new file mode 100644 index 00000000..b95fbf0a --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/include/lusb0_usb.h @@ -0,0 +1,427 @@ +#ifndef __USB_H__ +#define __USB_H__ + +#include +#include + +/* + * 'interface' is defined somewhere in the Windows header files. This macro + * is deleted here to avoid conflicts and compile errors. + */ + +#ifdef interface +#undef interface +#endif + +/* + * PATH_MAX from limits.h can't be used on Windows if the dll and + * import libraries are build/used by different compilers + */ + +#define LIBUSB_PATH_MAX 512 + + +/* + * USB spec information + * + * This is all stuff grabbed from various USB specs and is pretty much + * not subject to change + */ + +/* + * Device and/or Interface Class codes + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_DATA 10 +#define USB_CLASS_VENDOR_SPEC 0xff + +/* + * Descriptor types + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 + +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL 0x23 +#define USB_DT_HUB 0x29 + +/* + * Descriptor sizes per descriptor type + */ +#define USB_DT_DEVICE_SIZE 18 +#define USB_DT_CONFIG_SIZE 9 +#define USB_DT_INTERFACE_SIZE 9 +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ +#define USB_DT_HUB_NONVAR_SIZE 7 + + +/* ensure byte-packed structures */ +#include + + +/* All standard descriptors have these 2 fields in common */ +struct usb_descriptor_header +{ + unsigned char bLength; + unsigned char bDescriptorType; +}; + +/* String descriptor */ +struct usb_string_descriptor +{ + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short wData[1]; +}; + +/* HID descriptor */ +struct usb_hid_descriptor +{ + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short bcdHID; + unsigned char bCountryCode; + unsigned char bNumDescriptors; +}; + +/* Endpoint descriptor */ +#define USB_MAXENDPOINTS 32 +struct usb_endpoint_descriptor +{ + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bEndpointAddress; + unsigned char bmAttributes; + unsigned short wMaxPacketSize; + unsigned char bInterval; + unsigned char bRefresh; + unsigned char bSynchAddress; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_TYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_TYPE_CONTROL 0 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1 +#define USB_ENDPOINT_TYPE_BULK 2 +#define USB_ENDPOINT_TYPE_INTERRUPT 3 + +/* Interface descriptor */ +#define USB_MAXINTERFACES 32 +struct usb_interface_descriptor +{ + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bInterfaceNumber; + unsigned char bAlternateSetting; + unsigned char bNumEndpoints; + unsigned char bInterfaceClass; + unsigned char bInterfaceSubClass; + unsigned char bInterfaceProtocol; + unsigned char iInterface; + + struct usb_endpoint_descriptor *endpoint; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +#define USB_MAXALTSETTING 128 /* Hard limit */ + +struct usb_interface +{ + struct usb_interface_descriptor *altsetting; + + int num_altsetting; +}; + +/* Configuration descriptor information.. */ +#define USB_MAXCONFIG 8 +struct usb_config_descriptor +{ + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short wTotalLength; + unsigned char bNumInterfaces; + unsigned char bConfigurationValue; + unsigned char iConfiguration; + unsigned char bmAttributes; + unsigned char MaxPower; + + struct usb_interface *interface; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +/* Device descriptor */ +struct usb_device_descriptor +{ + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short bcdUSB; + unsigned char bDeviceClass; + unsigned char bDeviceSubClass; + unsigned char bDeviceProtocol; + unsigned char bMaxPacketSize0; + unsigned short idVendor; + unsigned short idProduct; + unsigned short bcdDevice; + unsigned char iManufacturer; + unsigned char iProduct; + unsigned char iSerialNumber; + unsigned char bNumConfigurations; +}; + +struct usb_ctrl_setup +{ + unsigned char bRequestType; + unsigned char bRequest; + unsigned short wValue; + unsigned short wIndex; + unsigned short wLength; +}; + +/* + * Standard requests + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +/* 0x02 is reserved */ +#define USB_REQ_SET_FEATURE 0x03 +/* 0x04 is reserved */ +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* + * Various libusb API related stuff + */ + +#define USB_ENDPOINT_IN 0x80 +#define USB_ENDPOINT_OUT 0x00 + +/* Error codes */ +#define USB_ERROR_BEGIN 500000 + +/* + * This is supposed to look weird. This file is generated from autoconf + * and I didn't want to make this too complicated. + */ +#define USB_LE16_TO_CPU(x) + +/* + * Device reset types for usb_reset_ex. + * http://msdn.microsoft.com/en-us/library/ff537269%28VS.85%29.aspx + * http://msdn.microsoft.com/en-us/library/ff537243%28v=vs.85%29.aspx + */ +#define USB_RESET_TYPE_RESET_PORT (1 << 0) +#define USB_RESET_TYPE_CYCLE_PORT (1 << 1) +#define USB_RESET_TYPE_FULL_RESET (USB_RESET_TYPE_CYCLE_PORT | USB_RESET_TYPE_RESET_PORT) + + +/* Data types */ +/* struct usb_device; */ +/* struct usb_bus; */ + +struct usb_device +{ + struct usb_device *next, *prev; + + char filename[LIBUSB_PATH_MAX]; + + struct usb_bus *bus; + + struct usb_device_descriptor descriptor; + struct usb_config_descriptor *config; + + void *dev; /* Darwin support */ + + unsigned char devnum; + + unsigned char num_children; + struct usb_device **children; +}; + +struct usb_bus +{ + struct usb_bus *next, *prev; + + char dirname[LIBUSB_PATH_MAX]; + + struct usb_device *devices; + unsigned long location; + + struct usb_device *root_dev; +}; + +/* Version information, Windows specific */ +struct usb_version +{ + struct + { + int major; + int minor; + int micro; + int nano; + } dll; + struct + { + int major; + int minor; + int micro; + int nano; + } driver; +}; + + +struct usb_dev_handle; +typedef struct usb_dev_handle usb_dev_handle; + +/* Variables */ +#ifndef __USB_C__ +#define usb_busses usb_get_busses() +#endif + + + +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Function prototypes */ + + /* usb.c */ + usb_dev_handle *usb_open(struct usb_device *dev); + int usb_close(usb_dev_handle *dev); + int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, + size_t buflen); + int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, + size_t buflen); + + /* descriptors.c */ + int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, + unsigned char type, unsigned char index, + void *buf, int size); + int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, + unsigned char index, void *buf, int size); + + /* .c */ + int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); + int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); + int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); + int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); + int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, + int value, int index, char *bytes, int size, + int timeout); + int usb_set_configuration(usb_dev_handle *dev, int configuration); + int usb_claim_interface(usb_dev_handle *dev, int interface); + int usb_release_interface(usb_dev_handle *dev, int interface); + int usb_set_altinterface(usb_dev_handle *dev, int alternate); + int usb_resetep(usb_dev_handle *dev, unsigned int ep); + int usb_clear_halt(usb_dev_handle *dev, unsigned int ep); + int usb_reset(usb_dev_handle *dev); + int usb_reset_ex(usb_dev_handle *dev, unsigned int reset_type); + + char *usb_strerror(void); + + void usb_init(void); + void usb_set_debug(int level); + int usb_find_busses(void); + int usb_find_devices(void); + struct usb_device *usb_device(usb_dev_handle *dev); + struct usb_bus *usb_get_busses(void); + + + /* Windows specific functions */ + +#define LIBUSB_HAS_INSTALL_SERVICE_NP 1 + int usb_install_service_np(void); + void CALLBACK usb_install_service_np_rundll(HWND wnd, HINSTANCE instance, + LPSTR cmd_line, int cmd_show); + +#define LIBUSB_HAS_UNINSTALL_SERVICE_NP 1 + int usb_uninstall_service_np(void); + void CALLBACK usb_uninstall_service_np_rundll(HWND wnd, HINSTANCE instance, + LPSTR cmd_line, int cmd_show); + +#define LIBUSB_HAS_INSTALL_DRIVER_NP 1 + int usb_install_driver_np(const char *inf_file); + void CALLBACK usb_install_driver_np_rundll(HWND wnd, HINSTANCE instance, + LPSTR cmd_line, int cmd_show); + +#define LIBUSB_HAS_TOUCH_INF_FILE_NP 1 + int usb_touch_inf_file_np(const char *inf_file); + void CALLBACK usb_touch_inf_file_np_rundll(HWND wnd, HINSTANCE instance, + LPSTR cmd_line, int cmd_show); + +#define LIBUSB_HAS_INSTALL_NEEDS_RESTART_NP 1 + int usb_install_needs_restart_np(void); + +#define LIBUSB_HAS_INSTALL_NP 1 + int usb_install_npW(HWND hwnd, HINSTANCE instance, LPCWSTR cmd_line, int starg_arg); + int usb_install_npA(HWND hwnd, HINSTANCE instance, LPCSTR cmd_line, int starg_arg); + #define usb_install_np usb_install_npA + void CALLBACK usb_install_np_rundll(HWND wnd, HINSTANCE instance, + LPSTR cmd_line, int cmd_show); + + const struct usb_version *usb_get_version(void); + + int usb_isochronous_setup_async(usb_dev_handle *dev, void **context, + unsigned char ep, int pktsize); + int usb_bulk_setup_async(usb_dev_handle *dev, void **context, + unsigned char ep); + int usb_interrupt_setup_async(usb_dev_handle *dev, void **context, + unsigned char ep); + + int usb_submit_async(void *context, char *bytes, int size); + int usb_reap_async(void *context, int timeout); + int usb_reap_async_nocancel(void *context, int timeout); + int usb_cancel_async(void *context); + int usb_free_async(void **context); + + +#ifdef __cplusplus +} +#endif + +#endif /* __USB_H__ */ + diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/installer_license.txt b/sparkfun/tiny/extras/uploader/library/libusb-win32/installer_license.txt new file mode 100644 index 00000000..56bb2cda --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/installer_license.txt @@ -0,0 +1,851 @@ +Copyright (c) 2002-2004 Stephan Meyer, +Copyright (c) 2000-2004 Johannes Erdfelt, +Copyright (c) 2000-2004 Thomas Sailer, +Copyright (c) 2010 Travis Robinson, + +This software is distributed under the following licenses: +Driver: GNU General Public License (GPL) +Library, Test Files, Installer: GNU Lesser General Public License (LGPL) + +*********************************************************************** + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/bcc/libusb.lib b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/bcc/libusb.lib new file mode 100644 index 00000000..86c0cede Binary files /dev/null and b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/bcc/libusb.lib differ diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/dynamic/libusb_dyn.c b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/dynamic/libusb_dyn.c new file mode 100644 index 00000000..31024ca0 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/dynamic/libusb_dyn.c @@ -0,0 +1,497 @@ +/* LIBUSB-WIN32, Generic Windows USB Library + * Copyright (c) 2002-2005 Stephan Meyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include + +#include "usb.h" + +#define LIBUSB_DLL_NAME "libusb0.dll" + + +typedef usb_dev_handle * (*usb_open_t)(struct usb_device *dev); +typedef int (*usb_close_t)(usb_dev_handle *dev); +typedef int (*usb_get_string_t)(usb_dev_handle *dev, int index, int langid, + char *buf, size_t buflen); +typedef int (*usb_get_string_simple_t)(usb_dev_handle *dev, int index, + char *buf, size_t buflen); +typedef int (*usb_get_descriptor_by_endpoint_t)(usb_dev_handle *udev, int ep, + unsigned char type, + unsigned char index, + void *buf, int size); +typedef int (*usb_get_descriptor_t)(usb_dev_handle *udev, unsigned char type, + unsigned char index, void *buf, int size); +typedef int (*usb_bulk_write_t)(usb_dev_handle *dev, int ep, char *bytes, + int size, int timeout); +typedef int (*usb_bulk_read_t)(usb_dev_handle *dev, int ep, char *bytes, + int size, int timeout); +typedef int (*usb_interrupt_write_t)(usb_dev_handle *dev, int ep, char *bytes, + int size, int timeout); +typedef int (*usb_interrupt_read_t)(usb_dev_handle *dev, int ep, char *bytes, + int size, int timeout); +typedef int (*usb_control_msg_t)(usb_dev_handle *dev, int requesttype, + int request, int value, int index, + char *bytes, int size, int timeout); +typedef int (*usb_set_configuration_t)(usb_dev_handle *dev, int configuration); +typedef int (*usb_claim_interface_t)(usb_dev_handle *dev, int interface); +typedef int (*usb_release_interface_t)(usb_dev_handle *dev, int interface); +typedef int (*usb_set_altinterface_t)(usb_dev_handle *dev, int alternate); +typedef int (*usb_resetep_t)(usb_dev_handle *dev, unsigned int ep); +typedef int (*usb_clear_halt_t)(usb_dev_handle *dev, unsigned int ep); +typedef int (*usb_reset_t)(usb_dev_handle *dev); +typedef int (*usb_reset_ex_t)(usb_dev_handle *dev, unsigned int reset_type); +typedef char * (*usb_strerror_t)(void); +typedef void (*usb_init_t)(void); +typedef void (*usb_set_debug_t)(int level); +typedef int (*usb_find_busses_t)(void); +typedef int (*usb_find_devices_t)(void); +typedef struct usb_device * (*usb_device_t)(usb_dev_handle *dev); +typedef struct usb_bus * (*usb_get_busses_t)(void); +typedef int (*usb_install_service_np_t)(void); +typedef int (*usb_uninstall_service_np_t)(void); +typedef int (*usb_install_driver_np_t)(const char *inf_file); +typedef const struct usb_version * (*usb_get_version_t)(void); +typedef int (*usb_isochronous_setup_async_t)(usb_dev_handle *dev, + void **context, + unsigned char ep, int pktsize); +typedef int (*usb_bulk_setup_async_t)(usb_dev_handle *dev, void **context, + unsigned char ep); +typedef int (*usb_interrupt_setup_async_t)(usb_dev_handle *dev, void **context, + unsigned char ep); +typedef int (*usb_submit_async_t)(void *context, char *bytes, int size); +typedef int (*usb_reap_async_t)(void *context, int timeout); +typedef int (*usb_free_async_t)(void **context); + + +static usb_open_t _usb_open = NULL; +static usb_close_t _usb_close = NULL; +static usb_get_string_t _usb_get_string = NULL; +static usb_get_string_simple_t _usb_get_string_simple = NULL; +static usb_get_descriptor_by_endpoint_t _usb_get_descriptor_by_endpoint = NULL; +static usb_get_descriptor_t _usb_get_descriptor = NULL; +static usb_bulk_write_t _usb_bulk_write = NULL; +static usb_bulk_read_t _usb_bulk_read = NULL; +static usb_interrupt_write_t _usb_interrupt_write = NULL; +static usb_interrupt_read_t _usb_interrupt_read = NULL; +static usb_control_msg_t _usb_control_msg = NULL; +static usb_set_configuration_t _usb_set_configuration = NULL; +static usb_claim_interface_t _usb_claim_interface = NULL; +static usb_release_interface_t _usb_release_interface = NULL; +static usb_set_altinterface_t _usb_set_altinterface = NULL; +static usb_resetep_t _usb_resetep = NULL; +static usb_clear_halt_t _usb_clear_halt = NULL; +static usb_reset_t _usb_reset = NULL; +static usb_reset_ex_t _usb_reset_ex = NULL; +static usb_strerror_t _usb_strerror = NULL; +static usb_init_t _usb_init = NULL; +static usb_set_debug_t _usb_set_debug = NULL; +static usb_find_busses_t _usb_find_busses = NULL; +static usb_find_devices_t _usb_find_devices = NULL; +static usb_device_t _usb_device = NULL; +static usb_get_busses_t _usb_get_busses = NULL; +static usb_install_service_np_t _usb_install_service_np = NULL; +static usb_uninstall_service_np_t _usb_uninstall_service_np = NULL; +static usb_install_driver_np_t _usb_install_driver_np = NULL; +static usb_get_version_t _usb_get_version = NULL; +static usb_isochronous_setup_async_t _usb_isochronous_setup_async = NULL; +static usb_bulk_setup_async_t _usb_bulk_setup_async = NULL; +static usb_interrupt_setup_async_t _usb_interrupt_setup_async = NULL; +static usb_submit_async_t _usb_submit_async = NULL; +static usb_reap_async_t _usb_reap_async = NULL; +static usb_free_async_t _usb_free_async = NULL; + + + + +void usb_init(void) +{ + HINSTANCE libusb_dll = LoadLibrary(LIBUSB_DLL_NAME); + + if (!libusb_dll) + return; + + _usb_open = (usb_open_t) + GetProcAddress(libusb_dll, "usb_open"); + _usb_close = (usb_close_t) + GetProcAddress(libusb_dll, "usb_close"); + _usb_get_string = (usb_get_string_t) + GetProcAddress(libusb_dll, "usb_get_string"); + _usb_get_string_simple = (usb_get_string_simple_t) + GetProcAddress(libusb_dll, "usb_get_string_simple"); + _usb_get_descriptor_by_endpoint = (usb_get_descriptor_by_endpoint_t) + GetProcAddress(libusb_dll, "usb_get_descriptor_by_endpoint"); + _usb_get_descriptor = (usb_get_descriptor_t) + GetProcAddress(libusb_dll, "usb_get_descriptor"); + _usb_bulk_write = (usb_bulk_write_t) + GetProcAddress(libusb_dll, "usb_bulk_write"); + _usb_bulk_read = (usb_bulk_read_t) + GetProcAddress(libusb_dll, "usb_bulk_read"); + _usb_interrupt_write = (usb_interrupt_write_t) + GetProcAddress(libusb_dll, "usb_interrupt_write"); + _usb_interrupt_read = (usb_interrupt_read_t) + GetProcAddress(libusb_dll, "usb_interrupt_read"); + _usb_control_msg = (usb_control_msg_t) + GetProcAddress(libusb_dll, "usb_control_msg"); + _usb_set_configuration = (usb_set_configuration_t) + GetProcAddress(libusb_dll, "usb_set_configuration"); + _usb_claim_interface = (usb_claim_interface_t) + GetProcAddress(libusb_dll, "usb_claim_interface"); + _usb_release_interface = (usb_release_interface_t) + GetProcAddress(libusb_dll, "usb_release_interface"); + _usb_set_altinterface = (usb_set_altinterface_t) + GetProcAddress(libusb_dll, "usb_set_altinterface"); + _usb_resetep = (usb_resetep_t) + GetProcAddress(libusb_dll, "usb_resetep"); + _usb_clear_halt = (usb_clear_halt_t) + GetProcAddress(libusb_dll, "usb_clear_halt"); + _usb_reset = (usb_reset_t) + GetProcAddress(libusb_dll, "usb_reset"); + _usb_reset_ex = (usb_reset_ex_t) + GetProcAddress(libusb_dll, "usb_reset_ex"); + _usb_strerror = (usb_strerror_t) + GetProcAddress(libusb_dll, "usb_strerror"); + _usb_init = (usb_init_t) + GetProcAddress(libusb_dll, "usb_init"); + _usb_set_debug = (usb_set_debug_t) + GetProcAddress(libusb_dll, "usb_set_debug"); + _usb_find_busses = (usb_find_busses_t) + GetProcAddress(libusb_dll, "usb_find_busses"); + _usb_find_devices = (usb_find_devices_t) + GetProcAddress(libusb_dll, "usb_find_devices"); + _usb_device = (usb_device_t) + GetProcAddress(libusb_dll, "usb_device"); + _usb_get_busses = (usb_get_busses_t) + GetProcAddress(libusb_dll, "usb_get_busses"); + _usb_install_service_np = (usb_install_service_np_t) + GetProcAddress(libusb_dll, "usb_install_service_np"); + _usb_uninstall_service_np = (usb_uninstall_service_np_t) + GetProcAddress(libusb_dll, "usb_uninstall_service_np"); + _usb_install_driver_np = (usb_install_driver_np_t) + GetProcAddress(libusb_dll, "usb_install_driver_np"); + _usb_get_version = (usb_get_version_t) + GetProcAddress(libusb_dll, "usb_get_version"); + _usb_isochronous_setup_async = (usb_isochronous_setup_async_t) + GetProcAddress(libusb_dll, "usb_isochronous_setup_async"); + _usb_bulk_setup_async = (usb_bulk_setup_async_t) + GetProcAddress(libusb_dll, "usb_bulk_setup_async"); + _usb_interrupt_setup_async = (usb_interrupt_setup_async_t) + GetProcAddress(libusb_dll, "usb_interrupt_setup_async"); + _usb_submit_async = (usb_submit_async_t) + GetProcAddress(libusb_dll, "usb_submit_async"); + _usb_reap_async = (usb_reap_async_t) + GetProcAddress(libusb_dll, "usb_reap_async"); + _usb_free_async = (usb_free_async_t) + GetProcAddress(libusb_dll, "usb_free_async"); + + if (_usb_init) + _usb_init(); +} + +usb_dev_handle *usb_open(struct usb_device *dev) +{ + if (_usb_open) + return _usb_open(dev); + else + return NULL; +} + +int usb_close(usb_dev_handle *dev) +{ + if (_usb_close) + return _usb_close(dev); + else + return -ENOFILE; +} + +int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, + size_t buflen) +{ + if (_usb_get_string) + return _usb_get_string(dev, index, langid, buf, buflen); + else + return -ENOFILE; +} + +int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, + size_t buflen) +{ + if (_usb_get_string_simple) + return _usb_get_string_simple(dev, index, buf, buflen); + else + return -ENOFILE; +} + +int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, + unsigned char type, unsigned char index, + void *buf, int size) +{ + if (_usb_get_descriptor_by_endpoint) + return _usb_get_descriptor_by_endpoint(udev, ep, type, index, buf, size); + else + return -ENOFILE; +} + +int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, + unsigned char index, void *buf, int size) +{ + if (_usb_get_descriptor) + return _usb_get_descriptor(udev, type, index, buf, size); + else + return -ENOFILE; +} + +int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + if (_usb_bulk_write) + return _usb_bulk_write(dev, ep, bytes, size, timeout); + else + return -ENOFILE; +} + +int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + if (_usb_bulk_read) + return _usb_bulk_read(dev, ep, bytes, size, timeout); + else + return -ENOFILE; +} + +int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + if (_usb_interrupt_write) + return _usb_interrupt_write(dev, ep, bytes, size, timeout); + else + return -ENOFILE; +} + +int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + if (_usb_interrupt_read) + return _usb_interrupt_read(dev, ep, bytes, size, timeout); + else + return -ENOFILE; +} + +int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, + int value, int index, char *bytes, int size, + int timeout) +{ + if (_usb_control_msg) + return _usb_control_msg(dev, requesttype, request, value, index, bytes, + size, timeout); + else + return -ENOFILE; +} + +int usb_set_configuration(usb_dev_handle *dev, int configuration) +{ + if (_usb_set_configuration) + return _usb_set_configuration(dev, configuration); + else + return -ENOFILE; +} + +int usb_claim_interface(usb_dev_handle *dev, int interface) +{ + if (_usb_claim_interface) + return _usb_claim_interface(dev, interface); + else + return -ENOFILE; +} + +int usb_release_interface(usb_dev_handle *dev, int interface) +{ + if (_usb_release_interface) + return _usb_release_interface(dev, interface); + else + return -ENOFILE; +} + +int usb_set_altinterface(usb_dev_handle *dev, int alternate) +{ + if (_usb_set_altinterface) + return _usb_set_altinterface(dev, alternate); + else + return -ENOFILE; +} + +int usb_resetep(usb_dev_handle *dev, unsigned int ep) +{ + if (_usb_resetep) + return _usb_resetep(dev, ep); + else + return -ENOFILE; +} + +int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) +{ + if (_usb_clear_halt) + return _usb_clear_halt(dev, ep); + else + return -ENOFILE; +} + +int usb_reset(usb_dev_handle *dev) +{ + if (_usb_reset) + return _usb_reset(dev); + else + return -ENOFILE; +} + +int usb_reset_ex(usb_dev_handle *dev, unsigned int reset_type) +{ + if (_usb_reset_ex) + return _usb_reset_ex(dev, reset_type); + else + return -ENOFILE; +} + +char *usb_strerror(void) +{ + if (_usb_strerror) + return _usb_strerror(); + else + return NULL; +} + +void usb_set_debug(int level) +{ + if (_usb_set_debug) + return _usb_set_debug(level); +} + +int usb_find_busses(void) +{ + if (_usb_find_busses) + return _usb_find_busses(); + else + return -ENOFILE; +} + +int usb_find_devices(void) +{ + if (_usb_find_devices) + return _usb_find_devices(); + else + return -ENOFILE; +} + +struct usb_device *usb_device(usb_dev_handle *dev) +{ + if (_usb_device) + return _usb_device(dev); + else + return NULL; +} + +struct usb_bus *usb_get_busses(void) +{ + if (_usb_get_busses) + return _usb_get_busses(); + else + return NULL; +} + +int usb_install_service_np(void) +{ + if (_usb_install_service_np) + return _usb_install_service_np(); + else + return -ENOFILE; +} + +int usb_uninstall_service_np(void) +{ + if (_usb_uninstall_service_np) + return _usb_uninstall_service_np(); + else + return -ENOFILE; +} + +int usb_install_driver_np(const char *inf_file) +{ + if (_usb_install_driver_np) + return _usb_install_driver_np(inf_file); + else + return -ENOFILE; +} + +const struct usb_version *usb_get_version(void) +{ + if (_usb_get_version) + return _usb_get_version(); + else + return NULL; +} + +int usb_isochronous_setup_async(usb_dev_handle *dev, void **context, + unsigned char ep, int pktsize) +{ + if (_usb_isochronous_setup_async) + return _usb_isochronous_setup_async(dev, context, ep, pktsize); + else + return -ENOFILE; +} + +int usb_bulk_setup_async(usb_dev_handle *dev, void **context, + unsigned char ep) +{ + if (_usb_bulk_setup_async) + return _usb_bulk_setup_async(dev, context, ep); + else + return -ENOFILE; +} + +int usb_interrupt_setup_async(usb_dev_handle *dev, void **context, + unsigned char ep) +{ + if (_usb_interrupt_setup_async) + return _usb_interrupt_setup_async(dev, context, ep); + else + return -ENOFILE; +} + +int usb_submit_async(void *context, char *bytes, int size) +{ + if (_usb_submit_async) + return _usb_submit_async(context, bytes, size); + else + return -ENOFILE; +} + +int usb_reap_async(void *context, int timeout) +{ + if (_usb_reap_async) + return _usb_reap_async(context, timeout); + else + return -ENOFILE; +} + +int usb_free_async(void **context) +{ + if (_usb_free_async) + return _usb_free_async(context); + else + return -ENOFILE; +} diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/gcc/libusb.a b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/gcc/libusb.a new file mode 100644 index 00000000..6861a0aa Binary files /dev/null and b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/gcc/libusb.a differ diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc/libusb.lib b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc/libusb.lib new file mode 100644 index 00000000..64ac6f79 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc/libusb.lib differ diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc_i64/libusb.lib b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc_i64/libusb.lib new file mode 100644 index 00000000..21c73d5e Binary files /dev/null and b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc_i64/libusb.lib differ diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc_x64/libusb.lib b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc_x64/libusb.lib new file mode 100644 index 00000000..dfdaad05 Binary files /dev/null and b/sparkfun/tiny/extras/uploader/library/libusb-win32/lib/msvc_x64/libusb.lib differ diff --git a/sparkfun/tiny/extras/uploader/library/libusb-win32/libusb-win32-changelog-1.2.6.0.txt b/sparkfun/tiny/extras/uploader/library/libusb-win32/libusb-win32-changelog-1.2.6.0.txt new file mode 100644 index 00000000..99445f7d --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/libusb-win32/libusb-win32-changelog-1.2.6.0.txt @@ -0,0 +1,239 @@ +LibUsb-Win32 Change Log +V1.2.6.0 (01/17/2012) +============================================== +* Official release. + +* Removed ISO maximum transfer size restrictions/transfer spltting. + +* Fixed inf-wizard device notification issue. + +V1.2.5.0 (07/23/2011) +============================================== +* Official release. + +V1.2.4.9 (07/13/2011) - SNAPSHOT RELEASE +============================================== +* Updated GCC lib file 'libusb.a' + +V1.2.4.8 (07/12/2011) - SNAPSHOT RELEASE +============================================== +* Added new public api function 'usb_reset_ex'. This is an extended + device reset function which allows developers to specify a port reset, a + port cycle, or both. + +* Added new public defines 'USB_RESET_TYPE_XXX' for 'usb_reset_ex' + function. + +V1.2.4.7 (07/02/2011) - SNAPSHOT RELEASE +============================================== +* Sync transfers which specify a zero (0) timeout are now considered to be + INFINITE. + +V1.2.4.6 (05/12/2011) - SNAPSHOT RELEASE +============================================== +* Added device interface registration. This provides identical + functionality to the "DeviceInterfaceGUIDs" supported by WinUSB and + libusbK. A device interface guid can be specified in the .inf file. They + can be used to quickly locate a usb device or set of USB devices using + the setup api as well as device notification registration. + +* New IOCTL codes added to for native libusbK/WinUSB compatibility. + NOTE: These IOCTLs are currently used only by libusbK.dll. + o LIBUSB_IOCTL_QUERY_DEVICE_INFORMATION + o LIBUSB_IOCTL_SET_PIPE_POLICY + o LIBUSB_IOCTL_GET_PIPE_POLICY + o LIBUSB_IOCTL_SET_POWER_POLICY + o LIBUSB_IOCTL_GET_POWER_POLICY + o LIBUSB_IOCTL_CONTROL_WRITE + o LIBUSB_IOCTL_CONTROL_READ + o LIBUSB_IOCTL_FLUSH_PIPE + o LIBUSBK_IOCTL_CLAIM_INTERFACE + o LIBUSBK_IOCTL_RELEASE_INTERFACE + o LIBUSBK_IOCTL_RELEASE_ALL_INTERFACES + o LIBUSBK_IOCTL_SET_INTERFACE + o LIBUSBK_IOCTL_GET_INTERFACE + +* Renamed main header file (usb.h) to lusb0_usb.h. This eliminates + conflicts with the main WDK usb include as well as making the + libusb-win32 header more distinguishable from other usb library header + files. + +* Added device descriptor caching and active/first config descriptor + caching. Descriptor caching prevents unnecessary control requests from + interrupting devices that could potentially be in-use. It also makes + libusb0.sys more compliant with usb libraries targeting platform where + descriptor caching is done automatically. (linux/mac) + +* Upgraded to libwdi v1.1.1 + o Zadig UI improvements + o wdi-simple now handles certificate related operations + o New NSIS (Nullsoft Scriptable Install System) script sample + o improved INNO Setup script sample + o libusbK support + o autogeneration and self-signing of a .cat file, to prevent further security + prompts during driver installation on Vista and later. + for more information, see http://libwdi-cps.akeo.ie + o disable restore point creation during installation + o Visual Studio 2010 support and overall MS file cleanup + o use of the Kerberos/e2fsprogs parser in Zadig instead of libconfig + +V1.2.4.0 (04/11/2011) +======================= +* Removed get configuration request from the core driver + set_configuration function. This caused problems with + some non-compliant usb devices. + +* Added device descriptor dump to test applications. + +V1.2.3.0 (03/16/2011) +======================= +* Fixed bug-id 3117686 reported by Tim Schuerewegen. + +* Added LIBUSB_IOCTL_GET_OBJECT_NAME. This new IOCTL code retrieves object + from the driver. The only valid object name index is 0. Index 0 is + returns the devices plug and play registry key pathname. + +* Removed maximum timeout restriction for vendor class requests. + +V1.2.2.0 (10/02/2010) +======================= +* Added install-filter-win.exe. A gui installer for device filters. + +* Added new libusb0.dll function usb_install_np_rundll(). This function + is designed for rundll32.exe and takes the same parameters as + install-filter.exe. + +* Updated install-filter.exe. This application has several new features. + Type "install-filter --help" for more details. + +* Updated libusb-win32-devel-filter package. This package is once again + available for download as a setup.exe. + +* Updated libusb-win32 "bin" package format. inf-wizard.exe has been moved + up one directory. + +* Updated driver_installer_template.iss example. This is an Inno Setup + Script showing how to create your own setup.exe for installing your + application and driver. + +* Fixed missing byte order marker in inf-wizard.exe .inf files. (libwdi) + +* Fixed auto-configuration issue when there is more than one driver in the + stack. + +* Fixed BSOD when using the filter driver with devices that are auto + suspended by other drivers in the stack. + +* Fixed BSOD for devices with endpoints that have '0' for wMaxPacketSize. + +* Fixed BSOD when cancelling large transfers on high speed devices. + + +V1.2.1.0 (07/28/2010) +======================= +* Updated bulk.c to include async i/o example code. + +* Fixed usb_install_driver_np() issue with inf-wizard generated infs. + +* Fixed inf2cat.exe issue with inf-wizard generated infs. + +* Added 'Install Now' feature to inf-wizard. (libwdi) + +* Added embedded libusb-win32 binaries to inf-wizard. (libwdi) + +* Added libwdi (http://www.libusb.org/wiki/libwdi) to inf-wizard. + +* Added get cached configuration request to usb_open(). This is a new + control code that involves no device i/o and allows + usb_set_configuration() to be omitted if the driver has already + configured it. + +* Fixed set_configuration() failure for devices that do not properly + support get_configuration(). + +V1.2.0.0 (07/07/2010) +======================= +* First signed driver release! The libusb-win32 kernel driver (libusb0.sys) + can now be used on x64 Windows machines that require signed drivers. + +* Fixed 2128187 reported by Tim Green. usb_get_descriptor() can fail + because the given buffer of 8 bytes is too small. + +* Fixed 2928293 reported by Tim Green. Sometimes the call to + usb_fetch_and_parse_descriptors() in usb_find_devices() can fail. This + patch moves the LIST_ADD to after a successful read of the device's + configuration descriptors. + +* Fixed issue causing libusb-win32 to not act as power policy owner + when it should. + +* Fixed issue in which on rare occasion, a libusb-win32 filter device could + run as a "normal" device. + +* Fixed filter driver issue for device using wudfr.sys. + +* Added large transfer splitting to driver (bulk, int, iso). NOTE: + The dll continues to break transfers in the same manner it always has. + + +V1.1.14.3 (06/12/2010) +======================= +* Remove get_configuration() request from usb_open(). This caused claim + interface to fail when used as a filter driver. + +V1.1.14.0 (06/01/2010) +======================= +* Updated logging functions and standardized log message display format. + +* Updated inf-wizard to use the new directory format for the libusb-win32 + binaries. + +* Updated package directories to reflect the winddk BUILDARCH env variable. + (i64 := ia64, x64 := amd64) + +* Added request to get the current configuration in usb_open(). + +* Fixed 2960644 (reported by farthen) crash on shutdown with x64 based + systems while using inf files for each libusb device. + +* Added additional log message only included in debug/chk builds. + +* Updated default log levels to highest verbose level for debug builds. + +* Added test signing support to the libusb-win32 make.cmd. This allows + libusb0.sys and libusb0.dll to be signed with a digital signature. + (see make.cmd for mmore details) + +* Added MSVC 2008 project files + +* Moved version defines to an include file (libusb_version.h) + This file is generated from libusb_version_h.in with "make.cmd makever" + +* Removed all "dist" commands from cyg/mingw makefile. Instead use "make.cmd" + in the "ddk_make" directory. + +* Fixed filter setup not running in 64bit mode + +* Fixed 64bit inf-wizard, testlibusb-win builds + +* Added set initial config value #1 when the driver is not a filter. + optionally, the initial configuration value can be specified in the inf + file: HKR,,"InitialConfigValue",0x00010001, + +* Added support for querying device registry keys + (LIBUSB_IOCTL_GET_CUSTOM_REG_PROPERTY) + +* Added support for querying device properties + (LIBUSB_IOCTL_GET_DEVICE_PROPERTY) + +* Fixed possible race condition in kernel add_device() + +* Updated default ddk build version number to 1.1.14.0 to facilitate + Microsoft WHQL submission. + +* Added DDK build distribution system. Official libusb-win32 releases + (after 0.1.12.2) are built using Microsoft's WinDDK. (see make.cmd) + +* Fixed 2658937 (reported by Tim Roberts) The libusb-win32 driver always + acts as a power policy owner. + diff --git a/sparkfun/tiny/extras/uploader/library/littleWire_util.c b/sparkfun/tiny/extras/uploader/library/littleWire_util.c new file mode 100644 index 00000000..c34460c6 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/littleWire_util.c @@ -0,0 +1,13 @@ +#include + +/* Delay in miliseconds */ +void delay(unsigned int duration) { + #if defined _WIN32 || defined _WIN64 + // use windows sleep api with milliseconds + // * 2 to make it run at half speed, because windows seems to have some trouble with this... + Sleep(duration * 2); + #else + // use standard unix api with microseconds + usleep(duration*1000); + #endif +} diff --git a/sparkfun/tiny/extras/uploader/library/littleWire_util.h b/sparkfun/tiny/extras/uploader/library/littleWire_util.h new file mode 100644 index 00000000..1f060c39 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/littleWire_util.h @@ -0,0 +1,14 @@ +#ifndef LITTLEWIRE_UTIL_H +#define LITTLEWIRE_UTIL_H + +#if defined WIN + #include +#else + #include +#endif + +/* Delay in miliseconds */ +void delay(unsigned int duration); + +// end LITTLEWIRE_UTIL_H section: +#endif diff --git a/sparkfun/tiny/extras/uploader/library/micronucleus_lib.c b/sparkfun/tiny/extras/uploader/library/micronucleus_lib.c new file mode 100644 index 00000000..0569dbe9 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/micronucleus_lib.c @@ -0,0 +1,323 @@ + +/* + Created: September 2012 + (c) 2012 by ihsan Kehribar + Changes for Micronucleus protocol version V2.x + (c) 2014 T. Bo"scke + + 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: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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. +*/ + +/***************************************************************/ +/* See the micronucleus_lib.h for the function descriptions/comments */ +/***************************************************************/ +#include "micronucleus_lib.h" +#include "littleWire_util.h" + +micronucleus* micronucleus_connect(int fast_mode) { + micronucleus *nucleus = NULL; + struct usb_bus *busses; + + // intialise usb and find micronucleus device + usb_init(); + usb_find_busses(); + usb_find_devices(); + + busses = usb_get_busses(); + struct usb_bus *bus; + for (bus = busses; bus; bus = bus->next) { + struct usb_device *dev; + + for (dev = bus->devices; dev; dev = dev->next) { + /* Check if this device is a micronucleus */ + if (dev->descriptor.idVendor == MICRONUCLEUS_VENDOR_ID && dev->descriptor.idProduct == MICRONUCLEUS_PRODUCT_ID) { + nucleus = malloc(sizeof(micronucleus)); + nucleus->version.major = (dev->descriptor.bcdDevice >> 8) & 0xFF; + nucleus->version.minor = dev->descriptor.bcdDevice & 0xFF; + + if (nucleus->version.major > MICRONUCLEUS_MAX_MAJOR_VERSION) { + fprintf(stderr, + "Warning: device with unknown new version of Micronucleus detected.\n" + "This tool doesn't know how to upload to this new device. Updates may be available.\n" + "Device reports version as: %d.%d\n", + nucleus->version.major, nucleus->version.minor); + return NULL; + } + + nucleus->device = usb_open(dev); + + if (nucleus->version.major>=2) { // Version 2.x + // get nucleus info + unsigned char buffer[6]; + int res = usb_control_msg(nucleus->device, USB_ENDPOINT_IN| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, 0, (char *)buffer, 6, MICRONUCLEUS_USB_TIMEOUT); + + // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. + if (res<0) return NULL; + + assert(res >= 6); + + nucleus->flash_size = (buffer[0]<<8) + buffer[1]; + nucleus->page_size = buffer[2]; + nucleus->pages = (nucleus->flash_size / nucleus->page_size); + if (nucleus->pages * nucleus->page_size < nucleus->flash_size) nucleus->pages += 1; + + nucleus->bootloader_start = nucleus->pages*nucleus->page_size; + + if ((nucleus->version.major>=2)&&(!fast_mode)) { + // firmware v2 reports more aggressive write times. Add 2ms if fast mode is not used. + nucleus->write_sleep = (buffer[3] & 127) + 2; + } else { + nucleus->write_sleep = (buffer[3] & 127); + } + + // if bit 7 of write sleep time is set, divide the erase time by four to + // accomodate to the 4*page erase of the ATtiny841/441 + if (buffer[3]&128) { + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages / 4; + } else { + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + } + + nucleus->signature1 = buffer[4]; + nucleus->signature2 = buffer[5]; + + } else { // Version 1.x + // get nucleus info + unsigned char buffer[4]; + int res = usb_control_msg(nucleus->device, USB_ENDPOINT_IN| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, 0, (char *)buffer, 4, MICRONUCLEUS_USB_TIMEOUT); + + // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. + if (res<0) return NULL; + + assert(res >= 4); + + nucleus->flash_size = (buffer[0]<<8) + buffer[1]; + nucleus->page_size = buffer[2]; + nucleus->pages = (nucleus->flash_size / nucleus->page_size); + if (nucleus->pages * nucleus->page_size < nucleus->flash_size) nucleus->pages += 1; + + nucleus->bootloader_start = nucleus->pages*nucleus->page_size; + + nucleus->write_sleep = (buffer[3] & 127); + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + + nucleus->signature1 = 0; + nucleus->signature2 = 0; + } + } + } + } + + return nucleus; +} + +int micronucleus_eraseFlash(micronucleus* deviceHandle, micronucleus_callback progress) { + int res; + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 2, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + + // give microcontroller enough time to erase all writable pages and come back online + float i = 0; + while (i < 1.0) { + // update progress callback if one was supplied + if (progress) progress(i); + + delay(((float) deviceHandle->erase_sleep) / 100.0f); + i += 0.01; + } + + /* Under Linux, the erase process is often aborted with errors such as: + usbfs: USBDEVFS_CONTROL failed cmd micronucleus rqt 192 rq 2 len 0 ret -84 + This seems to be because the erase is taking long enough that the device + is disconnecting and reconnecting. Under Windows, micronucleus can see this + and automatically reconnects prior to uploading the program. To get the + the same functionality, we must flag this state (the "-84" error result) by + converting the return to -2 for the upper layer. + + On Mac OS a common error is -34 = epipe, but adding it to this list causes: + Assertion failed: (res >= 4), function micronucleus_connect, file library/micronucleus_lib.c, line 63. + */ + if (res == -5 || res == -34 || res == -84) { + if (res == -34) { + usb_close(deviceHandle->device); + deviceHandle->device = NULL; + } + + return 1; // recoverable errors + } else { + return res; + } +} + +int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_size, unsigned char* program, micronucleus_callback prog) { + unsigned char page_length = deviceHandle->page_size; + unsigned char page_buffer[page_length]; + unsigned int address; // overall flash memory address + unsigned int page_address; // address within this page when copying buffer + unsigned int res; + unsigned int pagecontainsdata; + unsigned int userReset; + + for (address = 0; address < deviceHandle->flash_size; address += deviceHandle->page_size) { + // work around a bug in older bootloader versions + if (deviceHandle->version.major == 1 && deviceHandle->version.minor <= 2 + && address / deviceHandle->page_size == deviceHandle->pages - 1) { + page_length = deviceHandle->flash_size % deviceHandle->page_size; + } + + pagecontainsdata=0; + + // copy in bytes from user program + for (page_address = 0; page_address < page_length; page_address += 1) { + if (address + page_address > program_size) { + page_buffer[page_address] = 0xFF; // pad out remainder with unprogrammed bytes + } else { + pagecontainsdata=1; // page contains data and needs to be written + page_buffer[page_address] = program[address + page_address]; // load from user program + } + } + + // Reset vector patching is done in the host tool in micronucleus >=2 + if (deviceHandle->version.major >=2) + { + if ( address == 0 ) { + // save user reset vector (bootloader will patch with its vector) + unsigned int word0,word1; + word0 = page_buffer [1] * 0x100 + page_buffer [0]; + word1 = page_buffer [3] * 0x100 + page_buffer [2]; + + if (word0==0x940c) { // long jump + userReset = word1; + } else if ((word0&0xf000)==0xc000) { // rjmp + userReset = (word0 & 0x0fff) - 0 + 1; + } else { + fprintf(stderr, + "The reset vector of the user program does not contain a branch instruction,\n" + "therefore the bootloader can not be inserted. Please rearrage your code.\n" + ); + return -1; + } + + // Patch in jmp to bootloader. + if (deviceHandle->bootloader_start > 0x2000) { + // jmp + unsigned data = 0x940c; + page_buffer [ 0 ] = data >> 0 & 0xff; + page_buffer [ 1 ] = data >> 8 & 0xff; + page_buffer [ 2 ] = deviceHandle->bootloader_start >> 0 & 0xff; + page_buffer [ 3 ] = deviceHandle->bootloader_start >> 8 & 0xff; + } else { + // rjmp + unsigned data = 0xc000 | ((deviceHandle->bootloader_start/2 - 1) & 0x0fff); + page_buffer [ 0 ] = data >> 0 & 0xff; + page_buffer [ 1 ] = data >> 8 & 0xff; + } + + } + + if ( address >= deviceHandle->bootloader_start - deviceHandle->page_size ) { + // move user reset vector to end of last page + // The reset vector is always the last vector in the tinyvectortable + unsigned int user_reset_addr = (deviceHandle->pages*deviceHandle->page_size) - 4; + + if (user_reset_addr > 0x2000) { + // jmp + unsigned data = 0x940c; + page_buffer [user_reset_addr - address + 0] = data >> 0 & 0xff; + page_buffer [user_reset_addr - address + 1] = data >> 8 & 0xff; + page_buffer [user_reset_addr - address + 2] = userReset >> 0 & 0xff; + page_buffer [user_reset_addr - address + 3] = userReset >> 8 & 0xff; + } else { + // rjmp + unsigned data = 0xc000 | ((userReset - user_reset_addr/2 - 1) & 0x0fff); + page_buffer [user_reset_addr - address + 0] = data >> 0 & 0xff; + page_buffer [user_reset_addr - address + 1] = data >> 8 & 0xff; + } + } + } + + + // always write last page so bootloader can insert the tiny vector table + if ( address >= deviceHandle->bootloader_start - deviceHandle->page_size ) + pagecontainsdata = 1; + + // ask microcontroller to write this page's data + if (pagecontainsdata) { + + if (deviceHandle->version.major == 1) { + // Firmware rev.1 transfers a page as a single block + // ask microcontroller to write this page's data + res = usb_control_msg(deviceHandle->device, + USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, + page_length, address, + page_buffer, page_length, + MICRONUCLEUS_USB_TIMEOUT); + } else if (deviceHandle->version.major >= 2) { + // Firmware rev.2 uses individual set up packets to transfer data + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, page_length, address, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + if (res) return -1; + int i; + + for (i=0; i< page_length; i+=4) + { + int w1,w2; + w1=(page_buffer[i+1]<<8)+(page_buffer[i+0]<<0); + w2=(page_buffer[i+3]<<8)+(page_buffer[i+2]<<0); + + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 3, w1, w2, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + if (res) return -1; + } + } + /* + res = usb_control_msg(deviceHandle->device, + USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, + page_length, address, + (char*)page_buffer, page_length, + MICRONUCLEUS_USB_TIMEOUT); + + if (res != page_length) return -1; + */ + // give microcontroller enough time to write this page and come back online + delay(deviceHandle->write_sleep); + } + + // call progress update callback if that's a thing + if (prog) prog(((float) address) / ((float) deviceHandle->flash_size)); + + } + + // call progress update callback with completion status + if (prog) prog(1.0); + + return 0; +} + +int micronucleus_startApp(micronucleus* deviceHandle) { + int res; + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 4, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + + if(res!=0) + return -1; + else + return 0; +} + + + diff --git a/sparkfun/tiny/extras/uploader/library/micronucleus_lib.h b/sparkfun/tiny/extras/uploader/library/micronucleus_lib.h new file mode 100644 index 00000000..79445288 --- /dev/null +++ b/sparkfun/tiny/extras/uploader/library/micronucleus_lib.h @@ -0,0 +1,112 @@ +#ifndef MICRONUCLEUS_LIB_H +#define MICRONUCLEUS_LIB_H + +/* + Created: September 2012 + (c) 2012 by ihsan Kehribar + Changes for Micronucleus protocol version V2.x + (c) 2014 T. Bo"scke + Modified for custom ATtiny USB VID/PID + (c) 2017 SparkFun Electronics + + 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: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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. +*/ + +/******************************************************************************** +* Header files +********************************************************************************/ +#if defined WIN + #include // this is libusb, see http://libusb.sourceforge.net/ +#else + #include // this is libusb, see http://libusb.sourceforge.net/ +#endif +//#include "opendevice.h" // common code moved to separate module +#include +#include +#include +/*******************************************************************************/ + +/******************************************************************************** +* USB details +********************************************************************************/ +#define MICRONUCLEUS_VENDOR_ID 0x1B4F +#define MICRONUCLEUS_PRODUCT_ID 0x0014 +#define MICRONUCLEUS_USB_TIMEOUT 0xFFFF +#define MICRONUCLEUS_MAX_MAJOR_VERSION 2 + +/*******************************************************************************/ + +/******************************************************************************** +* Declarations +********************************************************************************/ +//typedef usb_dev_handle micronucleus; +// representing version number of micronucleus device +typedef struct _micronucleus_version { + unsigned char major; + unsigned char minor; +} micronucleus_version; + +#define MICRONUCLEUS_COMMANDLINE_VERSION "Commandline tool version: 2.0a5" + +// handle representing one micronucleus device +typedef struct _micronucleus { + usb_dev_handle *device; + // general information about device + micronucleus_version version; + unsigned int flash_size; // programmable size (in bytes) of progmem + unsigned int page_size; // size (in bytes) of page + unsigned int bootloader_start; // Start of the bootloader + unsigned int pages; // total number of pages to program + unsigned int write_sleep; // milliseconds + unsigned int erase_sleep; // milliseconds + unsigned char signature1; // only used in protocol v2 + unsigned char signature2; // only used in protocol v2 +} micronucleus; + +typedef void (*micronucleus_callback)(float progress); + +/*******************************************************************************/ + +/******************************************************************************** +* Try to connect to the device +* Returns: device handle for success, NULL for fail +********************************************************************************/ +micronucleus* micronucleus_connect(int fast_mode); +/*******************************************************************************/ + +/******************************************************************************** +* Erase the flash memory +********************************************************************************/ +int micronucleus_eraseFlash(micronucleus* deviceHandle, micronucleus_callback progress); +/*******************************************************************************/ + +/******************************************************************************** +* Write the flash memory +********************************************************************************/ +int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_length, + unsigned char* program, micronucleus_callback progress); +/*******************************************************************************/ + +/******************************************************************************** +* Starts the user application +********************************************************************************/ +int micronucleus_startApp(micronucleus* deviceHandle); +/*******************************************************************************/ + +#endif diff --git a/sparkfun/tiny/extras/uploader/micronucleus.c b/sparkfun/tiny/extras/uploader/micronucleus.c new file mode 100644 index 00000000..14c1761b --- /dev/null +++ b/sparkfun/tiny/extras/uploader/micronucleus.c @@ -0,0 +1,434 @@ +/* +Created: September 2012 + (c) 2012 by ihsan Kehribar + Changes for Micronucleus protocol version V2.x + (c) 2014 T. Bo"scke + + 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: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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 +#include +#include +#include +#include +#include "micronucleus_lib.h" +#include "littleWire_util.h" + +#define FILE_TYPE_INTEL_HEX 1 +#define FILE_TYPE_RAW 2 +#define CONNECT_WAIT 250 /* milliseconds to wait after detecting device on usb bus - probably excessive */ + +/****************************************************************************** +* Global definitions +******************************************************************************/ +unsigned char dataBuffer[65536 + 256]; /* buffer for file data */ +/*****************************************************************************/ + +/****************************************************************************** +* Function prototypes +******************************************************************************/ +static int parseRaw(char *hexfile, unsigned char *buffer, int *startAddr, int *endAddr); +static int parseIntelHex(char *hexfile, unsigned char *buffer, int *startAddr, int *endAddr); /* taken from bootloadHID example from obdev */ +static int parseUntilColon(FILE *fp); /* taken from bootloadHID example from obdev */ +static int parseHex(FILE *fp, int numDigits); /* taken from bootloadHID example from obdev */ +static void printProgress(float progress); +static void setProgressData(char* friendly, int step); +static int progress_step = 0; // current step +static int progress_total_steps = 0; // total steps for upload +static char* progress_friendly_name; // name of progress section +static int dump_progress = 0; // output computer friendly progress info +static int use_ansi = 0; // output ansi control character stuff +static int erase_only = 0; // only erase, dont't write file +static int fast_mode = 0; // normal mode adds 2ms to page writing times and waits longer for connect. +static int timeout = 0; +/*****************************************************************************/ + +/****************************************************************************** +* Main function! +******************************************************************************/ +int main(int argc, char **argv) { + int res; + char *file = NULL; + micronucleus *my_device = NULL; + + // parse arguments + int run = 0; + int file_type = FILE_TYPE_INTEL_HEX; + int arg_pointer = 1; + #if defined(WIN) + char* usage = "usage: micronucleus [--help] [--run] [--dump-progress] [--fast-mode] [--type intel-hex|raw] [--timeout integer] [--erase-only] filename"; + #else + char* usage = "usage: micronucleus [--help] [--run] [--dump-progress] [--fast-mode] [--type intel-hex|raw] [--timeout integer] [--erase-only] filename [--no-ansi]"; + #endif + progress_step = 0; + progress_total_steps = 5; // steps: waiting, connecting, parsing, erasing, writing, (running)? + dump_progress = 0; + erase_only = 0; + fast_mode=0; + timeout = 0; // no timeout by default + #if defined(WIN) + use_ansi = 0; + #else + use_ansi = 1; + #endif + + while (arg_pointer < argc) { + if (strcmp(argv[arg_pointer], "--run") == 0) { + run = 1; + progress_total_steps += 1; + } else if (strcmp(argv[arg_pointer], "--type") == 0) { + arg_pointer += 1; + if (strcmp(argv[arg_pointer], "intel-hex") == 0) { + file_type = FILE_TYPE_INTEL_HEX; + } else if (strcmp(argv[arg_pointer], "raw") == 0) { + file_type = FILE_TYPE_RAW; + } else { + printf("Unknown File Type specified with --type option"); + return EXIT_FAILURE; + } + } else if (strcmp(argv[arg_pointer], "--help") == 0 || strcmp(argv[arg_pointer], "-h") == 0) { + puts(usage); + puts(""); + puts(" --type [intel-hex, raw]: Set upload file type to either intel hex or raw"); + puts(" bytes (intel hex is default)"); + puts(" --dump-progress: Output progress data in computer-friendly form"); + puts(" for driving GUIs"); + puts(" --erase-only: Erase the device without programming. Fills the"); + puts(" program memory with 0xFFFF. Any files are ignored."); + puts(" --fast-mode: Speed up the timing of micronucleus. Do not use if"); + puts(" you encounter USB errors. "); + puts(" --run: Ask bootloader to run the program when finished"); + puts(" uploading provided program"); + #ifndef WIN + puts(" --no-ansi: Don't use ANSI in terminal output"); + #endif + puts(" --timeout [integer]: Timeout after waiting specified number of seconds"); + puts(" filename: Path to intel hex or raw data file to upload,"); + puts(" or \"-\" to read from stdin"); + puts(""); + puts(MICRONUCLEUS_COMMANDLINE_VERSION); + return EXIT_SUCCESS; + } else if (strcmp(argv[arg_pointer], "--dump-progress") == 0) { + dump_progress = 1; + } else if (strcmp(argv[arg_pointer], "--no-ansi") == 0) { + use_ansi = 0; + } else if (strcmp(argv[arg_pointer], "--fast-mode") == 0) { + fast_mode = 1; + } else if (strcmp(argv[arg_pointer], "--erase-only") == 0) { + erase_only = 1; + progress_total_steps -= 1; + } else if (strcmp(argv[arg_pointer], "--timeout") == 0) { + arg_pointer += 1; + if (sscanf(argv[arg_pointer], "%d", &timeout) != 1) { + printf("Did not understand --timeout value\n"); + return EXIT_FAILURE; + } + } else { + file = argv[arg_pointer]; + } + + arg_pointer += 1; + } + + if (argc < 2) { + puts(usage); + return EXIT_FAILURE; + } + + setProgressData("waiting", 1); + if (dump_progress) printProgress(0.5); + printf("> Please plug in the device ... \n"); + printf("> Press CTRL+C to terminate the program.\n"); + + + time_t start_time, current_time; + time(&start_time); + + while (my_device == NULL) { + delay(100); + my_device = micronucleus_connect(fast_mode); + + time(¤t_time); + if (timeout && start_time + timeout < current_time) { + break; + } + } + + if (my_device == NULL) { + printf("> Device search timed out\n"); + return EXIT_FAILURE; + } + + printf("> Device is found!\n"); + + if (!fast_mode) { + // wait for CONNECT_WAIT milliseconds with progress output + float wait = 0.0f; + setProgressData("connecting", 2); + while (wait < CONNECT_WAIT) { + printProgress((wait / ((float) CONNECT_WAIT)) * 0.9f); + wait += 50.0f; + delay(50); + } + } + printProgress(1.0); + + printf("> Device has firmware version %d.%d\n",my_device->version.major,my_device->version.minor); + if (my_device->signature1) printf("> Device signature: 0x1e%02x%02x \n",(int)my_device->signature1,(int)my_device->signature2); + printf("> Available space for user applications: %d bytes\n", my_device->flash_size); + printf("> Suggested sleep time between sending pages: %ums\n", my_device->write_sleep); + printf("> Whole page count: %d page size: %d\n", my_device->pages,my_device->page_size); + printf("> Erase function sleep duration: %dms\n", my_device->erase_sleep); + + int startAddress = 1, endAddress = 0; + + if (!erase_only) { + setProgressData("parsing", 3); + printProgress(0.0); + memset(dataBuffer, 0xFF, sizeof(dataBuffer)); + + if (file_type == FILE_TYPE_INTEL_HEX) { + if (parseIntelHex(file, dataBuffer, &startAddress, &endAddress)) { + printf("> Error loading or parsing hex file.\n"); + return EXIT_FAILURE; + } + } else if (file_type == FILE_TYPE_RAW) { + if (parseRaw(file, dataBuffer, &startAddress, &endAddress)) { + printf("> Error loading raw file.\n"); + return EXIT_FAILURE; + } + } + + printProgress(1.0); + + if (startAddress >= endAddress) { + printf("> No data in input file, exiting.\n"); + return EXIT_FAILURE; + } + + if (endAddress > my_device->flash_size) { + printf("> Program file is %d bytes too big for the bootloader!\n", endAddress - my_device->flash_size); + return EXIT_FAILURE; + } + } + + printProgress(1.0); + + setProgressData("erasing", 4); + printf("> Erasing the memory ...\n"); + res = micronucleus_eraseFlash(my_device, printProgress); + + if (res == 1) { // erase disconnection bug workaround + printf(">> Eep! Connection to device lost during erase! Not to worry\n"); + printf(">> This happens on some computers - reconnecting...\n"); + my_device = NULL; + + delay(CONNECT_WAIT); + + int deciseconds_till_reconnect_notice = 50; // notice after 5 seconds + while (my_device == NULL) { + delay(100); + my_device = micronucleus_connect(fast_mode); + deciseconds_till_reconnect_notice -= 1; + + if (deciseconds_till_reconnect_notice == 0) { + printf(">> (!) Automatic reconnection not working. Unplug and reconnect\n"); + printf(" device usb connector, or reset it some other way to continue.\n"); + } + } + + printf(">> Reconnected! Continuing upload sequence...\n"); + + } else if (res != 0) { + printf(">> Flash erase error %d has occured ...\n", res); + printf(">> Please unplug the device and restart the program.\n"); + return EXIT_FAILURE; + } + printProgress(1.0); + + if (!erase_only) { + printf("> Starting to upload ...\n"); + setProgressData("writing", 5); + res = micronucleus_writeFlash(my_device, endAddress, dataBuffer, printProgress); + if (res != 0) { + printf(">> Flash write error %d has occured ...\n", res); + printf(">> Please unplug the device and restart the program.\n"); + return EXIT_FAILURE; + } + } + + if (run) { + printf("> Starting the user app ...\n"); + setProgressData("running", 6); + printProgress(0.0); + + res = micronucleus_startApp(my_device); + + if (res != 0) { + printf(">> Run error %d has occured ...\n", res); + printf(">> Please unplug the device and restart the program. \n"); + return EXIT_FAILURE; + } + + printProgress(1.0); + } + + printf(">> Micronucleus done. Thank you!\n"); + + return EXIT_SUCCESS; +} +/******************************************************************************/ + +/******************************************************************************/ +static void printProgress(float progress) { + static int last_step; + static int last_integer_total_progress; + + if (dump_progress) { + printf("{status:\"%s\",step:%d,steps:%d,progress:%f}\n", progress_friendly_name, progress_step, progress_total_steps, progress); + } else { + if (last_step == progress_step && use_ansi) { + #ifndef WIN + printf("\033[1F\033[2K"); // move cursor to previous line and erase last update in this progress sequence + #else + printf("\r"); // return carriage to start of line so we can type over existing text + #endif + } + + float total_progress = ((float) progress_step - 1.0f) / (float) progress_total_steps; + total_progress += progress / (float) progress_total_steps; + int integer_total_progress = total_progress * 100.0f; + + if (use_ansi || integer_total_progress >= last_integer_total_progress + 5) { + printf("%s: %d%% complete\n", progress_friendly_name, integer_total_progress); + last_integer_total_progress = integer_total_progress; + } + } + + last_step = progress_step; +} + +static void setProgressData(char* friendly, int step) { + progress_friendly_name = friendly; + progress_step = step; +} +/******************************************************************************/ + +/******************************************************************************/ +static int parseUntilColon(FILE *file_pointer) { + int character; + + do { + character = getc(file_pointer); + } while(character != ':' && character != EOF); + + return character; +} +/******************************************************************************/ + +/******************************************************************************/ +static int parseHex(FILE *file_pointer, int num_digits) { + int iter; + char temp[9]; + + for(iter = 0; iter < num_digits; iter++) { + temp[iter] = getc(file_pointer); + } + temp[iter] = 0; + + return strtol(temp, NULL, 16); +} +/******************************************************************************/ + +/******************************************************************************/ +static int parseIntelHex(char *hexfile, unsigned char *buffer, int *startAddr, int *endAddr) { + int address, base, d, segment, i, lineLen, sum; + FILE *input; + + input = strcmp(hexfile, "-") == 0 ? stdin : fopen(hexfile, "r"); + if (input == NULL) { + printf("> Error opening %s: %s\n", hexfile, strerror(errno)); + return 1; + } + + while (parseUntilColon(input) == ':') { + sum = 0; + sum += lineLen = parseHex(input, 2); + base = address = parseHex(input, 4); + sum += address >> 8; + sum += address; + sum += segment = parseHex(input, 2); /* segment value? */ + if (segment != 0) { /* ignore lines where this byte is not 0 */ + continue; + } + + for (i = 0; i < lineLen; i++) { + d = parseHex(input, 2); + buffer[address++] = d; + sum += d; + } + + sum += parseHex(input, 2); + if ((sum & 0xff) != 0) { + printf("> Warning: Checksum error between address 0x%x and 0x%x\n", base, address); + } + + if(*startAddr > base) { + *startAddr = base; + } + if(*endAddr < address) { + *endAddr = address; + } + } + + fclose(input); + return 0; +} +/******************************************************************************/ + +/******************************************************************************/ +static int parseRaw(char *filename, unsigned char *data_buffer, int *start_address, int *end_address) { + FILE *input; + + input = strcmp(filename, "-") == 0 ? stdin : fopen(filename, "r"); + + if (input == NULL) { + printf("> Error reading %s: %s\n", filename, strerror(errno)); + return 1; + } + + *start_address = 0; + *end_address = 0; + + // read in bytes from file + int byte = 0; + while (1) { + byte = getc(input); + if (byte == EOF) break; + + *data_buffer = byte; + data_buffer += 1; + *end_address += 1; + } + + fclose(input); + return 0; +} +/******************************************************************************/ diff --git a/sparkfun/tiny/libraries/EEPROM/EEPROM.h b/sparkfun/tiny/libraries/EEPROM/EEPROM.h new file mode 100644 index 00000000..49f4949c --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/EEPROM.h @@ -0,0 +1,146 @@ +/* + EEPROM.h - EEPROM library + Original Copyright (c) 2006 David A. Mellis. All right reserved. + New version by Christopher Andrews 2015. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EEPROM_h +#define EEPROM_h + +#include +#include +#include + +/*** + EERef class. + + This object references an EEPROM cell. + Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. + This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. +***/ + +struct EERef{ + + EERef( const int index ) + : index( index ) {} + + //Access/read members. + uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); } + operator uint8_t() const { return **this; } + + //Assignment/write members. + EERef &operator=( const EERef &ref ) { return *this = *ref; } + EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; } + EERef &operator +=( uint8_t in ) { return *this = **this + in; } + EERef &operator -=( uint8_t in ) { return *this = **this - in; } + EERef &operator *=( uint8_t in ) { return *this = **this * in; } + EERef &operator /=( uint8_t in ) { return *this = **this / in; } + EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; } + EERef &operator %=( uint8_t in ) { return *this = **this % in; } + EERef &operator &=( uint8_t in ) { return *this = **this & in; } + EERef &operator |=( uint8_t in ) { return *this = **this | in; } + EERef &operator <<=( uint8_t in ) { return *this = **this << in; } + EERef &operator >>=( uint8_t in ) { return *this = **this >> in; } + + EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; } + + /** Prefix increment/decrement **/ + EERef& operator++() { return *this += 1; } + EERef& operator--() { return *this -= 1; } + + /** Postfix increment/decrement **/ + uint8_t operator++ (int){ + uint8_t ret = **this; + return ++(*this), ret; + } + + uint8_t operator-- (int){ + uint8_t ret = **this; + return --(*this), ret; + } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPtr class. + + This object is a bidirectional pointer to EEPROM cells represented by EERef objects. + Just like a normal pointer type, this can be dereferenced and repositioned using + increment/decrement operators. +***/ + +struct EEPtr{ + + EEPtr( const int index ) + : index( index ) {} + + operator int() const { return index; } + EEPtr &operator=( int in ) { return index = in, *this; } + + //Iterator functionality. + bool operator!=( const EEPtr &ptr ) { return index != ptr.index; } + EERef operator*() { return index; } + + /** Prefix & Postfix increment/decrement **/ + EEPtr& operator++() { return ++index, *this; } + EEPtr& operator--() { return --index, *this; } + EEPtr operator++ (int) { return index++; } + EEPtr operator-- (int) { return index--; } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPROMClass class. + + This object represents the entire EEPROM space. + It wraps the functionality of EEPtr and EERef into a basic interface. + This class is also 100% backwards compatible with earlier Arduino core releases. +***/ + +struct EEPROMClass{ + + //Basic user access methods. + EERef operator[]( const int idx ) { return idx; } + uint8_t read( int idx ) { return EERef( idx ); } + void write( int idx, uint8_t val ) { (EERef( idx )) = val; } + void update( int idx, uint8_t val ) { EERef( idx ).update( val ); } + + //STL and C++11 iteration capability. + EEPtr begin() { return 0x00; } + EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. + uint16_t length() { return E2END + 1; } + + //Functionality to 'get' and 'put' objects to and from EEPROM. + template< typename T > T &get( int idx, T &t ){ + EEPtr e = idx; + uint8_t *ptr = (uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e; + return t; + } + + template< typename T > const T &put( int idx, const T &t ){ + EEPtr e = idx; + const uint8_t *ptr = (const uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ ); + return t; + } +}; + +static EEPROMClass EEPROM; +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/EEPROM/README.md b/sparkfun/tiny/libraries/EEPROM/README.md new file mode 100644 index 00000000..a6241361 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/README.md @@ -0,0 +1,139 @@ +## **EEPROM Library V2.0** for Arduino + +**Written by:** _Christopher Andrews_. + +### **What is the EEPROM library.** + +Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips. + +### **How to use it** +The EEPROM library is included in your IDE download. To add its functionality to your sketch you'll need to reference the library header file. You do this by adding an include directive to the top of your sketch. + +```Arduino +#include + +void setup(){ + +} + +void loop(){ + +} + +``` + +The library provides a global variable named `EEPROM`, you use this variable to access the library functions. The methods provided in the EEPROM class are listed below. + +You can view all the examples [here](examples/). + +### **Library functions** + +#### **`EEPROM.read( address )`** [[_example_]](examples/eeprom_read/eeprom_read.ino) + +This function allows you to read a single byte of data from the eeprom. +Its only parameter is an `int` which should be set to the address you wish to read. + +The function returns an `unsigned char` containing the value read. + +#### **`EEPROM.write( address, value )`** [[_example_]](examples/eeprom_write/eeprom_write.ino) + +The `write()` method allows you to write a single byte of data to the EEPROM. +Two parameters are needed. The first is an `int` containing the address that is to be written, and the second is a the data to be written (`unsigned char`). + +This function does not return any value. + +#### **`EEPROM.update( address, value )`** [[_example_]](examples/eeprom_update/eeprom_update.ino) + +This function is similar to `EEPROM.write()` however this method will only write data if the cell contents pointed to by `address` is different to `value`. This method can help prevent unnecessary wear on the EEPROM cells. + +This function does not return any value. + +#### **`EEPROM.get( address, object )`** [[_example_]](examples/eeprom_get/eeprom_get.ino) + +This function will retrieve any object from the EEPROM. +Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to read. + +This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience. + +#### **`EEPROM.put( address, object )`** [[_example_]](examples/eeprom_put/eeprom_put.ino) + +This function will write any object to the EEPROM. +Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to write. + +This function uses the _update_ method to write its data, and therefore only rewrites changed cells. + +This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience. + +#### **Subscript operator: `EEPROM[address]`** [[_example_]](examples/eeprom_crc/eeprom_crc.ino) + +This operator allows using the identifier `EEPROM` like an array. +EEPROM cells can be read _and_ **_written_** directly using this method. + +This operator returns a reference to the EEPROM cell. + +```c++ +unsigned char val; + +//Read first EEPROM cell. +val = EEPROM[ 0 ]; + +//Write first EEPROM cell. +EEPROM[ 0 ] = val; + +//Compare contents +if( val == EEPROM[ 0 ] ){ + //Do something... +} +``` + +#### **`EEPROM.length()`** + +This function returns an `unsigned int` containing the number of cells in the EEPROM. + +--- + +### **Advanced features** + +This library uses a component based approach to provide its functionality. This means you can also use these components to design a customized approach. Two background classes are available for use: `EERef` & `EEPtr`. + +#### **`EERef` class** + +This object references an EEPROM cell. +Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. +This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. + +```C++ +EERef ref = EEPROM[ 10 ]; //Create a reference to 11th cell. + +ref = 4; //write to EEPROM cell. + +unsigned char val = ref; //Read referenced cell. +``` + +#### **`EEPtr` class** + +This object is a bidirectional pointer to EEPROM cells represented by `EERef` objects. +Just like a normal pointer type, this type can be dereferenced and repositioned using +increment/decrement operators. + +```C++ +EEPtr ptr = 10; //Create a pointer to 11th cell. + +*ptr = 4; //dereference and write to EEPROM cell. + +unsigned char val = *ptr; //dereference and read. + +ptr++; //Move to next EEPROM cell. +``` + +#### **`EEPROM.begin()`** + +This function returns an `EEPtr` pointing to the first cell in the EEPROM. +This is useful for STL objects, custom iteration and C++11 style ranged for loops. + +#### **`EEPROM.end()`** + +This function returns an `EEPtr` pointing at the location after the last EEPROM cell. +Used with `begin()` to provide custom iteration. + +**Note:** The `EEPtr` returned is invalid as it is out of range. Infact the hardware causes wrapping of the address (overflow) and `EEPROM.end()` actually references the first EEPROM cell. diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino new file mode 100644 index 00000000..8b5121c8 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino @@ -0,0 +1,39 @@ +/* + * EEPROM Clear + * + * Sets all of the bytes of the EEPROM to 0. + * Please see eeprom_iteration for a more in depth + * look at how to traverse the EEPROM. + * + * This example code is in the public domain. + */ + +#include + +void setup() { + // initialize the LED pin as an output. + pinMode(13, OUTPUT); + + /*** + Iterate through each byte of the EEPROM storage. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + + for (int i = 0 ; i < EEPROM.length() ; i++) { + EEPROM.write(i, 0); + } + + // turn the LED on when we're done + digitalWrite(13, HIGH); +} + +void loop() { + /** Empty loop. **/ +} diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino new file mode 100644 index 00000000..c6db85c3 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino @@ -0,0 +1,52 @@ +/*** + Written by Christopher Andrews. + CRC algorithm generated by pycrc, MIT licence ( https://github.com/tpircher/pycrc ). + + A CRC is a simple way of checking whether data has changed or become corrupted. + This example calculates a CRC value directly on the EEPROM values. + The purpose of this example is to highlight how the EEPROM object can be used just like an array. +***/ + +#include +#include + +void setup() { + + //Start serial + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + //Print length of data to run CRC on. + Serial.print("EEPROM length: "); + Serial.println(EEPROM.length()); + + //Print the result of calling eeprom_crc() + Serial.print("CRC32 of EEPROM data: 0x"); + Serial.println(eeprom_crc(), HEX); + Serial.print("\n\nDone!"); +} + +void loop() { + /* Empty loop */ +} + +unsigned long eeprom_crc(void) { + + const unsigned long crc_table[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + + unsigned long crc = ~0L; + + for (int index = 0 ; index < EEPROM.length() ; ++index) { + crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4); + crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4); + crc = ~crc; + } + return crc; +} diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino new file mode 100644 index 00000000..a07cee7c --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino @@ -0,0 +1,68 @@ +/*** + eeprom_get example. + + This shows how to use the EEPROM.get() method. + + To pre-set the EEPROM data, run the example sketch eeprom_put. + This sketch will run without it, however, the values shown + will be shown from what ever is already on the EEPROM. + + This may cause the serial object to print out a large string + of garbage if there is no null character inside one of the strings + loaded. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +void setup() { + + float f = 0.00f; //Variable to store data read from EEPROM. + int eeAddress = 0; //EEPROM address to start reading from + + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + Serial.print("Read float from EEPROM: "); + + //Get the float data from the EEPROM at position 'eeAddress' + EEPROM.get(eeAddress, f); + Serial.println(f, 3); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float. + + /*** + As get also returns a reference to 'f', you can use it inline. + E.g: Serial.print( EEPROM.get( eeAddress, f ) ); + ***/ + + /*** + Get can be used with custom structures too. + I have separated this into an extra function. + ***/ + + secondTest(); //Run the next test. +} + +struct MyObject { + float field1; + byte field2; + char name[10]; +}; + +void secondTest() { + int eeAddress = sizeof(float); //Move address to the next byte after float 'f'. + + MyObject customVar; //Variable to store custom object read from EEPROM. + EEPROM.get(eeAddress, customVar); + + Serial.println("Read custom object from EEPROM: "); + Serial.println(customVar.field1); + Serial.println(customVar.field2); + Serial.println(customVar.name); +} + +void loop() { + /* Empty loop */ +} diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino new file mode 100644 index 00000000..3673b472 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino @@ -0,0 +1,57 @@ +/*** + eeprom_iteration example. + + A set of example snippets highlighting the + simplest methods for traversing the EEPROM. + + Running this sketch is not necessary, this is + simply highlighting certain programming methods. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +void setup() { + + /*** + Iterate the EEPROM using a for loop. + ***/ + + for (int index = 0 ; index < EEPROM.length() ; index++) { + + //Add one to each cell in the EEPROM + EEPROM[ index ] += 1; + } + + /*** + Iterate the EEPROM using a while loop. + ***/ + + int index = 0; + + while (index < EEPROM.length()) { + + //Add one to each cell in the EEPROM + EEPROM[ index ] += 1; + index++; + } + + /*** + Iterate the EEPROM using a do-while loop. + ***/ + + int idx = 0; //Used 'idx' to avoid name conflict with 'index' above. + + do { + + //Add one to each cell in the EEPROM + EEPROM[ idx ] += 1; + idx++; + } while (idx < EEPROM.length()); + + +} //End of setup function. + +void loop() {} \ No newline at end of file diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino new file mode 100644 index 00000000..c1ba0a57 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino @@ -0,0 +1,58 @@ +/*** + eeprom_put example. + + This shows how to use the EEPROM.put() method. + Also, this sketch will pre-set the EEPROM data for the + example sketch eeprom_get. + + Note, unlike the single byte version EEPROM.write(), + the put method will use update semantics. As in a byte + will only be written to the EEPROM if the data is actually + different. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +struct MyObject { + float field1; + byte field2; + char name[10]; +}; + +void setup() { + + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + float f = 123.456f; //Variable to store in EEPROM. + int eeAddress = 0; //Location we want the data to be put. + + + //One simple call, with the address first and the object second. + EEPROM.put(eeAddress, f); + + Serial.println("Written float data type!"); + + /** Put is designed for use with custom structures also. **/ + + //Data to store. + MyObject customVar = { + 3.14f, + 65, + "Working!" + }; + + eeAddress += sizeof(float); //Move address to the next byte after float 'f'. + + EEPROM.put(eeAddress, customVar); + Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!"); +} + +void loop() { + /* Empty loop */ +} diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino new file mode 100644 index 00000000..a8a3510d --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino @@ -0,0 +1,56 @@ +/* + * EEPROM Read + * + * Reads the value of each byte of the EEPROM and prints it + * to the computer. + * This example code is in the public domain. + */ + +#include + +// start reading from the first byte (address 0) of the EEPROM +int address = 0; +byte value; + +void setup() { + // initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } +} + +void loop() { + // read a byte from the current address of the EEPROM + value = EEPROM.read(address); + + Serial.print(address); + Serial.print("\t"); + Serial.print(value, DEC); + Serial.println(); + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + address = address + 1; + if (address == EEPROM.length()) { + address = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++address &= EEPROM.length() - 1; + ***/ + + delay(500); +} diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino new file mode 100644 index 00000000..5e3db5b4 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino @@ -0,0 +1,71 @@ +/*** + EEPROM Update method + + Stores values read from analog input 0 into the EEPROM. + These values will stay in the EEPROM when the board is + turned off and may be retrieved later by another sketch. + + If a value has not changed in the EEPROM, it is not overwritten + which would reduce the life span of the EEPROM unnecessarily. + + Released using MIT licence. + ***/ + +#include + +/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ +int address = 0; + +void setup() { + /** EMpty setup **/ +} + +void loop() { + /*** + need to divide by 4 because analog inputs range from + 0 to 1023 and each byte of the EEPROM can only hold a + value from 0 to 255. + ***/ + int val = analogRead(0) / 4; + + /*** + Update the particular EEPROM cell. + these values will remain there when the board is + turned off. + ***/ + EEPROM.update(address, val); + + /*** + The function EEPROM.update(address, val) is equivalent to the following: + + if( EEPROM.read(address) != val ){ + EEPROM.write(address, val); + } + ***/ + + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + address = address + 1; + if (address == EEPROM.length()) { + address = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++address &= EEPROM.length() - 1; + ***/ + + delay(100); +} diff --git a/sparkfun/tiny/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino new file mode 100644 index 00000000..f9bea641 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino @@ -0,0 +1,60 @@ +/* + * EEPROM Write + * + * Stores values read from analog input 0 into the EEPROM. + * These values will stay in the EEPROM when the board is + * turned off and may be retrieved later by another sketch. + */ + +#include + +/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ +int addr = 0; + +void setup() { + /** Empty setup. **/ +} + +void loop() { + /*** + Need to divide by 4 because analog inputs range from + 0 to 1023 and each byte of the EEPROM can only hold a + value from 0 to 255. + ***/ + + int val = analogRead(0) / 4; + + /*** + Write the value to the appropriate byte of the EEPROM. + these values will remain there when the board is + turned off. + ***/ + + EEPROM.write(addr, val); + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + addr = addr + 1; + if (addr == EEPROM.length()) { + addr = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++addr &= EEPROM.length() - 1; + ***/ + + + delay(100); +} diff --git a/sparkfun/tiny/libraries/EEPROM/keywords.txt b/sparkfun/tiny/libraries/EEPROM/keywords.txt new file mode 100644 index 00000000..2cabc0b0 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/keywords.txt @@ -0,0 +1,22 @@ +####################################### +# Syntax Coloring Map For EEPROM +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +EEPROM KEYWORD1 +EERef KEYWORD1 +EEPtr KEYWORD2 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +update KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/sparkfun/tiny/libraries/EEPROM/library.properties b/sparkfun/tiny/libraries/EEPROM/library.properties new file mode 100644 index 00000000..dfa46cd4 --- /dev/null +++ b/sparkfun/tiny/libraries/EEPROM/library.properties @@ -0,0 +1,10 @@ +name=EEPROM +version=2.0 +author=Arduino, Christopher Andrews +maintainer=Arduino +sentence=Enables reading and writing to the permanent board storage. For all Arduino boards BUT Arduino DUE and Arduino ZERO. +paragraph= +category=Data Storage +url=http://www.arduino.cc/en/Reference/EEPROM +architectures=avr + diff --git a/sparkfun/tiny/libraries/SPI/SPI.cpp b/sparkfun/tiny/libraries/SPI/SPI.cpp new file mode 100644 index 00000000..50dad386 --- /dev/null +++ b/sparkfun/tiny/libraries/SPI/SPI.cpp @@ -0,0 +1,564 @@ +/*-------------------------------------------------------------------------* + * tinySPI.h - Arduino hardware SPI master library for ATtiny24/44/84, * + * ATtiny25/45/85, and Attiny2313/4313. * + * * + * Original version of tinyISP by Jack Christensen 24Oct2013 * + * * + * Added support for Attiny24/25, and Attiny2313/4313 * + * by Leonardo Miliani 28Nov2014 * + * * + * CC BY-SA-NC: * + * This work is licensed under the Creative Commons Attribution- * + * ShareAlike- Not Commercial 4.0 Unported License. To view a copy of this * + * license, visit * + * http://creativecommons.org/licenses/by-sa/4.0/ or send a * + * letter to Creative Commons, 171 Second Street, Suite 300, * + * San Francisco, California, 94105, USA. * + *-------------------------------------------------------------------------*/ + +#include "SPI.h" + + +#ifdef SPDR //Then we have hardware SPI, let's use it: + + +#include "SPI.h" + +SPIClass SPI; + +uint8_t SPIClass::initialized = 0; +uint8_t SPIClass::interruptMode = 0; +uint8_t SPIClass::interruptMask = 0; +uint8_t SPIClass::interruptSave = 0; +#ifdef SPI_TRANSACTION_MISMATCH_LED +uint8_t SPIClass::inTransactionFlag = 0; +#endif + +void SPIClass::begin() +{ + uint8_t sreg = SREG; + noInterrupts(); // Protect from a scheduler and prevent transactionBegin + if (!initialized) { + + #ifdef REMAP + uint8_t SS_pin=0; + + if (REMAP & 1< + +tinySPI::tinySPI() +{ +} + +USI_impl::ClockOut tinySPI::clockoutfn = 0; +uint8_t tinySPI::delay = 0; +uint8_t tinySPI::msb1st = MSBFIRST; + +uint8_t tinySPI::interruptMode = 0; +uint8_t tinySPI::interruptMask = 0; +uint8_t tinySPI::interruptSave = 0; + +void tinySPI::begin(void) +{ + USICR &= ~(_BV(USISIE) | _BV(USIOIE) | _BV(USIWM1)); + USICR |= _BV(USIWM0) | _BV(USICS1) | _BV(USICLK); + USI_SCK_PORT |= _BV(USCK_DD_PIN); //set the USCK pin as output + USI_DDR_PORT |= _BV(DO_DD_PIN); //set the DO pin as output + USI_DDR_PORT &= ~_BV(DI_DD_PIN); //set the DI pin as input + applySettings(SPISettings()); +} + +void tinySPI::setDataMode(uint8_t spiDataMode) +{ + if (spiDataMode == SPI_MODE1) { + USICR |= _BV(USICS0); + } else { + USICR &= ~_BV(USICS0); + } + if (spiDataMode == SPI_MODE2 || spiDataMode == SPI_MODE3) { + digitalWrite(SCK, HIGH); + } else { + digitalWrite(SCK, LOW); + } +} + +USI_impl::ClockOut USI_impl::dispatchClockout_slow(uint8_t div, uint8_t* delay) +{ + return dispatchClockout(div, delay); +} + +static byte reverse (byte x){ + byte result; + asm("mov __tmp_reg__, %[in] \n\t" + "lsl __tmp_reg__ \n\t" /* shift out high bit to carry */ + "ror %[out] \n\t" /* rotate carry __tmp_reg__to low bit (eventually) */ + "lsl __tmp_reg__ \n\t" /* 2 */ + "ror %[out] \n\t" + "lsl __tmp_reg__ \n\t" /* 3 */ + "ror %[out] \n\t" + "lsl __tmp_reg__ \n\t" /* 4 */ + "ror %[out] \n\t" + "lsl __tmp_reg__ \n\t" /* 5 */ + "ror %[out] \n\t" + "lsl __tmp_reg__ \n\t" /* 6 */ + "ror %[out] \n\t" + "lsl __tmp_reg__ \n\t" /* 7 */ + "ror %[out] \n\t" + "lsl __tmp_reg__ \n\t" /* 8 */ + "ror %[out] \n\t" + : [out] "=r" (result) : [in] "r" (x)); + return(result); +} + +uint8_t USI_impl::clockoutUSI2(uint8_t data, uint8_t) +{ + // Unlike other clockout methods, this one cannot rely on the + // "external" clock source (USICS1) because it is too slow and + // glitches. Instead, it uses software strobe explicitly. + uint8_t strobe1 = _BV(USIWM0) | _BV(USITC); + uint8_t strobe2 = _BV(USIWM0) | _BV(USITC) | _BV(USICLK); + uint8_t usicr = USICR; + bool mode1 = usicr & _BV(USICS0); + USISR = _BV(USIOIF); //clear counter and counter overflow interrupt flag + USIDR = data; + // Use asm to prevent instruction reordering. + if (!mode1) { + asm volatile("out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + :: [usicr] "I" (_SFR_IO_ADDR(USICR)), + [strobe1] "r" (strobe1), + [strobe2] "r" (strobe2)); + } else { + asm volatile("out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + "out %[usicr], %[strobe1] \n\t" + "out %[usicr], %[strobe2] \n\t" + :: [usicr] "I" (_SFR_IO_ADDR(USICR)), + [strobe1] "r" (strobe1), + [strobe2] "r" (strobe2)); + } + uint8_t retval = USIDR; + USICR = usicr; + return retval; +} + +__attribute__((optimize (3, "unroll-all-loops"))) +uint8_t USI_impl::clockoutUSI4(uint8_t data, uint8_t) +{ + USISR = _BV(USIOIF); + USIDR = data; + for (byte i = 0; i < 16; ++i) { + USICR |= _BV(USITC); // compiles to sbi, two cycles + } + return USIDR; +} + +__attribute__((optimize (3, "unroll-all-loops"))) +uint8_t USI_impl::clockoutUSI8(uint8_t data, uint8_t) +{ + USISR = _BV(USIOIF); + USIDR = data; + for (byte i = 0; i < 16; ++i) { + USICR |= _BV(USITC); // compiles to sbi, two cycles + USICR &= ~_BV(USITC); // compiles to cbi, two cycles, effectively nop + } + return USIDR; +} + +__attribute__((optimize ("Os"))) +uint8_t USI_impl::clockoutUSI(uint8_t data, uint8_t delay) +{ + uint8_t tmp = USICR | _BV(USITC); + USISR = _BV(USIOIF); + USIDR = data; + for (byte i = 0; i < 16; ++i) { + USICR = tmp; // compiles to out, one cycle + _delay_loop_1(delay); // delay calculated by SPISettings. + } + return USIDR; +} + +uint8_t tinySPI::transfer(uint8_t spiData) +{ + if (msb1st) { + return clockoutfn(spiData, delay); + } else { + return reverse(clockoutfn(reverse(spiData), delay)); + } +} + +uint16_t tinySPI::transfer16(uint16_t data) +{ + union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } tmp; + tmp.val = data; + if (msb1st) { + tmp.msb = clockoutfn(tmp.msb, delay); + tmp.lsb = clockoutfn(tmp.lsb, delay); + } else { + tmp.lsb = reverse(clockoutfn(reverse(tmp.lsb), delay)); + tmp.msb = reverse(clockoutfn(reverse(tmp.msb), delay)); + } + return tmp.val; +} + +void tinySPI::transfer(void* _buf, size_t count) { + uint8_t* buf = (uint8_t*)_buf; + if (!msb1st) { + for (uint8_t i = 0; i < count; ++i) { + buf[i] = reverse(buf[i]); + } + } + for (uint8_t i = 0; i < count; ++i) { + buf[i] = clockoutfn(buf[i], delay); + } + if (!msb1st) { + for (uint8_t i = 0; i < count; ++i) { + buf[i] = reverse(buf[i]); + } + } +} + +void tinySPI::applySettings(SPISettings settings) { + USICR = settings.usicr; + msb1st = settings.msb1st ; + delay = settings.delay; + clockoutfn = settings.clockoutfn; + if (settings.cpol) { + digitalWrite(SCK, HIGH); + } else { + digitalWrite(SCK, LOW); + } +} + +void tinySPI::beginTransaction(SPISettings settings) { + if (interruptMode > 0) { + uint8_t sreg = SREG; + noInterrupts(); + + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + interruptSave = SPI_AVR_EIMSK; + SPI_AVR_EIMSK &= ~interruptMask; + SREG = sreg; + } else + #endif + { + interruptSave = sreg; + } + } + applySettings(settings); + } + +void tinySPI::endTransaction(void) { + if (interruptMode > 0) { + #ifdef SPI_AVR_EIMSK + uint8_t sreg = SREG; + #endif + noInterrupts(); + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + SPI_AVR_EIMSK = interruptSave; + SREG = sreg; + } else + #endif + { + SREG = interruptSave; + } + } +} +#ifdef INT0 +#define SPI_INT0_MASK (1< +#include +#include +#include + +#ifndef LSBFIRST +#define LSBFIRST 0 +#endif +#ifndef MSBFIRST +#define MSBFIRST 1 +#endif + +// define SPI_AVR_EIMSK for AVR boards with external interrupt pins +#if defined(EIMSK) + #define SPI_AVR_EIMSK EIMSK +#elif defined(GICR) + #define SPI_AVR_EIMSK GICR +#elif defined(GIMSK) + #define SPI_AVR_EIMSK GIMSK +#endif + + +#ifdef SPDR //Then we have hardware SPI, let's use it: + +// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), +// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method +#define SPI_HAS_NOTUSINGINTERRUPT 1 + +// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. +// This way when there is a bug fix you can check this define to alert users +// of your code if it uses better version of this library. +// This also implies everything that SPI_HAS_TRANSACTION as documented above is +// available too. +#define SPI_ATOMIC_VERSION 1 + +// Uncomment this line to add detection of mismatched begin/end transactions. +// A mismatch occurs if other libraries fail to use SPI.endTransaction() for +// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn +// on if any mismatch is ever detected. +//#define SPI_TRANSACTION_MISMATCH_LED 5 + +#ifndef LSBFIRST +#define LSBFIRST 0 +#endif +#ifndef MSBFIRST +#define MSBFIRST 1 +#endif + +#define SPI_CLOCK_DIV4 0x00 +#define SPI_CLOCK_DIV16 0x01 +#define SPI_CLOCK_DIV64 0x02 +#define SPI_CLOCK_DIV128 0x03 +#define SPI_CLOCK_DIV2 0x04 +#define SPI_CLOCK_DIV8 0x05 +#define SPI_CLOCK_DIV32 0x06 + +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x04 +#define SPI_MODE2 0x08 +#define SPI_MODE3 0x0C + +#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR +#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR +#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR + +class SPISettings { +public: + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode); + } else { + init_MightInline(clock, bitOrder, dataMode); + } + } + SPISettings() { + init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); + } +private: + void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + __attribute__((__always_inline__)) { + // Clock settings are defined as follows. Note that this shows SPI2X + // inverted, so the bits form increasing numbers. Also note that + // fosc/64 appears twice + // SPR1 SPR0 ~SPI2X Freq + // 0 0 0 fosc/2 + // 0 0 1 fosc/4 + // 0 1 0 fosc/8 + // 0 1 1 fosc/16 + // 1 0 0 fosc/32 + // 1 0 1 fosc/64 + // 1 1 0 fosc/64 + // 1 1 1 fosc/128 + + // We find the fastest clock that is less than or equal to the + // given clock rate. The clock divider that results in clock_setting + // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the + // slowest (128 == 2 ^^ 7, so clock_div = 6). + uint8_t clockDiv; + + // When the clock is known at compiletime, use this if-then-else + // cascade, which the compiler knows how to completely optimize + // away. When clock is not known, use a loop instead, which generates + // shorter code. + if (__builtin_constant_p(clock)) { + if (clock >= F_CPU / 2) { + clockDiv = 0; + } else if (clock >= F_CPU / 4) { + clockDiv = 1; + } else if (clock >= F_CPU / 8) { + clockDiv = 2; + } else if (clock >= F_CPU / 16) { + clockDiv = 3; + } else if (clock >= F_CPU / 32) { + clockDiv = 4; + } else if (clock >= F_CPU / 64) { + clockDiv = 5; + } else { + clockDiv = 6; + } + } else { + uint32_t clockSetting = F_CPU / 2; + clockDiv = 0; + while (clockDiv < 6 && clock < clockSetting) { + clockSetting /= 2; + clockDiv++; + } + } + + // Compensate for the duplicate fosc/64 + if (clockDiv == 6) + clockDiv = 7; + + // Invert the SPI2X bit + clockDiv ^= 0x1; + + // Pack into the SPISettings class + spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) | + (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK); + spsr = clockDiv & SPI_2XCLOCK_MASK; + } + uint8_t spcr; + uint8_t spsr; + friend class SPIClass; +}; + + +class SPIClass { +public: + // Initialize the SPI library + static void begin(); + + // If SPI is used from within an interrupt, this function registers + // that interrupt with the SPI library, so beginTransaction() can + // prevent conflicts. The input interruptNumber is the number used + // with attachInterrupt. If SPI is used from a different interrupt + // (eg, a timer), interruptNumber should be 255. + static void usingInterrupt(uint8_t interruptNumber); + // And this does the opposite. + static void notUsingInterrupt(uint8_t interruptNumber); + // Note: the usingInterrupt and notUsingInterrupt functions should + // not to be called from ISR context or inside a transaction. + // For details see: + // https://github.com/arduino/Arduino/pull/2381 + // https://github.com/arduino/Arduino/pull/2449 + + // Before using SPI.transfer() or asserting chip select pins, + // this function is used to gain exclusive access to the SPI bus + // and configure the correct settings. + inline static void beginTransaction(SPISettings settings) { + if (interruptMode > 0) { + uint8_t sreg = SREG; + noInterrupts(); + + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + interruptSave = SPI_AVR_EIMSK; + SPI_AVR_EIMSK &= ~interruptMask; + SREG = sreg; + } else + #endif + { + interruptSave = sreg; + } + } + + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 1; + #endif + + SPCR = settings.spcr; + SPSR = settings.spsr; + } + + // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + inline static uint8_t transfer(uint8_t data) { + SPDR = data; + /* + * The following NOP introduces a small delay that can prevent the wait + * loop form iterating when running at the maximum speed. This gives + * about 10% more speed, even if it seems counter-intuitive. At lower + * speeds it is unnoticed. + */ + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; // wait + return SPDR; + } + inline static uint16_t transfer16(uint16_t data) { + union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out; + in.val = data; + if (!(SPCR & _BV(DORD))) { + SPDR = in.msb; + asm volatile("nop"); // See transfer(uint8_t) function + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + } else { + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + SPDR = in.msb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + } + return out.val; + } + inline static void transfer(void *buf, size_t count) { + if (count == 0) return; + uint8_t *p = (uint8_t *)buf; + SPDR = *p; + while (--count > 0) { + uint8_t out = *(p + 1); + while (!(SPSR & _BV(SPIF))) ; + uint8_t in = SPDR; + SPDR = out; + *p++ = in; + } + while (!(SPSR & _BV(SPIF))) ; + *p = SPDR; + } + // After performing a group of transfers and releasing the chip select + // signal, this function allows others to access the SPI bus + inline static void endTransaction(void) { + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (!inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 0; + #endif + + if (interruptMode > 0) { + #ifdef SPI_AVR_EIMSK + uint8_t sreg = SREG; + #endif + noInterrupts(); + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + SPI_AVR_EIMSK = interruptSave; + SREG = sreg; + } else + #endif + { + SREG = interruptSave; + } + } + } + + // Disable the SPI bus + static void end(); + + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setBitOrder(uint8_t bitOrder) { + if (bitOrder == LSBFIRST) SPCR |= _BV(DORD); + else SPCR &= ~(_BV(DORD)); + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setDataMode(uint8_t dataMode) { + SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode; + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setClockDivider(uint8_t clockDiv) { + SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK); + SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK); + } + // These undocumented functions should not be used. SPI.transfer() + // polls the hardware flag which is automatically cleared as the + // AVR responds to SPI's interrupt + inline static void attachInterrupt() { SPCR |= _BV(SPIE); } + inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); } + +private: + static uint8_t initialized; + static uint8_t interruptMode; // 0=none, 1=mask, 2=global + static uint8_t interruptMask; // which interrupts to mask + static uint8_t interruptSave; // temp storage, to restore state + #ifdef SPI_TRANSACTION_MISMATCH_LED + static uint8_t inTransactionFlag; + #endif +}; + +extern SPIClass SPI; + + +#else + +#ifdef USICR //if we have a USI instead, use that + +//SPI data modes +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x01 +#define SPI_MODE2 0x02 +#define SPI_MODE3 0x03 + +#define SPI_CLOCK_DIV2 2 +#define SPI_CLOCK_DIV4 4 +#define SPI_CLOCK_DIV8 8 +#define SPI_CLOCK_DIV16 16 +#define SPI_CLOCK_DIV32 32 +#define SPI_CLOCK_DIV64 64 +#define SPI_CLOCK_DIV128 128 + +//This implementation does have transaction: +#define SPI_HAS_TRANSACTION 1 +#define SPI_HAS_NOTUSINGINTERRUPT 1 +// Settings for default USI based SPI bus for different chips + +namespace USI_impl { + using ClockOut = uint8_t (*)(uint8_t,uint8_t); + uint8_t clockoutUSI(uint8_t data, uint8_t delay); + uint8_t clockoutUSI2(uint8_t data, uint8_t delay); + uint8_t clockoutUSI4(uint8_t data, uint8_t delay); + uint8_t clockoutUSI8(uint8_t data, uint8_t delay); + + __attribute__((always_inline)) + inline ClockOut dispatchClockout(uint8_t div, uint8_t* delay) + { + *delay = 0; + if (div <= 2) { + return clockoutUSI2; + } else if (div <= 4) { + return clockoutUSI4; + } else if (div <= 8) { + return clockoutUSI8; + } else { + // Slow mode, convert clockdiv into delay loop count. + // Calculated inline to allow compile-time evaluation. + *delay = ((uint16_t)div*100 - 780) / 59; + // Round it to nearest integer. + *delay = *delay < 10 ? 1 : (*delay + 5) / 10; + return clockoutUSI; + } + } + + ClockOut dispatchClockout_slow(uint8_t div, uint8_t* delay) + __attribute__((warning("SPI clock is not a runtime constant, increasing code size a lot."))); +} + +class SPISettings { +public: + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + SPISettings() { + init_AlwaysInline(F_CPU / 16, MSBFIRST, SPI_MODE0); + } +private: + void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + __attribute__((always_inline)) { + usicr = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK); + if (dataMode == SPI_MODE1 || dataMode == SPI_MODE3) { + usicr |= _BV(USICS0); + } + msb1st = bitOrder; + cpol = dataMode == SPI_MODE2 || dataMode == SPI_MODE3; + // Round up. + uint8_t div = F_CPU / clock + (F_CPU % clock ? 1 : 0); + if (__builtin_constant_p(clock)) { + clockoutfn = USI_impl::dispatchClockout(div, &delay); + } else { + clockoutfn = USI_impl::dispatchClockout_slow(div, &delay); + } + } + + uint8_t msb1st; + uint8_t cpol; + uint8_t usicr; + uint8_t delay; + USI_impl::ClockOut clockoutfn; + friend class tinySPI; +}; + +class tinySPI +{ + public: + tinySPI(); + static void begin(); + static void beginTransaction(SPISettings settings); + static uint8_t transfer(uint8_t data); + static uint16_t transfer16(uint16_t data); + static void transfer(void *buf, size_t count); + static void endTransaction(void); + static void end(); + + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + static void setBitOrder(uint8_t bitOrder) {msb1st = bitOrder;} + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + static void setDataMode(uint8_t dataMode); + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + static void setClockDivider(uint8_t div) { + if (__builtin_constant_p(div)) { + clockoutfn = USI_impl::dispatchClockout(div, &delay); + } else { + clockoutfn = USI_impl::dispatchClockout_slow(div, &delay); + } + } + + static void usingInterrupt(uint8_t interruptNumber); + static void notUsingInterrupt(uint8_t interruptNumber); + +private: + static void applySettings(SPISettings settings); + + static uint8_t msb1st; + static uint8_t delay; + static USI_impl::ClockOut clockoutfn; + static uint8_t interruptMode; // 0=none, 1=mask, 2=global + static uint8_t interruptMask; // which interrupts to mask + static uint8_t interruptSave; // temp storage, to restore state +}; + +extern tinySPI SPI; + + + +#else +//if no USICR and no TWBR + +#error No supported hardware + +#endif //end if USICR +#endif //end if TWBR +#endif //end of module include guard + + + diff --git a/sparkfun/tiny/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/sparkfun/tiny/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100644 index 00000000..8104fcbc --- /dev/null +++ b/sparkfun/tiny/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,143 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + */ + +// the sensor communicates using SPI, so include the library: +#include + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading +const byte READ = 0b11111100; // SCP1000's read command +const byte WRITE = 0b00000010; // SCP1000's write command + +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +void setup() { + Serial.begin(9600); + + // start the SPI library: + SPI.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + // give the sensor time to set up: + delay(100); +} + +void loop() { + //Select High Resolution Mode + writeRegister(0x03, 0x0A); + + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + float realTemp = (float)tempData / 20.0; + Serial.print("Temp[C]="); + Serial.print(realTemp); + + + //Read the pressure data highest 3 bits: + byte pressure_data_high = readRegister(0x1F, 1); + pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressure_data_low = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4; + + // display the temperature: + Serial.println("\tPressure [Pa]=" + String(pressure)); + } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead ) { + byte inByte = 0; // incoming byte from the SPI + unsigned int result = 0; // result to return + Serial.print(thisRegister, BIN); + Serial.print("\t"); + // SCP1000 expects the register name in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the address and the command into one byte + byte dataToSend = thisRegister & READ; + Serial.println(thisRegister, BIN); + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + SPI.transfer(dataToSend); + // send a value of 0 to read the first byte returned: + result = SPI.transfer(0x00); + // decrement the number of bytes left to read: + bytesToRead--; + // if you still have another byte to read: + if (bytesToRead > 0) { + // shift the first byte left, then get the second byte: + result = result << 8; + inByte = SPI.transfer(0x00); + // combine the byte you just got with the previous one: + result = result | inByte; + // decrement the number of bytes left to read: + bytesToRead--; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return(result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + + // SCP1000 expects the register address in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the register address and the command into one byte: + byte dataToSend = thisRegister | WRITE; + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(dataToSend); //Send register location + SPI.transfer(thisValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + diff --git a/sparkfun/tiny/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/sparkfun/tiny/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino new file mode 100644 index 00000000..b135a74f --- /dev/null +++ b/sparkfun/tiny/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -0,0 +1,71 @@ +/* + Digital Pot Control + + This example controls an Analog Devices AD5206 digital potentiometer. + The AD5206 has 6 potentiometer channels. Each channel's pins are labeled + A - connect this to voltage + W - this is the pot's wiper, which changes when you set it + B - connect this to ground. + + The AD5206 is SPI-compatible,and to command it, you send two bytes, + one with the channel number (0 - 5) and one with the resistance value for the + channel (0 - 255). + + The circuit: + * All A pins of AD5206 connected to +5V + * All B pins of AD5206 connected to ground + * An LED and a 220-ohm resisor in series connected from each W pin to ground + * CS - to digital pin 10 (SS pin) + * SDI - to digital pin 11 (MOSI pin) + * CLK - to digital pin 13 (SCK pin) + + created 10 Aug 2010 + by Tom Igoe + + Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 + +*/ + + +// inslude the SPI library: +#include + + +// set pin 10 as the slave select for the digital pot: +const int slaveSelectPin = 10; + +void setup() { + // set the slaveSelectPin as an output: + pinMode (slaveSelectPin, OUTPUT); + // initialize SPI: + SPI.begin(); +} + +void loop() { + // go through the six channels of the digital pot: + for (int channel = 0; channel < 6; channel++) { + // change the resistance on this channel from min to max: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, level); + delay(10); + } + // wait a second at the top: + delay(100); + // change the resistance on this channel from max to min: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, 255 - level); + delay(10); + } + } + +} + +void digitalPotWrite(int address, int value) { + // take the SS pin low to select the chip: + digitalWrite(slaveSelectPin, LOW); + // send in the address and value via SPI: + SPI.transfer(address); + SPI.transfer(value); + // take the SS pin high to de-select the chip: + digitalWrite(slaveSelectPin, HIGH); +} diff --git a/sparkfun/tiny/libraries/SPI/keywords.txt b/sparkfun/tiny/libraries/SPI/keywords.txt new file mode 100644 index 00000000..fa761658 --- /dev/null +++ b/sparkfun/tiny/libraries/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4 LITERAL1 +SPI_CLOCK_DIV16 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_CLOCK_DIV128 LITERAL1 +SPI_CLOCK_DIV2 LITERAL1 +SPI_CLOCK_DIV8 LITERAL1 +SPI_CLOCK_DIV32 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 \ No newline at end of file diff --git a/sparkfun/tiny/libraries/SPI/library.properties b/sparkfun/tiny/libraries/SPI/library.properties new file mode 100644 index 00000000..f2f2a4fc --- /dev/null +++ b/sparkfun/tiny/libraries/SPI/library.properties @@ -0,0 +1,9 @@ +name=SPI +version=1.0 +author=Arduino +maintainer=Dr. Azzy +sentence=Clone of SPI library for ATTiny Classic +paragraph= +category=Communication +url=http://arduino.cc/en/Reference/SPI +architectures=avr diff --git a/sparkfun/tiny/libraries/Servo/README.adoc b/sparkfun/tiny/libraries/Servo/README.adoc new file mode 100644 index 00000000..2c404431 --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/README.adoc @@ -0,0 +1,28 @@ += Servo Library for Arduino = + +This library allows an Arduino board to control RC (hobby) servo motors. + +This library has been modified to add support for additional ATTiny processors. + +For more information about this library please visit us at +http://www.arduino.cc/en/Reference/Servo + +== License == + +Copyright (c) 2017 Spence Konde. +Copyright (c) 2013 Arduino LLC. All right reserved. +Copyright (c) 2009 Michael Margolis. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/sparkfun/tiny/libraries/Servo/examples/Knob/Knob.ino b/sparkfun/tiny/libraries/Servo/examples/Knob/Knob.ino new file mode 100644 index 00000000..0db8770b --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/examples/Knob/Knob.ino @@ -0,0 +1,27 @@ +/* + Controlling a servo position using a potentiometer (variable resistor) + by Michal Rinott + + modified on 8 Nov 2013 + by Scott Fitzgerald + http://www.arduino.cc/en/Tutorial/Knob +*/ + +#include + +Servo myservo; // create servo object to control a servo + +int potpin = 0; // analog pin used to connect the potentiometer +int val; // variable to read the value from the analog pin + +void setup() { + myservo.attach(9); // attaches the servo on pin 9 to the servo object +} + +void loop() { + val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023) + val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180) + myservo.write(val); // sets the servo position according to the scaled value + delay(15); // waits for the servo to get there +} + diff --git a/sparkfun/tiny/libraries/Servo/examples/Sweep/Sweep.ino b/sparkfun/tiny/libraries/Servo/examples/Sweep/Sweep.ino new file mode 100644 index 00000000..df904afb --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/examples/Sweep/Sweep.ino @@ -0,0 +1,32 @@ +/* Sweep + by BARRAGAN + This example code is in the public domain. + + modified 8 Nov 2013 + by Scott Fitzgerald + http://www.arduino.cc/en/Tutorial/Sweep +*/ + +#include + +Servo myservo; // create servo object to control a servo +// twelve servo objects can be created on most boards + +int pos = 0; // variable to store the servo position + +void setup() { + myservo.attach(9); // attaches the servo on pin 9 to the servo object +} + +void loop() { + for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees + // in steps of 1 degree + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } + for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } +} + diff --git a/sparkfun/tiny/libraries/Servo/keywords.txt b/sparkfun/tiny/libraries/Servo/keywords.txt new file mode 100644 index 00000000..0a7ca1e3 --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map Servo +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Servo KEYWORD1 Servo + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +read KEYWORD2 +attached KEYWORD2 +writeMicroseconds KEYWORD2 +readMicroseconds KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/sparkfun/tiny/libraries/Servo/library.properties b/sparkfun/tiny/libraries/Servo/library.properties new file mode 100644 index 00000000..f27ae5d4 --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/library.properties @@ -0,0 +1,9 @@ +name=Servo +version=1.1.2 +author=Michael Margolis, Arduino +maintainer=Arduino +sentence=Allows Arduino/Genuino boards to control a variety of servo motors. +paragraph=This library can control a great number of servos.
It makes careful use of timers: the library can control 12 servos using only 1 timer.
On the Arduino Due you can control up to 60 servos.
+category=Device Control +url=http://www.arduino.cc/en/Reference/Servo +architectures=avr,sam,samd diff --git a/sparkfun/tiny/libraries/Servo/src/Servo.h b/sparkfun/tiny/libraries/Servo/src/Servo.h new file mode 100644 index 00000000..06e1954f --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/src/Servo.h @@ -0,0 +1,103 @@ +/* + Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 + Copyright (c) 2009 Michael Margolis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + A servo is activated by creating an instance of the Servo class passing + the desired pin to the attach() method. + The servos are pulsed in the background using the value most recently + written using the write() method. + + Note that analogWrite of PWM on pins associated with the timer are + disabled when the first servo is attached. + Timers are seized as needed in groups of 12 servos - 24 servos use two + timers, 48 servos will use four. + The sequence used to sieze timers is defined in timers.h + + The methods are: + + Servo - Class for manipulating servo motors connected to Arduino pins. + + attach(pin ) - Attaches a servo motor to an i/o pin. + attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds + default min is 544, max is 2400 + + write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds) + writeMicroseconds() - Sets the servo pulse width in microseconds + read() - Gets the last written servo pulse width as an angle between 0 and 180. + readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) + attached() - Returns true if there is a servo attached. + detach() - Stops an attached servos from pulsing its i/o pin. + */ + +#ifndef Servo_h +#define Servo_h + +#include + +/* + * Defines for 16 bit timers used with Servo library + * + * If _useTimerX is defined then TimerX is a 16 bit timer on the current board + * timer16_Sequence_t enumerates the sequence that the timers should be allocated + * _Nbr_16timers indicates how many 16 bit timers are available. + */ + +#include "avr/ServoTimers.h" + +#define Servo_VERSION 2 // software version of this library + +#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo +#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo +#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached +#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds + +#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer +#define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER) + +#define INVALID_SERVO 255 // flag indicating an invalid servo index + +typedef struct { + uint8_t nbr :6 ; // a pin number from 0 to 63 + uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false +} ServoPin_t ; + +typedef struct { + ServoPin_t Pin; + volatile unsigned int ticks; +} servo_t; + +class Servo +{ +public: + Servo(); + uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure + uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. + void detach(); + void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + int read(); // returns current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) + bool attached(); // return true if this servo is attached, otherwise false +private: + uint8_t servoIndex; // index into the channel data for this servo + int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH + int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH +}; + +#endif diff --git a/sparkfun/tiny/libraries/Servo/src/avr/Servo.cpp b/sparkfun/tiny/libraries/Servo/src/avr/Servo.cpp new file mode 100644 index 00000000..0cc96673 --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/src/avr/Servo.cpp @@ -0,0 +1,317 @@ +/* + Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 + Copyright (c) 2009 Michael Margolis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if defined(ARDUINO_ARCH_AVR) + +#include +#include + +#include "Servo.h" + +#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009 +#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds + + +#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009 + +//#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER) + +static servo_t servos[MAX_SERVOS]; // static array of servo structures +static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval) + +uint8_t ServoCount = 0; // the total number of attached servos + + +// convenience macros +#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo +#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer +#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel +#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel + +#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo +#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo + +/************ static functions common to all instances ***********************/ + +static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA) +{ + if( Channel[timer] < 0 ) + *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer + else{ + if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true ) + digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated + } + + Channel[timer]++; // increment to the next channel + if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { + *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks; + if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated + digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high + } + else { + // finished all channels so wait for the refresh period to expire before starting over + if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed + *OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL); + else + *OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed + Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel + } +} + +#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform +// Interrupt handlers for Arduino +#if defined(_useTimer1) +SIGNAL (TIMER1_COMPA_vect) +{ + handle_interrupts(_timer1, &TCNT1, &OCR1A); +} +#endif + +#if defined(_useTimer3) +SIGNAL (TIMER3_COMPA_vect) +{ + handle_interrupts(_timer3, &TCNT3, &OCR3A); +} +#endif + +#if defined(_useTimer4) +SIGNAL (TIMER4_COMPA_vect) +{ + handle_interrupts(_timer4, &TCNT4, &OCR4A); +} +#endif + +#if defined(_useTimer5) +SIGNAL (TIMER5_COMPA_vect) +{ + handle_interrupts(_timer5, &TCNT5, &OCR5A); +} +#endif + +#elif defined WIRING +// Interrupt handlers for Wiring +#if defined(_useTimer1) +void Timer1Service() +{ + handle_interrupts(_timer1, &TCNT1, &OCR1A); +} +#endif +#if defined(_useTimer3) +void Timer3Service() +{ + handle_interrupts(_timer3, &TCNT3, &OCR3A); +} +#endif +#endif + + +static void initISR(timer16_Sequence_t timer) +{ +#if defined (_useTimer1) + if(timer == _timer1) { + TCCR1A = 0; // normal counting mode + TCCR1B = _BV(CS11); // set prescaler of 8 + TCNT1 = 0; // clear the timer count +#if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__) || defined(__AVR_ATtiny1634__) + TIFR |= _BV(OCF1A); // clear any pending interrupts; + TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt +#else + // here if not ATmega8 or ATmega128 + TIFR1 |= _BV(OCF1A); // clear any pending interrupts; + TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt +#endif +#if defined(WIRING) + timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service); +#endif + } +#endif + +#if defined (_useTimer3) + if(timer == _timer3) { + TCCR3A = 0; // normal counting mode + TCCR3B = _BV(CS31); // set prescaler of 8 + TCNT3 = 0; // clear the timer count +#if defined(__AVR_ATmega128__) || defined(__AVR_ATtiny1634__) + TIFR |= _BV(OCF3A); // clear any pending interrupts; + ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt +#else + TIFR3 = _BV(OCF3A); // clear any pending interrupts; + TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt +#endif +#if defined(WIRING) + timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only +#endif + } +#endif + +#if defined (_useTimer4) + if(timer == _timer4) { + TCCR4A = 0; // normal counting mode + TCCR4B = _BV(CS41); // set prescaler of 8 + TCNT4 = 0; // clear the timer count + TIFR4 = _BV(OCF4A); // clear any pending interrupts; + TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt + } +#endif + +#if defined (_useTimer5) + if(timer == _timer5) { + TCCR5A = 0; // normal counting mode + TCCR5B = _BV(CS51); // set prescaler of 8 + TCNT5 = 0; // clear the timer count + TIFR5 = _BV(OCF5A); // clear any pending interrupts; + TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt + } +#endif +} + +static void finISR(timer16_Sequence_t timer) +{ + //disable use of the given timer +#if defined WIRING // Wiring + if(timer == _timer1) { + #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) + TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt + #else + TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt + #endif + timerDetach(TIMER1OUTCOMPAREA_INT); + } + else if(timer == _timer3) { + #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) + TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt + #else + ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt + #endif + timerDetach(TIMER3OUTCOMPAREA_INT); + } +#else + //For arduino - in future: call here to a currently undefined function to reset the timer +#endif +} + +static boolean isTimerActive(timer16_Sequence_t timer) +{ + // returns true if any servo is active on this timer + for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) { + if(SERVO(timer,channel).Pin.isActive == true) + return true; + } + return false; +} + + +/****************** end of static functions ******************************/ + +Servo::Servo() +{ + if( ServoCount < MAX_SERVOS) { + this->servoIndex = ServoCount++; // assign a servo index to this instance + servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009 + } + else + this->servoIndex = INVALID_SERVO ; // too many servos +} + +uint8_t Servo::attach(int pin) +{ + return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); +} + +uint8_t Servo::attach(int pin, int min, int max) +{ + if(this->servoIndex < MAX_SERVOS ) { + pinMode( pin, OUTPUT) ; // set servo pin to output + servos[this->servoIndex].Pin.nbr = pin; + // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 + this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS + this->max = (MAX_PULSE_WIDTH - max)/4; + // initialize the timer if it has not already been initialized + timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); + if(isTimerActive(timer) == false) + initISR(timer); + servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive + } + return this->servoIndex ; +} + +void Servo::detach() +{ + servos[this->servoIndex].Pin.isActive = false; + timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); + if(isTimerActive(timer) == false) { + finISR(timer); + } +} + +void Servo::write(int value) +{ + if(value < MIN_PULSE_WIDTH) + { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + if(value < 0) value = 0; + if(value > 180) value = 180; + value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + } + this->writeMicroseconds(value); +} + +void Servo::writeMicroseconds(int value) +{ + // calculate and store the values for the given channel + byte channel = this->servoIndex; + if( (channel < MAX_SERVOS) ) // ensure channel is valid + { + if( value < SERVO_MIN() ) // ensure pulse width is valid + value = SERVO_MIN(); + else if( value > SERVO_MAX() ) + value = SERVO_MAX(); + + value = value - TRIM_DURATION; + value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 + + uint8_t oldSREG = SREG; + cli(); + servos[channel].ticks = value; + SREG = oldSREG; + } +} + +int Servo::read() // return the value as degrees +{ + return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); +} + +int Servo::readMicroseconds() +{ + unsigned int pulsewidth; + if( this->servoIndex != INVALID_SERVO ) + pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009 + else + pulsewidth = 0; + + return pulsewidth; +} + +bool Servo::attached() +{ + return servos[this->servoIndex].Pin.isActive ; +} + +#endif // ARDUINO_ARCH_AVR + diff --git a/sparkfun/tiny/libraries/Servo/src/avr/ServoTimers.h b/sparkfun/tiny/libraries/Servo/src/avr/ServoTimers.h new file mode 100644 index 00000000..9794c8ef --- /dev/null +++ b/sparkfun/tiny/libraries/Servo/src/avr/ServoTimers.h @@ -0,0 +1,59 @@ +/* + Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 + Copyright (c) 2009 Michael Margolis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * Defines for 16 bit timers used with Servo library + * + * If _useTimerX is defined then TimerX is a 16 bit timer on the current board + * timer16_Sequence_t enumerates the sequence that the timers should be allocated + * _Nbr_16timers indicates how many 16 bit timers are available. + */ + +/** + * AVR Only definitions + * -------------------- + */ + +// Say which 16 bit timers can be used and in what order +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define _useTimer5 +#define _useTimer1 +#define _useTimer3 +#define _useTimer4 +typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t; + +#elif defined(__AVR_ATmega32U4__) +#define _useTimer1 +typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t; + +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +#define _useTimer3 +#define _useTimer1 +typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t; + +#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__) +#define _useTimer3 +#define _useTimer1 +typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t; + +#else // everything else +#define _useTimer1 +typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t; +#endif + diff --git a/sparkfun/tiny/libraries/SoftwareSerial/SoftwareSerial.cpp b/sparkfun/tiny/libraries/SoftwareSerial/SoftwareSerial.cpp new file mode 100644 index 00000000..027b1a33 --- /dev/null +++ b/sparkfun/tiny/libraries/SoftwareSerial/SoftwareSerial.cpp @@ -0,0 +1,490 @@ +/* +SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + +// When set, _DEBUG co-opts pins 11 and 13 for debugging with an +// oscilloscope or logic analyzer. Beware: it also slightly modifies +// the bit times, so don't rely on it too much at high baud rates +#define _DEBUG 0 +#define _DEBUG_PIN1 11 +#define _DEBUG_PIN2 13 +// +// Includes +// +#include +#include +#include +#include +#include + +// +// Statics +// +SoftwareSerial *SoftwareSerial::active_object = 0; +char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; +volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; +volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; + +// +// Debugging +// +// This function generates a brief pulse +// for debugging or measuring on an oscilloscope. +inline void DebugPulse(uint8_t pin, uint8_t count) +{ +#if _DEBUG + volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); + + uint8_t val = *pport; + while (count--) + { + *pport = val | digitalPinToBitMask(pin); + *pport = val; + } +#endif +} + +// +// Private methods +// + +/* static */ +inline void SoftwareSerial::tunedDelay(uint16_t delay) { + _delay_loop_2(delay); +} + +// This function sets the current object as the "listening" +// one and returns true if it replaces another +bool SoftwareSerial::listen() +{ + if (!_rx_delay_stopbit) + return false; + + if (active_object != this) + { + if (active_object) + active_object->stopListening(); + + _buffer_overflow = false; + _receive_buffer_head = _receive_buffer_tail = 0; + active_object = this; + + setRxIntMsk(true); + return true; + } + + return false; +} + +// Stop listening. Returns true if we were actually listening. +bool SoftwareSerial::stopListening() +{ + if (active_object == this) + { + setRxIntMsk(false); + active_object = NULL; + return true; + } + return false; +} + +// +// The receive routine called by the interrupt handler +// +void SoftwareSerial::recv() +{ + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Preserve the registers that the compiler misses +// (courtesy of Arduino forum user *etracer*) + asm volatile( + "push r18 \n\t" + "push r19 \n\t" + "push r20 \n\t" + "push r21 \n\t" + "push r22 \n\t" + "push r23 \n\t" + "push r26 \n\t" + "push r27 \n\t" + ::); +#endif + + uint8_t d = 0; + + // If RX line is high, then we don't see any start bit + // so interrupt is probably not for us + if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) + { + // Disable further interrupts during reception, this prevents + // triggering another interrupt directly after we return, which can + // cause problems at higher baudrates. + setRxIntMsk(false); + + // Wait approximately 1/2 of a bit width to "center" the sample + tunedDelay(_rx_delay_centering); + DebugPulse(_DEBUG_PIN2, 1); + + // Read each of the 8 bits + for (uint8_t i=8; i > 0; --i) + { + tunedDelay(_rx_delay_intrabit); + d >>= 1; + DebugPulse(_DEBUG_PIN2, 1); + if (rx_pin_read()) + d |= 0x80; + } + + if (_inverse_logic) + d = ~d; + + // if buffer full, set the overflow flag and return + uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; + if (next != _receive_buffer_head) + { + // save new data in buffer: tail points to where byte goes + _receive_buffer[_receive_buffer_tail] = d; // save new byte + _receive_buffer_tail = next; + } + else + { + DebugPulse(_DEBUG_PIN1, 1); + _buffer_overflow = true; + } + + // skip the stop bit + tunedDelay(_rx_delay_stopbit); + DebugPulse(_DEBUG_PIN1, 1); + + // Re-enable interrupts when we're sure to be inside the stop bit + setRxIntMsk(true); + + } + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Restore the registers that the compiler misses + asm volatile( + "pop r27 \n\t" + "pop r26 \n\t" + "pop r23 \n\t" + "pop r22 \n\t" + "pop r21 \n\t" + "pop r20 \n\t" + "pop r19 \n\t" + "pop r18 \n\t" + ::); +#endif +} + +uint8_t SoftwareSerial::rx_pin_read() +{ + return *_receivePortRegister & _receiveBitMask; +} + +// +// Interrupt handling +// + +/* static */ +inline void SoftwareSerial::handle_interrupt() +{ + if (active_object) + { + active_object->recv(); + } +} + +#if defined(PCINT0_vect) +ISR(PCINT0_vect) +{ + SoftwareSerial::handle_interrupt(); +} +#endif + +#if defined(PCINT1_vect) +ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT2_vect) +ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT3_vect) +ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +// +// Constructor +// +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : + _rx_delay_centering(0), + _rx_delay_intrabit(0), + _rx_delay_stopbit(0), + _tx_delay(0), + _buffer_overflow(false), + _inverse_logic(inverse_logic) +{ + setTX(transmitPin); + setRX(receivePin); +} + +// +// Destructor +// +SoftwareSerial::~SoftwareSerial() +{ + end(); +} + +void SoftwareSerial::setTX(uint8_t tx) +{ + // First write, then set output. If we do this the other way around, + // the pin would be output low for a short while before switching to + // output hihg. Now, it is input with pullup for a short while, which + // is fine. With inverse logic, either order is fine. + digitalWrite(tx, _inverse_logic ? LOW : HIGH); + pinMode(tx, OUTPUT); + _transmitBitMask = digitalPinToBitMask(tx); + uint8_t port = digitalPinToPort(tx); + _transmitPortRegister = portOutputRegister(port); +} + +void SoftwareSerial::setRX(uint8_t rx) +{ + pinMode(rx, INPUT); + if (!_inverse_logic) + digitalWrite(rx, HIGH); // pullup for normal logic! + _receivePin = rx; + _receiveBitMask = digitalPinToBitMask(rx); + uint8_t port = digitalPinToPort(rx); + _receivePortRegister = portInputRegister(port); +} + +uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) { + if (num > sub) + return num - sub; + else + return 1; +} + +// +// Public methods +// + +void SoftwareSerial::begin(long speed) +{ + _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; + + // Precalculate the various delays, in number of 4-cycle delays + uint16_t bit_delay = (F_CPU / speed) / 4; + + // 12 (gcc 4.8.2) or 13 (gcc 4.3.2) cycles from start bit to first bit, + // 15 (gcc 4.8.2) or 16 (gcc 4.3.2) cycles between bits, + // 12 (gcc 4.8.2) or 14 (gcc 4.3.2) cycles from last bit to stop bit + // These are all close enough to just use 15 cycles, since the inter-bit + // timings are the most critical (deviations stack 8 times) + _tx_delay = subtract_cap(bit_delay, 15 / 4); + + // Only setup rx when we have a valid PCINT for this pin + if (digitalPinToPCICR(_receivePin)) { + #if GCC_VERSION > 40800 + // Timings counted from gcc 4.8.2 output. This works up to 115200 on + // 16Mhz and 57600 on 8Mhz. + // + // When the start bit occurs, there are 3 or 4 cycles before the + // interrupt flag is set, 4 cycles before the PC is set to the right + // interrupt vector address and the old PC is pushed on the stack, + // and then 75 cycles of instructions (including the RJMP in the + // ISR vector table) until the first delay. After the delay, there + // are 17 more cycles until the pin value is read (excluding the + // delay in the loop). + // We want to have a total delay of 1.5 bit time. Inside the loop, + // we already wait for 1 bit time - 23 cycles, so here we wait for + // 0.5 bit time - (71 + 18 - 22) cycles. + _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4); + + // There are 23 cycles in each loop iteration (excluding the delay) + _rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4); + + // There are 37 cycles from the last bit read to the start of + // stopbit delay and 11 cycles from the delay until the interrupt + // mask is enabled again (which _must_ happen during the stopbit). + // This delay aims at 3/4 of a bit time, meaning the end of the + // delay will be at 1/4th of the stopbit. This allows some extra + // time for ISR cleanup, which makes 115200 baud at 16Mhz work more + // reliably + _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4); + #else // Timings counted from gcc 4.3.2 output + // Note that this code is a _lot_ slower, mostly due to bad register + // allocation choices of gcc. This works up to 57600 on 16Mhz and + // 38400 on 8Mhz. + _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 97 + 29 - 11) / 4); + _rx_delay_intrabit = subtract_cap(bit_delay, 11 / 4); + _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (44 + 17) / 4); + #endif + + + // Enable the PCINT for the entire port here, but never disable it + // (others might also need it, so we disable the interrupt by using + // the per-pin PCMSK register). + *digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin)); + // Precalculate the pcint mask register and value, so setRxIntMask + // can be used inside the ISR without costing too much time. + _pcint_maskreg = digitalPinToPCMSK(_receivePin); + _pcint_maskvalue = _BV(digitalPinToPCMSKbit(_receivePin)); + + tunedDelay(_tx_delay); // if we were low this establishes the end + } + +#if _DEBUG + pinMode(_DEBUG_PIN1, OUTPUT); + pinMode(_DEBUG_PIN2, OUTPUT); +#endif + + listen(); +} + +void SoftwareSerial::setRxIntMsk(bool enable) +{ + if (enable) + *_pcint_maskreg |= _pcint_maskvalue; + else + *_pcint_maskreg &= ~_pcint_maskvalue; +} + +void SoftwareSerial::end() +{ + stopListening(); +} + + +// Read data from buffer +int SoftwareSerial::read() +{ + if (!isListening()) + return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + return -1; + + // Read from "head" + uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte + _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; + return d; +} + +int SoftwareSerial::available() +{ + if (!isListening()) + return 0; + + return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; +} + +size_t SoftwareSerial::write(uint8_t b) +{ + if (_tx_delay == 0) { + setWriteError(); + return 0; + } + + // By declaring these as local variables, the compiler will put them + // in registers _before_ disabling interrupts and entering the + // critical timing sections below, which makes it a lot easier to + // verify the cycle timings + volatile uint8_t *reg = _transmitPortRegister; + uint8_t reg_mask = _transmitBitMask; + uint8_t inv_mask = ~_transmitBitMask; + uint8_t oldSREG = SREG; + bool inv = _inverse_logic; + uint16_t delay = _tx_delay; + + if (inv) + b = ~b; + + cli(); // turn off interrupts for a clean txmit + + // Write the start bit + if (inv) + *reg |= reg_mask; + else + *reg &= inv_mask; + + tunedDelay(delay); + + // Write each of the 8 bits + for (uint8_t i = 8; i > 0; --i) + { + if (b & 1) // choose bit + *reg |= reg_mask; // send 1 + else + *reg &= inv_mask; // send 0 + + tunedDelay(delay); + b >>= 1; + } + + // restore pin to natural state + if (inv) + *reg &= inv_mask; + else + *reg |= reg_mask; + + SREG = oldSREG; // turn interrupts back on + tunedDelay(_tx_delay); + + return 1; +} + +void SoftwareSerial::flush() +{ + if (!isListening()) + return; + + uint8_t oldSREG = SREG; + cli(); + _receive_buffer_head = _receive_buffer_tail = 0; + SREG = oldSREG; +} + +int SoftwareSerial::peek() +{ + if (!isListening()) + return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + return -1; + + // Read from "head" + return _receive_buffer[_receive_buffer_head]; +} diff --git a/sparkfun/tiny/libraries/SoftwareSerial/SoftwareSerial.h b/sparkfun/tiny/libraries/SoftwareSerial/SoftwareSerial.h new file mode 100644 index 00000000..680e40db --- /dev/null +++ b/sparkfun/tiny/libraries/SoftwareSerial/SoftwareSerial.h @@ -0,0 +1,121 @@ +/* +SoftwareSerial.h (formerly NewSoftSerial.h) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + +#ifndef SoftwareSerial_h +#define SoftwareSerial_h + +#include +#include + +/****************************************************************************** +* Definitions +******************************************************************************/ + +#define _SS_MAX_RX_BUFF 64 // RX buffer size +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +class SoftwareSerial : public Stream +{ +private: + // per object data + uint8_t _receivePin; + uint8_t _receiveBitMask; + volatile uint8_t *_receivePortRegister; + uint8_t _transmitBitMask; + volatile uint8_t *_transmitPortRegister; + volatile uint8_t *_pcint_maskreg; + uint8_t _pcint_maskvalue; + + // Expressed as 4-cycle delays (must never be 0!) + uint16_t _rx_delay_centering; + uint16_t _rx_delay_intrabit; + uint16_t _rx_delay_stopbit; + uint16_t _tx_delay; + + uint16_t _buffer_overflow:1; + uint16_t _inverse_logic:1; + + // static data + static char _receive_buffer[_SS_MAX_RX_BUFF]; + static volatile uint8_t _receive_buffer_tail; + static volatile uint8_t _receive_buffer_head; + static SoftwareSerial *active_object; + + // private methods + void recv() __attribute__((__always_inline__)); + uint8_t rx_pin_read(); + void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__)); + void setTX(uint8_t transmitPin); + void setRX(uint8_t receivePin); + void setRxIntMsk(bool enable) __attribute__((__always_inline__)); + + // Return num - sub, or 1 if the result would be < 1 + static uint16_t subtract_cap(uint16_t num, uint16_t sub); + + // private static method for timing + static inline void tunedDelay(uint16_t delay); + +public: + // public methods + SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); + ~SoftwareSerial(); + void begin(long speed); + bool listen(); + void end(); + bool isListening() { return this == active_object; } + bool stopListening(); + bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } + int peek(); + + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + operator bool() { return true; } + + using Print::write; + + // public only for easy access by interrupt handlers + static inline void handle_interrupt() __attribute__((__always_inline__)); +}; + +// Arduino 0012 workaround +#undef int +#undef char +#undef long +#undef byte +#undef float +#undef abs +#undef round + +#endif diff --git a/sparkfun/tiny/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino b/sparkfun/tiny/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino new file mode 100644 index 00000000..f6591330 --- /dev/null +++ b/sparkfun/tiny/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino @@ -0,0 +1,55 @@ +/* + Software serial multple serial test + + Receives from the hardware serial, sends to software serial. + Receives from software serial, sends to hardware serial. + + The circuit: + * RX is digital pin 10 (connect to TX of other device) + * TX is digital pin 11 (connect to RX of other device) + + Note: + Not all pins on the Mega and Mega 2560 support change interrupts, + so only the following can be used for RX: + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + + Not all pins on the Leonardo support change interrupts, + so only the following can be used for RX: + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). + + created back in the mists of time + modified 25 May 2012 + by Tom Igoe + based on Mikal Hart's example + + This example code is in the public domain. + + */ +#include + +SoftwareSerial mySerial(10, 11); // RX, TX + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(57600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.println("Goodnight moon!"); + + // set the data rate for the SoftwareSerial port + mySerial.begin(4800); + mySerial.println("Hello, world?"); +} + +void loop() // run over and over +{ + if (mySerial.available()) + Serial.write(mySerial.read()); + if (Serial.available()) + mySerial.write(Serial.read()); +} + diff --git a/sparkfun/tiny/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino b/sparkfun/tiny/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino new file mode 100644 index 00000000..95881a6c --- /dev/null +++ b/sparkfun/tiny/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino @@ -0,0 +1,93 @@ +/* + Software serial multple serial test + + Receives from the two software serial ports, + sends to the hardware serial port. + + In order to listen on a software port, you call port.listen(). + When using two software serial ports, you have to switch ports + by listen()ing on each one in turn. Pick a logical time to switch + ports, like the end of an expected transmission, or when the + buffer is empty. This example switches ports when there is nothing + more to read from a port + + The circuit: + Two devices which communicate serially are needed. + * First serial device's TX attached to digital pin 2, RX to pin 3 + * Second serial device's TX attached to digital pin 4, RX to pin 5 + + Note: + Not all pins on the Mega and Mega 2560 support change interrupts, + so only the following can be used for RX: + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + + Not all pins on the Leonardo support change interrupts, + so only the following can be used for RX: + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). + + created 18 Apr. 2011 + modified 25 May 2012 + by Tom Igoe + based on Mikal Hart's twoPortRXExample + + This example code is in the public domain. + + */ + +#include +// software serial #1: TX = digital pin 10, RX = digital pin 11 +SoftwareSerial portOne(10, 11); + +// software serial #2: TX = digital pin 8, RX = digital pin 9 +// on the Mega, use other pins instead, since 8 and 9 don't work on the Mega +SoftwareSerial portTwo(8, 9); + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + // Start each software serial port + portOne.begin(9600); + portTwo.begin(9600); +} + +void loop() +{ + // By default, the last intialized port is listening. + // when you want to listen on a port, explicitly select it: + portOne.listen(); + Serial.println("Data from port one:"); + // while there is data coming in, read it + // and send to the hardware serial port: + while (portOne.available() > 0) { + char inByte = portOne.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); + + // Now listen on the second port + portTwo.listen(); + // while there is data coming in, read it + // and send to the hardware serial port: + Serial.println("Data from port two:"); + while (portTwo.available() > 0) { + char inByte = portTwo.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); +} + + + + + + diff --git a/sparkfun/tiny/libraries/SoftwareSerial/keywords.txt b/sparkfun/tiny/libraries/SoftwareSerial/keywords.txt new file mode 100644 index 00000000..aaea17c2 --- /dev/null +++ b/sparkfun/tiny/libraries/SoftwareSerial/keywords.txt @@ -0,0 +1,30 @@ +####################################### +# Syntax Coloring Map for SoftwareSerial +# (formerly NewSoftSerial) +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SoftwareSerial KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +read KEYWORD2 +write KEYWORD2 +available KEYWORD2 +isListening KEYWORD2 +overflow KEYWORD2 +flush KEYWORD2 +listen KEYWORD2 +peek KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/sparkfun/tiny/libraries/SoftwareSerial/library.properties b/sparkfun/tiny/libraries/SoftwareSerial/library.properties new file mode 100644 index 00000000..c0a80769 --- /dev/null +++ b/sparkfun/tiny/libraries/SoftwareSerial/library.properties @@ -0,0 +1,11 @@ +name=SoftwareSerial +version=1.0 +author=Arduino +maintainer=Dr. Azzy +sentence=Clone of SoftwareSerial for ATTiny Classic (note - these boards already have a different software serial available - see core documentation) +paragraph= +category=Communication +url=http://arduino.cc/en/Reference/SoftwareSerial +architectures=avr +types=Arduino + diff --git a/sparkfun/tiny/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino b/sparkfun/tiny/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino new file mode 100644 index 00000000..4d0a68f8 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino @@ -0,0 +1,84 @@ +// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder +// by Nicholas Zambetti +// and James Tichenor + +// Demonstrates use of the Wire library reading data from the +// Devantech Utrasonic Rangers SFR08 and SFR10 + +// Created 29 April 2006 + +// This example code is in the public domain. + + +#include + +void setup() { + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial communication at 9600bps +} + +int reading = 0; + +void loop() { + // step 1: instruct sensor to read echoes + Wire.beginTransmission(112); // transmit to device #112 (0x70) + // the address specified in the datasheet is 224 (0xE0) + // but i2c adressing uses the high 7 bits so it's 112 + Wire.write(byte(0x00)); // sets register pointer to the command register (0x00) + Wire.write(byte(0x50)); // command sensor to measure in "inches" (0x50) + // use 0x51 for centimeters + // use 0x52 for ping microseconds + Wire.endTransmission(); // stop transmitting + + // step 2: wait for readings to happen + delay(70); // datasheet suggests at least 65 milliseconds + + // step 3: instruct sensor to return a particular echo reading + Wire.beginTransmission(112); // transmit to device #112 + Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02) + Wire.endTransmission(); // stop transmitting + + // step 4: request reading from sensor + Wire.requestFrom(112, 2); // request 2 bytes from slave device #112 + + // step 5: receive reading from sensor + if (2 <= Wire.available()) { // if two bytes were received + reading = Wire.read(); // receive high byte (overwrites previous reading) + reading = reading << 8; // shift high byte to be high 8 bits + reading |= Wire.read(); // receive low byte as lower 8 bits + Serial.println(reading); // print the reading + } + + delay(250); // wait a bit since people have to read the output :) +} + + +/* + +// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08) +// usage: changeAddress(0x70, 0xE6); + +void changeAddress(byte oldAddress, byte newAddress) +{ + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA0)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xAA)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA5)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(newAddress); + Wire.endTransmission(); +} + +*/ diff --git a/sparkfun/tiny/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino b/sparkfun/tiny/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino new file mode 100644 index 00000000..5fb91fba --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino @@ -0,0 +1,36 @@ +// I2C Digital Potentiometer +// by Nicholas Zambetti +// and Shawn Bonkowski + +// Demonstrates use of the Wire library +// Controls AD5171 digital potentiometer via I2C/TWI + +// Created 31 March 2006 + +// This example code is in the public domain. + +// This example code is in the public domain. + + +#include + +void setup() { + Wire.begin(); // join i2c bus (address optional for master) +} + +byte val = 0; + +void loop() { + Wire.beginTransmission(44); // transmit to device #44 (0x2c) + // device address is specified in datasheet + Wire.write(byte(0x00)); // sends instruction byte + Wire.write(val); // sends potentiometer value byte + Wire.endTransmission(); // stop transmitting + + val++; // increment value + if (val == 64) { // if reached 64th position (max) + val = 0; // start over from lowest value + } + delay(500); +} + diff --git a/sparkfun/tiny/libraries/Wire/examples/master_reader/master_reader.ino b/sparkfun/tiny/libraries/Wire/examples/master_reader/master_reader.ino new file mode 100644 index 00000000..ecab72ab --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/examples/master_reader/master_reader.ino @@ -0,0 +1,29 @@ +// Wire Master Reader +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() { + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial for output +} + +void loop() { + Wire.requestFrom(8, 6); // request 6 bytes from slave device #8 + + while (Wire.available()) { // slave may send less than requested + char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + + delay(500); +} diff --git a/sparkfun/tiny/libraries/Wire/examples/master_writer/master_writer.ino b/sparkfun/tiny/libraries/Wire/examples/master_writer/master_writer.ino new file mode 100644 index 00000000..5cbea117 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/examples/master_writer/master_writer.ino @@ -0,0 +1,29 @@ +// Wire Master Writer +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() { + Wire.begin(); // join i2c bus (address optional for master) +} + +byte x = 0; + +void loop() { + Wire.beginTransmission(8); // transmit to device #8 + Wire.write("x is "); // sends five bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} diff --git a/sparkfun/tiny/libraries/Wire/examples/slave_receiver/slave_receiver.ino b/sparkfun/tiny/libraries/Wire/examples/slave_receiver/slave_receiver.ino new file mode 100644 index 00000000..8051d53a --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/examples/slave_receiver/slave_receiver.ino @@ -0,0 +1,34 @@ +// Wire Slave Receiver +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() { + Wire.begin(8); // join i2c bus with address #8 + Wire.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output +} + +void loop() { + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int howMany) { + while (1 < Wire.available()) { // loop through all but the last + char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} diff --git a/sparkfun/tiny/libraries/Wire/examples/slave_sender/slave_sender.ino b/sparkfun/tiny/libraries/Wire/examples/slave_sender/slave_sender.ino new file mode 100644 index 00000000..d2e72bbc --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/examples/slave_sender/slave_sender.ino @@ -0,0 +1,29 @@ +// Wire Slave Sender +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() { + Wire.begin(8); // join i2c bus with address #8 + Wire.onRequest(requestEvent); // register event +} + +void loop() { + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + Wire.write("hello "); // respond with message of 6 bytes + // as expected by master +} diff --git a/sparkfun/tiny/libraries/Wire/keywords.txt b/sparkfun/tiny/libraries/Wire/keywords.txt new file mode 100644 index 00000000..ff314759 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/keywords.txt @@ -0,0 +1,32 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setClock KEYWORD2 +beginTransmission KEYWORD2 +endTransmission KEYWORD2 +requestFrom KEYWORD2 +send KEYWORD2 +receive KEYWORD2 +onReceive KEYWORD2 +onRequest KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Wire KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/sparkfun/tiny/libraries/Wire/library.properties b/sparkfun/tiny/libraries/Wire/library.properties new file mode 100644 index 00000000..811527bb --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/library.properties @@ -0,0 +1,10 @@ +name=Wire +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For all Arduino boards, BUT Arduino DUE. +paragraph= +category=Communication +url=http://www.arduino.cc/en/Reference/Wire +architectures=avr + diff --git a/sparkfun/tiny/libraries/Wire/src/SoftI2CMaster.h b/sparkfun/tiny/libraries/Wire/src/SoftI2CMaster.h new file mode 100644 index 00000000..73e16726 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/SoftI2CMaster.h @@ -0,0 +1,528 @@ +/* Arduino SoftI2C library. + * + * Copyright (C) 2013, Bernhard Nebel and Peter Fleury + * + * This is a very fast and very light-weight software I2C-master library + * written in assembler. It is based on Peter Fleury's I2C software + * library: http://homepage.hispeed.ch/peterfleury/avr-software.html + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino I2cMaster Library. If not, see + * . + */ + +/* In order to use the library, you need to define SDA_PIN, SCL_PIN, + * SDA_PORT and SCL_PORT before including this file. Have a look at + * http://www.arduino.cc/en/Reference/PortManipulation for finding out + * which values to use. For example, if you use digital pin 3 (corresponding + * to PD3) for SDA and digital pin 13 (corresponding to PB5) + * for SCL on a standard Arduino, + * you have to use the following definitions: + * #define SDA_PIN 3 + * #define SDA_PORT PORTD + * #define SCL_PIN 5 + * #define SCL_PORT PORTB + * + * You can also define the following constants (see also below): + * - I2C_CPUFREQ, when changing CPU clock frequency dynamically + * - I2C_FASTMODE = 1 meaning that the I2C bus allows speeds up to 400 kHz + * - I2C_SLOWMODE = 1 meaning that the I2C bus will allow only up to 25 kHz + * - I2C_NOINTERRUPT = 1 in order to prohibit interrupts while + * communicating (see below). This can be useful if you use the library + * for communicationg with SMbus devices, which have timeouts. + * Note, however, that interrupts are disabled from issuing a start condition + * until issuing a stop condition. So use this option with care! + * - I2C_TIMEOUT = 0..10000 mssec in order to return from the I2C functions + * in case of a I2C bus lockup (i.e., SCL constantly low). 0 means no timeout + */ + +/* Changelog: + * Version 1.3: + * - added "__attribute__ ((used))" for all functions declared with "__attribute__ ((noinline))" + * Now the module is also usable in Arduino 1.6.11+ + * Version 1.2: + * - added pragma to avoid "unused parameter warnings" (suggestion by Walter) + * - replaced wrong license file + * Version 1.1: + * - removed I2C_CLOCK_STRETCHING + * - added I2C_TIMEOUT time in msec (0..10000) until timeout or 0 if no timeout + * - changed i2c_init to return true iff both SDA and SCL are high + * - changed interrupt disabling so that the previous IRQ state is restored + * Version 1.0: basic functionality + */ +#include +#include + +#ifndef _SOFTI2C_H +#define _SOFTI2C_H 1 + +#pragma GCC diagnostic push + +#pragma GCC diagnostic ignored "-Wunused-parameter" + + + +// Init function. Needs to be called once in the beginning. +// Returns false if SDA or SCL are low, which probably means +// a I2C bus lockup or that the lines are not pulled up. +bool __attribute__ ((noinline)) i2c_init(void) __attribute__ ((used)); + +// Start transfer function: is the 8-bit I2C address (including the R/W +// bit). +// Return: true if the slave replies with an "acknowledge", false otherwise +bool __attribute__ ((noinline)) i2c_start(uint8_t addr) __attribute__ ((used)); + +// Similar to start function, but wait for an ACK! Be careful, this can +// result in an infinite loop! +void __attribute__ ((noinline)) i2c_start_wait(uint8_t addr) __attribute__ ((used)); + +// Repeated start function: After having claimed the bus with a start condition, +// you can address another or the same chip again without an intervening +// stop condition. +// Return: true if the slave replies with an "acknowledge", false otherwise +bool __attribute__ ((noinline)) i2c_rep_start(uint8_t addr) __attribute__ ((used)); + +// Issue a stop condition, freeing the bus. +void __attribute__ ((noinline)) i2c_stop(void) asm("ass_i2c_stop") __attribute__ ((used)); + +// Write one byte to the slave chip that had been addressed +// by the previous start call. is the byte to be sent. +// Return: true if the slave replies with an "acknowledge", false otherwise +bool __attribute__ ((noinline)) i2c_write(uint8_t value) asm("ass_i2c_write") __attribute__ ((used)); + + +// Read one byte. If is true, we send a NAK after having received +// the byte in order to terminate the read sequence. +uint8_t __attribute__ ((noinline)) i2c_read(bool last) __attribute__ ((used)); + +// You can set I2C_CPUFREQ independently of F_CPU if you +// change the CPU frequency on the fly. If you do not define it, +// it will use the value of F_CPU +#ifndef I2C_CPUFREQ +#define I2C_CPUFREQ F_CPU +#endif + +// If I2C_FASTMODE is set to 1, then the highest possible frequency below 400kHz +// is selected. Be aware that not all slave chips may be able to deal with that! +#ifndef I2C_FASTMODE +#define I2C_FASTMODE 0 +#endif + +// If I2C_FASTMODE is not defined or defined to be 0, then you can set +// I2C_SLOWMODE to 1. In this case, the I2C frequency will not be higher +// than 25KHz. This could be useful for problematic buses. +#ifndef I2C_SLOWMODE +#define I2C_SLOWMODE 0 +#endif + +// if I2C_NOINTERRUPT is 1, then the I2C routines are not interruptable. +// This is most probably only necessary if you are using a 1MHz system clock, +// you are communicating with a SMBus device, and you want to avoid timeouts. +// Be aware that the interrupt bit is enabled after each call. So the +// I2C functions should not be called in interrupt routines or critical regions. +#ifndef I2C_NOINTERRUPT +#define I2C_NOINTERRUPT 0 +#endif + +// I2C_TIMEOUT can be set to a value between 1 and 10000. +// If it is defined and nonzero, it leads to a timeout if the +// SCL is low longer than I2C_TIMEOUT milliseconds, i.e., max timeout is 10 sec +#ifndef I2C_TIMEOUT +#define I2C_TIMEOUT 0 +#else +#if I2C_TIMEOUT > 10000 +#error I2C_TIMEOUT is too large +#endif +#endif + +#define I2C_TIMEOUT_DELAY_LOOPS (I2C_CPUFREQ/1000UL)*I2C_TIMEOUT/4000UL +#if I2C_TIMEOUT_DELAY_LOOPS < 1 +#define I2C_MAX_STRETCH 1 +#else +#if I2C_TIMEOUT_DELAY_LOOPS > 60000UL +#define I2C_MAX_STRETCH 60000UL +#else +#define I2C_MAX_STRETCH I2C_TIMEOUT_DELAY_LOOPS +#endif +#endif + +#if I2C_FASTMODE +#define I2C_DELAY_COUNTER (((I2C_CPUFREQ/350000L)/2-18)/3) +#else +#if I2C_SLOWMODE +#define I2C_DELAY_COUNTER (((I2C_CPUFREQ/23500L)/2-18)/3) +#else +#define I2C_DELAY_COUNTER (((I2C_CPUFREQ/90000L)/2-18)/3) +#endif +#endif + +// Table of I2C bus speed in kbit/sec: +// CPU clock: 1MHz 2MHz 4MHz 8MHz 16MHz 20MHz +// Fast I2C mode 40 80 150 300 400 400 +// Standard I2C mode 40 80 100 100 100 100 +// Slow I2C mode 25 25 25 25 25 25 + +// constants for reading & writing +#define I2C_READ 1 +#define I2C_WRITE 0 + +// map the IO register back into the IO address space +#define SDA_DDR (_SFR_IO_ADDR(SDA_PORT) - 1) +#define SCL_DDR (_SFR_IO_ADDR(SCL_PORT) - 1) +#define SDA_OUT _SFR_IO_ADDR(SDA_PORT) +#define SCL_OUT _SFR_IO_ADDR(SCL_PORT) +#define SDA_IN (_SFR_IO_ADDR(SDA_PORT) - 2) +#define SCL_IN (_SFR_IO_ADDR(SCL_PORT) - 2) + +#ifndef __tmp_reg__ +#define __tmp_reg__ 0 +#endif + + +// Internal delay functions. +void __attribute__ ((noinline)) i2c_delay_half(void) asm("ass_i2c_delay_half") __attribute__ ((used)); +void __attribute__ ((noinline)) i2c_wait_scl_high(void) asm("ass_i2c_wait_scl_high") __attribute__ ((used)); + +void i2c_delay_half(void) +{ // function call 3 cycles => 3C +#if I2C_DELAY_COUNTER < 1 + __asm__ __volatile__ (" ret"); + // 7 cycles for call and return +#else + __asm__ __volatile__ + ( + " ldi r25, %[DELAY] ;load delay constant ;; 4C \n\t" + "_Lidelay: \n\t" + " dec r25 ;decrement counter ;; 4C+xC \n\t" + " brne _Lidelay ;;5C+(x-1)2C+xC\n\t" + " ret ;; 9C+(x-1)2C+xC = 7C+xC" + : : [DELAY] "M" I2C_DELAY_COUNTER : "r25"); + // 7 cycles + 3 times x cycles +#endif +} + +void i2c_wait_scl_high(void) +{ +#if I2C_TIMEOUT <= 0 + __asm__ __volatile__ + ("_Li2c_wait_stretch: \n\t" + " sbis %[SCLIN],%[SCLPIN] ;wait for SCL high \n\t" + " rjmp _Li2c_wait_stretch \n\t" + " cln ;signal: no timeout \n\t" + " ret " + : : [SCLIN] "I" (SCL_IN), [SCLPIN] "I" (SCL_PIN)); +#else + __asm__ __volatile__ + ( " ldi r27, %[HISTRETCH] ;load delay counter \n\t" + " ldi r26, %[LOSTRETCH] \n\t" + "_Lwait_stretch: \n\t" + " clr __tmp_reg__ ;do next loop 255 times \n\t" + "_Lwait_stretch_inner_loop: \n\t" + " rcall _Lcheck_scl_level ;call check function ;; 12C \n\t" + " brpl _Lstretch_done ;done if N=0 ;; +1 = 13C\n\t" + " dec __tmp_reg__ ;dec inner loop counter;; +1 = 14C\n\t" + " brne _Lwait_stretch_inner_loop ;; +2 = 16C\n\t" + " sbiw r26,1 ;dec outer loop counter \n\t" + " brne _Lwait_stretch ;continue with outer loop \n\t" + " sen ;timeout -> set N-bit=1 \n\t" + " rjmp _Lwait_return ;and return with N=1\n\t" + "_Lstretch_done: ;SCL=1 sensed \n\t" + " cln ;OK -> clear N-bit \n\t" + " rjmp _Lwait_return ; and return with N=0 \n\t" + + "_Lcheck_scl_level: ;; call = 3C\n\t" + " cln ;; +1C = 4C \n\t" + " sbic %[SCLIN],%[SCLPIN] ;skip if SCL still low ;; +2C = 6C \n\t" + " rjmp _Lscl_high ;; +0C = 6C \n\t" + " sen ;; +1 = 7C\n\t " + "_Lscl_high: " + " nop ;; +1C = 8C \n\t" + " ret ;return N-Bit=1 if low ;; +4 = 12C\n\t" + + "_Lwait_return:" + : : [SCLIN] "I" (SCL_IN), [SCLPIN] "I" (SCL_PIN), + [HISTRETCH] "M" (I2C_MAX_STRETCH>>8), + [LOSTRETCH] "M" (I2C_MAX_STRETCH&0xFF) + : "r26", "r27"); +#endif +} + + +bool i2c_init(void) +{ + __asm__ __volatile__ + (" cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t" + " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t" + " cbi %[SDAOUT],%[SDAPIN] ;clear SDA output value \n\t" + " cbi %[SCLOUT],%[SCLPIN] ;clear SCL output value \n\t" + " clr r24 ;set return value to false \n\t" + " clr r25 ;set return value to false \n\t" + " sbis %[SDAIN],%[SDAPIN] ;check for SDA high\n\t" + " ret ;if low return with false \n\t" + " sbis %[SCLIN],%[SCLPIN] ;check for SCL high \n\t" + " ret ;if low return with false \n\t" + " ldi r24,1 ;set return value to true \n\t" + " ret " + : : + [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), + [SCLIN] "I" (SCL_IN), [SCLOUT] "I" (SCL_OUT), + [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), + [SDAIN] "I" (SDA_IN), [SDAOUT] "I" (SDA_OUT)); + return true; +} + +bool i2c_start(uint8_t addr) +{ + __asm__ __volatile__ + ( +#if I2C_NOINTERRUPT + " cli ;clear IRQ bit \n\t" +#endif + " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" + " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" + " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" + " rcall ass_i2c_delay_half ;wait T/2 \n\t" + " rcall ass_i2c_write ;now write address \n\t" + " ret" + : : [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), + [SCLIN] "I" (SCL_IN),[SCLPIN] "I" (SCL_PIN)); + return true; // we never return here! +} + +bool i2c_rep_start(uint8_t addr) +{ + __asm__ __volatile__ + + ( +#if I2C_NOINTERRUPT + " cli \n\t" +#endif + " sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t" + " rcall ass_i2c_delay_half ;delay T/2 \n\t" + " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t" + " rcall ass_i2c_delay_half ;delay T/2 \n\t" + " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t" + " rcall ass_i2c_delay_half ;delay T/2 \n\t" + " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" + " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" + " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" + " rcall ass_i2c_delay_half ;delay T/2 \n\t" + " rcall ass_i2c_write \n\t" + " ret" + : : [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN),[SCLIN] "I" (SCL_IN), + [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN)); + return true; // just to fool the compiler +} + +void i2c_start_wait(uint8_t addr) +{ + __asm__ __volatile__ + ( + " push r24 ;save original parameter \n\t" + "_Li2c_start_wait1: \n\t" + " pop r24 ;restore original parameter\n\t" + " push r24 ;and save again \n\t" +#if I2C_NOINTERRUPT + " cli ;disable interrupts \n\t" +#endif + " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" + " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" + " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" + " rcall ass_i2c_delay_half ;delay T/2 \n\t" + " rcall ass_i2c_write ;write address \n\t" + " tst r24 ;if device not busy -> done \n\t" + " brne _Li2c_start_wait_done \n\t" + " rcall ass_i2c_stop ;terminate write & enable IRQ \n\t" + " rjmp _Li2c_start_wait1 ;device busy, poll ack again \n\t" + "_Li2c_start_wait_done: \n\t" + " pop __tmp_reg__ ;pop off orig argument \n\t" + " ret " + : : [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), + [SCLIN] "I" (SCL_IN),[SCLPIN] "I" (SCL_PIN)); +} + +void i2c_stop(void) +{ + __asm__ __volatile__ + ( + " sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t" + " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" + " rcall ass_i2c_delay_half ;T/2 delay \n\t" + " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t" + " rcall ass_i2c_delay_half ;T/2 delay \n\t" + " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" + " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" + " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t" + " rcall ass_i2c_delay_half \n\t" +#if I2C_NOINTERRUPT + " sei ;enable interrupts again!\n\t" +#endif + : : [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN), + [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN)); +} + +bool i2c_write(uint8_t value) +{ + __asm__ __volatile__ + ( + " sec ;set carry flag \n\t" + " rol r24 ;shift in carry and shift out MSB \n\t" + " rjmp _Li2c_write_first \n\t" + "_Li2c_write_bit:\n\t" + " lsl r24 ;left shift into carry ;; 1C\n\t" + "_Li2c_write_first:\n\t" + " breq _Li2c_get_ack ;jump if TXreg is empty;; +1 = 2C \n\t" + " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 4C \n\t" + " nop \n\t" + " nop \n\t" + " nop \n\t" + " brcc _Li2c_write_low ;;+1/+2=5/6C\n\t" + " nop ;; +1 = 7C \n\t" + " cbi %[SDADDR],%[SDAPIN] ;release SDA ;; +2 = 9C \n\t" + " rjmp _Li2c_write_high ;; +2 = 11C \n\t" + "_Li2c_write_low: \n\t" + " sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; +2 = 9C \n\t" + " rjmp _Li2c_write_high ;;+2 = 11C \n\t" + "_Li2c_write_high: \n\t" +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;;+X = 11C+X\n\t" +#endif + " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;;+2 = 13C+X\n\t" + " cln ;clear N-bit ;;+1 = 14C+X\n\t" + " nop \n\t" + " nop \n\t" + " nop \n\t" + " sbis %[SCLIN],%[SCLPIN] ;check for SCL high ;;+2 = 16C+X\n\t" + " rcall ass_i2c_wait_scl_high \n\t" + " brpl _Ldelay_scl_high ;;+2 = 18C+X\n\t" + "_Li2c_write_return_false: \n\t" + " clr r24 ; return false because of timeout \n\t" + " rjmp _Li2c_write_return \n\t" + "_Ldelay_scl_high: \n\t" +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;;+X= 18C+2X\n\t" +#endif + " rjmp _Li2c_write_bit \n\t" + " ;; +2 = 20C +2X for one bit-loop \n\t" + "_Li2c_get_ack: \n\t" + " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 5C \n\t" + " nop \n\t" + " nop \n\t" + " cbi %[SDADDR],%[SDAPIN] ;release SDA ;;+2 = 7C \n\t" +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;; +X = 7C+X \n\t" +#endif + " clr r25 ;; 17C+2X \n\t" + " clr r24 ;return 0 ;; 14C + X \n\t" + " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; +2 = 9C+X\n\t" + "_Li2c_ack_wait: \n\t" + " cln ; clear N-bit ;; 10C + X\n\t" + " nop \n\t" + " sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X \n\t" + " rcall ass_i2c_wait_scl_high \n\t" + " brmi _Li2c_write_return_false ;; 13C + X \n\t " + " sbis %[SDAIN],%[SDAPIN] ;if SDA hi -> return 0 ;; 15C + X \n\t" + " ldi r24,1 ;return true ;; 16C + X \n\t" +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;; 16C + 2X \n\t" +#endif + "_Li2c_write_return: \n\t" + " nop \n\t " + " nop \n\t " + " sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t" + " ret \n\t" + " ;; + 4 = 17C + 2X for acknowldge bit" + :: + [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN), + [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), [SDAIN] "I" (SDA_IN)); + return true; // fooling the compiler +} + +uint8_t i2c_read(bool last) +{ + __asm__ __volatile__ + ( + " ldi r23,0x01 \n\t" + "_Li2c_read_bit: \n\t" + " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t" + " cbi %[SDADDR],%[SDAPIN] ;release SDA(prev. ACK);; 4C \n\t" + " nop \n\t" + " nop \n\t" + " nop \n\t" +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;; 4C+X \n\t" +#endif + " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 6C + X \n\t" +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;; 6C + 2X \n\t" +#endif + " cln ; clear N-bit ;; 7C + 2X \n\t" + " nop \n\t " + " nop \n\t " + " nop \n\t " + " sbis %[SCLIN], %[SCLPIN] ;check for SCL high ;; 9C +2X \n\t" + " rcall ass_i2c_wait_scl_high \n\t" + " brmi _Li2c_read_return ;return if timeout ;; 10C + 2X\n\t" + " clc ;clear carry flag ;; 11C + 2X\n\t" + " sbic %[SDAIN],%[SDAPIN] ;if SDA is high ;; 11C + 2X\n\t" + " sec ;set carry flag ;; 12C + 2X\n\t" + " rol r23 ;store bit ;; 13C + 2X\n\t" + " brcc _Li2c_read_bit ;while receiv reg not full \n\t" + " ;; 15C + 2X for one bit loop \n\t" + + "_Li2c_put_ack: \n\t" + " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t" + " cpi r24,0 ;; 3C \n\t" + " breq _Li2c_put_ack_low ;if (ack=0) ;; 5C \n\t" + " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t" + " rjmp _Li2c_put_ack_high \n\t" + "_Li2c_put_ack_low: ;else \n\t" + " sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; 7C \n\t" + "_Li2c_put_ack_high: \n\t" + " nop \n\t " + " nop \n\t " + " nop \n\t " +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;; 7C + X \n\t" +#endif + " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 9C +X \n\t" + " cln ;clear N ;; +1 = 10C\n\t" + " nop \n\t " + " nop \n\t " + " sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X\n\t" + " rcall ass_i2c_wait_scl_high \n\t" +#if I2C_DELAY_COUNTER >= 1 + " rcall ass_i2c_delay_half ;delay T/2 ;; 11C + 2X\n\t" +#endif + "_Li2c_read_return: \n\t" + " nop \n\t " + " nop \n\t " + "sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t" + " mov r24,r23 ;; 12C + 2X \n\t" + " clr r25 ;; 13 C + 2X\n\t" + " ret ;; 17C + X" + :: + [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN), + [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), [SDAIN] "I" (SDA_IN) + ); + return ' '; // fool the compiler! +} + + +#pragma GCC diagnostic pop + +#endif + + + + diff --git a/sparkfun/tiny/libraries/Wire/src/SoftWire.h b/sparkfun/tiny/libraries/Wire/src/SoftWire.h new file mode 100644 index 00000000..c1194132 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/SoftWire.h @@ -0,0 +1,200 @@ +/* + SoftWire.h - A Wire compatible wrapper for SoftI2CMaster + Copyright (c) 2016 Bernhard Nebel. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SoftWire_h +#define _SoftWire_h + +#include +#include +#include "Stream.h" + +#define BUFFER_LENGTH 32 + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +class SoftWire : public Stream +{ +private: + uint8_t rxBuffer[BUFFER_LENGTH]; + uint8_t rxBufferIndex; + uint8_t rxBufferLength; + uint8_t transmitting; + uint8_t error; +public: + SoftWire(void) { + } + + void begin(void) { + rxBufferIndex = 0; + rxBufferLength = 0; + error = 0; + transmitting = false; + + i2c_init(); + } + + void end(void) { + } + + void setClock(uint32_t _) { + } + + void beginTransmission(uint8_t address) { + if (transmitting) { + error = (i2c_rep_start((address<<1)|I2C_WRITE) ? 0 : 2); + } else { + error = (i2c_start((address<<1)|I2C_WRITE) ? 0 : 2); + } + // indicate that we are transmitting + transmitting = 1; + } + + void beginTransmission(int address) { + beginTransmission((uint8_t)address); + } + + uint8_t endTransmission(uint8_t sendStop) + { + uint8_t transError = error; + if (sendStop) { + i2c_stop(); + transmitting = 0; + } + error = 0; + return transError; + } + + // This provides backwards compatibility with the original + // definition, and expected behaviour, of endTransmission + // + uint8_t endTransmission(void) + { + return endTransmission(true); + } + + size_t write(uint8_t data) { + if (i2c_write(data)) { + return 1; + } else { + if (error == 0) error = 3; + return 0; + } + } + + size_t write(const uint8_t *data, size_t quantity) { + size_t trans = 0; + for(size_t i = 0; i < quantity; ++i){ + trans += write(data[i]); + } + return trans; + } + + uint8_t requestFrom(uint8_t address, uint8_t quantity, + uint32_t iaddress, uint8_t isize, uint8_t sendStop) { + uint8_t localerror = 0; + if (isize > 0) { + // send internal address; this mode allows sending a repeated start to access + // some devices' internal registers. This function is executed by the hardware + // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) + beginTransmission(address); + // the maximum size of internal address is 3 bytes + if (isize > 3){ + isize = 3; + } + // write internal register address - most significant byte first + while (isize-- > 0) + write((uint8_t)(iaddress >> (isize*8))); + endTransmission(false); + } + // clamp to buffer length + if(quantity > BUFFER_LENGTH){ + quantity = BUFFER_LENGTH; + } + localerror = !i2c_rep_start((address<<1) | I2C_READ); + if (error == 0 && localerror) error = 2; + // perform blocking read into buffer + for (uint8_t cnt=0; cnt < quantity; cnt++) + rxBuffer[cnt] = i2c_read(cnt == quantity-1); + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = quantity; + if (sendStop) { + transmitting = 0; + i2c_stop(); + } + return quantity; + } + + uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop); + } + + uint8_t requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); + } + + + uint8_t requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); + } + + uint8_t requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); + } + + int available(void) { + return rxBufferLength - rxBufferIndex; + } + + int read(void) { + int value = -1; + if(rxBufferIndex < rxBufferLength){ + value = rxBuffer[rxBufferIndex]; + ++rxBufferIndex; + } + return value; + } + + int peek(void) { + int value = -1; + + if(rxBufferIndex < rxBufferLength){ + value = rxBuffer[rxBufferIndex]; + } + return value; + } + + void flush(void) { + } + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + + inline size_t write(long n) { return write((uint8_t)n); } + + inline size_t write(unsigned int n) { return write((uint8_t)n); } + + inline size_t write(int n) { return write((uint8_t)n); } + + using Print::write; +}; + + +#endif + diff --git a/sparkfun/tiny/libraries/Wire/src/TWSWire.cpp b/sparkfun/tiny/libraries/Wire/src/TWSWire.cpp new file mode 100644 index 00000000..7a195346 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/TWSWire.cpp @@ -0,0 +1,210 @@ +/* + TWSWire.h - TWI HW slave and software master based TWI/I2C library for Arduino + Copyright (c) 2017 j54n1n. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Based on TwoWire form Arduino https://github.com/arduino/Arduino. +*/ +#if defined(TWSD) && !defined(__AVR_ATtiny1634__) +#include "TWSWire.h" +#include + +#if defined(__AVR_ATtiny841__) || defined(__AVR_ATtiny441__) +#define SCL_PIN 4 +#define SCL_PORT PORTA +#define SDA_PIN 6 +#define SDA_PORT PORTA +#elif defined(__AVR_ATtiny828__) +#define SCL_PIN 3 +#define SCL_PORT PORTD +#define SDA_PIN 0 +#define SDA_PORT PORTD +#else +#error No pins for software I2C defined +#endif +#define I2C_TIMEOUT 100 +#include "SoftWire.h" +static SoftWire softWire; + +#include "WireS.h" + +// Constructors //////////////////////////////////////////////////////////////// + +TWSWire::TWSWire() : slaveMode(false) { +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void TWSWire::begin(void) { + softWire.begin(); + slaveMode = false; +} + +void TWSWire::begin(uint8_t address) { + TinyWireS.begin(address, 0); + slaveMode = true; +} + +void TWSWire::begin(int address) { + begin((uint8_t)address); +} + +void TWSWire::end(void) { + // XXX: to be implemented. +} + +void TWSWire::setClock(uint32_t clock) { + // XXX: to be implemented. + (void)clock; //disable warning +} + +uint8_t TWSWire::requestFrom(uint8_t address, uint8_t quantity, + uint32_t iaddress, uint8_t isize, + uint8_t sendStop) { + if(!slaveMode) { + return softWire.requestFrom(address, quantity, iaddress, isize, sendStop); + } + return 0; +} + +uint8_t TWSWire::requestFrom(uint8_t address, uint8_t quantity, + uint8_t sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, + (uint8_t)0, (uint8_t)sendStop); +} + +uint8_t TWSWire::requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TWSWire::requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TWSWire::requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); +} + +void TWSWire::beginTransmission(uint8_t address) { + if(!slaveMode) { + softWire.beginTransmission(address); + } +} + +void TWSWire::beginTransmission(int address) { + beginTransmission((uint8_t)address); +} + +uint8_t TWSWire::endTransmission(uint8_t sendStop) { + if(!slaveMode) { + return softWire.endTransmission(sendStop); + } + return 4; //other error +} + +uint8_t TWSWire::endTransmission(void) { + return endTransmission(true); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TWSWire::write(uint8_t data) { + size_t numBytes = 0; + if(!slaveMode) { + numBytes = softWire.write(data); + } else { + numBytes = TinyWireS.write(data); + } + return numBytes; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TWSWire::write(const uint8_t *data, size_t quantity) { + size_t numBytes = 0; + for (size_t i = 0; i < quantity; ++i){ + numBytes += write(data[i]); + } + return numBytes; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TWSWire::write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TWSWire::available(void) { + int value = -1; + if(!slaveMode) { + value = softWire.available(); + } else { + value = TinyWireS.available(); + } + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TWSWire::read(void) { + int value = -1; + if(!slaveMode) { + value = softWire.read(); + } else { + value = TinyWireS.read(); + } + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TWSWire::peek(void) { + int value = -1; + if(!slaveMode) { + value = softWire.peek(); + } else { + value = TinyWireS.peek(); + } + return value; +} + +void TWSWire::flush(void) { + // XXX: to be implemented. +} + +// sets function called on slave write +void TWSWire::onReceive( void (*function)(int) ) { + TinyWireS.onReceive(function); +} + +// sets function called on slave read +void TWSWire::onRequest( void (*function)(void) ) { + TinyWireS.onRequest(function); +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +TWSWire Wire = TWSWire(); +#endif // TWSD diff --git a/sparkfun/tiny/libraries/Wire/src/TWSWire.h b/sparkfun/tiny/libraries/Wire/src/TWSWire.h new file mode 100644 index 00000000..cbab325c --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/TWSWire.h @@ -0,0 +1,69 @@ +/* + TWSWire.h - TWI HW slave and software master based TWI/I2C library for Arduino + Copyright (c) 2017 j54n1n. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Based on TwoWire form Arduino https://github.com/arduino/Arduino. +*/ +#ifndef TWSWire_h +#define TWSWire_h + +#if defined(TWSD) && !defined(__AVR_ATtiny1634__) +#include +#include + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +class TWSWire { + private: + bool slaveMode; + public: + TWSWire(); + void begin(); + void begin(uint8_t); + void begin(int); + void end(); + void setClock(uint32_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t endTransmission(uint8_t); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(int, int); + uint8_t requestFrom(int, int, int); + size_t write(uint8_t); + size_t write(const uint8_t *, size_t); + size_t write(const char *); + int available(void); + int read(void); + int peek(void); + void flush(void); + void onReceive( void (*)(int) ); + void onRequest( void (*)(void) ); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } +}; + +extern TWSWire Wire; + +#endif // TWSD +#endif // TWSWire_h diff --git a/sparkfun/tiny/libraries/Wire/src/USIWire.cpp b/sparkfun/tiny/libraries/Wire/src/USIWire.cpp new file mode 100644 index 00000000..45c47b16 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/USIWire.cpp @@ -0,0 +1,295 @@ +/* + USIWire.cpp - USI based TWI/I2C library for Arduino + Copyright (c) 2017 Puuu. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Based on TwoWire form Arduino https://github.com/arduino/Arduino. +*/ +#ifdef USIDR +extern "C" { +#include +#include +#include +#include "USI_TWI_Slave/USI_TWI_Slave.h" +#include "USI_TWI_Master/USI_TWI_Master.h" +} + +#include "USIWire.h" + +const uint8_t WIRE_BUFFER_LENGTH = TWI_BUFFER_SIZE - 1; //reserve slave addr + +// Initialize Class Variables ////////////////////////////////////////////////// + +uint8_t *USIWire::Buffer = TWI_Buffer; +uint8_t USIWire::BufferIndex = 0; +uint8_t USIWire::BufferLength = 0; + +uint8_t USIWire::transmitting = 0; + +// Constructors //////////////////////////////////////////////////////////////// + +USIWire::USIWire() { +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void USIWire::begin(void) { + BufferIndex = 0; + BufferLength = 0; + + transmitting = 0; + + USI_TWI_Master_Initialise(); +} + +void USIWire::begin(uint8_t address) { + USI_TWI_Slave_Initialise(address); +} + +void USIWire::begin(int address) { + begin((uint8_t)address); +} + +void USIWire::end(void) { + USI_TWI_Slave_Disable(); +} + +void USIWire::setClock(uint32_t clock) { + // XXX: to be implemented. + (void)clock; //disable warning +} + +uint8_t USIWire::requestFrom(uint8_t address, uint8_t quantity, + uint32_t iaddress, uint8_t isize, + uint8_t sendStop) { + if (isize > 0) { + // send internal address; this mode allows sending a repeated + // start to access some devices' internal registers. This function + // is executed by the hardware TWI module on other processors (for + // example Due's TWI_IADR and TWI_MMR registers) + + beginTransmission(address); + + // the maximum size of internal address is 3 bytes + if (isize > 3) { + isize = 3; + } + + // write internal register address - most significant byte first + while (isize-- > 0) { + write((uint8_t)(iaddress >> (isize*8))); + } + endTransmission(false); + } + + // reserve one byte for slave address + quantity++; + // clamp to buffer length + if (quantity > TWI_BUFFER_SIZE) { + quantity = TWI_BUFFER_SIZE; + } + // set address of targeted slave and read mode + Buffer[0] = (address << TWI_ADR_BITS) | (1 << TWI_READ_BIT); + // perform blocking read into buffer + uint8_t ret = USI_TWI_Start_Transceiver_With_Data_Stop(Buffer, quantity, + sendStop); + // set rx buffer iterator vars + BufferIndex = 1; // ignore slave address + // check for error + if (ret == FALSE) { + BufferLength = BufferIndex; + return 0; + } + BufferLength = quantity; + + return quantity - 1; // ignore slave address +} + +uint8_t USIWire::requestFrom(uint8_t address, uint8_t quantity, + uint8_t sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, + (uint8_t)0, (uint8_t)sendStop); +} + +uint8_t USIWire::requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t USIWire::requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t USIWire::requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); +} + +void USIWire::beginTransmission(uint8_t address) { + // indicate that we are transmitting + transmitting = 1; + // set address of targeted slave and write mode + Buffer[0] = (address << TWI_ADR_BITS) | (0 << TWI_READ_BIT); + // reset tx buffer iterator vars + BufferIndex = 1; // reserved by slave address + BufferLength = BufferIndex; +} + +void USIWire::beginTransmission(int address) { + beginTransmission((uint8_t)address); +} + +uint8_t USIWire::endTransmission(uint8_t sendStop) { + // transmit buffer (blocking) + uint8_t ret = USI_TWI_Start_Transceiver_With_Data_Stop(Buffer, + BufferLength, + sendStop); + // reset tx buffer iterator vars + BufferIndex = 0; + BufferLength = 0; + // indicate that we are done transmitting + transmitting = 0; + // check for error + if (ret == FALSE) { + switch (USI_TWI_Get_State_Info()) { + case USI_TWI_DATA_OUT_OF_BOUND: + return 1; //data too long to fit in transmit buffer + case USI_TWI_NO_ACK_ON_ADDRESS: + return 2; //received NACK on transmit of address + case USI_TWI_NO_ACK_ON_DATA: + return 3; //received NACK on transmit of data + } + return 4; //other error + } + return 0; //success +} + +uint8_t USIWire::endTransmission(void) { + return endTransmission(true); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t USIWire::write(uint8_t data) { + if (transmitting) { // in master transmitter mode + // don't bother if buffer is full + if (BufferLength >= TWI_BUFFER_SIZE) { + return 0; + } + // put byte in tx buffer + Buffer[BufferIndex] = data; + ++BufferIndex; + // update amount in buffer + BufferLength = BufferIndex; + } else { // in slave send mode + // don't bother if buffer is full + if (!USI_TWI_Space_In_Transmission_Buffer()) { + return 0; + } + // reply to master + USI_TWI_Transmit_Byte(data); + } + return 1; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t USIWire::write(const uint8_t *data, size_t quantity) { + size_t numBytes = 0; + for (size_t i = 0; i < quantity; ++i){ + numBytes += write(data[i]); + } + return numBytes; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t USIWire::write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int USIWire::available(void) { + if (BufferLength) { + return BufferLength - BufferIndex; + } else { + return USI_TWI_Data_In_Receive_Buffer(); + } +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int USIWire::read(void) { + int value = -1; + + // get each successive byte on each call + if (available()) { + if (BufferLength) { + value = Buffer[BufferIndex]; + ++BufferIndex; + } else { + value = USI_TWI_Receive_Byte(); + } + } + + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int USIWire::peek(void) { + int value = -1; + + if (available()) { + if (BufferLength) { + value = Buffer[BufferIndex]; + } else { + value = USI_TWI_Peek_Receive_Byte(); + } + } + + return value; +} + +void USIWire::flush(void) { + // XXX: to be implemented. +} + +// sets function called on slave write +void USIWire::onReceive( void (*function)(int) ) { + USI_TWI_On_Slave_Receive = function; +} + +// sets function called on slave read +void USIWire::onRequest( void (*function)(void) ) { + USI_TWI_On_Slave_Transmit = function; +} + +// return true on I2C/TWI activity +uint8_t USIWire::isActive(void) { + return USI_TWI_Slave_Is_Active(); +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +USIWire Wire = USIWire(); +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/USIWire.h b/sparkfun/tiny/libraries/Wire/src/USIWire.h new file mode 100644 index 00000000..5647345a --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/USIWire.h @@ -0,0 +1,77 @@ +/* + USIWire.h - USI based TWI/I2C library for Arduino + Copyright (c) 2017 Puuu. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Based on TwoWire form Arduino https://github.com/arduino/Arduino. +*/ +#ifndef USIWire_h +#define USIWire_h + +#ifdef USIDR +#include + +// Buffer sizes are defined in USI_TWI_Slave/USI_TWI_Slave.h +extern const uint8_t WIRE_BUFFER_LENGTH; +#define BUFFER_LENGTH (WIRE_BUFFER_LENGTH) + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +class USIWire { + private: + static uint8_t *Buffer; + static uint8_t BufferIndex; + static uint8_t BufferLength; + + static uint8_t transmitting; + public: + USIWire(); + void begin(); + void begin(uint8_t); + void begin(int); + void end(); + void setClock(uint32_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t endTransmission(uint8_t); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(int, int); + uint8_t requestFrom(int, int, int); + size_t write(uint8_t); + size_t write(const uint8_t *, size_t); + size_t write(const char *); + int available(void); + int read(void); + int peek(void); + void flush(void); + void onReceive( void (*)(int) ); + void onRequest( void (*)(void) ); + uint8_t isActive(void); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } +}; + +extern USIWire Wire; + +#endif +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/USI_TWI_Master/USI_TWI_Master.c b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Master/USI_TWI_Master.c new file mode 100644 index 00000000..6b7f9eec --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Master/USI_TWI_Master.c @@ -0,0 +1,272 @@ +/***************************************************************************** +* +* Atmel Corporation +* +* File : USI_TWI_Master.c +* Date : $Date: 2016-7-15 $ +* Updated by : $Author: Atmel $ +* +* Support mail : avr@atmel.com +* +* Supported devices : All device with USI module can be used. +* The example is written for the ATmega169, ATtiny26 and ATtiny2313 +* +* AppNote : AVR310 - Using the USI module as a TWI Master +* +* Description : This is an implementation of an TWI master using +* the USI module as basis. The implementation assumes the AVR to +* be the only TWI master in the system and can therefore not be +* used in a multi-master system. +* Usage : Initialize the USI module by calling the USI_TWI_Master_Initialise() +* function. Hence messages/data are transceived on the bus using +* the USI_TWI_Transceive() function. The transceive function +* returns a status byte, which can be used to evaluate the +* success of the transmission. +* +****************************************************************************/ + + +#if __GNUC__ +#include +#else +#include +#include +#endif +#ifdef USIDR +#include "USI_TWI_Master.h" + +unsigned char USI_TWI_Master_Transfer(unsigned char); +unsigned char USI_TWI_Master_Stop(void); + +union USI_TWI_state { + unsigned char errorState; // Can reuse the TWI_state for error states due to that it will not be need if there + // exists an error. + struct { + unsigned char addressMode : 1; + unsigned char masterWriteDataMode : 1; + unsigned char unused : 6; + }; +} USI_TWI_state; + +/*--------------------------------------------------------------- + USI TWI single master initialization function +---------------------------------------------------------------*/ +void USI_TWI_Master_Initialise(void) +{ + PORT_USI |= (1 << PIN_USI_SDA); // Enable pullup on SDA, to set high as released state. + PORT_USI_CL |= (1 << PIN_USI_SCL); // Enable pullup on SCL, to set high as released state. + + DDR_USI_CL |= (1 << PIN_USI_SCL); // Enable SCL as output. + DDR_USI |= (1 << PIN_USI_SDA); // Enable SDA as output. + + USIDR = 0xFF; // Preload dataregister with "released level" data. + USICR = (0 << USISIE) | (0 << USIOIE) | // Disable Interrupts. + (1 << USIWM1) | (0 << USIWM0) | // Set USI in Two-wire mode. + (1 << USICS1) | (0 << USICS0) | (1 << USICLK) | // Software stobe as counter clock source + (0 << USITC); + USISR = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) | // Clear flags, + (0x0 << USICNT0); // and reset counter. +} + +/*--------------------------------------------------------------- +Use this function to get hold of the error message from the last transmission +---------------------------------------------------------------*/ +unsigned char USI_TWI_Get_State_Info(void) +{ + return (USI_TWI_state.errorState); // Return error state. +} + +/*--------------------------------------------------------------- + USI Transmit and receive function. LSB of first byte in data + indicates if a read or write cycles is performed. If set a read + operation is performed. + + Function generates (Repeated) Start Condition, sends address and + R/W, Reads/Writes Data, and verifies/sends ACK. + + Success or error code is returned. Error codes are defined in + USI_TWI_Master.h +---------------------------------------------------------------*/ +unsigned char USI_TWI_Start_Transceiver_With_Data(unsigned char *msg, unsigned char msgSize) { + return USI_TWI_Start_Transceiver_With_Data_Stop(msg, msgSize, TRUE); +} + +/*--------------------------------------------------------------- + USI Transmit and receive function. + + Same as USI_TWI_Start_Transceiver_With_Data() but with an additional + parameter that defines if a Stop Condition should be send at the end + of the transmission. +---------------------------------------------------------------*/ +#ifndef __GNUC__ +__x // AVR compiler +#endif + unsigned char + USI_TWI_Start_Transceiver_With_Data_Stop(unsigned char *msg, unsigned char msgSize, unsigned char stop) +{ + unsigned char tempUSISR_8bit = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) + | // Prepare register value to: Clear flags, and + (0x0 << USICNT0); // set USI to shift 8 bits i.e. count 16 clock edges. + unsigned char tempUSISR_1bit = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) + | // Prepare register value to: Clear flags, and + (0xE << USICNT0); // set USI to shift 1 bit i.e. count 2 clock edges. + + USI_TWI_state.errorState = 0; + USI_TWI_state.addressMode = TRUE; + +#ifdef PARAM_VERIFICATION + if (msg > (unsigned char *)RAMEND) // Test if address is outside SRAM space + { + USI_TWI_state.errorState = USI_TWI_DATA_OUT_OF_BOUND; + return (FALSE); + } + if (msgSize <= 1) // Test if the transmission buffer is empty + { + USI_TWI_state.errorState = USI_TWI_NO_DATA; + return (FALSE); + } +#endif + +#ifdef NOISE_TESTING // Test if any unexpected conditions have arrived prior to this execution. + if (USISR & (1 << USISIF)) { + USI_TWI_state.errorState = USI_TWI_UE_START_CON; + return (FALSE); + } + if (USISR & (1 << USIPF)) { + USI_TWI_state.errorState = USI_TWI_UE_STOP_CON; + return (FALSE); + } + if (USISR & (1 << USIDC)) { + USI_TWI_state.errorState = USI_TWI_UE_DATA_COL; + return (FALSE); + } +#endif + + if (!(*msg + & (1 << TWI_READ_BIT))) // The LSB in the address byte determines if is a masterRead or masterWrite operation. + { + USI_TWI_state.masterWriteDataMode = TRUE; + } + + /* Release SCL to ensure that (repeated) Start can be performed */ + PORT_USI_CL |= (1 << PIN_USI_SCL); // Release SCL. + while (!(PIN_USI_CL & (1 << PIN_USI_SCL))) + ; // Verify that SCL becomes high. +#ifdef TWI_FAST_MODE + DELAY_T4TWI; // Delay for T4TWI if TWI_FAST_MODE +#else + DELAY_T2TWI; // Delay for T2TWI if TWI_STANDARD_MODE +#endif + + /* Generate Start Condition */ + PORT_USI &= ~(1 << PIN_USI_SDA); // Force SDA LOW. + DELAY_T4TWI; + PORT_USI_CL &= ~(1 << PIN_USI_SCL); // Pull SCL LOW. + PORT_USI |= (1 << PIN_USI_SDA); // Release SDA. + +#ifdef SIGNAL_VERIFY + if (!(USISR & (1 << USISIF))) { + USI_TWI_state.errorState = USI_TWI_MISSING_START_CON; + return (FALSE); + } +#endif + + /*Write address and Read/Write data */ + do { + /* If masterWrite cycle (or inital address tranmission)*/ + if (USI_TWI_state.addressMode || USI_TWI_state.masterWriteDataMode) { + /* Write a byte */ + PORT_USI_CL &= ~(1 << PIN_USI_SCL); // Pull SCL LOW. + USIDR = *(msg++); // Setup data. + USI_TWI_Master_Transfer(tempUSISR_8bit); // Send 8 bits on bus. + + /* Clock and verify (N)ACK from slave */ + DDR_USI &= ~(1 << PIN_USI_SDA); // Enable SDA as input. + if (USI_TWI_Master_Transfer(tempUSISR_1bit) & (1 << TWI_NACK_BIT)) { + if (USI_TWI_state.addressMode) + USI_TWI_state.errorState = USI_TWI_NO_ACK_ON_ADDRESS; + else + USI_TWI_state.errorState = USI_TWI_NO_ACK_ON_DATA; + return (FALSE); + } + USI_TWI_state.addressMode = FALSE; // Only perform address transmission once. + } + /* Else masterRead cycle*/ + else { + /* Read a data byte */ + DDR_USI &= ~(1 << PIN_USI_SDA); // Enable SDA as input. + *(msg++) = USI_TWI_Master_Transfer(tempUSISR_8bit); + + /* Prepare to generate ACK (or NACK in case of End Of Transmission) */ + if (msgSize == 1) // If transmission of last byte was performed. + { + USIDR = 0xFF; // Load NACK to confirm End Of Transmission. + } else { + USIDR = 0x00; // Load ACK. Set data register bit 7 (output for SDA) low. + } + USI_TWI_Master_Transfer(tempUSISR_1bit); // Generate ACK/NACK. + } + } while (--msgSize); // Until all data sent/received. + + if (stop) { + USI_TWI_Master_Stop(); // Send a STOP condition on the TWI bus. + } + + /* Transmission successfully completed*/ + return (TRUE); +} + +/*--------------------------------------------------------------- + Core function for shifting data in and out from the USI. + Data to be sent has to be placed into the USIDR prior to calling + this function. Data read, will be return'ed from the function. +---------------------------------------------------------------*/ +unsigned char USI_TWI_Master_Transfer(unsigned char temp) +{ + USISR = temp; // Set USISR according to temp. + // Prepare clocking. + temp = (0 << USISIE) | (0 << USIOIE) | // Interrupts disabled + (1 << USIWM1) | (0 << USIWM0) | // Set USI in Two-wire mode. + (1 << USICS1) | (0 << USICS0) | (1 << USICLK) | // Software clock strobe as source. + (1 << USITC); // Toggle Clock Port. + do { + DELAY_T2TWI; + USICR = temp; // Generate positve SCL edge. + while (!(PIN_USI_CL & (1 << PIN_USI_SCL))) + ; // Wait for SCL to go high. + DELAY_T4TWI; + USICR = temp; // Generate negative SCL edge. + } while (!(USISR & (1 << USIOIF))); // Check for transfer complete. + + DELAY_T2TWI; + temp = USIDR; // Read out data. + USIDR = 0xFF; // Release SDA. + DDR_USI |= (1 << PIN_USI_SDA); // Enable SDA as output. + + return temp; // Return the data from the USIDR +} + +/*--------------------------------------------------------------- + Function for generating a TWI Stop Condition. Used to release + the TWI bus. +---------------------------------------------------------------*/ +unsigned char USI_TWI_Master_Stop(void) +{ + PORT_USI &= ~(1 << PIN_USI_SDA); // Pull SDA low. + PORT_USI_CL |= (1 << PIN_USI_SCL); // Release SCL. + while (!(PIN_USI_CL & (1 << PIN_USI_SCL))) + ; // Wait for SCL to go high. + DELAY_T4TWI; + PORT_USI |= (1 << PIN_USI_SDA); // Release SDA. + DELAY_T2TWI; + +#ifdef SIGNAL_VERIFY + if (!(USISR & (1 << USIPF))) { + USI_TWI_state.errorState = USI_TWI_MISSING_STOP_CON; + return (FALSE); + } +#endif + + return (TRUE); +} +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/USI_TWI_Master/USI_TWI_Master.h b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Master/USI_TWI_Master.h new file mode 100644 index 00000000..f3385aba --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Master/USI_TWI_Master.h @@ -0,0 +1,102 @@ +/***************************************************************************** +* +* Atmel Corporation +* +* File : USI_TWI_Master.h +* Date : $Date: 2016-7-15 $ +* Updated by : $Author: Atmel $ +* +* Support mail : avr@atmel.com +* +* Supported devices : All device with USI module can be used. +* The example is written for the ATmega169, ATtiny26 and ATtiny2313 +* +* AppNote : AVR310 - Using the USI module as a TWI Master +* +* Description : This is an implementation of an TWI master using +* the USI module as basis. The implementation assumes the AVR to +* be the only TWI master in the system and can therefore not be +* used in a multi-master system. +* Usage : Initialize the USI module by calling the USI_TWI_Master_Initialise() +* function. Hence messages/data are transceived on the bus using +* the USI_TWI_Start_Transceiver_With_Data() function. If the transceiver +* returns with a fail, then use USI_TWI_Get_Status_Info to evaluate the +* couse of the failure. +* +****************************************************************************/ + +#include +#ifndef TWDR + +#if __GNUC__ +#ifndef F_CPU +#define F_CPU 4000000 +#endif +#include +#endif +//********** Defines **********// +// Defines controlling timing limits +#define TWI_FAST_MODE + +#define SYS_CLK 4000.0 // [kHz] + +#ifdef TWI_FAST_MODE // TWI FAST mode timing limits. SCL = 100-400kHz +#define T2_TWI ((SYS_CLK * 1300) / 1000000) + 1 // >1,3us +#define T4_TWI ((SYS_CLK * 600) / 1000000) + 1 // >0,6us + +#else // TWI STANDARD mode timing limits. SCL <= 100kHz +#define T2_TWI ((SYS_CLK * 4700) / 1000000) + 1 // >4,7us +#define T4_TWI ((SYS_CLK * 4000) / 1000000) + 1 // >4,0us +#endif + +// Defines controling code generating +//#define PARAM_VERIFICATION +//#define NOISE_TESTING +#define SIGNAL_VERIFY + +// USI_TWI messages and flags and bit masks +//#define SUCCESS 7 +//#define MSG 0 +/**************************************************************************** + Bit and byte definitions +****************************************************************************/ +#define TWI_READ_BIT 0 // Bit position for R/W bit in "address byte". +#define TWI_ADR_BITS 1 // Bit position for LSB of the slave address bits in the init byte. +#define TWI_NACK_BIT 0 // Bit position for (N)ACK bit. + +#define USI_TWI_NO_DATA 0x00 // Transmission buffer is empty +#define USI_TWI_DATA_OUT_OF_BOUND 0x01 // Transmission buffer is outside SRAM space +#define USI_TWI_UE_START_CON 0x02 // Unexpected Start Condition +#define USI_TWI_UE_STOP_CON 0x03 // Unexpected Stop Condition +#define USI_TWI_UE_DATA_COL 0x04 // Unexpected Data Collision (arbitration) +#define USI_TWI_NO_ACK_ON_DATA 0x05 // The slave did not acknowledge all data +#define USI_TWI_NO_ACK_ON_ADDRESS 0x06 // The slave did not acknowledge the address +#define USI_TWI_MISSING_START_CON 0x07 // Generated Start Condition not detected on bus +#define USI_TWI_MISSING_STOP_CON 0x08 // Generated Stop Condition not detected on bus + + +#include "pins_arduino.h" + +// General defines +#define TRUE 1 +#define FALSE 0 + +#if __GNUC__ +#define DELAY_T2TWI (_delay_us(T2_TWI / 4)) +#define DELAY_T4TWI (_delay_us(T4_TWI / 4)) +#else +#define DELAY_T2TWI (__delay_cycles(T2_TWI)) +#define DELAY_T4TWI (__delay_cycles(T4_TWI)) +#endif +//********** Prototypes **********// + +void USI_TWI_Master_Initialise(void); +#ifndef __GNUC__ +__x // AVR compiler +#endif + unsigned char + USI_TWI_Start_Transceiver_With_Data_Stop(unsigned char *, unsigned char, unsigned char); +unsigned char USI_TWI_Start_Transceiver_With_Data(unsigned char *, unsigned char); + +unsigned char USI_TWI_Get_State_Info(void); +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/USI_TWI_Slave/USI_TWI_Slave.c b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Slave/USI_TWI_Slave.c new file mode 100644 index 00000000..8e401408 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Slave/USI_TWI_Slave.c @@ -0,0 +1,311 @@ +// This file has been prepared for Doxygen automatic documentation generation. +/*! \file ******************************************************************** +* +* Atmel Corporation +* +* File : USI_TWI_Slave.c +* Compiler : IAR EWAAVR 4.11A +* Revision : $Revision: 614 $ +* Date : $Date: 2006-07-07 16:27:05 +0800 (Fri, 07 Jul 2006) $ +* Updated by : $Author: jllassen $ +* +* Support mail : avr@atmel.com +* +* Supported devices : All device with USI module can be used. +* The example is written for the ATmega169, ATtiny26, ATmega325 & ATtiny2313 +* +* AppNote : AVR312 - Using the USI module as a I2C slave +* +* Description : Functions for USI_TWI_receiver and USI_TWI_transmitter. +* +* +****************************************************************************/ + + +#ifdef __GNUC__ +#include "avr/io.h" +#include "avr/interrupt.h" +#elif __ICCAVR__ +#include "ioavr.h" +#include "inavr.h" +#endif +#ifdef USIDR +#include "USI_TWI_Slave.h" + +//********** Buffer **********// +uint8_t TWI_Buffer[TWI_BUFFER_SIZE]; + +//********** Static Variables **********// + +static unsigned char TWI_slaveAddress; +static volatile unsigned char USI_TWI_Overflow_State; + +/*=========================> Locals <=======================================*/ +static uint8_t * TWI_RxBuf = TWI_Buffer; +static volatile uint8_t TWI_RxHead; +static volatile uint8_t TWI_RxTail; + +static uint8_t * TWI_TxBuf = TWI_Buffer + TWI_RX_BUFFER_SIZE; +static volatile uint8_t TWI_TxHead; +static volatile uint8_t TWI_TxTail; + +void Flush_TWI_Buffers(void) +{ + TWI_RxTail = 0; + TWI_RxHead = 0; + TWI_TxTail = 0; + TWI_TxHead = 0; +} + +//********** USI_TWI functions **********// + +/*---------------------------------------------------------- + Initialise USI for TWI Slave mode. +----------------------------------------------------------*/ +void USI_TWI_Slave_Initialise(unsigned char TWI_ownAddress) +{ + Flush_TWI_Buffers(); + + TWI_slaveAddress = TWI_ownAddress; + + USI_TWI_On_Slave_Transmit = 0; + USI_TWI_On_Slave_Receive = 0; + + PORT_USI_CL |= (1 << PORT_USI_SCL); // Set SCL high + PORT_USI |= (1 << PORT_USI_SDA); // Set SDA high + DDR_USI_CL |= (1 << PORT_USI_SCL); // Set SCL as output + DDR_USI &= ~(1 << PORT_USI_SDA); // Set SDA as input + USICR = (1 << USISIE) | (0 << USIOIE) | // Enable Start Condition Interrupt. Disable Overflow Interrupt. + (1 << USIWM1) | (0 << USIWM0) | // Set USI in Two-wire mode. No USI Counter overflow prior + // to first Start Condition (potentail failure) + (1 << USICS1) | (0 << USICS0) | (0 << USICLK) | // Shift Register Clock Source = External, positive edge + (0 << USITC); + USISR = 0xF0; // Clear all flags and reset overflow counter +} + +// Disable USI for TWI Slave mode. +void USI_TWI_Slave_Disable() +{ + DDR_USI_CL &= ~(1 << PORT_USI_SCL); // Set SCL as input + DDR_USI &= ~(1 << PORT_USI_SDA); // Set SDA as input + USICR = 0x00; // Disable USI + USISR = 0xF0; // Clear all flags and reset overflow counter +} + +// Puts data in the transmission buffer, Waits if buffer is full. +void USI_TWI_Transmit_Byte(unsigned char data) +{ + unsigned char tmphead; + + tmphead = (TWI_TxHead + 1) & TWI_TX_BUFFER_MASK; // Calculate buffer index. + while (tmphead == TWI_TxTail) + ; // Wait for free space in buffer. + TWI_TxBuf[tmphead] = data; // Store data in buffer. + TWI_TxHead = tmphead; // Store new index. +} + +// Returns a byte from the receive buffer. Waits if buffer is empty. +unsigned char USI_TWI_Receive_Byte(void) +{ + unsigned char tmptail; + unsigned char tmpRxTail; // Temporary variable to store volatile + tmpRxTail = TWI_RxTail; // Not necessary, but prevents warnings + while (TWI_RxHead == tmpRxTail) + ; + tmptail = (TWI_RxTail + 1) & TWI_RX_BUFFER_MASK; // Calculate buffer index + TWI_RxTail = tmptail; // Store new index + return TWI_RxBuf[tmptail]; // Return data from the buffer. +} + +// Returns a byte from the receive buffer without incrementing TWI_RxTail. Waits if buffer is empty. +unsigned char USI_TWI_Peek_Receive_Byte(void) +{ + unsigned char tmptail; + unsigned char tmpRxTail; // Temporary variable to store volatile + tmpRxTail = TWI_RxTail; // Not necessary, but prevents warnings + while (TWI_RxHead == tmpRxTail) + ; + tmptail = (TWI_RxTail + 1) & TWI_RX_BUFFER_MASK; // Calculate buffer index + return TWI_RxBuf[tmptail]; // Return data from the buffer. +} + +// Check if there is data in the receive buffer. +unsigned char USI_TWI_Data_In_Receive_Buffer(void) +{ + unsigned char tmpRxTail; // Temporary variable to store volatile + tmpRxTail = TWI_RxTail; // Not necessary, but prevents warnings + return (TWI_RxHead - tmpRxTail) & TWI_RX_BUFFER_MASK; // Return 0 (FALSE) if the receive buffer is empty. +} + +// Check if there is space in the transmission buffer. +unsigned char USI_TWI_Space_In_Transmission_Buffer(void) +{ + unsigned char tmpTxHead; + tmpTxHead = (TWI_TxHead + 1) & TWI_TX_BUFFER_MASK; // Calculate next buffer index. + return (TWI_TxTail - tmpTxHead) & TWI_TX_BUFFER_MASK; // Return 0 (FALSE) if the transmission buffer is full. +} + +// Check if there is an active data session. +unsigned char USI_TWI_Slave_Is_Active() +{ + // Active if Overflow Interrupt is enabled and no Stop Condition occurred + return (USICR & (1 << USIOIE)) && ((USISR & (1 << USIPF)) == 0); +} + +/*---------------------------------------------------------- + Detects the USI_TWI Start Condition and intialises the USI + for reception of the "TWI Address" packet. +----------------------------------------------------------*/ +#ifdef __GNUC__ +ISR(USI_START_VECTOR) +#elif __ICCAVR__ +#pragma vector = USI_START_VECTOR +__interrupt void USI_Start_Condition_ISR(void) +#endif +{ + unsigned char tmpPin; // Temporary variable for pin state + unsigned char tmpRxHead; // Temporary variable to store volatile + // call slave receive callback on repeated start + if (USI_TWI_On_Slave_Receive) { + tmpRxHead = TWI_RxHead; + if (TWI_RxTail != tmpRxHead) { // data in receive buffer + USI_TWI_On_Slave_Receive(USI_TWI_Data_In_Receive_Buffer()); + // reset rx buffer + TWI_RxTail = tmpRxHead; + } + } + + USI_TWI_Overflow_State = USI_SLAVE_CHECK_ADDRESS; + DDR_USI &= ~(1 << PORT_USI_SDA); // Set SDA as input + while ((tmpPin = (PIN_USI_CL & (1 << PORT_USI_SCL))) && ((PIN_USI & (1 << PIN_USI_SDA)) == 0)) + ; // Wait for SCL to go low to ensure the "Start Condition" has completed. + // If a Stop condition arises then leave the interrupt to prevent waiting forever. + if (tmpPin) { + // Stop Condition (waiting for next Start Condition) + USICR = (1 << USISIE) | (0 << USIOIE) | // Enable Start Condition Interrupt. Disable Overflow Interrupt. + (1 << USIWM1) | (0 << USIWM0) | // Set USI in Two-wire mode. No USI Counter overflow prior + // to first Start Condition (potentail failure) + (1 << USICS1) | (0 << USICS0) | (0 << USICLK) | // Shift Register Clock Source = External, positive edge + (0 << USITC); + } else { + // really Start Condition (Enable Overflow Interrupt) + USICR = (1 << USISIE) | (1 << USIOIE) + | // Enable Overflow and Start Condition Interrupt. (Keep StartCondInt to detect RESTART) + (1 << USIWM1) | (1 << USIWM0) | // Set USI in Two-wire mode. + (1 << USICS1) | (0 << USICS0) | (0 << USICLK) | // Shift Register Clock Source = External, positive edge + (0 << USITC); + } + USISR = (1 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) | // Clear flags + (0x0 << USICNT0); // Set USI to sample 8 bits i.e. count 16 external pin toggles. +} + +/*---------------------------------------------------------- + Handels all the comunication. Is disabled only when waiting + for new Start Condition. +----------------------------------------------------------*/ +#ifdef __GNUC__ +ISR(USI_OVERFLOW_VECTOR) +#elif __ICCAVR__ +#pragma vector = USI_OVERFLOW_VECTOR +__interrupt void USI_Counter_Overflow_ISR(void) +#endif +{ + unsigned char tmpRxHead; + unsigned char tmpTxTail; // Temporary variables to store volatiles + unsigned char tmpUSIDR; + + switch (USI_TWI_Overflow_State) { + // ---------- Address mode ---------- + // Check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK, else reset USI. + case USI_SLAVE_CHECK_ADDRESS: + if ((USIDR == 0) || ((USIDR >> 1) == TWI_slaveAddress)) { + if (USIDR & 0x01) { + if (USI_TWI_On_Slave_Transmit) { + // reset tx buffer and call callback + tmpTxTail = TWI_TxHead; + TWI_TxTail = tmpTxTail; + USI_TWI_On_Slave_Transmit(); + } + USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA; + } else { + USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA; + } + SET_USI_TO_SEND_ACK(); + } else { + SET_USI_TO_TWI_START_CONDITION_MODE(); + } + break; + + // ----- Master write data mode ------ + // Check reply and goto USI_SLAVE_SEND_DATA if OK, else reset USI. + case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA: + if (USIDR) // If NACK, the master does not want more data. + { + SET_USI_TO_TWI_START_CONDITION_MODE(); + return; + } + // From here we just drop straight into USI_SLAVE_SEND_DATA if the master sent an ACK + + // Copy data from buffer to USIDR and set USI to shift byte. Next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA + case USI_SLAVE_SEND_DATA: + + // Get data from Buffer + tmpTxTail = TWI_TxTail; // Not necessary, but prevents warnings + if (TWI_TxHead != tmpTxTail) { + TWI_TxTail = (TWI_TxTail + 1) & TWI_TX_BUFFER_MASK; + USIDR = TWI_TxBuf[TWI_TxTail]; + } else // If the buffer is empty then: + { + SET_USI_TO_TWI_START_CONDITION_MODE(); + return; + } + USI_TWI_Overflow_State = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA; + SET_USI_TO_SEND_DATA(); + break; + + // Set USI to sample reply from master. Next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA + case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA: + USI_TWI_Overflow_State = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA; + SET_USI_TO_READ_ACK(); + break; + + // ----- Master read data mode ------ + // Set USI to sample data from master. Next USI_SLAVE_GET_DATA_AND_SEND_ACK. + case USI_SLAVE_REQUEST_DATA: + USI_TWI_Overflow_State = USI_SLAVE_GET_DATA_AND_SEND_ACK; + SET_USI_TO_READ_DATA(); + // call slave receive callback on stop condition + if (USI_TWI_On_Slave_Receive) { + tmpRxHead = TWI_RxHead; + if (TWI_RxTail != tmpRxHead) { // data in receive buffer + // check for stop Condition + while ((USISR & ((1 << USI_START_COND_INT) | (1 << USIPF) | (0xE << USICNT0))) == 0) + ;// wait for either Start or Stop Condition + // cancel after one SCL cycle + if (USISR & (1 << USIPF)) { // Stop Condition + USI_TWI_On_Slave_Receive(USI_TWI_Data_In_Receive_Buffer()); + // reset rx buffer + TWI_RxTail = tmpRxHead; + } + } + } + break; + + // Copy data from USIDR and send ACK. Next USI_SLAVE_REQUEST_DATA + case USI_SLAVE_GET_DATA_AND_SEND_ACK: + // Put data into Buffer + USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA; + tmpUSIDR = USIDR; // Not necessary, but prevents warnings + tmpRxHead = (TWI_RxHead + 1) & TWI_RX_BUFFER_MASK; + if (TWI_RxTail != tmpRxHead) { + TWI_RxHead = tmpRxHead; + TWI_RxBuf[TWI_RxHead] = tmpUSIDR; + SET_USI_TO_SEND_ACK(); + } else // If the buffer is full then: + { + SET_USI_TO_SEND_NACK(); + } + break; + } +} +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/USI_TWI_Slave/USI_TWI_Slave.h b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Slave/USI_TWI_Slave.h new file mode 100644 index 00000000..24f766e9 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/USI_TWI_Slave/USI_TWI_Slave.h @@ -0,0 +1,135 @@ +// This file has been prepared for Doxygen automatic documentation generation. +/*! \file ******************************************************************** + * + * Atmel Corporation + * + * File : USI_TWI_Slave.h + * Compiler : IAR EWAAVR 4.11A + * Revision : $Revision: 6351 $ + * Date : $Date: 2010-01-29 20:15:43 +0800 (Fri, 29 Jan 2010) $ + * Updated by : $Author: hskinnemoen $ + * + * Support mail : avr@atmel.com + * + * Supported devices : All device with USI module can be used. + * The example is written for the ATmega169, ATtiny26 & ATtiny2313 + * + * AppNote : AVR312 - Using the USI module as a TWI slave + * + * Description : Header file for USI_TWI driver + * + * + * + ****************************************************************************/ +//********** Prototypes **********// +#include +#ifndef TWDR +void USI_TWI_Slave_Initialise(unsigned char); +void USI_TWI_Slave_Disable(); +void USI_TWI_Transmit_Byte(unsigned char); +unsigned char USI_TWI_Receive_Byte(void); +unsigned char USI_TWI_Peek_Receive_Byte(void); +unsigned char USI_TWI_Data_In_Receive_Buffer(void); +unsigned char USI_TWI_Space_In_Transmission_Buffer(void); +unsigned char USI_TWI_Slave_Is_Active(); + +void (*USI_TWI_On_Slave_Transmit)(void); +void (*USI_TWI_On_Slave_Receive)(int); + +void Timer_Init(void); + +#define TRUE 1 +#define FALSE 0 + +typedef unsigned char uint8_t; + +////////////////////////////////////////////////////////////////// +///////////////// Driver Buffer Definitions ////////////////////// +////////////////////////////////////////////////////////////////// +// 1,2,4,8,16,32,64,128 or 256 bytes are allowed buffer sizes +extern uint8_t TWI_Buffer[]; + +#define TWI_RX_BUFFER_SIZE (16) +#define TWI_RX_BUFFER_MASK (TWI_RX_BUFFER_SIZE - 1) + +#if (TWI_RX_BUFFER_SIZE & TWI_RX_BUFFER_MASK) +#error TWI RX buffer size is not a power of 2 +#endif + +// 1,2,4,8,16,32,64,128 or 256 bytes are allowed buffer sizes + +#define TWI_TX_BUFFER_SIZE (16) +#define TWI_TX_BUFFER_MASK (TWI_TX_BUFFER_SIZE - 1) + +#if (TWI_TX_BUFFER_SIZE & TWI_TX_BUFFER_MASK) +#error TWI TX buffer size is not a power of 2 +#endif + +#define TWI_BUFFER_SIZE (TWI_RX_BUFFER_SIZE + TWI_TX_BUFFER_SIZE) +////////////////////////////////////////////////////////////////// + +#define USI_SLAVE_CHECK_ADDRESS (0x00) +#define USI_SLAVE_SEND_DATA (0x01) +#define USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA (0x02) +#define USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA (0x03) +#define USI_SLAVE_REQUEST_DATA (0x04) +#define USI_SLAVE_GET_DATA_AND_SEND_ACK (0x05) + +// Device dependant defines +#include "pins_arduino.h" + +#define SET_USI_TO_SEND_ACK() \ + { \ + USIDR = 0; /* Prepare ACK */ \ + DDR_USI |= (1 << PORT_USI_SDA); /* Set SDA as output */ \ + USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) \ + | /* Clear all flags, except Start Cond */ \ + (0x0E << USICNT0); /* set USI counter to shift 1 bit. */ \ + } + +#define SET_USI_TO_SEND_NACK() \ + { \ + DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as intput, NACK is SDA high */ \ + USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) \ + | /* Clear all flags, except Start Cond */ \ + (0x0E << USICNT0); /* set USI counter to shift 1 bit. */ \ + } + +#define SET_USI_TO_READ_ACK() \ + { \ + DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as intput */ \ + USIDR = 0; /* Prepare ACK */ \ + USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) \ + | /* Clear all flags, except Start Cond */ \ + (0x0E << USICNT0); /* set USI counter to shift 1 bit. */ \ + } + +#define SET_USI_TO_TWI_START_CONDITION_MODE() \ + { \ + DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as intput */ \ + USICR = (1 << USISIE) | (0 << USIOIE) | /* Enable Start Condition Interrupt. Disable Overflow Interrupt.*/ \ + (1 << USIWM1) | (0 << USIWM0) | /* Set USI in Two-wire mode. No USI Counter overflow hold. */ \ + (1 << USICS1) | (0 << USICS0) | (0 << USICLK) \ + | /* Shift Register Clock Source = External, positive edge */ \ + (0 << USITC); \ + USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) \ + | /* Clear all flags, except Start Cond */ \ + (0x0 << USICNT0); \ + } + +#define SET_USI_TO_SEND_DATA() \ + { \ + DDR_USI |= (1 << PORT_USI_SDA); /* Set SDA as output */ \ + USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) \ + | /* Clear all flags, except Start Cond */ \ + (0x0 << USICNT0); /* set USI to shift out 8 bits */ \ + } + +#define SET_USI_TO_READ_DATA() \ + { \ + DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as input */ \ + USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) \ + | /* Clear all flags, except Start Cond */ \ + (0x0 << USICNT0); /* set USI to shift out 8 bits */ \ + } +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/Wire.cpp b/sparkfun/tiny/libraries/Wire/src/Wire.cpp new file mode 100644 index 00000000..2baeba0d --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/Wire.cpp @@ -0,0 +1,803 @@ +/* + TwoWire.cpp - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts +*/ +#include +#ifdef TWDR +extern "C" { + #include + #include + #include + #include "twi.h" +} + +#include "Wire.h" + +// Initialize Class Variables ////////////////////////////////////////////////// + +uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; +uint8_t TwoWire::rxBufferIndex = 0; +uint8_t TwoWire::rxBufferLength = 0; + +uint8_t TwoWire::txAddress = 0; +uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; +uint8_t TwoWire::txBufferIndex = 0; +uint8_t TwoWire::txBufferLength = 0; + +uint8_t TwoWire::transmitting = 0; +void (*TwoWire::user_onRequest)(void); +void (*TwoWire::user_onReceive)(int); + +// Constructors //////////////////////////////////////////////////////////////// + +TwoWire::TwoWire() +{ +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void TwoWire::begin(void) +{ + rxBufferIndex = 0; + rxBufferLength = 0; + + txBufferIndex = 0; + txBufferLength = 0; + + twi_init(); +} + +void TwoWire::begin(uint8_t address) +{ + twi_setAddress(address); + twi_attachSlaveTxEvent(onRequestService); + twi_attachSlaveRxEvent(onReceiveService); + begin(); +} + +void TwoWire::begin(int address) +{ + begin((uint8_t)address); +} + +void TwoWire::end(void) +{ + twi_disable(); +} + +void TwoWire::setClock(uint32_t frequency) +{ + TWBR = ((F_CPU / frequency) - 16) / 2; +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) +{ + if (isize > 0) { + // send internal address; this mode allows sending a repeated start to access + // some devices' internal registers. This function is executed by the hardware + // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) + + beginTransmission(address); + + // the maximum size of internal address is 3 bytes + if (isize > 3){ + isize = 3; + } + + // write internal register address - most significant byte first + while (isize-- > 0) + write((uint8_t)(iaddress >> (isize*8))); + endTransmission(false); + } + + // clamp to buffer length + if(quantity > BUFFER_LENGTH){ + quantity = BUFFER_LENGTH; + } + // perform blocking read into buffer + uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop); + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = read; + + return read; +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop); +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) +{ + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity) +{ + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) +{ + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); +} + +void TwoWire::beginTransmission(uint8_t address) +{ + // indicate that we are transmitting + transmitting = 1; + // set address of targeted slave + txAddress = address; + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; +} + +void TwoWire::beginTransmission(int address) +{ + beginTransmission((uint8_t)address); +} + +// +// Originally, 'endTransmission' was an f(void) function. +// It has been modified to take one parameter indicating +// whether or not a STOP should be performed on the bus. +// Calling endTransmission(false) allows a sketch to +// perform a repeated start. +// +// WARNING: Nothing in the library keeps track of whether +// the bus tenure has been properly ended with a STOP. It +// is very possible to leave the bus in a hung state if +// no call to endTransmission(true) is made. Some I2C +// devices will behave oddly if they do not see a STOP. +// +uint8_t TwoWire::endTransmission(uint8_t sendStop) +{ + // transmit buffer (blocking) + int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop); + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; + // indicate that we are done transmitting + transmitting = 0; + return ret; +} + +// This provides backwards compatibility with the original +// definition, and expected behaviour, of endTransmission +// +uint8_t TwoWire::endTransmission(void) +{ + return endTransmission(true); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TwoWire::write(uint8_t data) +{ + if(transmitting){ + // in master transmitter mode + // don't bother if buffer is full + if(txBufferLength >= BUFFER_LENGTH){ + setWriteError(); + return 0; + } + // put byte in tx buffer + txBuffer[txBufferIndex] = data; + ++txBufferIndex; + // update amount in buffer + txBufferLength = txBufferIndex; + }else{ + // in slave send mode + // reply to master + twi_transmit(&data, 1); + } + return 1; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TwoWire::write(const uint8_t *data, size_t quantity) +{ + if(transmitting){ + // in master transmitter mode + for(size_t i = 0; i < quantity; ++i){ + write(data[i]); + } + }else{ + // in slave send mode + // reply to master + twi_transmit(data, quantity); + } + return quantity; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::available(void) +{ + return rxBufferLength - rxBufferIndex; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::read(void) +{ + int value = -1; + + // get each successive byte on each call + if(rxBufferIndex < rxBufferLength){ + value = rxBuffer[rxBufferIndex]; + ++rxBufferIndex; + } + + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::peek(void) +{ + int value = -1; + + if(rxBufferIndex < rxBufferLength){ + value = rxBuffer[rxBufferIndex]; + } + + return value; +} + +void TwoWire::flush(void) +{ + // XXX: to be implemented. +} + +// behind the scenes function that is called when data is received +void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) +{ + // don't bother if user hasn't registered a callback + if(!user_onReceive){ + return; + } + // don't bother if rx buffer is in use by a master requestFrom() op + // i know this drops data, but it allows for slight stupidity + // meaning, they may not have read all the master requestFrom() data yet + if(rxBufferIndex < rxBufferLength){ + return; + } + // copy twi rx buffer into local read buffer + // this enables new reads to happen in parallel + for(uint8_t i = 0; i < numBytes; ++i){ + rxBuffer[i] = inBytes[i]; + } + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = numBytes; + // alert user program + user_onReceive(numBytes); +} + +// behind the scenes function that is called when data is requested +void TwoWire::onRequestService(void) +{ + // don't bother if user hasn't registered a callback + if(!user_onRequest){ + return; + } + // reset tx buffer iterator vars + // !!! this will kill any pending pre-master sendTo() activity + txBufferIndex = 0; + txBufferLength = 0; + // alert user program + user_onRequest(); +} + +// sets function called on slave write +void TwoWire::onReceive( void (*function)(int) ) +{ + user_onReceive = function; +} + +// sets function called on slave read +void TwoWire::onRequest( void (*function)(void) ) +{ + user_onRequest = function; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +TwoWire Wire = TwoWire(); + +#else +#ifdef USIDR +extern "C" { +#include +#include +#include +#include "USI_TWI_Slave/USI_TWI_Slave.h" +#include "USI_TWI_Master/USI_TWI_Master.h" +} + +#include "Wire.h" + +const uint8_t WIRE_BUFFER_LENGTH = TWI_BUFFER_SIZE - 1; //reserve slave addr + +// Initialize Class Variables ////////////////////////////////////////////////// + +uint8_t *USIWire::Buffer = TWI_Buffer; +uint8_t USIWire::BufferIndex = 0; +uint8_t USIWire::BufferLength = 0; + +uint8_t USIWire::transmitting = 0; + +// Constructors //////////////////////////////////////////////////////////////// + +USIWire::USIWire() { +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void USIWire::begin(void) { + BufferIndex = 0; + BufferLength = 0; + + transmitting = 0; + + USI_TWI_Master_Initialise(); +} + +void USIWire::begin(uint8_t address) { + USI_TWI_Slave_Initialise(address); +} + +void USIWire::begin(int address) { + begin((uint8_t)address); +} + +void USIWire::end(void) { + USI_TWI_Slave_Disable(); +} + +void USIWire::setClock(uint32_t clock) { + // XXX: to be implemented. + (void)clock; //disable warning +} + +uint8_t USIWire::requestFrom(uint8_t address, uint8_t quantity, + uint32_t iaddress, uint8_t isize, + uint8_t sendStop) { + if (isize > 0) { + // send internal address; this mode allows sending a repeated + // start to access some devices' internal registers. This function + // is executed by the hardware TWI module on other processors (for + // example Due's TWI_IADR and TWI_MMR registers) + + beginTransmission(address); + + // the maximum size of internal address is 3 bytes + if (isize > 3) { + isize = 3; + } + + // write internal register address - most significant byte first + while (isize-- > 0) { + write((uint8_t)(iaddress >> (isize*8))); + } + endTransmission(false); + } + + // reserve one byte for slave address + quantity++; + // clamp to buffer length + if (quantity > TWI_BUFFER_SIZE) { + quantity = TWI_BUFFER_SIZE; + } + // set address of targeted slave and read mode + Buffer[0] = (address << TWI_ADR_BITS) | (1 << TWI_READ_BIT); + // perform blocking read into buffer + uint8_t ret = USI_TWI_Start_Transceiver_With_Data_Stop(Buffer, quantity, + sendStop); + // set rx buffer iterator vars + BufferIndex = 1; // ignore slave address + // check for error + if (ret == FALSE) { + BufferLength = BufferIndex; + return 0; + } + BufferLength = quantity; + + return quantity - 1; // ignore slave address +} + +uint8_t USIWire::requestFrom(uint8_t address, uint8_t quantity, + uint8_t sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, + (uint8_t)0, (uint8_t)sendStop); +} + +uint8_t USIWire::requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t USIWire::requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t USIWire::requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); +} + +void USIWire::beginTransmission(uint8_t address) { + // indicate that we are transmitting + transmitting = 1; + // set address of targeted slave and write mode + Buffer[0] = (address << TWI_ADR_BITS) | (0 << TWI_READ_BIT); + // reset tx buffer iterator vars + BufferIndex = 1; // reserved by slave address + BufferLength = BufferIndex; +} + +void USIWire::beginTransmission(int address) { + beginTransmission((uint8_t)address); +} + +uint8_t USIWire::endTransmission(uint8_t sendStop) { + // transmit buffer (blocking) + uint8_t ret = USI_TWI_Start_Transceiver_With_Data_Stop(Buffer, + BufferLength, + sendStop); + // reset tx buffer iterator vars + BufferIndex = 0; + BufferLength = 0; + // indicate that we are done transmitting + transmitting = 0; + // check for error + if (ret == FALSE) { + switch (USI_TWI_Get_State_Info()) { + case USI_TWI_DATA_OUT_OF_BOUND: + return 1; //data too long to fit in transmit buffer + case USI_TWI_NO_ACK_ON_ADDRESS: + return 2; //received NACK on transmit of address + case USI_TWI_NO_ACK_ON_DATA: + return 3; //received NACK on transmit of data + } + return 4; //other error + } + return 0; //success +} + +uint8_t USIWire::endTransmission(void) { + return endTransmission(true); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t USIWire::write(uint8_t data) { + if (transmitting) { // in master transmitter mode + // don't bother if buffer is full + if (BufferLength >= TWI_BUFFER_SIZE) { + return 0; + } + // put byte in tx buffer + Buffer[BufferIndex] = data; + ++BufferIndex; + // update amount in buffer + BufferLength = BufferIndex; + } else { // in slave send mode + // don't bother if buffer is full + if (!USI_TWI_Space_In_Transmission_Buffer()) { + return 0; + } + // reply to master + USI_TWI_Transmit_Byte(data); + } + return 1; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t USIWire::write(const uint8_t *data, size_t quantity) { + size_t numBytes = 0; + for (size_t i = 0; i < quantity; ++i){ + numBytes += write(data[i]); + } + return numBytes; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t USIWire::write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int USIWire::available(void) { + if (BufferLength) { + return BufferLength - BufferIndex; + } else { + return USI_TWI_Data_In_Receive_Buffer(); + } +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int USIWire::read(void) { + int value = -1; + + // get each successive byte on each call + if (available()) { + if (BufferLength) { + value = Buffer[BufferIndex]; + ++BufferIndex; + } else { + value = USI_TWI_Receive_Byte(); + } + } + + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int USIWire::peek(void) { + int value = -1; + + if (available()) { + if (BufferLength) { + value = Buffer[BufferIndex]; + } else { + value = USI_TWI_Peek_Receive_Byte(); + } + } + + return value; +} + +void USIWire::flush(void) { + // XXX: to be implemented. +} + +// sets function called on slave write +void USIWire::onReceive( void (*function)(int) ) { + USI_TWI_On_Slave_Receive = function; +} + +// sets function called on slave read +void USIWire::onRequest( void (*function)(void) ) { + USI_TWI_On_Slave_Transmit = function; +} + +// return true on I2C/TWI activity +uint8_t USIWire::isActive(void) { + return USI_TWI_Slave_Is_Active(); +} + +// Preinstantiate Objects //////////////////////////////////////////////////////s +USIWire Wire = USIWire(); +#else +#if defined(TWSD) && !defined(__AVR_ATtiny1634__) +#include "TWSWire.h" +#include + +#if defined(__AVR_ATtiny841__) || defined(__AVR_ATtiny441__) +#define SCL_PIN 4 +#define SCL_PORT PORTA +#define SDA_PIN 6 +#define SDA_PORT PORTA +#elif defined(__AVR_ATtiny828__) +#define SCL_PIN 3 +#define SCL_PORT PORTD +#define SDA_PIN 0 +#define SDA_PORT PORTD +#else +#error No pins for software I2C defined +#endif +#define I2C_TIMEOUT 100 +#include "SoftWire.h" +static SoftWire softWire; + +#include "WireS.h" + +// Constructors //////////////////////////////////////////////////////////////// + +TWSWire::TWSWire() : slaveMode(false) { +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void TWSWire::begin(void) { + softWire.begin(); + slaveMode = false; +} + +void TWSWire::begin(uint8_t address) { + TinyWireS.begin(address, 0); + slaveMode = true; +} + +void TWSWire::begin(int address) { + begin((uint8_t)address); +} + +void TWSWire::end(void) { + // XXX: to be implemented. +} + +void TWSWire::setClock(uint32_t clock) { + // XXX: to be implemented. + (void)clock; //disable warning +} + +uint8_t TWSWire::requestFrom(uint8_t address, uint8_t quantity, + uint32_t iaddress, uint8_t isize, + uint8_t sendStop) { + if (!slaveMode) { + return softWire.requestFrom(address, quantity, iaddress, isize, sendStop); + } + return 0; +} + +uint8_t TWSWire::requestFrom(uint8_t address, uint8_t quantity, + uint8_t sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, + (uint8_t)0, (uint8_t)sendStop); +} + +uint8_t TWSWire::requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TWSWire::requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TWSWire::requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); +} + +void TWSWire::beginTransmission(uint8_t address) { + if (!slaveMode) { + softWire.beginTransmission(address); + } +} + +void TWSWire::beginTransmission(int address) { + beginTransmission((uint8_t)address); +} + +uint8_t TWSWire::endTransmission(uint8_t sendStop) { + if (!slaveMode) { + return softWire.endTransmission(sendStop); + } + return 4; //other error +} + +uint8_t TWSWire::endTransmission(void) { + return endTransmission(true); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TWSWire::write(uint8_t data) { + size_t numBytes = 0; + if (!slaveMode) { + numBytes = softWire.write(data); + } + else { + numBytes = TinyWireS.write(data); + } + return numBytes; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TWSWire::write(const uint8_t *data, size_t quantity) { + size_t numBytes = 0; + for (size_t i = 0; i < quantity; ++i) { + numBytes += write(data[i]); + } + return numBytes; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TWSWire::write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TWSWire::available(void) { + int value = -1; + if (!slaveMode) { + value = softWire.available(); + } + else { + value = TinyWireS.available(); + } + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TWSWire::read(void) { + int value = -1; + if (!slaveMode) { + value = softWire.read(); + } + else { + value = TinyWireS.read(); + } + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TWSWire::peek(void) { + int value = -1; + if (!slaveMode) { + value = softWire.peek(); + } + else { + value = TinyWireS.peek(); + } + return value; +} + +void TWSWire::flush(void) { + // XXX: to be implemented. +} + +// sets function called on slave write +void TWSWire::onReceive(void(*function)(int)) { + TinyWireS.onReceive(function); +} + +// sets function called on slave read +void TWSWire::onRequest(void(*function)(void)) { + TinyWireS.onRequest(function); +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// +TWSWire Wire = TWSWire(); +#else +#error No Wire support on unknown board +#endif // TWSD +#endif // USIDR +#endif // TWDR \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/Wire.h b/sparkfun/tiny/libraries/Wire/src/Wire.h new file mode 100644 index 00000000..1431ad31 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/Wire.h @@ -0,0 +1,191 @@ +/* + TwoWire.h - TWI/I2C library for Arduino & Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts +*/ + +#include +#ifdef TWDR + +#ifndef TwoWire_h +#define TwoWire_h + +#include +#include "Stream.h" + +#define BUFFER_LENGTH 32 + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +class TwoWire : public Stream +{ + private: + static uint8_t rxBuffer[]; + static uint8_t rxBufferIndex; + static uint8_t rxBufferLength; + + static uint8_t txAddress; + static uint8_t txBuffer[]; + static uint8_t txBufferIndex; + static uint8_t txBufferLength; + + static uint8_t transmitting; + static void (*user_onRequest)(void); + static void (*user_onReceive)(int); + static void onRequestService(void); + static void onReceiveService(uint8_t*, int); + public: + TwoWire(); + void begin(); + void begin(uint8_t); + void begin(int); + void end(); + void setClock(uint32_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t endTransmission(uint8_t); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(int, int); + uint8_t requestFrom(int, int, int); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *, size_t); + virtual int available(void); + virtual int read(void); + virtual int peek(void); + virtual void flush(void); + void onReceive( void (*)(int) ); + void onRequest( void (*)(void) ); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + using Print::write; +}; + +extern TwoWire Wire; + +#endif +#else +#ifdef USIDR +#ifndef USIWire_h +#define USIWire_h +#include +// Buffer sizes are defined in USI_TWI_Slave/USI_TWI_Slave.h +extern const uint8_t WIRE_BUFFER_LENGTH; +#define BUFFER_LENGTH (WIRE_BUFFER_LENGTH) + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +class USIWire { + private: + static uint8_t *Buffer; + static uint8_t BufferIndex; + static uint8_t BufferLength; + + static uint8_t transmitting; + public: + USIWire(); + void begin(); + void begin(uint8_t); + void begin(int); + void end(); + void setClock(uint32_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t endTransmission(uint8_t); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(int, int); + uint8_t requestFrom(int, int, int); + size_t write(uint8_t); + size_t write(const uint8_t *, size_t); + size_t write(const char *); + int available(void); + int read(void); + int peek(void); + void flush(void); + void onReceive( void (*)(int) ); + void onRequest( void (*)(void) ); + uint8_t isActive(void); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } +}; +extern USIWire Wire; +#endif +#else +#if defined(TWSD) && !defined(__AVR_ATtiny1634__) +#ifndef TWSWire_h +#define TWSWire_h +#include +#include + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +class TWSWire { +private: + bool slaveMode; +public: + TWSWire(); + void begin(); + void begin(uint8_t); + void begin(int); + void end(); + void setClock(uint32_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t endTransmission(uint8_t); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(int, int); + uint8_t requestFrom(int, int, int); + size_t write(uint8_t); + size_t write(const uint8_t *, size_t); + size_t write(const char *); + int available(void); + int read(void); + int peek(void); + void flush(void); + void onReceive(void(*)(int)); + void onRequest(void(*)(void)); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } +}; +extern TWSWire Wire; +#endif // TWSWire_h +#else +#error No Wire support on unknown board +#endif // TWSD +#endif // USIDR +#endif // TWDR \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/WireS.cpp b/sparkfun/tiny/libraries/Wire/src/WireS.cpp new file mode 100644 index 00000000..a1c1418b --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/WireS.cpp @@ -0,0 +1,177 @@ +/*==============================================================================================================* + + @file WireS.h + @license MIT (c) 2016 Nadav Matalon + + ATtiny841 I2C Slave Library + + Ver. 1.0.0 - First release (1.12.16) + + *===============================================================================================================* + LICENSE + *===============================================================================================================* + + The MIT License (MIT) + Copyright (c) 2016 Nadav Matalon + + 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: + + The above copyright notice and this permission notice shall be included in all copies or substantial + portions of the Software. + + 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. + + *==============================================================================================================*/ + +#if defined(__AVR_ATtiny1634__) || defined(__AVR_ATtiny841__) || defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny828__) || defined(__AVR_ATtiny40__) || defined(__AVR_ATtiny20__) + +#include +#include "WireS.h" + +#define TWI_HIGH_NOISE_MODE 0 + +#ifndef TWAE +#define TWAE 0 +#endif + +#define SET_TENBIT do { i2c->Addr |= 0x8000; } while(0) +#define CLEAR_TENBIT do { i2c->Addr &= 0x7FFF; } while(0) +#define IS_TENBIT (i2c->Addr & 0x8000) + +struct i2cStruct i2c_tinyS::i2cData; + +i2c_tinyS::i2c_tinyS() { + i2c = &i2cData; +} + +i2c_tinyS::~i2c_tinyS() {} + +void i2c_tinyS::begin_(struct i2cStruct* i2c, uint8_t address, uint8_t mask) { + I2C_INTR_FLAG_INIT; + TWSA = (address << 1); + TWSAM = mask; + i2c->startCount = -1; + TWSCRA = (_BV(TWSHE) | _BV(TWDIE) | _BV(TWASIE) | _BV(TWEN) | _BV(TWSIE)); +} + +size_t i2c_tinyS::write(uint8_t data) { + if(i2c->txBufferLength < I2C_BUFFER_LENGTH) { + i2c->Buffer[i2c->txBufferLength++] = data; + return 1; + } + return 0; +} + +size_t i2c_tinyS::write(const uint8_t* data, size_t quantity) { + if(i2c->txBufferLength < I2C_BUFFER_LENGTH) { + size_t avail = I2C_BUFFER_LENGTH - i2c->txBufferLength; + uint8_t* dest = i2c->Buffer + i2c->txBufferLength; + if(quantity > avail) quantity = avail; + for (size_t count=quantity; count; count--) *dest++ = *data++; + i2c->txBufferLength += quantity; + } +} + +int i2c_tinyS::read_(struct i2cStruct* i2c) { + if(i2c->rxBufferIndex >= i2c->rxBufferLength) return -1; + return i2c->Buffer[i2c->rxBufferIndex++]; +} + +int i2c_tinyS::peek_(struct i2cStruct* i2c) { + if(i2c->rxBufferIndex >= i2c->rxBufferLength) return -1; + return i2c->Buffer[i2c->rxBufferIndex]; +} + +uint8_t i2c_tinyS::readByte_(struct i2cStruct* i2c) { + if(i2c->rxBufferIndex >= i2c->rxBufferLength) return 0; + return i2c->Buffer[i2c->rxBufferIndex++]; +} + +uint8_t i2c_tinyS::peekByte_(struct i2cStruct* i2c) { + if(i2c->rxBufferIndex >= i2c->rxBufferLength) return 0; + return i2c->Buffer[i2c->rxBufferIndex]; +} + +void i2c_isr_handler() { + struct i2cStruct *i2c = &(i2c_tinyS::i2cData); + byte status = TWSSRA; + if ((status & (_BV(TWC) | _BV(TWBE)))) { + i2c->startCount = -1; + CLEAR_TENBIT; + TWSSRA |= (_BV(TWASIF) | _BV(TWDIF) | _BV(TWBE)); + return; + } + if ((status & _BV(TWASIF)) || IS_TENBIT) { + if ((status & _BV(TWAS))) { + if (IS_TENBIT) i2c->Addr = (((i2c->Addr & B110) << 7) | TWSD); + else { + i2c->Addr = TWSD; + i2c->startCount++; + if ((i2c->Addr & B11111001) == B11110000) { + SET_TENBIT; + TWSCRB = (B0011 | TWI_HIGH_NOISE_MODE); + return; + } + } + if (i2c->user_onAddrReceive != (void *)NULL) { + i2c->rxBufferIndex = 0; + if (!i2c->user_onAddrReceive(i2c->Addr, i2c->startCount)) { + TWSCRB = (B0111 | TWI_HIGH_NOISE_MODE); + return; + } + } + if ((status & _BV(TWDIR))) { + i2c->txBufferLength = 0; + if (i2c->user_onRequest != (void *)NULL) i2c->user_onRequest(); + i2c->txBufferIndex = 0; + } else i2c->rxBufferLength = 0; + } else { + if ((status & _BV(TWDIR))) { + if (i2c->user_onStop != (void *)NULL) i2c->user_onStop(); + } else { + if (i2c->user_onReceive != (void *)NULL) { + i2c->rxBufferIndex = 0; + i2c->user_onReceive(i2c->rxBufferLength); + } + } + i2c->startCount = -1; + CLEAR_TENBIT; + TWSSRA = _BV(TWASIF); + return; + } + } else if ((status & _BV(TWDIF))) { + if ((status & _BV(TWDIR))) { + if (i2c->txBufferIndex < i2c->txBufferLength) TWSD = i2c->Buffer[i2c->txBufferIndex++]; + else { + TWSCRB = (B0010 | TWI_HIGH_NOISE_MODE); + return; + } + } else { + if (i2c->rxBufferLength < I2C_BUFFER_LENGTH) i2c->Buffer[i2c->rxBufferLength++] = TWSD; + else { + TWSCRB = (B0110 | TWI_HIGH_NOISE_MODE); + return; + } + } + } + TWSCRB = (B0011 | TWI_HIGH_NOISE_MODE); +} + +ISR(TWI_SLAVE_vect) { + I2C_INTR_FLAG_ON; + i2c_isr_handler(); + I2C_INTR_FLAG_OFF; +} + +i2c_tinyS TinyWireS = i2c_tinyS(); + +#endif + diff --git a/sparkfun/tiny/libraries/Wire/src/WireS.h b/sparkfun/tiny/libraries/Wire/src/WireS.h new file mode 100644 index 00000000..a053f2da --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/WireS.h @@ -0,0 +1,122 @@ +/*==============================================================================================================* + + @file WireS.h + @license MIT (c) 2016 Nadav Matalon + + ATtiny841 I2C Slave Library + + Ver. 1.0.0 - First release (1.12.16) + + *===============================================================================================================* + INTRODUCTION + *===============================================================================================================* + + This library enables the newer members of the ATtiny family (ATtiny441/841, ATtiny1634 & ATtiny828) to become + Slaves on an I2C Bus. The library is based on a hardware implementation of I2C which is faster than the + software one, but requries using a specific set of pins for SDA (PA6 on ATtiny841) & SCL (PA4 on ATtiny841). + + *===============================================================================================================* + LICENSE + *===============================================================================================================* + + The MIT License (MIT) + Copyright (c) 2016 Nadav Matalon + + 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: + + The above copyright notice and this permission notice shall be included in all copies or substantial + portions of the Software. + + 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. + + *==============================================================================================================*/ + +#if !defined(WIRE_S_H) && (defined(__AVR_ATtiny1634__) || defined(__AVR_ATtiny841__) || defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny828__) || defined(__AVR_ATtiny40__) || defined(__AVR_ATtiny20__)) +#define WIRE_S_H + +#include +#include "Arduino.h" + +#define I2C_BUFFER_LENGTH 32 + +#if defined(I2C_INTR_FLAG_PIN) + #define I2C_INTR_FLAG_INIT do { \ + pinMode(I2C_INTR_FLAG_PIN, OUTPUT); \ + digitalWrite(I2C_INTR_FLAG_PIN, LOW); \ + } while(0) + #define I2C_INTR_FLAG_ON do {digitalWrite(I2C_INTR_FLAG_PIN, HIGH);} while(0) + #define I2C_INTR_FLAG_OFF do {digitalWrite(I2C_INTR_FLAG_PIN, LOW);} while(0) +#else + #define I2C_INTR_FLAG_INIT do{}while(0) + #define I2C_INTR_FLAG_ON do{}while(0) + #define I2C_INTR_FLAG_OFF do{}while(0) +#endif + +struct i2cStruct { + uint8_t Buffer[I2C_BUFFER_LENGTH]; // Tx/Rx Buffer (ISR) + volatile size_t rxBufferIndex; // Rx Index (User&ISR) + volatile size_t rxBufferLength; // Rx Length (ISR) + volatile size_t txBufferIndex; // Tx Index (User&ISR) + volatile size_t txBufferLength; // Tx Length (User&ISR) + volatile char startCount; // repeated START count (User&ISR) + volatile uint16_t Addr; // Tx/Rx address (User&ISR) + boolean (*user_onAddrReceive)(uint16_t, uint8_t); // Slave Addr Callback Function (User) + void (*user_onReceive)(size_t); // Slave Rx Callback Function (User) + void (*user_onRequest)(void); // Slave Tx Callback Function (User) + void (*user_onStop)(void); // Stop Callback Function (User) +}; + +extern "C" void i2c_isr_handler(struct i2cStruct* i2c); + +class i2c_tinyS : public Stream { + private: + static struct i2cStruct i2cData; + friend void i2c_isr_handler(void); + public: + struct i2cStruct* i2c; + i2c_tinyS(); + ~i2c_tinyS(); + static void begin_(struct i2cStruct* i2c, uint8_t address, uint8_t mask); + inline void begin(int address) { + begin_(i2c, (uint8_t)address, 0); + } + inline void begin(uint8_t address, uint8_t mask) { + begin_(i2c, address, mask); + } + size_t write(uint8_t data); + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + size_t write(const uint8_t* data, size_t quantity); + inline size_t write(const char* str) { write((const uint8_t*)str, strlen(str)); } + inline int available(void) { return i2c->rxBufferLength - i2c->rxBufferIndex; } + static int read_(struct i2cStruct* i2c); + inline int read(void) { return read_(i2c); } + static int peek_(struct i2cStruct* i2c); + inline int peek(void) { return peek_(i2c); } + static uint8_t readByte_(struct i2cStruct* i2c); + inline uint8_t readByte(void) { return readByte_(i2c); } + static uint8_t peekByte_(struct i2cStruct* i2c); + inline uint8_t peekByte(void) { return peekByte_(i2c); } + inline void flush(void) {} + inline uint16_t getRxAddr(void) { return i2c->Addr; } + inline size_t getTransmitBytes(void) { return i2c->txBufferIndex; } + inline void onAddrReceive(boolean (*function)(uint16_t, uint8_t)) { i2c->user_onAddrReceive = function; } + inline void onReceive(void (*function)(size_t)) { i2c->user_onReceive = function; } + inline void onRequest(void (*function)(void)) { i2c->user_onRequest = function; } + inline void onStop(void (*function)(void)) { i2c->user_onStop = function; } +}; + +extern i2c_tinyS TinyWireS; + +#endif + diff --git a/sparkfun/tiny/libraries/Wire/src/twi.c b/sparkfun/tiny/libraries/Wire/src/twi.c new file mode 100644 index 00000000..38e95959 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/twi.c @@ -0,0 +1,548 @@ +/* + twi.c - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts +*/ + + +#include +#include +#include +#include +#include +#include +#include "Arduino.h" // for digitalWrite + +#ifdef TWDR +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif + +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#include "pins_arduino.h" +#include "twi.h" + +static volatile uint8_t twi_state; +static volatile uint8_t twi_slarw; +static volatile uint8_t twi_sendStop; // should the transaction end with a stop +static volatile uint8_t twi_inRepStart; // in the middle of a repeated start + +static void (*twi_onSlaveTransmit)(void); +static void (*twi_onSlaveReceive)(uint8_t*, int); + +static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_masterBufferIndex; +static volatile uint8_t twi_masterBufferLength; + +static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_rxBufferIndex; + +static volatile uint8_t twi_error; + +/* + * Function twi_init + * Desc readys twi pins and sets twi bitrate + * Input none + * Output none + */ +void twi_init(void) +{ + // initialize state + twi_state = TWI_READY; + twi_sendStop = true; // default value + twi_inRepStart = false; + + // activate internal pullups for twi. + digitalWrite(SDA, 1); + digitalWrite(SCL, 1); + + // initialize twi prescaler and bit rate + cbi(TWSR, TWPS0); + cbi(TWSR, TWPS1); + TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; + + /* twi bit rate formula from atmega128 manual pg 204 + SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) + note: TWBR should be 10 or higher for master mode + It is 72 for a 16mhz Wiring board with 100kHz TWI */ + + // enable twi module, acks, and twi interrupt + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); +} + +/* + * Function twi_disable + * Desc disables twi pins + * Input none + * Output none + */ +void twi_disable(void) +{ + // disable twi module, acks, and twi interrupt + TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA)); + + // deactivate internal pullups for twi. + digitalWrite(SDA, 0); + digitalWrite(SCL, 0); +} + +/* + * Function twi_slaveInit + * Desc sets slave address and enables interrupt + * Input none + * Output none + */ +void twi_setAddress(uint8_t address) +{ + // set twi slave address (skip over TWGCE bit) + TWAR = address << 1; +} + +/* + * Function twi_readFrom + * Desc attempts to become twi bus master and read a + * series of bytes from a device on the bus + * Input address: 7bit i2c device address + * data: pointer to byte array + * length: number of bytes to read into array + * sendStop: Boolean indicating whether to send a stop at the end + * Output number of bytes read + */ +uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) +{ + uint8_t i; + + // ensure data will fit into buffer + if(TWI_BUFFER_LENGTH < length){ + return 0; + } + + // wait until twi is ready, become master receiver + while(TWI_READY != twi_state){ + continue; + } + twi_state = TWI_MRX; + twi_sendStop = sendStop; + // reset error state (0xFF.. no error occured) + twi_error = 0xFF; + + // initialize buffer iteration vars + twi_masterBufferIndex = 0; + twi_masterBufferLength = length-1; // This is not intuitive, read on... + // On receive, the previously configured ACK/NACK setting is transmitted in + // response to the received byte before the interrupt is signalled. + // Therefor we must actually set NACK when the _next_ to last byte is + // received, causing that NACK to be sent in response to receiving the last + // expected byte of data. + + // build sla+w, slave device address + w bit + twi_slarw = TW_READ; + twi_slarw |= address << 1; + + if (true == twi_inRepStart) { + // if we're in the repeated start state, then we've already sent the start, + // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. + // We need to remove ourselves from the repeated start state before we enable interrupts, + // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning + // up. Also, don't enable the START interrupt. There may be one pending from the + // repeated start that we sent outselves, and that would really confuse things. + twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR + do { + TWDR = twi_slarw; + } while(TWCR & _BV(TWWC)); + TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START + } + else + // send start condition + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); + + // wait for read operation to complete + while(TWI_MRX == twi_state){ + continue; + } + + if (twi_masterBufferIndex < length) + length = twi_masterBufferIndex; + + // copy twi buffer to data + for(i = 0; i < length; ++i){ + data[i] = twi_masterBuffer[i]; + } + + return length; +} + +/* + * Function twi_writeTo + * Desc attempts to become twi bus master and write a + * series of bytes to a device on the bus + * Input address: 7bit i2c device address + * data: pointer to byte array + * length: number of bytes in array + * wait: boolean indicating to wait for write or not + * sendStop: boolean indicating whether or not to send a stop at the end + * Output 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ +uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) +{ + uint8_t i; + + // ensure data will fit into buffer + if(TWI_BUFFER_LENGTH < length){ + return 1; + } + + // wait until twi is ready, become master transmitter + while(TWI_READY != twi_state){ + continue; + } + twi_state = TWI_MTX; + twi_sendStop = sendStop; + // reset error state (0xFF.. no error occured) + twi_error = 0xFF; + + // initialize buffer iteration vars + twi_masterBufferIndex = 0; + twi_masterBufferLength = length; + + // copy data to twi buffer + for(i = 0; i < length; ++i){ + twi_masterBuffer[i] = data[i]; + } + + // build sla+w, slave device address + w bit + twi_slarw = TW_WRITE; + twi_slarw |= address << 1; + + // if we're in a repeated start, then we've already sent the START + // in the ISR. Don't do it again. + // + if (true == twi_inRepStart) { + // if we're in the repeated start state, then we've already sent the start, + // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. + // We need to remove ourselves from the repeated start state before we enable interrupts, + // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning + // up. Also, don't enable the START interrupt. There may be one pending from the + // repeated start that we sent outselves, and that would really confuse things. + twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR + do { + TWDR = twi_slarw; + } while(TWCR & _BV(TWWC)); + TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START + } + else + // send start condition + TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs + + // wait for write operation to complete + while(wait && (TWI_MTX == twi_state)){ + continue; + } + + if (twi_error == 0xFF) + return 0; // success + else if (twi_error == TW_MT_SLA_NACK) + return 2; // error: address send, nack received + else if (twi_error == TW_MT_DATA_NACK) + return 3; // error: data send, nack received + else + return 4; // other twi error +} + +/* + * Function twi_transmit + * Desc fills slave tx buffer with data + * must be called in slave tx event callback + * Input data: pointer to byte array + * length: number of bytes in array + * Output 1 length too long for buffer + * 2 not slave transmitter + * 0 ok + */ +uint8_t twi_transmit(const uint8_t* data, uint8_t length) +{ + uint8_t i; + + // ensure data will fit into buffer + if(TWI_BUFFER_LENGTH < length){ + return 1; + } + + // ensure we are currently a slave transmitter + if(TWI_STX != twi_state){ + return 2; + } + + // set length and copy data into tx buffer + twi_txBufferLength = length; + for(i = 0; i < length; ++i){ + twi_txBuffer[i] = data[i]; + } + + return 0; +} + +/* + * Function twi_attachSlaveRxEvent + * Desc sets function called before a slave read operation + * Input function: callback function to use + * Output none + */ +void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) +{ + twi_onSlaveReceive = function; +} + +/* + * Function twi_attachSlaveTxEvent + * Desc sets function called before a slave write operation + * Input function: callback function to use + * Output none + */ +void twi_attachSlaveTxEvent( void (*function)(void) ) +{ + twi_onSlaveTransmit = function; +} + +/* + * Function twi_reply + * Desc sends byte or readys receive line + * Input ack: byte indicating to ack or to nack + * Output none + */ +void twi_reply(uint8_t ack) +{ + // transmit master read ready signal, with or without ack + if(ack){ + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); + }else{ + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); + } +} + +/* + * Function twi_stop + * Desc relinquishes bus master status + * Input none + * Output none + */ +void twi_stop(void) +{ + // send stop condition + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + + // wait for stop condition to be exectued on bus + // TWINT is not set after a stop condition! + while(TWCR & _BV(TWSTO)){ + continue; + } + + // update twi state + twi_state = TWI_READY; +} + +/* + * Function twi_releaseBus + * Desc releases bus control + * Input none + * Output none + */ +void twi_releaseBus(void) +{ + // release bus + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + + // update twi state + twi_state = TWI_READY; +} + +ISR(TWI_vect) +{ + switch(TW_STATUS){ + // All Master + case TW_START: // sent start condition + case TW_REP_START: // sent repeated start condition + // copy device address and r/w bit to output register and ack + TWDR = twi_slarw; + twi_reply(1); + break; + + // Master Transmitter + case TW_MT_SLA_ACK: // slave receiver acked address + case TW_MT_DATA_ACK: // slave receiver acked data + // if there is data to send, send it, otherwise stop + if(twi_masterBufferIndex < twi_masterBufferLength){ + // copy data to output register and ack + TWDR = twi_masterBuffer[twi_masterBufferIndex++]; + twi_reply(1); + }else{ + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + } + break; + case TW_MT_SLA_NACK: // address sent, nack received + twi_error = TW_MT_SLA_NACK; + twi_stop(); + break; + case TW_MT_DATA_NACK: // data sent, nack received + twi_error = TW_MT_DATA_NACK; + twi_stop(); + break; + case TW_MT_ARB_LOST: // lost bus arbitration + twi_error = TW_MT_ARB_LOST; + twi_releaseBus(); + break; + + // Master Receiver + case TW_MR_DATA_ACK: // data received, ack sent + // put byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + case TW_MR_SLA_ACK: // address sent, ack received + // ack if more bytes are expected, otherwise nack + if(twi_masterBufferIndex < twi_masterBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_MR_DATA_NACK: // data received, nack sent + // put final byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + break; + case TW_MR_SLA_NACK: // address sent, nack received + twi_stop(); + break; + // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case + + // Slave Receiver + case TW_SR_SLA_ACK: // addressed, returned ack + case TW_SR_GCALL_ACK: // addressed generally, returned ack + case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack + case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack + // enter slave receiver mode + twi_state = TWI_SRX; + // indicate that rx buffer can be overwritten and ack + twi_rxBufferIndex = 0; + twi_reply(1); + break; + case TW_SR_DATA_ACK: // data received, returned ack + case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack + // if there is still room in the rx buffer + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + // put byte in buffer and ack + twi_rxBuffer[twi_rxBufferIndex++] = TWDR; + twi_reply(1); + }else{ + // otherwise nack + twi_reply(0); + } + break; + case TW_SR_STOP: // stop or repeated start condition received + // ack future responses and leave slave receiver state + twi_releaseBus(); + // put a null char after data if there's room + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + twi_rxBuffer[twi_rxBufferIndex] = '\0'; + } + // callback to user defined callback + twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); + // since we submit rx buffer to "wire" library, we can reset it + twi_rxBufferIndex = 0; + break; + case TW_SR_DATA_NACK: // data received, returned nack + case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack + // nack back at master + twi_reply(0); + break; + + // Slave Transmitter + case TW_ST_SLA_ACK: // addressed, returned ack + case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack + // enter slave transmitter mode + twi_state = TWI_STX; + // ready the tx buffer index for iteration + twi_txBufferIndex = 0; + // set tx buffer length to be zero, to verify if user changes it + twi_txBufferLength = 0; + // request for txBuffer to be filled and length to be set + // note: user must call twi_transmit(bytes, length) to do this + twi_onSlaveTransmit(); + // if they didn't change buffer & length, initialize it + if(0 == twi_txBufferLength){ + twi_txBufferLength = 1; + twi_txBuffer[0] = 0x00; + } + // transmit first byte from buffer, fall + case TW_ST_DATA_ACK: // byte sent, ack returned + // copy data to output register + TWDR = twi_txBuffer[twi_txBufferIndex++]; + // if there is more to send, ack, otherwise nack + if(twi_txBufferIndex < twi_txBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_ST_DATA_NACK: // received nack, we are done + case TW_ST_LAST_DATA: // received ack, but we are done already! + // ack future responses + twi_reply(1); + // leave slave receiver state + twi_state = TWI_READY; + break; + + // All + case TW_NO_INFO: // no state information + break; + case TW_BUS_ERROR: // bus error, illegal stop/start + twi_error = TW_BUS_ERROR; + twi_stop(); + break; + } +} + +#endif \ No newline at end of file diff --git a/sparkfun/tiny/libraries/Wire/src/twi.h b/sparkfun/tiny/libraries/Wire/src/twi.h new file mode 100644 index 00000000..f1667968 --- /dev/null +++ b/sparkfun/tiny/libraries/Wire/src/twi.h @@ -0,0 +1,54 @@ +/* + twi.h - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifdef TWDR +#ifndef twi_h +#define twi_h + + #include + + //#define ATMEGA8 + + #ifndef TWI_FREQ + #define TWI_FREQ 100000L + #endif + + #ifndef TWI_BUFFER_LENGTH + #define TWI_BUFFER_LENGTH 32 + #endif + + #define TWI_READY 0 + #define TWI_MRX 1 + #define TWI_MTX 2 + #define TWI_SRX 3 + #define TWI_STX 4 + + void twi_init(void); + void twi_disable(void); + void twi_setAddress(uint8_t); + uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t); + uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t); + uint8_t twi_transmit(const uint8_t*, uint8_t); + void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); + void twi_attachSlaveTxEvent( void (*)(void) ); + void twi_reply(uint8_t); + void twi_stop(void); + void twi_releaseBus(void); + +#endif +#endif diff --git a/sparkfun/tiny/platform.txt b/sparkfun/tiny/platform.txt new file mode 100644 index 00000000..e57a5046 --- /dev/null +++ b/sparkfun/tiny/platform.txt @@ -0,0 +1,101 @@ +# SparkFun AVR ATtiny platforms + +name=SparkFun ATtiny Boards +version=0.1.6 + +# AVR compile variables +# --------------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra + +# Default "compiler.path" is correct, change only if you want to override the initial value +compiler.path={runtime.tools.avr-gcc.path}/bin/ +compiler.c.cmd=avr-gcc +compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects +compiler.c.elf.flags={compiler.warning_flags} -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections +compiler.c.elf.cmd=avr-gcc +compiler.S.flags=-c -g -x assembler-with-cpp -flto -MMD +compiler.cpp.cmd=avr-g++ +compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto +compiler.ar.cmd=avr-gcc-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=avr-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.flags=-O ihex -R .eeprom +compiler.elf2hex.cmd=avr-objcopy +compiler.ldflags= +compiler.size.cmd=avr-size + +# This can be overridden in boards.txt +build.extra_flags= + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +compiler.S.extra_flags= +compiler.cpp.extra_flags= +compiler.ar.extra_flags= +compiler.objcopy.eep.extra_flags= +compiler.elf2hex.extra_flags= + +# AVR compile patterns +# -------------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Create archives +# archive_file_path is needed for backwards compatibility with IDE 1.6.5 or older, IDE 1.6.6 or newer overrides this value +archive_file_path={build.path}/{archive_file} +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mmcu={build.mcu} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm + +## Create output files (.eep and .hex) +recipe.objcopy.eep.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.objcopy.eep.flags} {compiler.objcopy.eep.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.eep" +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Save hex +recipe.output.tmp_file={build.project_name}.hex +recipe.output.save_file={build.project_name}.{build.variant}.hex + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=^(?:\.text|\.data|\.bootloader)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* +recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).* + +## Preprocessor +preproc.includes.flags=-w -x c++ -M -MG -MP +recipe.preproc.includes="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.includes.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" + +preproc.macros.flags=-w -x c++ -E -CC +recipe.preproc.macros="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.macros.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{preprocessed_file_path}" + +# Micronucleus Loader +# ------------------- + +tools.micronucleus.path={runtime.tools.micronucleus-2.03-SFE.path} +tools.micronucleus.cmd=micronucleus +tools.micronucleus.cmd.windows=micronucleus.exe + +tools.micronucleus.upload.params.verbose=-verbose +tools.micronucleus.upload.params.quiet= +tools.micronucleus.upload.pattern="{path}/{cmd}" --timeout 30 "{build.path}/{build.project_name}.hex" + +# USB Default Flags +# Default blank usb manufacturer will be filled it at compile time +# - from numeric vendor ID, set to Unknown otherwise +build.usb_manufacturer= +build.usb_flags= diff --git a/sparkfun/tiny/variants/atto84/pins_arduino.h b/sparkfun/tiny/variants/atto84/pins_arduino.h new file mode 100644 index 00000000..d69a0959 --- /dev/null +++ b/sparkfun/tiny/variants/atto84/pins_arduino.h @@ -0,0 +1,254 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#define ATTINYX4 1 +#define __AVR_ATtinyX4__ +#define USE_SOFTWARE_SPI 1 + +#include + +#define NUM_DIGITAL_PINS 12 +#define NUM_ANALOG_INPUTS 64 + +#define analogInputToDigitalPin(p) (p) + +#define digitalPinHasPWM(p) ((p) == 5 || (p) == 6 || (p) == 7 || (p) == 8) + +//This part has a USI, not an SPI module. Accordingly, there is no MISO/MOSI in hardware. There's a DI and a DO. When the chip is used as master, DI is used as MISO, DO is MOSI; the defines here specify the pins for master mode, as SPI master is much more commonly used in Arduino-land than SPI slave, and these defines are required for compatibility. Be aware of this when using the USI SPI fucntionality (and also, be aware that the MISO and MOSI markings on the pinout diagram in the datasheet are for ISP programming, where the chip is a slave. The pinout diagram included with this core attempts to clarify this) + +#define ADC_TEMPERATURE 34 +#define LED_BUILTIN 8 + +#define SS 3 +#define MOSI 5 +#define MISO 6 +#define SCK 4 + + +#define USI_DDR_PORT DDRA +#define USI_SCK_PORT DDRA +#define USCK_DD_PIN DDA4 +#define DO_DD_PIN DDA5 +#define DI_DD_PIN DDA6 +# define DDR_USI DDRA +# define PORT_USI PORTA +# define PIN_USI PINA +# define PORT_USI_SDA PORTA6 +# define PORT_USI_SCL PORTA4 +# define PIN_USI_SDA PINA6 +# define PIN_USI_SCL PINA4 +# define USI_START_VECTOR USI_START_vect +# define USI_OVERFLOW_VECTOR USI_OVF_vect +# define DDR_USI_CL DDR_USI +# define PORT_USI_CL PORT_USI +# define PIN_USI_CL PIN_USI +#ifndef USI_START_COND_INT +# define USI_START_COND_INT USISIF +#endif + +static const uint8_t SDA = 6; +static const uint8_t SCL = 4; + +//Ax constants should not be used for digitalRead/digitalWrite/analogWrite functions, only analogRead(). +//#define ANALOG_PINS_ARE_ADC_NUMBERS 1 +static const uint8_t A0 = 0x80 | 0; +static const uint8_t A1 = 0x80 | 1; +static const uint8_t A2 = 0x80 | 2; +static const uint8_t A3 = 0x80 | 3; +static const uint8_t A4 = 0x80 | 4; +static const uint8_t A5 = 0x80 | 5; +static const uint8_t A6 = 0x80 | 6; +static const uint8_t A7 = 0x80 | 7; +#define PIN_A0 (0) +#define PIN_A1 ( 1) +#define PIN_A2 ( 2) +#define PIN_A3 ( 3) +#define PIN_A4 ( 4) +#define PIN_A5 ( 5) +#define PIN_A6 ( 6) +#define PIN_A7 ( 7) +#define PIN_B0 ( 10) +#define PIN_B1 ( 9) +#define PIN_B2 ( 8) +#define PIN_B3 (11) /* RESET */ +#define LED_BUILTIN (8) + +//---------------------------------------------------------- +//---------------------------------------------------------- +//Core Configuration (used to be in core_build_options.h) + +//If Software Serial communications doesn't work, run the TinyTuner sketch provided with the core to give you a calibrated OSCCAL value. +//Change the value here with the tuned value. By default this option uses the default value which the compiler will optimise out. +#define TUNED_OSCCAL_VALUE OSCCAL +//e.g +//#define TUNED_OSCCAL_VALUE 0x57 + +//Choosing not to initialise saves power and flash. 1 = initialise. +#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 1 +#define INITIALIZE_SECONDARY_TIMERS 1 +/* + The old standby ... millis on Timer 0. +*/ +#define TIMER_TO_USE_FOR_MILLIS 0 + +/* + Where to put the software serial? (Arduino Digital pin numbers) +*/ +//WARNING, if using software, TX is on AIN0, RX is on AIN1. Comparator is favoured to use its interrupt for the RX pin. +#define USE_SOFTWARE_SERIAL 1 +//Please define the port on which the analog comparator is found. +#define ANALOG_COMP_DDR DDRA +#define ANALOG_COMP_PORT PORTA +#define ANALOG_COMP_PIN PINA +#define ANALOG_COMP_AIN0_BIT 1 +#define ANALOG_COMP_AIN1_BIT 2 + + +/* + Analog reference bit masks. +*/ +// VCC used as analog reference, disconnected from PA0 (AREF) +#define DEFAULT (0) +// External voltage reference at PA0 (AREF) pin, internal reference turned off +#define EXTERNAL (1) +// Internal 1.1V voltage reference +#define INTERNAL (2) +#define INTERNAL1V1 INTERNAL + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- + + +// PCICR = Pin Change Interrupt Control Register +#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 11) ? (&GIMSK) : ((uint8_t *)NULL)) +#define digitalPinToPCICRbit(p) ( ((p) <= 7) ? PCIE0 : PCIE1 ) +#define digitalPinToPCMSK(p) ( ((p) <= 7) ? (&PCMSK0) : (((p) <= 10) ? (&PCMSK1) : ((uint8_t *)NULL)) ) +#define digitalPinToPCMSKbit(p) ( ((p) <= 7) ? (p) : (10 - (p)) ) + +#define digitalPinToInterrupt(p) ((p) == 8 ? 0 : NOT_AN_INTERRUPT) +#ifdef ARDUINO_MAIN + +// ATMEL ATTINY84 / ARDUINO +// +// +-\/-+ +// VCC 1| |14 GND +// (D 10) PB0 2| |13 PA0 (D 0) AREF +// (D 9) PB1 3| |12 PA1 (D 1) +// (D 11) PB3 4| |11 PA2 (D 2) +// PWM INT0 (D 8) PB2 5| |10 PA3 (D 3) +// PWM (D 7) PA7 6| |9 PA4 (D 4) +// PWM (D 6) PA6 7| |8 PA5 (D 5) PWM +// +----+ +const uint16_t PROGMEM port_to_mode_PGM[] = +{ + NOT_A_PORT, + (uint16_t)&DDRA, + (uint16_t)&DDRB, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = +{ + NOT_A_PORT, + (uint16_t)&PORTA, + (uint16_t)&PORTB, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = +{ + NOT_A_PORT, + (uint16_t)&PINA, + (uint16_t)&PINB, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = +{ + PA, /* 0 */ + PA, + PA, + PA, + PA, + PA, + PA, + PA, + PB, /* 8 */ + PB, + PB, + PB, /* 11 */ +}; + + + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = +{ + _BV(0), /* port A */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(6), + _BV(7), + _BV(2), /* port B */ + _BV(1), + _BV(0), + _BV(3), +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = +{ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + TIMER1B, /* OC1B */ + TIMER1A, /* OC1A */ + TIMER0B, /* OC0B */ + TIMER0A, /* OC0A */ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +#endif + +#endif + + + + +//Old code, just here for temporary backup until I decide it is not needed. +/* +//WARNING, if using software, RX must be on a pin which has a Pin change interrupt <= 7 (e.g. PCINT6, or PCINT1, but not PCINT8) +#define USE_SOFTWARE_SERIAL 1 +//These are set to match Optiboot pins. +#define SOFTWARE_SERIAL_PORT PORTA +#define SOFTWARE_SERIAL_TX 9 +#define SOFTWARE_SERIAL_PIN PINA +#define SOFTWARE_SERIAL_RX 8*/ diff --git a/sparkfun/tiny/variants/tiny14/pins_arduino.h b/sparkfun/tiny/variants/tiny14/pins_arduino.h new file mode 100644 index 00000000..1a5711d1 --- /dev/null +++ b/sparkfun/tiny/variants/tiny14/pins_arduino.h @@ -0,0 +1,132 @@ +/* + pins_arduino.c - pin definitions for the Arduino board + Part of Arduino / Wiring Lite + + Copyright (c) 2005 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: pins_arduino.c 565 2009-03-25 10:50:00Z dmellis $ + + Modified 28-08-2009 for attiny84 R.Wiersma + Modified 09-10-2009 for attiny45 A.Saporetti +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +// ATMEL ATTINY84 / ARDUINO +// +// +-\/-+ +// VCC 1| |14 GND +// (D 10) PB0 2| |13 AREF (D 0) +// (D 9) PB1 3| |12 PA1 (D 1) +// PB3 4| |11 PA2 (D 2) +// PWM INT0 (D 8) PB2 5| |10 PA3 (D 3) +// PWM (D 7) PA7 6| |9 PA4 (D 4) +// PWM (D 6) PA6 7| |8 PA5 (D 5) PWM +// +----+ + +const static uint8_t A0 = 0; +const static uint8_t A1 = 1; +const static uint8_t A2 = 2; +const static uint8_t A3 = 3; +const static uint8_t A4 = 4; +const static uint8_t A5 = 5; +const static uint8_t A6 = 6; +const static uint8_t A7 = 7; + +#define digitalPinToPCICR(p) ( ((p) >= 0 && (p) <= 10) ? (&GIMSK) : ((uint8_t *)0) ) +#define digitalPinToPCICRbit(p) ( ((p) <= 7) ? PCIE0 : PCIE1 ) +#define digitalPinToPCMSK(p) ( ((p) <= 7) ? (&PCMSK0) : (((p) <= 10) ? (&PCMSK1) : ((uint8_t *)0)) ) +#define digitalPinToPCMSKbit(p) ( ((p) <= 7) ? (p) : (10 - (p)) ) + +#ifdef ARDUINO_MAIN + +// these arrays map port names (e.g. port B) to the +// appropriate addresses for various functions (e.g. reading +// and writing) +const uint16_t PROGMEM port_to_mode_PGM[] = +{ + NOT_A_PORT, + (uint16_t)&DDRA, + (uint16_t)&DDRB, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = +{ + NOT_A_PORT, + (uint16_t)&PORTA, + (uint16_t)&PORTB, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = +{ + NOT_A_PORT, + (uint16_t)&PINA, + (uint16_t)&PINB, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = +{ + PA, /* 0 */ + PA, + PA, + PA, + PA, + PA, + PA, + PA, + PB, /* 8 */ + PB, + PB, +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = +{ + _BV(0), /* port A */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(6), + _BV(7), + _BV(2), /* port B */ + _BV(1), + _BV(0), +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = +{ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + TIMER1B, /* OC1B */ + TIMER1A, /* OC1A */ + TIMER0B, /* OC0B */ + TIMER0A, /* OC0A */ + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +#endif + +#endif