Чуть правленные исходники v3.11 1.11: изменен делитель тактирования spi + частота кварца для мастер станции
parent
df18fedc7f
commit
3f886d0f98
|
|
@ -0,0 +1,4 @@
|
||||||
|
tags
|
||||||
|
# Vim files
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
## v3.11.0 - 2025-04-24
|
||||||
|
|
||||||
|
- Added write and read protection for NTAG 21x cards by 4 bytes password.
|
||||||
|
- Documentation update
|
||||||
|
|
||||||
|
Base station firmware **v3.11.0**:
|
||||||
|
- Reduced clearing time for NTAG cards by about 2 times
|
||||||
|
- Check RTC IC on waking up from sleep (beep 2 times if error)
|
||||||
|
- Card expiration time now is 180 days after initialization or clearing
|
||||||
|
- Don't wake up by Sleep master card
|
||||||
|
- Don't wait at measuring battery voltage when writing State master card
|
||||||
|
- Blink LED at reed switch triggering
|
||||||
|
|
||||||
|
Master station firmware **v1.11.0**:
|
||||||
|
- Added NTAG authentication password to config
|
||||||
|
- Fixed reading a card as empty in the SPORTident emulation mode
|
||||||
|
|
||||||
|
For working with this firmware version use [SportiduinoPQ](https://github.com/sportiduino/sportiduinopq/releases/latest) >= 0.13, [SportiduinoApp](https://github.com/sportiduino/sportiduinoapp/releases/latest) >= 1.6 and [SportOrgPlus](https://github.com/sembruk/sportorg-plus/releases/latest).
|
||||||
|
|
||||||
|
[All changes](https://github.com/sportiduino/sportiduino/compare/v3.10.0...v3.11.0)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- Добавлена защита паролем (4 байта) от записи и чтения для NTAG 213/215/216
|
||||||
|
- Обновлена документация
|
||||||
|
|
||||||
|
Прошивка базовой станции **v3.11.0**:
|
||||||
|
- Сокращено время очистки чипов NTAG 21x до 2-х раз
|
||||||
|
- Проверка RTC IC при пробуждении станции (двойной короткий сигнал в случае ошибки)
|
||||||
|
- Срок действия чипа увеличен до 180 дней после инициализации или очистки
|
||||||
|
- Выключено пробуждение по чипу сна
|
||||||
|
- Не ждать при измерении напряжения аккумулятора при записи чипа состояния
|
||||||
|
- Мигание светодиода при срабатывании геркона
|
||||||
|
|
||||||
|
Прошивка станции сопряжения **v1.11.0**:
|
||||||
|
- Добавлена пароль аутентификации NTAG в настройки
|
||||||
|
- Исправлено ошибочное чтение чипа как пустого в режиме эмуляции SPORTident
|
||||||
|
|
||||||
|
Для работы с данной версией прошивок используйте [SportiduinoPQ](https://github.com/sportiduino/sportiduinopq/releases/latest) >= 0.13, [SportiduinoApp](https://github.com/sportiduino/sportiduinoapp/releases/latest) >= 1.6 и [SportOrgPlus](https://github.com/sembruk/sportorg-plus/releases/latest).
|
||||||
|
|
||||||
|
[Все изменения](https://github.com/sportiduino/sportiduino/compare/v3.10.0...v3.11.0)
|
||||||
|
|
||||||
|
## v3.10.0 - 2022-05-17
|
||||||
|
|
||||||
|
Base station firmware **v3.10.0**:
|
||||||
|
- Added Password master card
|
||||||
|
- New format of punches log (store timestamp for cards numbers 1...65535, maximum 4000 records)
|
||||||
|
- Wake up from Sleep mode if RTC alarm doesn't work
|
||||||
|
- New fast punch mode
|
||||||
|
- Check battery every ~10 min in Sleep Mode (disabled by default) if voltage < 3.5V beep SOS
|
||||||
|
|
||||||
|
Master station firmware **v1.9.0**:
|
||||||
|
- Write Password master card
|
||||||
|
- Read Log master card of new format
|
||||||
|
|
||||||
|
Added 3D model of the custom box for Base station
|
||||||
|
|
||||||
|
For working with this firmware version use [SportiduinoPQ](https://github.com/sportiduino/sportiduinopq/releases/latest) >= 0.11, [SportiduinoApp](https://github.com/sportiduino/sportiduinoapp/releases/latest) >= 1.2 and [SportOrgPlus](https://github.com/sembruk/sportorg-plus/releases/latest).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Прошивка базовой станции **v3.10.0**:
|
||||||
|
- Добавлен мастер-чип пароля
|
||||||
|
- Новый формат лога отметок (записывается время для чипов от 1 до 65535, максимум 4000 записей)
|
||||||
|
- Реализован выход из спящего режима, даже если будильник RTC не сработает
|
||||||
|
- Новый режим быстрой отметки
|
||||||
|
- Проверка аккумулятора каждые ~10 минут в спящем режиме (по умолчанию отключено), если напряжение < 3,5 В, станция подаёт сигнал SOS
|
||||||
|
|
||||||
|
Прошивка станции сопряжения **v1.9.0**:
|
||||||
|
- Добавлена поддержка мастер-чипа пароля
|
||||||
|
- Добавлена поддержка мастер-чипа лога отметок нового формата
|
||||||
|
|
||||||
|
Добавлена 3D модель корпуса для базовой станции.
|
||||||
|
|
||||||
|
Для работы с данной версией прошивок используйте [SportiduinoPQ](https://github.com/sportiduino/sportiduinopq/releases/latest) >= 0.11, [SportiduinoApp](https://github.com/sportiduino/sportiduinoapp/releases/latest) >= 1.2 и [SportOrgPlus](https://github.com/sembruk/sportorg-plus/releases/latest).
|
||||||
|
|
||||||
|
[All changes/Все изменения](https://github.com/sportiduino/sportiduino/compare/v3.9.0...v3.10.0)
|
||||||
|
|
||||||
|
## MS-v1.8.4
|
||||||
|
|
||||||
|
- Fix SPORTident emulation for card reading
|
||||||
|
|
||||||
|
## MS-v1.8.3
|
||||||
|
|
||||||
|
- Disable autosend all SI-Card 6 pages for MeOS
|
||||||
|
|
||||||
|
## MS-v1.8.2
|
||||||
|
|
||||||
|
- SPORTident legacy protocol emulation for WinOrient 2014
|
||||||
|
|
||||||
|
## MS-v1.8.1
|
||||||
|
|
||||||
|
- Fix beep pause for time card
|
||||||
|
|
||||||
|
## [3.9.0] - 2021-05-14
|
||||||
|
Base station PCB v3b (2021-01-01):
|
||||||
|
- Added TP4056 with leds for Li-ion battery charging
|
||||||
|
- RC522 mini or RC522 boards
|
||||||
|
- Change board length to 73 mm
|
||||||
|
|
||||||
|
Base station firmware:
|
||||||
|
- Autosleep option in Config (go to sleep after ~48h in Wait Mode)
|
||||||
|
- Docs update
|
||||||
|
|
||||||
|
## [3.8.0] - 2020-11-25
|
||||||
|
Master station firmware:
|
||||||
|
- Emulation of SPORTident serial protocol ([GH-90](https://github.com/sportiduino/sportiduino/issues/90))
|
||||||
|
- Change baudrate to 38400 (SportiduinoPQ v0.9 and SportOrg v1.5.0+ >= [bf6c804](https://github.com/sportorg/pysport/commit/bf6c804))
|
||||||
|
|
||||||
|
Base station firmware:
|
||||||
|
- Fix card clearing ([GH-99](https://github.com/sportiduino/sportiduino/issues/99)) and checking ([GH-96](https://github.com/sportiduino/sportiduino/issues/96))
|
||||||
|
- Check Station: write punch to EEPROM ([GH-95](https://github.com/sportiduino/sportiduino/issues/95))
|
||||||
|
|
||||||
|
## [3.7.0] - 2020-04-13
|
||||||
|
New base station PCB:
|
||||||
|
- Added battery voltage measurement circuit (GH-63)
|
||||||
|
- Added EEPROM IC for backuping punches (GH-69)
|
||||||
|
- Added reed switch for wake up (GH-75)
|
||||||
|
- New 10-pin slot for programming (GH-68)
|
||||||
|
- Fixed increased power consumption by DS3231 (GH-61)
|
||||||
|
|
||||||
|
Firmware bug fixes and improvements:
|
||||||
|
- Decreased power consumption (GH-61)
|
||||||
|
- Fix overwriting last mark in full card (GH-84)
|
||||||
|
- Signal battery state at wake-up (GH-81)
|
||||||
|
- Card clearing accelerated
|
||||||
|
- New 3-bytes version format
|
||||||
|
- Deinitialize time and station number master cards by BS
|
||||||
|
- Simplified signal system
|
||||||
|
- Don't check password at serial BS communication
|
||||||
|
- Added makefiles for building and firmware uploading
|
||||||
|
- Refactoring
|
||||||
|
|
||||||
|
## [2.6.3] - 2020-01-20
|
||||||
|
- Fix NTAG cards detection (GH-73)
|
||||||
|
- Fix increased power consumption in sleep mode for PCB v2 (GH-61)
|
||||||
|
|
||||||
|
## [2.6.2] - 2019-12-12
|
||||||
|
- Fix increased power consumption in sleep mode for PCB v1 (GH-61)
|
||||||
|
- Changed default antenna gain to 33 dB
|
||||||
|
|
||||||
|
## [2.6.1] - 2019-08-26
|
||||||
|
- Fixed working with SportOrg
|
||||||
|
- Changed algorithm to work with Serial in BaseStation
|
||||||
|
- Added wake-up function for BaseStation v1
|
||||||
|
|
||||||
|
## [2.6.0] - 2019-07-26
|
||||||
|
- Base station - DS3231-Pin3 (Interrupt) has been connected to MCU-Pin26 (PC3)
|
||||||
|
- Base station - DS3231-Pin4 (Reset) has been connected to MCU-Pin32 (PD2)
|
||||||
|
- Base station - DS3231-Pin2 (VCC) has been disconnected from MCU-Pin9 (PD5) and connected to +3V3 directly (as single-supply scheme from datasheet)
|
||||||
|
- Base station - DS3231-Pin1 (32 kHz) has been connected to MCU-Pin9 (PD5)
|
||||||
|
- Base station - RC522-IRQ has been connected to MCU-Pin10 (PD6)
|
||||||
|
- Base station - BC847 (bipolar) has been changed to BSS138 (mosfet)
|
||||||
|
- Base station - The value of I2C pull-up resistors has been reduced from 10 kOm to 3.3 kOm
|
||||||
|
- Base station - New pcb board design
|
||||||
|
- Firmware of a base station has been fully refactored
|
||||||
|
- Firmware of a master station has been fully refactored
|
||||||
|
- Added wake-up function
|
||||||
|
- Added an ability to config a base station by UART
|
||||||
|
- Added GetInfo master-chip
|
||||||
|
- Added fast-mark setting
|
||||||
|
- Added antenna-gain setting
|
||||||
|
- Added an ability to determine a participant card type. And now the system can work with various card types simalteniously
|
||||||
|
- Designed a box for a master station to print on 3d-printer
|
||||||
|
|
||||||
|
## [1.4.2] - 2018-10-23
|
||||||
|
Delete antenna gain from setting-byte
|
||||||
|
|
||||||
|
## [1.4.1] - 2018-10-17
|
||||||
|
Mark beep change, reduce power for master station
|
||||||
|
|
||||||
|
## [1.4.0] - 2018-10-03
|
||||||
|
Added the ability to reduce the power of the antenna to choose the optimal range of the station
|
||||||
|
|
||||||
|
## [1.3.8] - 2018-06-25
|
||||||
|
### Added the program for work with the system
|
||||||
|
- The program is available at [separete rep](https://github.com/sportiduino/SportiduinoPQ). It is
|
||||||
|
based on [a python module](https://github.com/sportiduino/sportiduinoPython) and also on the PyQt package for creating window applications
|
||||||
|
|
||||||
|
## [1.3.7] - 2018-06-25
|
||||||
|
### Fix dump uploading
|
||||||
|
- Fix dump uploading
|
||||||
|
|
||||||
|
## [1.3.6] - 2018-06-23
|
||||||
|
### Mifare Bug fixes
|
||||||
|
- Fix setting bag fix for Mifare Base Station
|
||||||
|
|
||||||
|
## [1.3.5] - 2018-06-19
|
||||||
|
### Bug fixes
|
||||||
|
- The Check station signals the master chips
|
||||||
|
- The Clear station can clear a repeatedly non-empty chip with the same number
|
||||||
|
- Resetting the station settings with entering to sleep mode is configurable
|
||||||
|
|
||||||
|
## [1.3.4] - 2018-06-13
|
||||||
|
### Some changes
|
||||||
|
- reset station config with sleep entering
|
||||||
|
- fix sounds
|
||||||
|
- remove auto reading mode at master station
|
||||||
|
|
||||||
|
## [1.3.3] - 2018-06-10
|
||||||
|
### Added the capacitor to the battery power of the clock
|
||||||
|
- In some parts of the station, a problem arose with the hours rushing for 2-5 minutes per day. It turned out that the problem consists in unstabilized power supply, the output capacitor after the stabilizer does not cope. We need to add one more closer to clock. In new gerber files that problem is fixed. In older boards, the bug is easily corrected by soldering the capacitor directly to the clock's power outputs.
|
||||||
|
|
||||||
|
## [1.3.2] - 2018-06-08
|
||||||
|
### Add check station
|
||||||
|
- To simplify the procedure for checking the chips before the start, a check station mode was added. Also Since it does not record anything on the chip, participants can be trained in the marking chip on the base station
|
||||||
|
|
||||||
|
## [1.3.1] - 2018-06-06
|
||||||
|
### Speeded up the mark, changes in the settings of the base stations
|
||||||
|
- Due to optimization of chip reading, the time of the mark is reduced by 40 ms
|
||||||
|
- Added the ability to limit the maximum possible number of marks on the chip and, thereby, further reduce the time of the mark at the base stations
|
||||||
|
- In the cleaning station mode, the problem of re-cleaning the chip is solved.
|
||||||
|
|
||||||
|
## [1.3.0] - 2018-04-11
|
||||||
|
### Bug fix and new features
|
||||||
|
- Bug fix with set settings to station
|
||||||
|
- Add clear station mode
|
||||||
|
- Sound of the station is amplified by adding transistor to scheme
|
||||||
|
- Firmware for working with Mifare Classic S50 cards moved to the main repository
|
||||||
|
|
||||||
|
## [1.2.0] - 2018-02-17
|
||||||
|
### Changed the master station communication protocol
|
||||||
|
- The fixed packet up to 32 bytes is changed to a variable length packet with a maximum length of 32 bytes.
|
||||||
|
- Added functions to request the firmware version of the master station
|
||||||
|
- Added the function of transferring the station to automatic regime of cards reading
|
||||||
|
|
||||||
|
## [1.1.0] - 2018-02-13
|
||||||
|
### Delete regime station-page, bug fix
|
||||||
|
- To unify the work with the system, the mode in which the label was written to the page equal to the station number was deleted. A sequential mode is left with the search for the last blank page.
|
||||||
|
- Fixed the bug that occurs when initializing ntag 213 card
|
||||||
|
- Fixed the bug that occurs with transmitting log from base station
|
||||||
|
|
||||||
|
## [1.0.0] - 2018-02-11
|
||||||
|
### First stable version
|
||||||
|
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
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.
|
||||||
|
|
||||||
|
{one line to give the program's name and a brief idea of what it does.}
|
||||||
|
Copyright (C) {year} {name of author}
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
{project} Copyright (C) {year} {fullname}
|
||||||
|
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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
build-*
|
||||||
|
tags
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
|
||||||
|
|
||||||
|
ifndef ARDMK_DIR
|
||||||
|
$(error You should define ARDMK_DIR as enviroment variable or command line argument. See https://github.com/sudar/Arduino-Makefile)
|
||||||
|
endif
|
||||||
|
ifndef ARDUINO_DIR
|
||||||
|
$(error You should define ARDUINO_DIR as enviroment variable or command line argument. See https://github.com/sudar/Arduino-Makefile)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ARDUINO_SKETCHBOOK = ..
|
||||||
|
BOARD_TAG = sportiduino
|
||||||
|
ARDUINO_LIBS = sportiduino-common SPI EEPROM RFID Adafruit_SleepyDog_Library ds3231-master Wire PinChangeInterrupt
|
||||||
|
BOARDS_TXT = ../boards.txt
|
||||||
|
|
||||||
|
BOOTLOADER_PARENT = ..
|
||||||
|
BOOTLOADER_PATH = Optiboot
|
||||||
|
#BOOTLOADER_FILE = optiboot8_38400_sportiduino_led.hex
|
||||||
|
BOOTLOADER_FILE = optiboot8_19200_sportiduino_led.hex
|
||||||
|
ISP_PROG = stk500v1
|
||||||
|
AVRDUDE_ISP_BAUDRATE = 19200
|
||||||
|
AVRDUDE_ARD_BAUDRATE = 19200
|
||||||
|
|
||||||
|
ifdef port
|
||||||
|
MONITOR_PORT = $(port)
|
||||||
|
ISP_PORT = $(port)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef debug
|
||||||
|
CXXFLAGS += -DDEBUG
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef buzzfreq
|
||||||
|
CXXFLAGS += -DBUZZER_FREQUENCY=$(buzzfreq)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef pcbv
|
||||||
|
CXXFLAGS += -DHW_VERS=$(pcbv)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef nopoll
|
||||||
|
CXXFLAGS += -DNO_POLL_CARDS_IN_SLEEP_MODE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef check_battery
|
||||||
|
CXXFLAGS += -DCHECK_BATTERY_IN_SLEEP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef silent
|
||||||
|
CXXFLAGS += -DSILENT_BEEP
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(info CXXFLAGS = $(CXXFLAGS))
|
||||||
|
|
||||||
|
include $(ARDMK_DIR)/Arduino.mk
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1 @@
|
||||||
|
:00000001FF
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,2 @@
|
||||||
|
build-*
|
||||||
|
tags
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
|
||||||
|
|
||||||
|
ifndef ARDMK_DIR
|
||||||
|
$(error You should define ARDMK_DIR as enviroment variable or command line argument. See https://github.com/sudar/Arduino-Makefile)
|
||||||
|
endif
|
||||||
|
ifndef ARDUINO_DIR
|
||||||
|
$(error You should define ARDUINO_DIR as enviroment variable or command line argument. See https://github.com/sudar/Arduino-Makefile)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ARDUINO_SKETCHBOOK = ..
|
||||||
|
BOARD_TAG = nano
|
||||||
|
BOARD_SUB = atmega328noreset
|
||||||
|
ARDUINO_LIBS = sportiduino-common SPI EEPROM RFID Adafruit_SleepyDog_Library
|
||||||
|
BOARDS_TXT = ../boards.txt
|
||||||
|
|
||||||
|
BOOTLOADER_PARENT = ..
|
||||||
|
BOOTLOADER_PATH = Optiboot
|
||||||
|
BOOTLOADER_FILE = optiboot8_atmega328_38400_without_reset.hex
|
||||||
|
ISP_PROG = stk500v1
|
||||||
|
AVRDUDE_ISP_BAUDRATE = 19200
|
||||||
|
|
||||||
|
ifdef port
|
||||||
|
MONITOR_PORT = $(port)
|
||||||
|
ISP_PORT = $(port)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef debug
|
||||||
|
CXXFLAGS += -DDEBUG
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef buzzfreq
|
||||||
|
CXXFLAGS += -DBUZZER_FREQUENCY=$(buzzfreq)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef silent
|
||||||
|
CXXFLAGS += -DSILENT_BEEP
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(info CXXFLAGS = $(CXXFLAGS))
|
||||||
|
|
||||||
|
include $(ARDMK_DIR)/Arduino.mk
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,946 @@
|
||||||
|
:020000040000FA
|
||||||
|
:100000000C9463000C948B000C948B000C948B006C
|
||||||
|
:100010000C948B000C948B000C9462190C9488182F
|
||||||
|
:100020000C948B000C948B000C948B000C948B0024
|
||||||
|
:100030000C948B000C948B000C948B000C948B0014
|
||||||
|
:100040000C943E180C948B000C9430190C940A19E3
|
||||||
|
:100050000C948B000C948B000C948B000C948B00F4
|
||||||
|
:100060000C948B000C948B000000000023002600F1
|
||||||
|
:10007000290000000008000201000003040700003E
|
||||||
|
:100080000000000000000200000000250028002BF6
|
||||||
|
:100090000000000000240027002A000404040404D7
|
||||||
|
:1000A0000404040202020202020303030303030125
|
||||||
|
:1000B00002040810204080010204081020010204FC
|
||||||
|
:1000C000081020006C1911241FBECFEFD8E0DEBF4E
|
||||||
|
:1000D000CDBF24E0ACEFB1E001C01D92AD31B2075D
|
||||||
|
:1000E000E1F711E0A0E0B1E0ECEFF7E302C005902A
|
||||||
|
:1000F0000D92AC3FB107D9F710E0C3E6D0E004C0E1
|
||||||
|
:100100002197FE010E94C51BC236D107C9F70E9484
|
||||||
|
:10011000BB190C94FC1B0C94000020912B02222391
|
||||||
|
:1001200061F02FB7F89430912B02313049F43DB390
|
||||||
|
:1001300030932A023DB33DBB2FBF8CBD9DBD0895BA
|
||||||
|
:1001400020932A02FACFE0911B04E350E93028F40F
|
||||||
|
:10015000F0E0EF51FE4F8081089580E00895E09136
|
||||||
|
:10016000CC039091D003992301F1803248F491E0BF
|
||||||
|
:100170009E0F9093CC03F0E0E553FD4F90E1928306
|
||||||
|
:100180002091CD033091CE03280F311D3093CE0343
|
||||||
|
:100190002093CD03E091CC0391E09E0F9093CC038C
|
||||||
|
:1001A000F0E0E553FD4F828302C0EB3898F30895E9
|
||||||
|
:1001B00092E09093CD028093CE0287FD0BC081E048
|
||||||
|
:1001C0008093D0031092CE031092CD039093CC0372
|
||||||
|
:1001D0000C94AF001092D00384E08093CC03109273
|
||||||
|
:1001E000D00281E0F5CF90E0FC01E155FF4F249172
|
||||||
|
:1001F00085569F4FFC018491882399F090E0880FE9
|
||||||
|
:10020000991FFC01EF56FF4FA591B491FC01E957EE
|
||||||
|
:10021000FF4F859194918FB7F894EC91E22BEC937A
|
||||||
|
:100220008FBF08950F931F93CF93DF93EC018C0141
|
||||||
|
:10023000060F111DC017D10721F089910E94AF0050
|
||||||
|
:10024000F9CFDF91CF911F910F910895833081F005
|
||||||
|
:1002500028F4813099F08230A9F008958730A9F010
|
||||||
|
:100260008830C9F08430B1F4809180008F7D03C064
|
||||||
|
:10027000809180008F7780938000089584B58F7778
|
||||||
|
:1002800084BD089584B58F7DFBCF8091B0008F77BA
|
||||||
|
:100290008093B00008958091B0008F7DF9CF1F93B7
|
||||||
|
:1002A000CF93DF93282F30E0F901EE58FF4F849170
|
||||||
|
:1002B000F901E155FF4FD491F901E556FF4FC49183
|
||||||
|
:1002C000CC23A9F0162F81110E942601EC2FF0E01B
|
||||||
|
:1002D000EE0FFF1FE957FF4FA591B4918FB7F89428
|
||||||
|
:1002E000EC91111108C0D095DE23DC938FBFDF9114
|
||||||
|
:1002F000CF911F910895DE2BF8CF3FB7F8948091EE
|
||||||
|
:10030000100290911102A0911202B091130226B531
|
||||||
|
:10031000A89B05C02F3F19F00196A11DB11D3FBF3D
|
||||||
|
:10032000BA2FA92F982F8827BC01CD01620F711D0C
|
||||||
|
:10033000811D911D43E0660F771F881F991F4A9505
|
||||||
|
:10034000D1F708958F929F92AF92BF92CF92DF9292
|
||||||
|
:10035000EF92FF926B017C010E947D014B015C01D9
|
||||||
|
:10036000C114D104E104F104B9F00E947D016819BF
|
||||||
|
:1003700079098A099B09683E73408105910580F3DC
|
||||||
|
:1003800021E0C21AD108E108F10888EE880E83E066
|
||||||
|
:10039000981EA11CB11CE4CFFF90EF90DF90CF908E
|
||||||
|
:1003A000BF90AF909F908F900895AF92BF92CF92E1
|
||||||
|
:1003B000DF92EF92FF920F931F93CF93DF936C0125
|
||||||
|
:1003C0007B018B01040F151FEB015E01AE18BF0806
|
||||||
|
:1003D000C017D10759F06991D601ED91FC910190B8
|
||||||
|
:1003E000F081E02DC6010995892B79F7C501DF91D0
|
||||||
|
:1003F000CF911F910F91FF90EF90DF90CF90BF9022
|
||||||
|
:10040000AF900895FC01538D448D252F30E0842F4B
|
||||||
|
:1004100090E0821B930B541710F0CF96089501972C
|
||||||
|
:100420000895FC01918D828D981761F0A28DAE0F19
|
||||||
|
:10043000BF2FB11D5D968C91928D9F5F9F73928FA0
|
||||||
|
:1004400090E008958FEF9FEF0895CF92DF92EF92A3
|
||||||
|
:10045000FF920F931F93CF93DF937C018C01060FC4
|
||||||
|
:10046000171FEC016E01CE18DF080C171D0709F4E9
|
||||||
|
:100470003DC02FB7F8948091140290911502A0917D
|
||||||
|
:100480001602B09117022FBF809334029093350269
|
||||||
|
:10049000A0933602B09337028CE292E00E941102E0
|
||||||
|
:1004A00097FF2EC02FB7F8948091140290911502F7
|
||||||
|
:1004B000A0911602B09117022FBF409134025091C3
|
||||||
|
:1004C00035026091360270913702841B950BA60BA2
|
||||||
|
:1004D000B70B40913002509131026091320270911D
|
||||||
|
:1004E000330284179507A607B707B0F2C601DF915C
|
||||||
|
:1004F000CF911F910F91FF90EF90DF90CF900895D3
|
||||||
|
:100500008993B0CFFC01918D828D981731F0828D47
|
||||||
|
:10051000E80FF11D858D90E008958FEF9FEF08950E
|
||||||
|
:10052000FC01918D228D892F90E0805C9F4F821B72
|
||||||
|
:1005300091098F73992708958CE292E00E949002AE
|
||||||
|
:1005400021E0892B09F420E0822F0895FC01A48D7D
|
||||||
|
:10055000A80FB92FB11DA35ABF4F2C91848D90E0E5
|
||||||
|
:1005600001968F739927848FA689B7892C93A089C8
|
||||||
|
:10057000B1898C91837080648C93938D848D981352
|
||||||
|
:1005800006C00288F389E02D80818F7D80830895E5
|
||||||
|
:10059000EF92FF920F931F93CF93DF93EC0181E0D3
|
||||||
|
:1005A000888F9B8D8C8D98131AC0E889F98980817A
|
||||||
|
:1005B00085FF15C09FB7F894EE89FF896083E889AD
|
||||||
|
:1005C000F98980818370806480839FBF81E090E09F
|
||||||
|
:1005D000DF91CF911F910F91FF90EF900895F62E2C
|
||||||
|
:1005E0000B8D10E00F5F1F4F0F731127E02E8C8DC6
|
||||||
|
:1005F0008E110CC00FB607FCFACFE889F98980810B
|
||||||
|
:1006000085FFF5CFCE010E94A602F1CFEB8DEC0F56
|
||||||
|
:10061000FD2FF11DE35AFF4FF0829FB7F8940B8F27
|
||||||
|
:10062000EA89FB8980818062CFCFCF938091F203EA
|
||||||
|
:1006300083508D3150F09091F3038EE1890F2FE1BB
|
||||||
|
:100640002093F2039F5F9093F3038093D403E09190
|
||||||
|
:10065000F203F0E08D3108F08CE18E5FA3EDB3E0A2
|
||||||
|
:1006600090E021E03D91930F2F5F8217D8F7EF5272
|
||||||
|
:10067000FC4F9183C0E08091F2038C1758F0EC2F6F
|
||||||
|
:10068000F0E0EF52FC4F61818CE292E00E94C802E0
|
||||||
|
:10069000CF5FF1CF83E08093F203CF910895CF93A2
|
||||||
|
:1006A000C82F8091F2038F3128F08F5F8093F2037F
|
||||||
|
:1006B0000E9415038091F203E82FF0E0EF52FC4F07
|
||||||
|
:1006C000C1838F5F8093F203CF910895CF93DF931F
|
||||||
|
:1006D000EC01888D8823B9F0AA89BB89E889F9895A
|
||||||
|
:1006E0008C9185FD03C0808186FD0DC00FB607FC8F
|
||||||
|
:1006F000F7CF8C9185FFF2CF808185FFEDCFCE01C2
|
||||||
|
:100700000E94A602E9CFDF91CF91089580912B023C
|
||||||
|
:10071000882361F09FB7F89420912B0280912A02E0
|
||||||
|
:10072000213019F48DBB9FBF08958FBF08958EBDF2
|
||||||
|
:1007300000000DB407FEFDCF8EB508951F93CF9333
|
||||||
|
:10074000DF93182F83E590E00E948D00C8EFD3E07F
|
||||||
|
:1007500060E08C850E944F01812F80680E94970382
|
||||||
|
:1007600080E00E949703182F61E08C850E944F0162
|
||||||
|
:100770000E948603812FDF91CF911F9108950F93DF
|
||||||
|
:100780001F93CF93DF93082F162F83E590E00E94ED
|
||||||
|
:100790008D00C8EFD3E060E08C850E944F01802F70
|
||||||
|
:1007A0000E949703812F0E94970361E08C850E942D
|
||||||
|
:1007B0004F01DF91CF911F910F910C948603CF933E
|
||||||
|
:1007C000DF93D82FC62F0E949E03682F6C2B8D2F8E
|
||||||
|
:1007D000DF91CF910C94BF03CF93DF93D82FC62F17
|
||||||
|
:1007E0000E949E03C0956C2F68238D2FDF91CF91BF
|
||||||
|
:1007F0000C94BF0388E20E949E03982F937093305D
|
||||||
|
:1008000029F0682F636088E20C94BF030895FF927B
|
||||||
|
:100810000F931F93CF93DF93082FF62E172F83E5A7
|
||||||
|
:1008200090E00E948D0060E0809104040E944F01DE
|
||||||
|
:1008300082E10E949703CF2DD12F0C0F1D2F111D88
|
||||||
|
:10084000C017D10721F089910E949703F9CF61E089
|
||||||
|
:10085000809104040E944F01DF91CF911F910F916D
|
||||||
|
:10086000FF900C948603EF92FF920F931F93CF9308
|
||||||
|
:10087000DF937C01C62F8A0160E082E00E94BF0303
|
||||||
|
:1008800064E08AE00E94BF0360E884E10E94DF0325
|
||||||
|
:10089000B7018C2F0E94070463E082E00E94BF032F
|
||||||
|
:1008A000C8E8D3E18AE00E949E0382FD04C021973C
|
||||||
|
:1008B000C9F783E00FC060E082E00E94BF0384E4D8
|
||||||
|
:1008C0000E949E03F801808382E40E949E03F80147
|
||||||
|
:1008D000818380E0DF91CF911F910F91FF90EF9086
|
||||||
|
:1008E00008952F923F924F925F926F927F928F92D4
|
||||||
|
:1008F0009F92AF92BF92CF92DF92EF92FF920F93AF
|
||||||
|
:100900001F93CF93DF9300D0CDB7DEB7982E562E2E
|
||||||
|
:100910003A01422E80E0C114D10411F0F601808129
|
||||||
|
:100920003A2C329420EF3222380E60E082E00E94AE
|
||||||
|
:10093000BF036FE788E00E94BF0360E884E10E9484
|
||||||
|
:10094000DF03B301842D0E940704632D8AE10E9416
|
||||||
|
:10095000BF03692D82E00E94BF03FCE09F1204C028
|
||||||
|
:1009600060E88AE10E94DF0390ED692E97E0792E1E
|
||||||
|
:1009700088E00E949E03982F952141F480FD04C0D9
|
||||||
|
:1009800081E0681A7108A1F783E0A6C08CE00E949C
|
||||||
|
:100990009E03382E837109F0B4C00115110509F4C6
|
||||||
|
:1009A00066C0E114F10409F462C084E10E949E0370
|
||||||
|
:1009B000B82EF70180818B1508F4A5C0B082BB204A
|
||||||
|
:1009C00009F44BC083E590E00E948D0060E08091C7
|
||||||
|
:1009D00004040E944F01BA9482E90E9497033801EF
|
||||||
|
:1009E000212C44244394512C2B1438F5211020C081
|
||||||
|
:1009F000AA20F1F08A2D90E0912C883048F49201E1
|
||||||
|
:100A0000082E01C0220F0A94EAF7922A0196F5CF28
|
||||||
|
:100A100082E90E949703992D9095F80120819223F5
|
||||||
|
:100A20008921892B80832394FFEF6F1A7F0ADCCF03
|
||||||
|
:100A300082E90E949703F301F5CFC8018B0D911D48
|
||||||
|
:100A40005C0180E00E949703F501808361E0809162
|
||||||
|
:100A500004040E944F010E94860388E10E949E03C5
|
||||||
|
:100A60008770B82EC114D10411F0F601808382E0A2
|
||||||
|
:100A700033FC32C00115110509F447C0E114F1043B
|
||||||
|
:100A800009F443C0882009F440C0F7016081613057
|
||||||
|
:100A900029F4F4E0BF123BC08FEF1EC06230B8F102
|
||||||
|
:100AA000B11035C06250AE014F5F5F4FC8010E9468
|
||||||
|
:100AB0003304811111C0F7019081090F111DF80154
|
||||||
|
:100AC000329720819981291322C001501109F80120
|
||||||
|
:100AD00020819A8129131BC00F900F90DF91CF9135
|
||||||
|
:100AE0001F910F91FF90EF90DF90CF90BF90AF904C
|
||||||
|
:100AF0009F908F907F906F905F904F903F902F903E
|
||||||
|
:100B0000089581E0E9CF84E0E7CF80E0E5CF87E09A
|
||||||
|
:100B1000E3CF8F92AF92CF92DF92EF92FF920F933B
|
||||||
|
:100B20001F93CF93DF93CDB7DEB72C970FB6F89412
|
||||||
|
:100B3000DEBF0FBECDBF90E699838A83E2E0F1E08D
|
||||||
|
:100B4000DE01139681918D9381E0E830F807D1F7AB
|
||||||
|
:100B50008091F90389878091FA038A878091FB034A
|
||||||
|
:100B60008B878091FC038C87812CA12CD12CC12CEC
|
||||||
|
:100B7000F12CE12C10E000E02CE0AE014F5F5F4F64
|
||||||
|
:100B800060E18EE00E9471042C960FB6F894DEBFEF
|
||||||
|
:100B90000FBECDBFDF91CF911F910F91FF90EF90CE
|
||||||
|
:100BA000DF90CF90AF908F9008956F927F928F9249
|
||||||
|
:100BB000AF92CF92DF92EF92FF920F931F93CF935A
|
||||||
|
:100BC000DF9300D0CDB7DEB78A838B013A0160E8AE
|
||||||
|
:100BD0008CE10E94EC0387E08983812CA12CCE015B
|
||||||
|
:100BE00001966C01730121E0AE014E5F5F4F60E33F
|
||||||
|
:100BF0008CE00E947104811109C0F3018081823070
|
||||||
|
:100C0000A1F481E09981911101C080E00F900F90D3
|
||||||
|
:100C1000DF91CF911F910F91FF90EF90DF90CF90D8
|
||||||
|
:100C2000AF908F907F906F90089581E0EFCF2F92DB
|
||||||
|
:100C30003F924F925F926F927F928F929F92AF926C
|
||||||
|
:100C4000BF92CF92DF92EF92FF920F931F93CF93B9
|
||||||
|
:100C5000DF93CDB7DEB72B970FB6F894DEBF0FBE8C
|
||||||
|
:100C6000CDBF60E88CE10E94EC0344244394512CF6
|
||||||
|
:100C700083E9898333243394B12C912C992D977077
|
||||||
|
:100C80009B87892D8595859585958E5F282F229543
|
||||||
|
:100C9000207F290F2A8321E0911101C020E0222E1C
|
||||||
|
:100CA000280E66246394712C6C0E7D1E680E711CD8
|
||||||
|
:100CB00099E0981B9A8727C085E98983DECF87E969
|
||||||
|
:100CC000898346E0B42ED9CF40E74A838B819C814B
|
||||||
|
:100CD00089279D8189279E8189278F83AE01485F5F
|
||||||
|
:100CE0005F4F67E0CE0101960E943304182F8111F7
|
||||||
|
:100CF000ABC01B8653E05A8729E0222ECE0107960F
|
||||||
|
:100D00003C0130E2932EAB846A2D6295607F6A0DC0
|
||||||
|
:100D10008AE10E94BF03812CFE013B966F01AE0168
|
||||||
|
:100D2000465F5F4F7A018301222D4950510960E3EC
|
||||||
|
:100D30008CE00E947104182F8230A1F58CE10E9492
|
||||||
|
:100D40009E0385FD81C08F7109F480E2282F30E079
|
||||||
|
:100D5000492D990C550B421753070CF068C0982E7B
|
||||||
|
:100D60002150310927703327E82FE595E595E59562
|
||||||
|
:100D7000EF5F91E0211101C090E0E90F41E050E008
|
||||||
|
:100D80004C0F5D1F4E0F511DFA01A20102C0440F0E
|
||||||
|
:100D9000551F2A95E2F79081942B9083803209F0B9
|
||||||
|
:100DA0006DCF92CF811150C050E295128DCF8B81C3
|
||||||
|
:100DB000883809F03EC083E093E0EB2DF0E0E75087
|
||||||
|
:100DC000FC4F980FA1E0B0E0AC0FBD1FA80FB11D04
|
||||||
|
:100DD0002C9121938F5F8913F5CFBA8483E0B812E9
|
||||||
|
:100DE0004DC08B8581114AC0AE014D5F5F4F61E000
|
||||||
|
:100DF000C3010E943304182F811126C09B81F30187
|
||||||
|
:100E0000818198133DC09C818281981339C0808173
|
||||||
|
:100E100082FF12C03394F2E03F1609F44DCF43E055
|
||||||
|
:100E2000341609F44CCF51E0351609F421CF15E002
|
||||||
|
:100E30000BC082E094E0C1CF80930304832D880F20
|
||||||
|
:100E4000380E33943092F803812F2B960FB6F89416
|
||||||
|
:100E5000DEBF0FBECDBFDF91CF911F910F91FF90ED
|
||||||
|
:100E6000EF90DF90CF90BF90AF909F908F907F904A
|
||||||
|
:100E70006F905F904F903F902F90089511E0E4CFD6
|
||||||
|
:100E800017E0E2CF8F92AF92CF92DF92EF92FF9274
|
||||||
|
:100E90000F931F93CF93DF93CDB7DEB764970FB651
|
||||||
|
:100EA000F894DEBF0FBECDBF809106048F3F61F482
|
||||||
|
:100EB000909107049F3F41F4909108049F3F21F4D3
|
||||||
|
:100EC000909109049F3FF1F190911B049923D1F176
|
||||||
|
:100ED0009BE199838A83809107048B838091080426
|
||||||
|
:100EE0008C83809109048D83AE014A5F5F4F65E07A
|
||||||
|
:100EF000CE0101960E943304811115C01C8A85E041
|
||||||
|
:100F00008B8B812CA12CCE0144966C0101977C0126
|
||||||
|
:100F10008E010F5F1F4F27E0A80160E38CE00E9465
|
||||||
|
:100F20007104882379F0833069F482E08B8BAE0101
|
||||||
|
:100F30004D5E5F4FBE016F5F7F4F82E50E94D5051A
|
||||||
|
:100F40000E94170681E080931C0464960FB6F89403
|
||||||
|
:100F5000DEBF0FBECDBFDF91CF911F910F91FF90EC
|
||||||
|
:100F6000EF90DF90CF90AF908F9008958F92AF92D7
|
||||||
|
:100F7000CF92DF92EF92FF920F931F93CF93DF9365
|
||||||
|
:100F8000FA019081923128F17A01EB0190E3988384
|
||||||
|
:100F90008983AB014E5F5F4F62E0CE010E94330454
|
||||||
|
:100FA00081110CC088248394A12CD12CC12C8E01DA
|
||||||
|
:100FB00024E0AE0160E38CE00E947104DF91CF91E8
|
||||||
|
:100FC0001F910F91FF90EF90DF90CF90AF908F9097
|
||||||
|
:100FD000089584E0F3CFEF92FF920F931F93CF9386
|
||||||
|
:100FE000FA019081923110F490E00DC08A017B01EA
|
||||||
|
:100FF000C82F843078F4A801B7018C2F0E94B6075F
|
||||||
|
:1010000091E08111F1CF892FCF911F910F91FF9026
|
||||||
|
:10101000EF90089580911C048111EDCF0E9442074A
|
||||||
|
:101020008111E9CFE1CFCF93DF93FC01208130E044
|
||||||
|
:10103000322F22278181280F311D62307105B9F1CD
|
||||||
|
:101040003296DB01B695A79561707727109779F1F5
|
||||||
|
:10105000A130B105E9F04081842F90E0982F8827D6
|
||||||
|
:101060004181480F592F511D329680E1E901220F2D
|
||||||
|
:10107000331FD7FF17C057FF02C02F5F3F4F95E0C8
|
||||||
|
:1010800029273058440F551F815081F71197DECF23
|
||||||
|
:1010900050E040E06115710541F3408150E0542F6C
|
||||||
|
:1010A0004427E3CF57FFEECF2F5F3F4FEBCFC90170
|
||||||
|
:1010B000DF91CF910895CF938091D003882319F1C8
|
||||||
|
:1010C0008091CE02813621F48091CD030E94AF0041
|
||||||
|
:1010D000E091CC0381E08E0F8093CC03F0E0E553E8
|
||||||
|
:1010E000FD4F83E08283C0E08091CC03C81770F588
|
||||||
|
:1010F000EC2FF0E0E553FD4F62818CE292E00E941C
|
||||||
|
:10110000C802CF5FF1CFC091CC036DEF6C0F60933D
|
||||||
|
:10111000CF0270E06E5F7F4F8EEC92E00E9413086A
|
||||||
|
:101120008093CB029093CC02EC2FF0E0E553FD4F7F
|
||||||
|
:101130009283E1E0EC0FF0E0E553FD4F828383E022
|
||||||
|
:101140008C0F8093CC03CE5FEC2FC8CFCF91089546
|
||||||
|
:10115000AF92BF92CF92DF92EF92FF920F931F93C5
|
||||||
|
:10116000CF935C014115510561057105B9F1E4E8C2
|
||||||
|
:10117000F3E08F012003C001219F900D1124092E5F
|
||||||
|
:10118000000CAA0BBB0B6C017D01C40ED51EE61E24
|
||||||
|
:10119000F71EC701B60120E831E541E050E00E94AA
|
||||||
|
:1011A000A31B6B017C01CA01B9016C5F7F4F8F4F9C
|
||||||
|
:1011B0009F4F27E030E040E050E00E94A31BC62F85
|
||||||
|
:1011C000CC0FC701B60120EC38EA40E050E00E94A5
|
||||||
|
:1011D000A31BC22BF501C08372836383CF911F9140
|
||||||
|
:1011E0000F91FF90EF90DF90CF90BF90AF90089558
|
||||||
|
:1011F000CF93DF93C0910702D09108022097E1F0CE
|
||||||
|
:101200008091CF03882351F086E40E94D8008FE4B8
|
||||||
|
:101210000E94AF00DF91CF910C945B0887EE0E9493
|
||||||
|
:10122000D80080E00E94AF0080E00E94AF0088817B
|
||||||
|
:101230000E94AF008981ECCFDF91CF910895CF92CA
|
||||||
|
:10124000DF92EF92FF920F931F938A019B01FC01A3
|
||||||
|
:10125000AC014C5F5F4F60E070E0CB01982F872FAF
|
||||||
|
:10126000762F6627A1916A2B4E175F07B9F799274A
|
||||||
|
:1012700068017901CC24DD24EE246C297D298E2996
|
||||||
|
:101280009F29601771078207930708F493951F91B0
|
||||||
|
:101290000F91FF90EF90DF90CF900895CF93DF9361
|
||||||
|
:1012A000E1EDF3E093E091A312A2A4EDB3E09EE19F
|
||||||
|
:1012B000ED0119929A95E9F7908191838283DF91EC
|
||||||
|
:1012C000CF91089580E70E944E0980911B040E94EF
|
||||||
|
:1012D0004F030C9415038F92AF92CF92DF92EF924F
|
||||||
|
:1012E000FF920F931F93CF93DF93CDB7DEB7649731
|
||||||
|
:1012F0000FB6F894DEBF0FBECDBF162FE62EF12C31
|
||||||
|
:10130000A701BC01CE0101960E94EC1B41E050E018
|
||||||
|
:101310004C0F5D1F4E0D5F1D612FCE0101960E9487
|
||||||
|
:101320003304811122C082E18C8B1B8A22E0210FC1
|
||||||
|
:10133000812CA12CCE0143966C0101967C018E017B
|
||||||
|
:101340000F5F1F4FA80160E38CE00E9471048111C0
|
||||||
|
:101350000CC08C898130D1F48B898430B9F481E060
|
||||||
|
:1013600099819A3009F480E0819564960FB6F894DB
|
||||||
|
:10137000DEBF0FBECDBFDF91CF911F910F91FF90C8
|
||||||
|
:10138000EF90DF90CF90AF908F90089581E0EDCFF8
|
||||||
|
:10139000FF920F931F93CF93DF9300D000D000D024
|
||||||
|
:1013A000CDB7DEB7823010F480E01CC08B01F82E80
|
||||||
|
:1013B00080911C04882311F101151105A9F382EA1B
|
||||||
|
:1013C0008983FA8284E0F801DE01139601900D9280
|
||||||
|
:1013D0008A95E1F766E0CE0101960E946B098111C2
|
||||||
|
:1013E000E3CF81E026960FB6F894DEBF0FBECDBFE7
|
||||||
|
:1013F000DF91CF911F910F91FF9008950E944207B6
|
||||||
|
:101400008111DACFD1CFEF92FF921F93CF93DF9369
|
||||||
|
:10141000CDB7DEB762970FB6F894DEBF0FBECDBF73
|
||||||
|
:10142000182F9E012F5F3F4F790180E1F901119242
|
||||||
|
:101430008A95E9F750E0C9010E94EC1B80911B04DA
|
||||||
|
:101440008350833098F5133010F480E023C0212FAF
|
||||||
|
:101450002350330BC90163E070E00E948F1B1350CF
|
||||||
|
:10146000160F812F80958370810F0E94890581114D
|
||||||
|
:10147000ECCF80EA898B1A8B62E0CE0141960E9404
|
||||||
|
:101480006B098111E2CF60E1C7010E946B098111F4
|
||||||
|
:10149000DCCF81E062960FB6F894DEBF0FBECDBF01
|
||||||
|
:1014A000DF91CF911F91FF90EF90089540E1B70138
|
||||||
|
:1014B000812F0E94C809EECF9F92AF92BF92CF9228
|
||||||
|
:1014C000DF92EF92FF920F931F93CF93DF93A82E9B
|
||||||
|
:1014D0007B018A016A01D694C794D694C794B82E2A
|
||||||
|
:1014E000CB2DCA19D0E0CC15DD0518F599249394BD
|
||||||
|
:1014F0009B0C0E94A3008B1568F480E0DF91CF91D4
|
||||||
|
:101500001F910F91FF90EF90DF90CF90BF90AF9021
|
||||||
|
:101510009F900895BE01660F771F660F771F6E0DAF
|
||||||
|
:101520007F1D44E08B2D0E94030A882331F3B92CE0
|
||||||
|
:10153000D7CFC02FC37081E009F30E94A3008B15A1
|
||||||
|
:10154000E0F20C1B1109B701600F711F4C2F8B2D9E
|
||||||
|
:10155000DF91CF911F910F91FF90EF90DF90CF908F
|
||||||
|
:10156000BF90AF909F900C94030AEF92FF920F935D
|
||||||
|
:101570001F93CF93DF93CDB7DEB728970FB6F894BC
|
||||||
|
:10158000DEBF0FBECDBF90911B049923E1F17A011C
|
||||||
|
:101590008B01BE016F5F7F4F98E0FB0111929A951E
|
||||||
|
:1015A000E9F79FEF9B839BE09C838A838091FC01FA
|
||||||
|
:1015B0008D838091FD018E838091FE018F8348E0B1
|
||||||
|
:1015C00050E084E00E945C0A81110EC082E02896FF
|
||||||
|
:1015D0000FB6F894DEBF0FBECDBFDF91CF911F9144
|
||||||
|
:1015E0000F91FF90EF9008950115110551F0E1144E
|
||||||
|
:1015F000F10439F0A701B80186E00E945C0A882353
|
||||||
|
:1016000029F380E0E4CF85E0E2CFEF92FF921F93D1
|
||||||
|
:10161000CF93DF93CDB7DEB763970FB6F894DEBFF5
|
||||||
|
:101620000FBECDBF182F7B010E94A300811748F089
|
||||||
|
:1016300082E18B8B80911B0483508330B0F5133093
|
||||||
|
:1016400010F480E026C0212F2350330BC90163E042
|
||||||
|
:1016500070E00E948F1B1350160F812F80958370AE
|
||||||
|
:10166000810F0E9489058111ECCFAE014D5E5F4F65
|
||||||
|
:10167000BE016F5F7F4F812F0E94B6078111E1CFBE
|
||||||
|
:1016800084E0FE013196D70101900D928A95E1F731
|
||||||
|
:1016900081E063960FB6F894DEBF0FBECDBFDF9139
|
||||||
|
:1016A000CF911F91FF90EF900895AE014D5E5F4F77
|
||||||
|
:1016B000BE016F5F7F4F812F0E94EB078111E0CF4A
|
||||||
|
:1016C000C0CF1F93CF93DF93CDB7DEB728970FB668
|
||||||
|
:1016D000F894DEBF0FBECDBF182FBE016B5F7F4FEA
|
||||||
|
:1016E0000E94050B8823B9F0FE0135969E01275F05
|
||||||
|
:1016F0003F4F91919923D9F019821A821B821C8243
|
||||||
|
:101700000E94A300811788F044E0BE016F5F7F4F05
|
||||||
|
:10171000812F0E94030A28960FB6F894DEBF0FBEF1
|
||||||
|
:10172000CDBFDF91CF911F91089580E0F4CFE217F4
|
||||||
|
:10173000F307F9F6F0CF8F929F92AF92BF92DF92AC
|
||||||
|
:10174000EF92FF920F931F93CF93DF93CDB7DEB746
|
||||||
|
:10175000EA970FB6F894DEBF0FBECDBF2091070207
|
||||||
|
:1017600030910802232B09F4EDC190911B049923B9
|
||||||
|
:1017700009F4E8C1182F8091CF03882309F455C0DC
|
||||||
|
:1017800081E60E94D800812F0E94AF00111133C161
|
||||||
|
:10179000109200028091080190910901A0910A0124
|
||||||
|
:1017A000B0910B018FAB98AFA9AFBAAF8BAB9CAB2D
|
||||||
|
:1017B000ADABBEAB8FA798ABA9ABBAAB8090030221
|
||||||
|
:1017C00090900402A0900502B090060220910A02B7
|
||||||
|
:1017D000B501A401CE01C7960E94A80818AE0E94C8
|
||||||
|
:1017E000A300DD24D394D80E19821A821B821C8296
|
||||||
|
:1017F00080E018E008E00D15F0F4802F8D0D99279A
|
||||||
|
:10180000991F7C01F594E7941E2DBE016F5F7F4FF9
|
||||||
|
:101810008E2D0E94050B882309F494C189818823A9
|
||||||
|
:1018200031F00E1106C00F5FE6CF81EEAACFDE2C9D
|
||||||
|
:10183000E2CF0E2DE0CF81111F5F812F123108F40E
|
||||||
|
:1018400082E126EFF22EF80E0FEF010F0F1508F4CC
|
||||||
|
:101850007BC1BE016F5F7F4F802F0E94050B8823E5
|
||||||
|
:1018600009F470C18981853F79F4B501A401CE01E5
|
||||||
|
:1018700001960E941F09AB01BC014115510561058C
|
||||||
|
:10188000710521F4102F62C10150E0CF20910A02AE
|
||||||
|
:10189000CE018F960E94A80818AAF4CF1F5F1231BC
|
||||||
|
:1018A00009F058C171C10091000220910A02CE01D5
|
||||||
|
:1018B000C3960E94A8081CAA17501093FF01011B91
|
||||||
|
:1018C000009300021BA61CA61DA61EA685E5E82EF9
|
||||||
|
:1018D000E9A69AEAF92EFAA6E0910702F091080229
|
||||||
|
:1018E00000810DA711811EA766E070E0CE018996E8
|
||||||
|
:1018F0000E9413081A8A198A21E029832A832B83DC
|
||||||
|
:101900002C832DEE2D832E832F832887E986FA865C
|
||||||
|
:101910001B861C860D871E879F87888B80910002FF
|
||||||
|
:101920008B8B8F5F8C8B8FA58D8B88A98E8B89A9D4
|
||||||
|
:101930008F8B8AA9888F8BA9898F8CA98A8F8DA973
|
||||||
|
:101940008B8F8EA98C8F8EEE8D8F8E8F8F8F88A32D
|
||||||
|
:101950009FA999A398AD9AA399AD9BA39AAD9CA377
|
||||||
|
:101960008DA38EA38FA388A768E2CE0101960E9463
|
||||||
|
:1019700012018FEF0E94AF008FEF0E94AF008FEF38
|
||||||
|
:101980000E94AF008FEF0E94AF0048E250E060E29B
|
||||||
|
:1019900070E0CE0101960E94F51B64E0CE01019635
|
||||||
|
:1019A0000E94120164E1CE0101960E94120164E1DD
|
||||||
|
:1019B000CE0101960E94120164E0CE0101960E94C0
|
||||||
|
:1019C000120164E2CE0101960E9412010E945B089E
|
||||||
|
:1019D00081E0EA960FB6F894DEBF0FBECDBFDF916F
|
||||||
|
:1019E000CF911F910F91FF90EF90DF90BF90AF903C
|
||||||
|
:1019F0009F908F9008951130E9F544E250E060E245
|
||||||
|
:101A000070E0CE0101960E94F51B60E1CE010196C7
|
||||||
|
:101A10000E94120160E1CE0101960E94120164E26F
|
||||||
|
:101A2000CE0101960E94120164E1CE0101960E944E
|
||||||
|
:101A3000120160E1CE0101960E94120168E0CE0120
|
||||||
|
:101A400001960E94120164E0CE0101960E941201EB
|
||||||
|
:101A500068E0CE0101960E9412018FEF0E94AF0054
|
||||||
|
:101A60008FEF0E94AF008FEF0E94AF008FEF0E94B8
|
||||||
|
:101A7000AF00ACCF0E94A300082F88E0ECE0F1E0BB
|
||||||
|
:101A8000DE01119601900D928A95E1F7E1E0F0E018
|
||||||
|
:101A9000EC0FFD1FE10FF11D10811A5F1295110F60
|
||||||
|
:101AA000107E8091FF01885F180FE12EF12C9FE1DD
|
||||||
|
:101AB000E90EF11C8090080190900901A0900A01A4
|
||||||
|
:101AC000B0900B011E151F0411F00CF07FCF89A6FA
|
||||||
|
:101AD0009AA6ABA6BCA6011778F0BE01615D7F4F48
|
||||||
|
:101AE000812F0E94050B882309F473CF8FA5803FB7
|
||||||
|
:101AF00011F0853F79F41AA689A50E94AF008AA546
|
||||||
|
:101B00000E94AF008BA50E94AF008CA50E94AF0081
|
||||||
|
:101B10001F5FD8CF882381F38AA740910302509199
|
||||||
|
:101B200004026091050270910602CE018F960E9418
|
||||||
|
:101B30001F09AB01BC0120910A02CE0189960E94C7
|
||||||
|
:101B4000A808DACF80E045CF112319F01850109380
|
||||||
|
:101B5000000218E0BE016F5F7F4F812F0E94050BCE
|
||||||
|
:101B6000882381F38981803F09F098CEB501A401D3
|
||||||
|
:101B7000CE0101960E941F09AB01BC014115510520
|
||||||
|
:101B80006105710509F08FCE1092FF019BCE8F92F7
|
||||||
|
:101B9000AF92CF92DF92EF92FF920F931F93CF936A
|
||||||
|
:101BA000DF9300D000D0CDB7DEB780911B0488232F
|
||||||
|
:101BB00049F08CE0E8EFF3E0ACE0B4E001900D9286
|
||||||
|
:101BC0008A95E1F780E589831A82AE014D5F5F4F08
|
||||||
|
:101BD00062E0CE0101960E943304811110C0812C75
|
||||||
|
:101BE000A12CD12CC12CF12CE12C10E000E024E040
|
||||||
|
:101BF000AE014F5F5F4F60E38CE00E94710468E0CC
|
||||||
|
:101C000080E10E94EC039FB7F8948091180288232A
|
||||||
|
:101C100019F081508093180280911802811105C03B
|
||||||
|
:101C20008CB58F7B8CBD10922B029FBF60E08091A2
|
||||||
|
:101C300019040E944F010F900F900F900F90DF91A9
|
||||||
|
:101C4000CF911F910F91FF90EF90DF90CF90AF90C9
|
||||||
|
:101C50008F9008952F923F924F925F926F927F9252
|
||||||
|
:101C60008F929F92AF92BF92CF92DF92EF92FF92AC
|
||||||
|
:101C70000F931F93CF93DF9300D000D000D0CDB748
|
||||||
|
:101C8000DEB769835E834D83452B49F49E838D8344
|
||||||
|
:101C9000893C910520F028EC30E03E832D832C0117
|
||||||
|
:101CA000712C612C9C01A0E4BFE10E94741B28EE02
|
||||||
|
:101CB00033E040E050E00E94A31B49015A0110E0CC
|
||||||
|
:101CC00000E032EB232E30E0332E89818150990BD6
|
||||||
|
:101CD0009B838A83ED81FE816F01F12CE12CA89515
|
||||||
|
:101CE00061E084E00E944F0180910101833041F561
|
||||||
|
:101CF000E6E8F0E0F491FC83F7FDC6C083E00E94C3
|
||||||
|
:101D0000F300FC81FF2309F48EC02C81223009F0FE
|
||||||
|
:101D10009EC08091B100887F82608093B1008CE783
|
||||||
|
:101D20008093B30080921E0290921F02A092200224
|
||||||
|
:101D3000B092210280917000826080937000A4C0F4
|
||||||
|
:101D40008F3F09F0A1C083E080930101E6E8F0E055
|
||||||
|
:101D5000F491FC83FF3F09F497C0F13021F150F07A
|
||||||
|
:101D6000F23009F43EC02C8127FD8EC083E00E9432
|
||||||
|
:101D7000F300CBCF14BC15BC84B5826084BD85B59F
|
||||||
|
:101D8000816085BDEEE9F0E08491E82FF0E0EE0F90
|
||||||
|
:101D9000FF1FE957FF4F85919491F1018491809342
|
||||||
|
:101DA0001D021C82ABCF10928000109281008091A6
|
||||||
|
:101DB00081008860809381008091810081608093A0
|
||||||
|
:101DC0008100EEE9F0E08491E82FF0E0EE0FFF1FD4
|
||||||
|
:101DD000E957FF4F85919491F101849180931C0202
|
||||||
|
:101DE0008DCF1092B0001092B1008091B00082604F
|
||||||
|
:101DF0008093B0008091B10081608093B100EEE9E2
|
||||||
|
:101E0000F0E08491E82FF0E0EE0FFF1FE957FF4F5D
|
||||||
|
:101E10008591949190931B0280931A02F101849111
|
||||||
|
:101E2000809319026BCF85B5887F826085BD8CE772
|
||||||
|
:101E300087BD8092260290922702A0922802B0923B
|
||||||
|
:101E4000290280916E00826080936E001DC03C81EB
|
||||||
|
:101E5000313009F051C080918100887F816080938A
|
||||||
|
:101E6000810087EE93E090938900809388008092B0
|
||||||
|
:101E7000220290922302A0922402B0922502809125
|
||||||
|
:101E80006F00826080936F00C301B2010E94A201C3
|
||||||
|
:101E9000A89560E084E00E944F0160E083E00E942A
|
||||||
|
:101EA0004F01EA81FB810E171F072CF4C701B60111
|
||||||
|
:101EB0000E94A201A8950F5F1F4FF9810F1708F428
|
||||||
|
:101EC0000ECF26960FB6F894DEBF0FBECDBFDF91C2
|
||||||
|
:101ED000CF911F910F91FF90EF90DF90CF90BF9027
|
||||||
|
:101EE000AF909F908F907F906F905F904F903F90BA
|
||||||
|
:101EF0002F90089587EE14CF3C813230D9F3311101
|
||||||
|
:101F0000C3CF87EE95CF50E040E00C942A0ECF93DC
|
||||||
|
:101F1000C82F88E70E944E098C2F0E944F038091A2
|
||||||
|
:101F20001B040E944F030E94150363E084E690E0C7
|
||||||
|
:101F3000CF910C94830F61E084EF91E00C94830FB8
|
||||||
|
:101F4000CF92DF92EF92FF920F931F93CF93DF9385
|
||||||
|
:101F500000D000D0CDB7DEB77C01162F19821A82CF
|
||||||
|
:101F60001B821C8280911B04882309F44BC00E94B1
|
||||||
|
:101F7000A300082F123098F1F7011081818181119F
|
||||||
|
:101F800001C081E0412F480F5527551F0417150642
|
||||||
|
:101F90001CF00FEF010F080F85E60E944E0983E049
|
||||||
|
:101FA0006E0155E0C50ED11C0117D8F0BE016F5F60
|
||||||
|
:101FB0007F4F812F0E94050B882331F1812F0E94D2
|
||||||
|
:101FC0004F03CE0101967C01F70181917F010E94B0
|
||||||
|
:101FD0004F03CE14DF04C1F71F5F80E0E5CF14E0AC
|
||||||
|
:101FE000DBCF882399F00E94870F0F900F900F90FE
|
||||||
|
:101FF0000F90DF91CF911F910F91FF90EF90DF90A5
|
||||||
|
:10200000CF90089585E0EFCF83E0EDCF0E941503D8
|
||||||
|
:102010000E949B0FEACF8F929F92AF92BF92CF9276
|
||||||
|
:10202000DF92EF92FF920F931F93CF93DF9300D035
|
||||||
|
:1020300000D0CDB7DEB780911B04882371F01982E0
|
||||||
|
:102040001A821B821C82BE016F5F7F4F84E00E9458
|
||||||
|
:10205000050B811116C083E001C085E00E94870F47
|
||||||
|
:102060000F900F900F900F90DF91CF911F910F91D4
|
||||||
|
:10207000FF90EF90DF90CF90BF90AF909F908F90A8
|
||||||
|
:10208000089581E60E944E0989810E944F030E94B3
|
||||||
|
:10209000A300082F8C81813009F081C08FEF0E944E
|
||||||
|
:1020A0004F0316E0812C912C5401F12CE12C0117E7
|
||||||
|
:1020B00008F4B1C0BE016F5F7F4F812F0E94050BF6
|
||||||
|
:1020C000882349F28A81298130E0522F4427E11484
|
||||||
|
:1020D000F104D9F4982F907F7A01E92A90E0B0E0DA
|
||||||
|
:1020E000A0E0DC019927882788279927AF70BB27B4
|
||||||
|
:1020F0008B809C80982489249824B12CA12C882A38
|
||||||
|
:10210000992AAA2ABB2A1F5FD2CF482B64E0569592
|
||||||
|
:1021100047956A95E1F7452BB1F3C90134E09595F0
|
||||||
|
:1021200087953A95E1F70E944F03298180E1289F26
|
||||||
|
:10213000900111248A8182958F70822B0E944F0317
|
||||||
|
:102140008A8190E0B0E0A0E0DC0199278827882709
|
||||||
|
:102150009927AF70BB272B813C8132272327322759
|
||||||
|
:10216000A90170E060E0842B952BA62BB72B6701AB
|
||||||
|
:1021700088159905AA05BB0518F480E1C80ED11C85
|
||||||
|
:102180008D2D0E944F038A818F708C290E944F03EE
|
||||||
|
:102190008B810E944F038C810E944F03B4CF8A3001
|
||||||
|
:1021A000D0F18FEF0E944F0316E0F12CE12C0117C4
|
||||||
|
:1021B00090F1BE016F5F7F4F812F0E94050B882336
|
||||||
|
:1021C00009F449CF8981811114C09A81911111C0FC
|
||||||
|
:1021D0008B8190E0B0E0A0E0BA2FA92F982F88273C
|
||||||
|
:1021E0002C81822B9C01232B11F0F82EE92E1F5FEE
|
||||||
|
:1021F000DECF0E944F038A810E944F038E2D0E94E2
|
||||||
|
:102200004F038F2D0E944F038B810E944F038C81BF
|
||||||
|
:102210000E944F03ECCF0E9415030E949B0F20CF1A
|
||||||
|
:10222000CF93C82F89E70E944E0980911B040E941A
|
||||||
|
:102230004F030E941503CC2319F0CF910C949B0FF0
|
||||||
|
:10224000CF910895CF93DF93CDB7DEB728970FB620
|
||||||
|
:10225000F894DEBF0FBECDBFFC0187E06630F0F022
|
||||||
|
:102260009E012D5F3F4F86E0D9011D928A95E9F7C7
|
||||||
|
:102270008181898380818A8382818B8383818D831D
|
||||||
|
:1022800084818E8385818F8348E050E0BE016F5F3B
|
||||||
|
:102290007F4F8CEF0E94B50A882359F00E94870F68
|
||||||
|
:1022A00028960FB6F894DEBF0FBECDBFDF91CF9159
|
||||||
|
:1022B000089581E00E941011F3CF50E040E070E0FB
|
||||||
|
:1022C00060E089EF0E94B50A81110C94870F81E0CC
|
||||||
|
:1022D0000C94101150E040E070E060E08DEF0E943F
|
||||||
|
:1022E000B50A81110C94870F81E00C9410116830AD
|
||||||
|
:1022F00018F487E00C94870F20911B04222351F0DF
|
||||||
|
:10230000BC0148E050E086E00E945C0A811104C0F4
|
||||||
|
:1023100082E0F0CF85E0EECF81E00C9410117F9247
|
||||||
|
:102320008F929F92AF92BF92CF92DF92EF92FF92E5
|
||||||
|
:102330000F931F93CF93DF93CDB7DEB76A970FB696
|
||||||
|
:10234000F894DEBF0FBECDBF8C0187E06E3008F47D
|
||||||
|
:1023500049C080911B04882309F443C089506E3022
|
||||||
|
:1023600009F056C0833008F45FC061E084E00E9449
|
||||||
|
:102370004F010E94A300E82E2DEFF22EF80ED12C73
|
||||||
|
:102380003AE0932E45E0842E52E1752EF5E0FF15DC
|
||||||
|
:1023900008F0E7C08D2D692D0E94831B61E0992311
|
||||||
|
:1023A00039F08D2D682D0E94831B911104C060E0CF
|
||||||
|
:1023B00084E00E944F01D39490911B04992349F02B
|
||||||
|
:1023C000933038F0963008F48AC09950933008F46E
|
||||||
|
:1023D00096C082E00E94870F60E084E00E944F0177
|
||||||
|
:1023E00003C085E00E94870F6A960FB6F894DEBF9F
|
||||||
|
:1023F0000FBECDBFDF91CF911F910F91FF90EF9056
|
||||||
|
:10240000DF90CF90BF90AF909F908F907F90089576
|
||||||
|
:10241000F801E684833008F0A8CF0E94A300F82ECC
|
||||||
|
:1024200084E08F0DE0FC2AC00E94A300F82E80916A
|
||||||
|
:10243000140190911501A0911601B09117018B8B99
|
||||||
|
:102440009C8BAD8BBE8B44E0BE016D5E7F4F84E004
|
||||||
|
:102450008F0D0E94C809882379F019821A821B8285
|
||||||
|
:102460008FEF8C8344E0BE016F5F7F4F82E08F0D62
|
||||||
|
:102470000E94C809811179CF82E0B4CF44E066E0C0
|
||||||
|
:1024800074E00E94C8098823B9F31A8E198E8091CE
|
||||||
|
:102490000A048F8B80910B04888F44E0BE01695E33
|
||||||
|
:1024A0007F4F85E08F0D0E94C809882329F380E8BB
|
||||||
|
:1024B000E1FE80E01B8A1C8A1D8A1E8A8B8B44E009
|
||||||
|
:1024C000BE016D5E7F4F83E08F0D0E94C809882397
|
||||||
|
:1024D00099F219821A821B821C8284E0C2CF93E097
|
||||||
|
:1024E000C92E8C2D8F0D0E94610B882309F471CFAA
|
||||||
|
:1024F000CA942FEFC212F5CFFCEFFF0E47CF7F8AB1
|
||||||
|
:10250000AE01495E5F4FBE016F5F7F4F8F2D0E940E
|
||||||
|
:10251000EB07882309F45DCF5E013DE0A30EB11CFB
|
||||||
|
:1025200083E0C82EF50184E091919923B9F01B8ACC
|
||||||
|
:102530001C8A1D8A1E8A44E0BE016D5E7F4F8F2D6E
|
||||||
|
:102540008C0D0E94C809882309F443CFCA9484E003
|
||||||
|
:10255000A81AB108EFEFCE12E5CFCECF815021F708
|
||||||
|
:10256000F5CF2E2D2550330BC90164E070E00E9499
|
||||||
|
:102570008F1BF82EFF2049F085E08F0D0E94610B24
|
||||||
|
:10258000882309F426CFFA94F5CF60E084E00E9416
|
||||||
|
:102590004F011C821B828BE08C83F8018081898330
|
||||||
|
:1025A00081818A8382818D8383818E8384818F83DD
|
||||||
|
:1025B000858188878681898787818A8780858B87BF
|
||||||
|
:1025C00081858C8782858D8783858E8784858F879B
|
||||||
|
:1025D0008585888B40E150E0BE016F5F7F4F84E0CE
|
||||||
|
:1025E0000E945C0A882309F447CF81E00E94101101
|
||||||
|
:1025F000FBCE643018F487E00C94870F462FBC01A3
|
||||||
|
:1026000050E088EF0E94B50A8111F6CF81E00C946A
|
||||||
|
:102610001011633018F487E00C94870F462FBC012B
|
||||||
|
:1026200050E08FEF0E94B50A8111F6CF81E00C9443
|
||||||
|
:102630001011663018F487E00C94870F462FBC0108
|
||||||
|
:1026400050E08EEF0E94B50A8111F6CF81E00C9424
|
||||||
|
:102650001011CF93DF9300D000D0CDB7DEB761115A
|
||||||
|
:102660000AC087E00E94870F0F900F900F900F9085
|
||||||
|
:10267000DF91CF91089519821A821B821C82FC017E
|
||||||
|
:102680008081898344E050E0BE016F5F7F4F8BEF14
|
||||||
|
:102690000E94B50A8111E6CF81E00E941011E4CFBB
|
||||||
|
:1026A000CF93DF93CDB7DEB728970FB6F894DEBF90
|
||||||
|
:1026B0000FBECDBFFC0187E06630F0F09E012D5FBC
|
||||||
|
:1026C0003F4F86E0D9011D928A95E9F78181898380
|
||||||
|
:1026D00080818A8382818B8383818D8384818E83B1
|
||||||
|
:1026E00085818F8348E050E0BE016F5F7F4F8AEFA6
|
||||||
|
:1026F0000E94B50A882359F00E94870F28960FB6CA
|
||||||
|
:10270000F894DEBF0FBECDBFDF91CF91089580E07A
|
||||||
|
:102710000E94101144EF51E063E084EF91E00E94C9
|
||||||
|
:102720002A0E64EF71E080E090E00E94A20161E077
|
||||||
|
:1027300088EE93E00E94830FE1CF0F931F93CF9316
|
||||||
|
:10274000DF93CDB7DEB763970FB6F894DEBF0FBE49
|
||||||
|
:10275000CDBF811180931A0410921B0410921C04A7
|
||||||
|
:102760001FB7F89480911802811124C0E5EAF0E0C7
|
||||||
|
:102770008491E9EBF0E09491E82FF0E0EE0FFF1F79
|
||||||
|
:10278000EF56FF4FA591B491EC91E92321F461E05C
|
||||||
|
:102790008AE00E944F018AE00E94F3008CB58061BC
|
||||||
|
:1027A0008CBD8CB580648CBD8DE00E94F3008BE005
|
||||||
|
:1027B0000E94F300809118028F5F809318021FBF60
|
||||||
|
:1027C0009091190480911804809304049093050457
|
||||||
|
:1027D0000E94F30061E0809104040E944F01809107
|
||||||
|
:1027E00005040E94F3002091050430E0F901EE5841
|
||||||
|
:1027F000FF4F8491F901E155FF4F0491F901E5562E
|
||||||
|
:10280000FF4F14911123F1F081110E942601E12F55
|
||||||
|
:10281000F0E0EE0FFF1FE859FF4FA591B491EC9146
|
||||||
|
:102820000E2381F06FE082E00E94BF0365E070E05C
|
||||||
|
:1028300080E090E00E94A20182E00E949E0384FD5D
|
||||||
|
:10284000FBCF0BC061E0809105040E944F0165E061
|
||||||
|
:1028500070E080E090E00E94A20160E884E50E94C0
|
||||||
|
:10286000BF0366E486E50E94BF0363E088E50E943B
|
||||||
|
:10287000BF0368EE8AE50E94BF0360E48AE20E941B
|
||||||
|
:10288000BF036DE382E20E94BF030E94FA0363E08C
|
||||||
|
:1028900088E20E94EC0310911A041295107F8CE4D8
|
||||||
|
:1028A0000E949E038077181749F060E78CE40E942D
|
||||||
|
:1028B000EC03612F60778CE40E94DF030E94FA032F
|
||||||
|
:1028C00065E070E080E090E00E94A20182E08B8BE6
|
||||||
|
:1028D000AE014D5E5F4FBE016F5F7F4F86E20E948B
|
||||||
|
:1028E000D5058D7F21F40E941706882391F0ECE036
|
||||||
|
:1028F000F4E08CE0DF011D928A95E9F763960FB64C
|
||||||
|
:10290000F894DEBF0FBECDBFDF91CF911F910F9125
|
||||||
|
:102910000895E0910304EF77E13448F4F0E0E056E5
|
||||||
|
:10292000FE4F80818430F9F028F48330E1F010927A
|
||||||
|
:102930001B04E4CF8530B9F08630C9F782E18B8B78
|
||||||
|
:10294000AE014D5E5F4FBE016F5F7F4F83E00E941F
|
||||||
|
:10295000B6078111ECCF8B818E3341F08D3641F07B
|
||||||
|
:10296000823129F789E080931B04C8CF8AE0FBCF2E
|
||||||
|
:102970008BE0F9CFFF920F931F93CF93DF93EC017E
|
||||||
|
:102980008B01F42E80E00E949D136F2DC801FE0183
|
||||||
|
:102990000995DF91CF911F910F91FF900C94C70D76
|
||||||
|
:1029A0000F931F93CF93DF938C010E945E1BC82F60
|
||||||
|
:1029B000C80101960E945E1BD82FC80102960E9492
|
||||||
|
:1029C0005E1BCD1749F0C81711F0D81380E0DF91D6
|
||||||
|
:1029D000CF911F910F9108958C2FF9CF8F929F92D5
|
||||||
|
:1029E000AF92BF92CF92DF92EF92FF920F931F931D
|
||||||
|
:1029F000CF93DF9300D000D0CDB7DEB780911B041A
|
||||||
|
:102A0000882379F019821A821B821C82BE016F5FB3
|
||||||
|
:102A10007F4F84E00E94050B811114C083E00E9467
|
||||||
|
:102A2000870F0F900F900F900F90DF91CF911F9114
|
||||||
|
:102A30000F91FF90EF90DF90CF90BF90AF909F905D
|
||||||
|
:102A40008F9008958B818F3F61F344E050E06CE9F3
|
||||||
|
:102A500071E0CE0101960E94DF1B892B51F044E00A
|
||||||
|
:102A600050E068E971E0CE0101960E94DF1B892BDE
|
||||||
|
:102A700011F419821A8283E60E944E0989810E940C
|
||||||
|
:102A80004F038A810E944F03BE016F5F7F4F85E035
|
||||||
|
:102A90000E94050B882311F20981CA80DB801C810A
|
||||||
|
:102AA000BE016F5F7F4F86E00E94050B882309F40B
|
||||||
|
:102AB000B5CFCE0101965C014E0195E0890E911CC7
|
||||||
|
:102AC0007501F70181917F010E944F03E814F90419
|
||||||
|
:102AD000C1F7BE016F5F7F4F87E00E94050B88231F
|
||||||
|
:102AE00009F49CCFF50181915F010E944F03AE1460
|
||||||
|
:102AF000BF04C1F70E94A300B82EDC24CD24DC243F
|
||||||
|
:102B0000F12CE12CFE2CED2CDC2CCC24C12A18E07D
|
||||||
|
:102B1000AA24A394A00EB116C8F1BE016F5F7F4F27
|
||||||
|
:102B2000812F0E94050B882309F478CF89818111B8
|
||||||
|
:102B300009C09A81911106C09B81911103C09C81AB
|
||||||
|
:102B4000992321F10E944F038A819B81982789272D
|
||||||
|
:102B50009827B0E0A0E0BA2FA92F982F88272C81C2
|
||||||
|
:102B6000822B8C159D05AE05BF0570F48A2D0E9441
|
||||||
|
:102B70004F038A810E944F038B810E944F038C81F7
|
||||||
|
:102B80000E944F031F5FC7CF802FF1CF0E94150314
|
||||||
|
:102B900048CFCF92DF92EF92FF920F931F93CF9384
|
||||||
|
:102BA000DF93CDB7DEB728970FB6F894DEBF0FBE20
|
||||||
|
:102BB000CDBF1886E2EDF3E080E2DF011D928A9539
|
||||||
|
:102BC000E9F78CE292E00E949002181619060CF0C8
|
||||||
|
:102BD0000AC28CE292E00E9482029091D103981383
|
||||||
|
:102BE00002C260E270E082ED93E00E9425028091D3
|
||||||
|
:102BF000D403482F8D3108F04CE1242F30E0F90147
|
||||||
|
:102C0000EF52FC4F648172E0740FE3EDF3E090E06B
|
||||||
|
:102C100051E0A1919A0F5F5F7517D8F76913E1C171
|
||||||
|
:102C2000E091D303E88710920001E154EB3108F002
|
||||||
|
:102C3000FFC0F0E0E25EF94E0C94C51B39164E164B
|
||||||
|
:102C40005316621667166C167B16801618178516B3
|
||||||
|
:102C5000DF16E416E916F316F81608170D171817FD
|
||||||
|
:102C6000181718171817181718171217EE175816DD
|
||||||
|
:102C70005D1665ED73E080E593E10E94BA14289635
|
||||||
|
:102C80000FB6F894DEBF0FBECDBFDF91CF911F917D
|
||||||
|
:102C90000F91FF90EF90DF90CF90089565ED73E076
|
||||||
|
:102CA00089E293E1EACF65ED73E089E093E1E5CF56
|
||||||
|
:102CB00065ED73E089E193E1E0CF65ED73E089EFC5
|
||||||
|
:102CC00092E1DBCF65ED73E08FE891E1D6CF65ED62
|
||||||
|
:102CD00073E087E791E1D1CF86E60E944E0981E05B
|
||||||
|
:102CE0000E944F038BE00E944F0380E00E944F033D
|
||||||
|
:102CF0000E941503C4CF65ED73E08AE691E1BDCF74
|
||||||
|
:102D000065ED73E08BE090E1B8CF4B7F423021F06E
|
||||||
|
:102D100087E00E94870FB3CF8091D5038250863021
|
||||||
|
:102D200028F48091D603805D893610F088E0F1CFD9
|
||||||
|
:102D3000A90165ED73E089E092E00E94EC1B89E057
|
||||||
|
:102D4000C82E82E0D82E0EEE13E0F601F1906F014E
|
||||||
|
:102D5000C8010E94D014F81671F06F2DC8010E94AE
|
||||||
|
:102D6000661B6F2DC80101960E94661B6F2DC8015E
|
||||||
|
:102D700002960E94661B0D5F1F4F0115F4E01F07AE
|
||||||
|
:102D800021F780910902883008F087E0823008F44A
|
||||||
|
:102D900082E080931A0480910B0280930604809154
|
||||||
|
:102DA0000C028093070480910D02809308048091A7
|
||||||
|
:102DB0000E028093090481E00E94101160CF65ED3E
|
||||||
|
:102DC00073E08EEE94E159CF65ED73E080EA9FE009
|
||||||
|
:102DD00054CF87E60E944E09809109020E944F035A
|
||||||
|
:102DE00080910A0283CF65ED73E082E291E145CFE5
|
||||||
|
:102DF000833008F48DCF8091D5039091D603A091B4
|
||||||
|
:102E0000D7038093FC019093FD01A093FE01D3CFE3
|
||||||
|
:102E100065ED73E08DE591E130CF65ED73E082E61D
|
||||||
|
:102E200099E02BCF63E084E690E00E94830F27CFE8
|
||||||
|
:102E300086E06FCF8CE292E00E948202182F8630EB
|
||||||
|
:102E4000F9F48CE292E00E9411021887FE01389694
|
||||||
|
:102E500081E0809300018885833709F483C008F0FE
|
||||||
|
:102E6000D7C0813609F492C0803709F487C0863014
|
||||||
|
:102E700009F4B2C065E18CE292E00E94C802FFCE84
|
||||||
|
:102E8000823009F0B8C063E070E08DEC92E00E94FF
|
||||||
|
:102E900025028091CE02823051F48091CF0280933E
|
||||||
|
:102EA000CE0261E070E08FEC92E00E942502D090AB
|
||||||
|
:102EB000CE02D7FC20C081E08093CF030FEC12E05C
|
||||||
|
:102EC000780161E070E0C8010E942502D8018D916F
|
||||||
|
:102ED0008D01803151F461E070E0C7010E9425024C
|
||||||
|
:102EE000B3E009351B0761F702C08330C9F7D88604
|
||||||
|
:102EF000EFECF2E0ADCF1092CF030091CF02073894
|
||||||
|
:102F000008F0B8CF10E07801E3E0EE0EF11CA70165
|
||||||
|
:102F100070E060E080ED92E00E94F51BB70180ED6B
|
||||||
|
:102F200092E00E942502F701E553FD4F82818093D4
|
||||||
|
:102F3000CC02F801E553FD4F86818093CB02E090EF
|
||||||
|
:102F4000CB02F090CC02B8016E5F7F4F8EEC92E026
|
||||||
|
:102F50000E941308E816F90609F08CCFD886E0ED38
|
||||||
|
:102F6000F2E076CF83E70E94D80080E00E94AF00B5
|
||||||
|
:102F70006EE088E191E00E94120105C00E94D80035
|
||||||
|
:102F80008DE40E94AF000E945B0879CE108180E042
|
||||||
|
:102F90000E949D13183099F410E0812F0E949B0B22
|
||||||
|
:102FA000882391F0111105C080910002813408F44A
|
||||||
|
:102FB00015E01F5F183089F70E94C70D60CE812F82
|
||||||
|
:102FC0000E949B0B8111F8CF0E94F80863E084E611
|
||||||
|
:102FD00090E00E94830FF0CF0E94F8080E949B0FA0
|
||||||
|
:102FE0004ECE81E096CE8CE292E00E9490021816BE
|
||||||
|
:102FF00019060CF41FCF8CE292E00E949002181682
|
||||||
|
:1030000019060CF03CCE8CE292E00E94110237CE01
|
||||||
|
:10301000813E09F4BBCFC0F4833809F02BCF108177
|
||||||
|
:10302000113808F02CCE018107FF02C000E8011B17
|
||||||
|
:1030300083E80E94D800812F0E94AF00812F90E08A
|
||||||
|
:10304000602F885E9E4F97CF803F09F497CF873FD0
|
||||||
|
:1030500009F010CF8E010F5F1F4F87E0D8011D923E
|
||||||
|
:103060008A95E9F787EF0E94D80067E0C80183CF0F
|
||||||
|
:103070000E949C0281110C94C91508951F920F9211
|
||||||
|
:103080000FB60F9211242F933F938F939F93AF937B
|
||||||
|
:10309000BF938091140290911502A0911602B091F5
|
||||||
|
:1030A000170230910F0226E0230F2D3758F50296B4
|
||||||
|
:1030B000A11DB11D20930F0280931402909315025D
|
||||||
|
:1030C000A0931602B0931702809110029091110202
|
||||||
|
:1030D000A0911202B09113020196A11DB11D80931F
|
||||||
|
:1030E000100290931102A0931202B0931302BF91A9
|
||||||
|
:1030F000AF919F918F913F912F910F900FBE0F90A5
|
||||||
|
:103100001F90189529E8230F0396A11DB11DD2CF5A
|
||||||
|
:103110001F920F920FB60F9211242F933F934F934C
|
||||||
|
:103120005F936F937F938F939F93AF93BF93EF932F
|
||||||
|
:10313000FF9380911E0290911F02A0912002B091F6
|
||||||
|
:103140002102892B8A2B8B2BD1F190911902E091CE
|
||||||
|
:103150001A02F0911B0280818927808380911E02D0
|
||||||
|
:1031600090911F02A0912002B09121021816190619
|
||||||
|
:103170001A061B069CF480911E0290911F02A091DA
|
||||||
|
:103180002002B09121020197A109B10980931E028A
|
||||||
|
:1031900090931F02A0932002B0932102FF91EF9120
|
||||||
|
:1031A000BF91AF919F918F917F916F915F914F915F
|
||||||
|
:1031B0003F912F910F900FBE0F901F901895809107
|
||||||
|
:1031C0000101E6E8F0E0E4919FEF90930101E13026
|
||||||
|
:1031D00051F030F0E23069F060E00E944F01DECF44
|
||||||
|
:1031E00010926E00F9CF90916F009D7F90936F00C9
|
||||||
|
:1031F000F3CF909170009D7F9093700091E0909339
|
||||||
|
:10320000B0009091B100987F94609093B1001092BB
|
||||||
|
:10321000B300E2CF1F920F920FB60F9211242F939B
|
||||||
|
:103220003F934F935F936F937F938F939F93AF934E
|
||||||
|
:10323000BF93EF93FF938CE292E00E94A602FF916E
|
||||||
|
:10324000EF91BF91AF919F918F917F916F915F911E
|
||||||
|
:103250004F913F912F910F900FBE0F901F90189597
|
||||||
|
:103260001F920F920FB60F9211242F938F939F935B
|
||||||
|
:10327000EF93FF93E0913C02F0913D028081E09159
|
||||||
|
:103280004202F091430282FD1BC090818091450271
|
||||||
|
:103290008F5F8F7320914602821741F0E0914502C3
|
||||||
|
:1032A000F0E0E45DFD4F958F80934502FF91EF9133
|
||||||
|
:1032B0009F918F912F910F900FBE0F901F90189597
|
||||||
|
:1032C0008081F4CF1F920F920FB60F9211240F90AE
|
||||||
|
:1032D0000FBE0F901F901895ECE2F2E0138212825D
|
||||||
|
:1032E00088EE93E0A0E0B0E084839583A683B78363
|
||||||
|
:1032F0008EEE91E09183808385EC90E095878487C2
|
||||||
|
:1033000084EC90E09787868780EC90E0918B808BAF
|
||||||
|
:1033100081EC90E0938B828B82EC90E0958B848B98
|
||||||
|
:1033200086EC90E0978B868B118E128E138E148E06
|
||||||
|
:103330008FEF9FEF9093CA028093C902E8EFF3E00A
|
||||||
|
:1033400010A211A212A213A214A2E1EDF3E01082C6
|
||||||
|
:1033500083E081A312A213A214A215A216A2809345
|
||||||
|
:10336000CC031092CE031092CD0381E08093CF0363
|
||||||
|
:103370001092D0030895CF93DF9300D000D0CDB743
|
||||||
|
:10338000DEB7789484B5826084BD84B5816084BDE5
|
||||||
|
:1033900085B5826085BD85B5816085BD80916E00F3
|
||||||
|
:1033A000816080936E001092810080918100826024
|
||||||
|
:1033B0008093810080918100816080938100809161
|
||||||
|
:1033C00080008160809380008091B1008460809350
|
||||||
|
:1033D000B1008091B00081608093B00080917A004C
|
||||||
|
:1033E000846080937A0080917A00826080937A0072
|
||||||
|
:1033F00080917A008E7F80937A0080917A00806835
|
||||||
|
:1034000080937A001092C10084E00E94F30083E070
|
||||||
|
:103410000E94F30089E00E94F3008AE00E94F3001A
|
||||||
|
:1034200060E084E00E944F0160E083E00E944F0171
|
||||||
|
:1034300060E089E00E944F0159E0E52E52E0F52E50
|
||||||
|
:103440000EEE13E0C8010E94D014F70181937F01B2
|
||||||
|
:103450000D5F1F4F0115F4E01F07A1F780910902CE
|
||||||
|
:103460008250863080F084E08093090210920A0234
|
||||||
|
:103470008FEF9FEFDC0180930B0290930C02A093DF
|
||||||
|
:103480000D02B0930E02809109029AE09093180405
|
||||||
|
:1034900099E090931904883008F087E0823008F4AE
|
||||||
|
:1034A00082E080931A0410920B0410920A04809117
|
||||||
|
:1034B0000B028093060480910C0280930704809194
|
||||||
|
:1034C0000D028093080480910E02809309048EEF10
|
||||||
|
:1034D0008093D10380E096E9A0E0B0E08093F4030C
|
||||||
|
:1034E0009093F503A093F603B093F7038AE090E07E
|
||||||
|
:1034F000A0E0B0E08093300290933102A0933202BA
|
||||||
|
:10350000B0933302E0913C02F0913D0282E080836F
|
||||||
|
:10351000E0913802F09139021082E0913A02F09184
|
||||||
|
:103520003B0289E1808310924402E0914002F091D5
|
||||||
|
:10353000410286E08083E0913E02F0913F0280816B
|
||||||
|
:1035400080618083E0913E02F0913F02808188603B
|
||||||
|
:103550008083E0913E02F0913F0280818068808309
|
||||||
|
:10356000E0913E02F0913F0280818F7D808361E097
|
||||||
|
:1035700084E00E944F0162E370E080E090E00E94EE
|
||||||
|
:10358000A20160E084E00E944F0101E012E080911E
|
||||||
|
:103590000001882309F48AC0809109020E949D13CA
|
||||||
|
:1035A00080911B04882309F479C09091F80329EFD6
|
||||||
|
:1035B00033E080E0981709F471C0F90154892F5F56
|
||||||
|
:1035C0003F4F4081541306C08F5FF4CF86EE0E94B8
|
||||||
|
:1035D000D80054C019821A821B821C82BE016F5F00
|
||||||
|
:1035E0007F4F84E00E94050B882309F457C08B812C
|
||||||
|
:1035F0008F3F09F453C08981809301028A818093AF
|
||||||
|
:103600000202BE016F5F7F4F85E00E94050B882399
|
||||||
|
:1036100009F444C0898190E0B0E0A0E0BA2FA92F5E
|
||||||
|
:10362000982F88272A81822BBA2FA92F982F882795
|
||||||
|
:103630002B81822BBA2FA92F982F88272C81822BA0
|
||||||
|
:103640000097A105B10551F11093080200930702FC
|
||||||
|
:103650008093030290930402A0930502B0930602A4
|
||||||
|
:103660008091CF03882309F4B1CF86E60E94D80069
|
||||||
|
:1036700085E50E94AF008AEA0E94AF0080E00E94C8
|
||||||
|
:10368000AF0080E00E94AF00809101020E94AF0075
|
||||||
|
:10369000809102020E94AF000E945B080E94C70D49
|
||||||
|
:1036A00062E370E080E090E00E94A2010E949C0230
|
||||||
|
:1036B000882309F46CCF0E94C91569CFF999FECF10
|
||||||
|
:1036C00092BD81BDF89A992780B50895262FF99962
|
||||||
|
:1036D000FECF1FBA92BD81BD20BD0FB6F894FA9AF5
|
||||||
|
:1036E000F99A0FBE01960895A29FB001B39FC00141
|
||||||
|
:1036F000A39F700D811D1124911DB29F700D811D1E
|
||||||
|
:103700001124911D0895991B79E004C0991F961703
|
||||||
|
:1037100008F0961B881F7A95C9F78095089597FB46
|
||||||
|
:10372000072E16F4009407D077FD09D00E94CB1B1A
|
||||||
|
:1037300007FC05D03EF4909581959F4F08957095B4
|
||||||
|
:1037400061957F4F0895A1E21A2EAA1BBB1BFD01B4
|
||||||
|
:103750000DC0AA1FBB1FEE1FFF1FA217B307E40770
|
||||||
|
:10376000F50720F0A21BB30BE40BF50B661F771FC8
|
||||||
|
:10377000881F991F1A9469F76095709580959095A8
|
||||||
|
:103780009B01AC01BD01CF010895EE0FFF1F059015
|
||||||
|
:10379000F491E02D0994AA1BBB1B51E107C0AA1F9D
|
||||||
|
:1037A000BB1FA617B70710F0A61BB70B881F991FE2
|
||||||
|
:1037B0005A95A9F780959095BC01CD010895FB011C
|
||||||
|
:1037C000DC0104C08D910190801921F441505040DA
|
||||||
|
:1037D000C8F7881B990B0895FB01DC0102C001901A
|
||||||
|
:1037E0000D9241505040D8F70895DC0101C06D930F
|
||||||
|
:1037F00041505040E0F70895F894FFCF01FFFFFFDC
|
||||||
|
:10380000FFFFFFFFEEEEEEEE0001040506070203E8
|
||||||
|
:10381000FFFFFFFF00000001F73632330A01199164
|
||||||
|
:103820009780200D4B084EFA280A0119006DDD0023
|
||||||
|
:1038300000001804FF0380000000000000000000EA
|
||||||
|
:103840004D70FFFFFF00C3FF0000000A00000000F2
|
||||||
|
:10385000FF00EFFF0024FEC0FFFF1999051E7FF84F
|
||||||
|
:10386000850C0101A6E06FFFFFFFFFFFFFFFFFFFD9
|
||||||
|
:10387000FFFFFFFF303030357D20380000000000B2
|
||||||
|
:10388000FFFFFFFF300501350510080100000000B3
|
||||||
|
:103890001C2000780300FE000103A00C06080000B5
|
||||||
|
:1038A000FF00000004030000000000000707000004
|
||||||
|
:1038B0000000000005000000000000000100000002
|
||||||
|
:1038C00000000000000000000000000000000000F8
|
||||||
|
:1038D0000000000000000000000000000211326241
|
||||||
|
:1038E0002700002781E100000000C802D501020284
|
||||||
|
:0838F00066039002110282023E
|
||||||
|
:107E000001C0E5C0112484B7882359F083FF03C063
|
||||||
|
:107E100094B7967F94BF80FD04C0282E80E0C2D026
|
||||||
|
:107E2000EFC085E08093810082E08093C00088E10C
|
||||||
|
:107E30008093C10086E08093C20083E38093C400F6
|
||||||
|
:107E40008FE0B0D0259A86E020E33CEF91E03093BC
|
||||||
|
:107E500085002093840096BBB09BFECF1D9AA89509
|
||||||
|
:107E60004091C00047FD02C0815089F793E0E92EA0
|
||||||
|
:107E7000DD24D39425E0C22E31E1B32E87D0C82F64
|
||||||
|
:107E800089E290D0C13479F481D0C82F91D0C23822
|
||||||
|
:107E900011F480E004C088E0C13809F083E06FD0BD
|
||||||
|
:107EA00080E16DD0EBCF84E1C23419F0C53419F410
|
||||||
|
:107EB00085E086D0F5CFC53541F468D0082F66D06F
|
||||||
|
:107EC000182F000F111F74D0EBCFC63519F484E0C2
|
||||||
|
:107ED00077D0DFCFC43609F033C058D057D0F82E52
|
||||||
|
:107EE00055D0A82EC0E0D1E04E018FEF881A980A35
|
||||||
|
:107EF0004DD08883E401F810F7CF5AD0F5E4AF12E3
|
||||||
|
:107F000001C0FFCFF801E7BEE89507B600FCFDCF42
|
||||||
|
:107F1000F801A0E0B1E0CD0102962D913C9109015C
|
||||||
|
:107F2000D7BEE89511243296DC01F812F4CFF8019F
|
||||||
|
:107F3000C7BEE89507B600FCFDCFB7BEE895B0CF49
|
||||||
|
:107F4000C43771F423D022D0F82E20D031D0E801EC
|
||||||
|
:107F5000FE018591EF0113D0FA94F110F9CFA0CF73
|
||||||
|
:107F6000C53739F425D08EE10AD085E908D08FE0F5
|
||||||
|
:107F700096CFC13509F0A7CF88E014D0A4CF909157
|
||||||
|
:107F8000C00095FFFCCF8093C60008958091C0008B
|
||||||
|
:107F900087FFFCCF8091C00084FD01C0A89580912F
|
||||||
|
:107FA000C6000895E0E6F0E098E1908380830895AC
|
||||||
|
:107FB000EDDF803219F088E0F5DFFFCF84E1DFCF1D
|
||||||
|
:107FC000CF93C82FE3DFC150E9F7CF91F1CFFC0188
|
||||||
|
:107FD0000A0167BFE895112407B600FCFDCF667063
|
||||||
|
:0E7FE00029F0452B19F481E187BFE89508953B
|
||||||
|
:027FFE00000879
|
||||||
|
:00000001FF
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
:00000001FF
|
||||||
|
|
@ -0,0 +1,913 @@
|
||||||
|
:100000000C9463000C948B000C948B000C948B006C
|
||||||
|
:100010000C948B000C948B000C9462190C9488182F
|
||||||
|
:100020000C948B000C948B000C948B000C948B0024
|
||||||
|
:100030000C948B000C948B000C948B000C948B0014
|
||||||
|
:100040000C943E180C948B000C9430190C940A19E3
|
||||||
|
:100050000C948B000C948B000C948B000C948B00F4
|
||||||
|
:100060000C948B000C948B000000000023002600F1
|
||||||
|
:10007000290000000008000201000003040700003E
|
||||||
|
:100080000000000000000200000000250028002BF6
|
||||||
|
:100090000000000000240027002A000404040404D7
|
||||||
|
:1000A0000404040202020202020303030303030125
|
||||||
|
:1000B00002040810204080010204081020010204FC
|
||||||
|
:1000C000081020006C1911241FBECFEFD8E0DEBF4E
|
||||||
|
:1000D000CDBF24E0ACEFB1E001C01D92AD31B2075D
|
||||||
|
:1000E000E1F711E0A0E0B1E0ECEFF7E302C005902A
|
||||||
|
:1000F0000D92AC3FB107D9F710E0C3E6D0E004C0E1
|
||||||
|
:100100002197FE010E94C51BC236D107C9F70E9484
|
||||||
|
:10011000BB190C94FC1B0C94000020912B02222391
|
||||||
|
:1001200061F02FB7F89430912B02313049F43DB390
|
||||||
|
:1001300030932A023DB33DBB2FBF8CBD9DBD0895BA
|
||||||
|
:1001400020932A02FACFE0911B04E350E93028F40F
|
||||||
|
:10015000F0E0EF51FE4F8081089580E00895E09136
|
||||||
|
:10016000CC039091D003992301F1803248F491E0BF
|
||||||
|
:100170009E0F9093CC03F0E0E553FD4F90E1928306
|
||||||
|
:100180002091CD033091CE03280F311D3093CE0343
|
||||||
|
:100190002093CD03E091CC0391E09E0F9093CC038C
|
||||||
|
:1001A000F0E0E553FD4F828302C0EB3898F30895E9
|
||||||
|
:1001B00092E09093CD028093CE0287FD0BC081E048
|
||||||
|
:1001C0008093D0031092CE031092CD039093CC0372
|
||||||
|
:1001D0000C94AF001092D00384E08093CC03109273
|
||||||
|
:1001E000D00281E0F5CF90E0FC01E155FF4F249172
|
||||||
|
:1001F00085569F4FFC018491882399F090E0880FE9
|
||||||
|
:10020000991FFC01EF56FF4FA591B491FC01E957EE
|
||||||
|
:10021000FF4F859194918FB7F894EC91E22BEC937A
|
||||||
|
:100220008FBF08950F931F93CF93DF93EC018C0141
|
||||||
|
:10023000060F111DC017D10721F089910E94AF0050
|
||||||
|
:10024000F9CFDF91CF911F910F910895833081F005
|
||||||
|
:1002500028F4813099F08230A9F008958730A9F010
|
||||||
|
:100260008830C9F08430B1F4809180008F7D03C064
|
||||||
|
:10027000809180008F7780938000089584B58F7778
|
||||||
|
:1002800084BD089584B58F7DFBCF8091B0008F77BA
|
||||||
|
:100290008093B00008958091B0008F7DF9CF1F93B7
|
||||||
|
:1002A000CF93DF93282F30E0F901EE58FF4F849170
|
||||||
|
:1002B000F901E155FF4FD491F901E556FF4FC49183
|
||||||
|
:1002C000CC23A9F0162F81110E942601EC2FF0E01B
|
||||||
|
:1002D000EE0FFF1FE957FF4FA591B4918FB7F89428
|
||||||
|
:1002E000EC91111108C0D095DE23DC938FBFDF9114
|
||||||
|
:1002F000CF911F910895DE2BF8CF3FB7F8948091EE
|
||||||
|
:10030000100290911102A0911202B091130226B531
|
||||||
|
:10031000A89B05C02F3F19F00196A11DB11D3FBF3D
|
||||||
|
:10032000BA2FA92F982F8827BC01CD01620F711D0C
|
||||||
|
:10033000811D911D43E0660F771F881F991F4A9505
|
||||||
|
:10034000D1F708958F929F92AF92BF92CF92DF9292
|
||||||
|
:10035000EF92FF926B017C010E947D014B015C01D9
|
||||||
|
:10036000C114D104E104F104B9F00E947D016819BF
|
||||||
|
:1003700079098A099B09683E73408105910580F3DC
|
||||||
|
:1003800021E0C21AD108E108F10888EE880E83E066
|
||||||
|
:10039000981EA11CB11CE4CFFF90EF90DF90CF908E
|
||||||
|
:1003A000BF90AF909F908F900895AF92BF92CF92E1
|
||||||
|
:1003B000DF92EF92FF920F931F93CF93DF936C0125
|
||||||
|
:1003C0007B018B01040F151FEB015E01AE18BF0806
|
||||||
|
:1003D000C017D10759F06991D601ED91FC910190B8
|
||||||
|
:1003E000F081E02DC6010995892B79F7C501DF91D0
|
||||||
|
:1003F000CF911F910F91FF90EF90DF90CF90BF9022
|
||||||
|
:10040000AF900895FC01538D448D252F30E0842F4B
|
||||||
|
:1004100090E0821B930B541710F0CF96089501972C
|
||||||
|
:100420000895FC01918D828D981761F0A28DAE0F19
|
||||||
|
:10043000BF2FB11D5D968C91928D9F5F9F73928FA0
|
||||||
|
:1004400090E008958FEF9FEF0895CF92DF92EF92A3
|
||||||
|
:10045000FF920F931F93CF93DF937C018C01060FC4
|
||||||
|
:10046000171FEC016E01CE18DF080C171D0709F4E9
|
||||||
|
:100470003DC02FB7F8948091140290911502A0917D
|
||||||
|
:100480001602B09117022FBF809334029093350269
|
||||||
|
:10049000A0933602B09337028CE292E00E941102E0
|
||||||
|
:1004A00097FF2EC02FB7F8948091140290911502F7
|
||||||
|
:1004B000A0911602B09117022FBF409134025091C3
|
||||||
|
:1004C00035026091360270913702841B950BA60BA2
|
||||||
|
:1004D000B70B40913002509131026091320270911D
|
||||||
|
:1004E000330284179507A607B707B0F2C601DF915C
|
||||||
|
:1004F000CF911F910F91FF90EF90DF90CF900895D3
|
||||||
|
:100500008993B0CFFC01918D828D981731F0828D47
|
||||||
|
:10051000E80FF11D858D90E008958FEF9FEF08950E
|
||||||
|
:10052000FC01918D228D892F90E0805C9F4F821B72
|
||||||
|
:1005300091098F73992708958CE292E00E949002AE
|
||||||
|
:1005400021E0892B09F420E0822F0895FC01A48D7D
|
||||||
|
:10055000A80FB92FB11DA35ABF4F2C91848D90E0E5
|
||||||
|
:1005600001968F739927848FA689B7892C93A089C8
|
||||||
|
:10057000B1898C91837080648C93938D848D981352
|
||||||
|
:1005800006C00288F389E02D80818F7D80830895E5
|
||||||
|
:10059000EF92FF920F931F93CF93DF93EC0181E0D3
|
||||||
|
:1005A000888F9B8D8C8D98131AC0E889F98980817A
|
||||||
|
:1005B00085FF15C09FB7F894EE89FF896083E889AD
|
||||||
|
:1005C000F98980818370806480839FBF81E090E09F
|
||||||
|
:1005D000DF91CF911F910F91FF90EF900895F62E2C
|
||||||
|
:1005E0000B8D10E00F5F1F4F0F731127E02E8C8DC6
|
||||||
|
:1005F0008E110CC00FB607FCFACFE889F98980810B
|
||||||
|
:1006000085FFF5CFCE010E94A602F1CFEB8DEC0F56
|
||||||
|
:10061000FD2FF11DE35AFF4FF0829FB7F8940B8F27
|
||||||
|
:10062000EA89FB8980818062CFCFCF938091F203EA
|
||||||
|
:1006300083508D3150F09091F3038EE1890F2FE1BB
|
||||||
|
:100640002093F2039F5F9093F3038093D403E09190
|
||||||
|
:10065000F203F0E08D3108F08CE18E5FA3EDB3E0A2
|
||||||
|
:1006600090E021E03D91930F2F5F8217D8F7EF5272
|
||||||
|
:10067000FC4F9183C0E08091F2038C1758F0EC2F6F
|
||||||
|
:10068000F0E0EF52FC4F61818CE292E00E94C802E0
|
||||||
|
:10069000CF5FF1CF83E08093F203CF910895CF93A2
|
||||||
|
:1006A000C82F8091F2038F3128F08F5F8093F2037F
|
||||||
|
:1006B0000E9415038091F203E82FF0E0EF52FC4F07
|
||||||
|
:1006C000C1838F5F8093F203CF910895CF93DF931F
|
||||||
|
:1006D000EC01888D8823B9F0AA89BB89E889F9895A
|
||||||
|
:1006E0008C9185FD03C0808186FD0DC00FB607FC8F
|
||||||
|
:1006F000F7CF8C9185FFF2CF808185FFEDCFCE01C2
|
||||||
|
:100700000E94A602E9CFDF91CF91089580912B023C
|
||||||
|
:10071000882361F09FB7F89420912B0280912A02E0
|
||||||
|
:10072000213019F48DBB9FBF08958FBF08958EBDF2
|
||||||
|
:1007300000000DB407FEFDCF8EB508951F93CF9333
|
||||||
|
:10074000DF93182F83E590E00E948D00C8EFD3E07F
|
||||||
|
:1007500060E08C850E944F01812F80680E94970382
|
||||||
|
:1007600080E00E949703182F61E08C850E944F0162
|
||||||
|
:100770000E948603812FDF91CF911F9108950F93DF
|
||||||
|
:100780001F93CF93DF93082F162F83E590E00E94ED
|
||||||
|
:100790008D00C8EFD3E060E08C850E944F01802F70
|
||||||
|
:1007A0000E949703812F0E94970361E08C850E942D
|
||||||
|
:1007B0004F01DF91CF911F910F910C948603CF933E
|
||||||
|
:1007C000DF93D82FC62F0E949E03682F6C2B8D2F8E
|
||||||
|
:1007D000DF91CF910C94BF03CF93DF93D82FC62F17
|
||||||
|
:1007E0000E949E03C0956C2F68238D2FDF91CF91BF
|
||||||
|
:1007F0000C94BF0388E20E949E03982F937093305D
|
||||||
|
:1008000029F0682F636088E20C94BF030895FF927B
|
||||||
|
:100810000F931F93CF93DF93082FF62E172F83E5A7
|
||||||
|
:1008200090E00E948D0060E0809104040E944F01DE
|
||||||
|
:1008300082E10E949703CF2DD12F0C0F1D2F111D88
|
||||||
|
:10084000C017D10721F089910E949703F9CF61E089
|
||||||
|
:10085000809104040E944F01DF91CF911F910F916D
|
||||||
|
:10086000FF900C948603EF92FF920F931F93CF9308
|
||||||
|
:10087000DF937C01C62F8A0160E082E00E94BF0303
|
||||||
|
:1008800064E08AE00E94BF0360E884E10E94DF0325
|
||||||
|
:10089000B7018C2F0E94070463E082E00E94BF032F
|
||||||
|
:1008A000C8E8D3E18AE00E949E0382FD04C021973C
|
||||||
|
:1008B000C9F783E00FC060E082E00E94BF0384E4D8
|
||||||
|
:1008C0000E949E03F801808382E40E949E03F80147
|
||||||
|
:1008D000818380E0DF91CF911F910F91FF90EF9086
|
||||||
|
:1008E00008952F923F924F925F926F927F928F92D4
|
||||||
|
:1008F0009F92AF92BF92CF92DF92EF92FF920F93AF
|
||||||
|
:100900001F93CF93DF9300D0CDB7DEB7982E562E2E
|
||||||
|
:100910003A01422E80E0C114D10411F0F601808129
|
||||||
|
:100920003A2C329420EF3222380E60E082E00E94AE
|
||||||
|
:10093000BF036FE788E00E94BF0360E884E10E9484
|
||||||
|
:10094000DF03B301842D0E940704632D8AE10E9416
|
||||||
|
:10095000BF03692D82E00E94BF03FCE09F1204C028
|
||||||
|
:1009600060E88AE10E94DF0390ED692E97E0792E1E
|
||||||
|
:1009700088E00E949E03982F952141F480FD04C0D9
|
||||||
|
:1009800081E0681A7108A1F783E0A6C08CE00E949C
|
||||||
|
:100990009E03382E837109F0B4C00115110509F4C6
|
||||||
|
:1009A00066C0E114F10409F462C084E10E949E0370
|
||||||
|
:1009B000B82EF70180818B1508F4A5C0B082BB204A
|
||||||
|
:1009C00009F44BC083E590E00E948D0060E08091C7
|
||||||
|
:1009D00004040E944F01BA9482E90E9497033801EF
|
||||||
|
:1009E000212C44244394512C2B1438F5211020C081
|
||||||
|
:1009F000AA20F1F08A2D90E0912C883048F49201E1
|
||||||
|
:100A0000082E01C0220F0A94EAF7922A0196F5CF28
|
||||||
|
:100A100082E90E949703992D9095F80120819223F5
|
||||||
|
:100A20008921892B80832394FFEF6F1A7F0ADCCF03
|
||||||
|
:100A300082E90E949703F301F5CFC8018B0D911D48
|
||||||
|
:100A40005C0180E00E949703F501808361E0809162
|
||||||
|
:100A500004040E944F010E94860388E10E949E03C5
|
||||||
|
:100A60008770B82EC114D10411F0F601808382E0A2
|
||||||
|
:100A700033FC32C00115110509F447C0E114F1043B
|
||||||
|
:100A800009F443C0882009F440C0F7016081613057
|
||||||
|
:100A900029F4F4E0BF123BC08FEF1EC06230B8F102
|
||||||
|
:100AA000B11035C06250AE014F5F5F4FC8010E9468
|
||||||
|
:100AB0003304811111C0F7019081090F111DF80154
|
||||||
|
:100AC000329720819981291322C001501109F80120
|
||||||
|
:100AD00020819A8129131BC00F900F90DF91CF9135
|
||||||
|
:100AE0001F910F91FF90EF90DF90CF90BF90AF904C
|
||||||
|
:100AF0009F908F907F906F905F904F903F902F903E
|
||||||
|
:100B0000089581E0E9CF84E0E7CF80E0E5CF87E09A
|
||||||
|
:100B1000E3CF8F92AF92CF92DF92EF92FF920F933B
|
||||||
|
:100B20001F93CF93DF93CDB7DEB72C970FB6F89412
|
||||||
|
:100B3000DEBF0FBECDBF90E699838A83E2E0F1E08D
|
||||||
|
:100B4000DE01139681918D9381E0E830F807D1F7AB
|
||||||
|
:100B50008091F90389878091FA038A878091FB034A
|
||||||
|
:100B60008B878091FC038C87812CA12CD12CC12CEC
|
||||||
|
:100B7000F12CE12C10E000E02CE0AE014F5F5F4F64
|
||||||
|
:100B800060E18EE00E9471042C960FB6F894DEBFEF
|
||||||
|
:100B90000FBECDBFDF91CF911F910F91FF90EF90CE
|
||||||
|
:100BA000DF90CF90AF908F9008956F927F928F9249
|
||||||
|
:100BB000AF92CF92DF92EF92FF920F931F93CF935A
|
||||||
|
:100BC000DF9300D0CDB7DEB78A838B013A0160E8AE
|
||||||
|
:100BD0008CE10E94EC0387E08983812CA12CCE015B
|
||||||
|
:100BE00001966C01730121E0AE014E5F5F4F60E33F
|
||||||
|
:100BF0008CE00E947104811109C0F3018081823070
|
||||||
|
:100C0000A1F481E09981911101C080E00F900F90D3
|
||||||
|
:100C1000DF91CF911F910F91FF90EF90DF90CF90D8
|
||||||
|
:100C2000AF908F907F906F90089581E0EFCF2F92DB
|
||||||
|
:100C30003F924F925F926F927F928F929F92AF926C
|
||||||
|
:100C4000BF92CF92DF92EF92FF920F931F93CF93B9
|
||||||
|
:100C5000DF93CDB7DEB72B970FB6F894DEBF0FBE8C
|
||||||
|
:100C6000CDBF60E88CE10E94EC0344244394512CF6
|
||||||
|
:100C700083E9898333243394B12C912C992D977077
|
||||||
|
:100C80009B87892D8595859585958E5F282F229543
|
||||||
|
:100C9000207F290F2A8321E0911101C020E0222E1C
|
||||||
|
:100CA000280E66246394712C6C0E7D1E680E711CD8
|
||||||
|
:100CB00099E0981B9A8727C085E98983DECF87E969
|
||||||
|
:100CC000898346E0B42ED9CF40E74A838B819C814B
|
||||||
|
:100CD00089279D8189279E8189278F83AE01485F5F
|
||||||
|
:100CE0005F4F67E0CE0101960E943304182F8111F7
|
||||||
|
:100CF000ABC01B8653E05A8729E0222ECE0107960F
|
||||||
|
:100D00003C0130E2932EAB846A2D6295607F6A0DC0
|
||||||
|
:100D10008AE10E94BF03812CFE013B966F01AE0168
|
||||||
|
:100D2000465F5F4F7A018301222D4950510960E3EC
|
||||||
|
:100D30008CE00E947104182F8230A1F58CE10E9492
|
||||||
|
:100D40009E0385FD81C08F7109F480E2282F30E079
|
||||||
|
:100D5000492D990C550B421753070CF068C0982E7B
|
||||||
|
:100D60002150310927703327E82FE595E595E59562
|
||||||
|
:100D7000EF5F91E0211101C090E0E90F41E050E008
|
||||||
|
:100D80004C0F5D1F4E0F511DFA01A20102C0440F0E
|
||||||
|
:100D9000551F2A95E2F79081942B9083803209F0B9
|
||||||
|
:100DA0006DCF92CF811150C050E295128DCF8B81C3
|
||||||
|
:100DB000883809F03EC083E093E0EB2DF0E0E75087
|
||||||
|
:100DC000FC4F980FA1E0B0E0AC0FBD1FA80FB11D04
|
||||||
|
:100DD0002C9121938F5F8913F5CFBA8483E0B812E9
|
||||||
|
:100DE0004DC08B8581114AC0AE014D5F5F4F61E000
|
||||||
|
:100DF000C3010E943304182F811126C09B81F30187
|
||||||
|
:100E0000818198133DC09C818281981339C0808173
|
||||||
|
:100E100082FF12C03394F2E03F1609F44DCF43E055
|
||||||
|
:100E2000341609F44CCF51E0351609F421CF15E002
|
||||||
|
:100E30000BC082E094E0C1CF80930304832D880F20
|
||||||
|
:100E4000380E33943092F803812F2B960FB6F89416
|
||||||
|
:100E5000DEBF0FBECDBFDF91CF911F910F91FF90ED
|
||||||
|
:100E6000EF90DF90CF90BF90AF909F908F907F904A
|
||||||
|
:100E70006F905F904F903F902F90089511E0E4CFD6
|
||||||
|
:100E800017E0E2CF8F92AF92CF92DF92EF92FF9274
|
||||||
|
:100E90000F931F93CF93DF93CDB7DEB764970FB651
|
||||||
|
:100EA000F894DEBF0FBECDBF809106048F3F61F482
|
||||||
|
:100EB000909107049F3F41F4909108049F3F21F4D3
|
||||||
|
:100EC000909109049F3FF1F190911B049923D1F176
|
||||||
|
:100ED0009BE199838A83809107048B838091080426
|
||||||
|
:100EE0008C83809109048D83AE014A5F5F4F65E07A
|
||||||
|
:100EF000CE0101960E943304811115C01C8A85E041
|
||||||
|
:100F00008B8B812CA12CCE0144966C0101977C0126
|
||||||
|
:100F10008E010F5F1F4F27E0A80160E38CE00E9465
|
||||||
|
:100F20007104882379F0833069F482E08B8BAE0101
|
||||||
|
:100F30004D5E5F4FBE016F5F7F4F82E50E94D5051A
|
||||||
|
:100F40000E94170681E080931C0464960FB6F89403
|
||||||
|
:100F5000DEBF0FBECDBFDF91CF911F910F91FF90EC
|
||||||
|
:100F6000EF90DF90CF90AF908F9008958F92AF92D7
|
||||||
|
:100F7000CF92DF92EF92FF920F931F93CF93DF9365
|
||||||
|
:100F8000FA019081923128F17A01EB0190E3988384
|
||||||
|
:100F90008983AB014E5F5F4F62E0CE010E94330454
|
||||||
|
:100FA00081110CC088248394A12CD12CC12C8E01DA
|
||||||
|
:100FB00024E0AE0160E38CE00E947104DF91CF91E8
|
||||||
|
:100FC0001F910F91FF90EF90DF90CF90AF908F9097
|
||||||
|
:100FD000089584E0F3CFEF92FF920F931F93CF9386
|
||||||
|
:100FE000FA019081923110F490E00DC08A017B01EA
|
||||||
|
:100FF000C82F843078F4A801B7018C2F0E94B6075F
|
||||||
|
:1010000091E08111F1CF892FCF911F910F91FF9026
|
||||||
|
:10101000EF90089580911C048111EDCF0E9442074A
|
||||||
|
:101020008111E9CFE1CFCF93DF93FC01208130E044
|
||||||
|
:10103000322F22278181280F311D62307105B9F1CD
|
||||||
|
:101040003296DB01B695A79561707727109779F1F5
|
||||||
|
:10105000A130B105E9F04081842F90E0982F8827D6
|
||||||
|
:101060004181480F592F511D329680E1E901220F2D
|
||||||
|
:10107000331FD7FF17C057FF02C02F5F3F4F95E0C8
|
||||||
|
:1010800029273058440F551F815081F71197DECF23
|
||||||
|
:1010900050E040E06115710541F3408150E0542F6C
|
||||||
|
:1010A0004427E3CF57FFEECF2F5F3F4FEBCFC90170
|
||||||
|
:1010B000DF91CF910895CF938091D003882319F1C8
|
||||||
|
:1010C0008091CE02813621F48091CD030E94AF0041
|
||||||
|
:1010D000E091CC0381E08E0F8093CC03F0E0E553E8
|
||||||
|
:1010E000FD4F83E08283C0E08091CC03C81770F588
|
||||||
|
:1010F000EC2FF0E0E553FD4F62818CE292E00E941C
|
||||||
|
:10110000C802CF5FF1CFC091CC036DEF6C0F60933D
|
||||||
|
:10111000CF0270E06E5F7F4F8EEC92E00E9413086A
|
||||||
|
:101120008093CB029093CC02EC2FF0E0E553FD4F7F
|
||||||
|
:101130009283E1E0EC0FF0E0E553FD4F828383E022
|
||||||
|
:101140008C0F8093CC03CE5FEC2FC8CFCF91089546
|
||||||
|
:10115000AF92BF92CF92DF92EF92FF920F931F93C5
|
||||||
|
:10116000CF935C014115510561057105B9F1E4E8C2
|
||||||
|
:10117000F3E08F012003C001219F900D1124092E5F
|
||||||
|
:10118000000CAA0BBB0B6C017D01C40ED51EE61E24
|
||||||
|
:10119000F71EC701B60120E831E541E050E00E94AA
|
||||||
|
:1011A000A31B6B017C01CA01B9016C5F7F4F8F4F9C
|
||||||
|
:1011B0009F4F27E030E040E050E00E94A31BC62F85
|
||||||
|
:1011C000CC0FC701B60120EC38EA40E050E00E94A5
|
||||||
|
:1011D000A31BC22BF501C08372836383CF911F9140
|
||||||
|
:1011E0000F91FF90EF90DF90CF90BF90AF90089558
|
||||||
|
:1011F000CF93DF93C0910702D09108022097E1F0CE
|
||||||
|
:101200008091CF03882351F086E40E94D8008FE4B8
|
||||||
|
:101210000E94AF00DF91CF910C945B0887EE0E9493
|
||||||
|
:10122000D80080E00E94AF0080E00E94AF0088817B
|
||||||
|
:101230000E94AF008981ECCFDF91CF910895CF92CA
|
||||||
|
:10124000DF92EF92FF920F931F938A019B01FC01A3
|
||||||
|
:10125000AC014C5F5F4F60E070E0CB01982F872FAF
|
||||||
|
:10126000762F6627A1916A2B4E175F07B9F799274A
|
||||||
|
:1012700068017901CC24DD24EE246C297D298E2996
|
||||||
|
:101280009F29601771078207930708F493951F91B0
|
||||||
|
:101290000F91FF90EF90DF90CF900895CF93DF9361
|
||||||
|
:1012A000E1EDF3E093E091A312A2A4EDB3E09EE19F
|
||||||
|
:1012B000ED0119929A95E9F7908191838283DF91EC
|
||||||
|
:1012C000CF91089580E70E944E0980911B040E94EF
|
||||||
|
:1012D0004F030C9415038F92AF92CF92DF92EF924F
|
||||||
|
:1012E000FF920F931F93CF93DF93CDB7DEB7649731
|
||||||
|
:1012F0000FB6F894DEBF0FBECDBF162FE62EF12C31
|
||||||
|
:10130000A701BC01CE0101960E94EC1B41E050E018
|
||||||
|
:101310004C0F5D1F4E0D5F1D612FCE0101960E9487
|
||||||
|
:101320003304811122C082E18C8B1B8A22E0210FC1
|
||||||
|
:10133000812CA12CCE0143966C0101967C018E017B
|
||||||
|
:101340000F5F1F4FA80160E38CE00E9471048111C0
|
||||||
|
:101350000CC08C898130D1F48B898430B9F481E060
|
||||||
|
:1013600099819A3009F480E0819564960FB6F894DB
|
||||||
|
:10137000DEBF0FBECDBFDF91CF911F910F91FF90C8
|
||||||
|
:10138000EF90DF90CF90AF908F90089581E0EDCFF8
|
||||||
|
:10139000FF920F931F93CF93DF9300D000D000D024
|
||||||
|
:1013A000CDB7DEB7823010F480E01CC08B01F82E80
|
||||||
|
:1013B00080911C04882311F101151105A9F382EA1B
|
||||||
|
:1013C0008983FA8284E0F801DE01139601900D9280
|
||||||
|
:1013D0008A95E1F766E0CE0101960E946B098111C2
|
||||||
|
:1013E000E3CF81E026960FB6F894DEBF0FBECDBFE7
|
||||||
|
:1013F000DF91CF911F910F91FF9008950E944207B6
|
||||||
|
:101400008111DACFD1CFEF92FF921F93CF93DF9369
|
||||||
|
:10141000CDB7DEB762970FB6F894DEBF0FBECDBF73
|
||||||
|
:10142000182F9E012F5F3F4F790180E1F901119242
|
||||||
|
:101430008A95E9F750E0C9010E94EC1B80911B04DA
|
||||||
|
:101440008350833098F5133010F480E023C0212FAF
|
||||||
|
:101450002350330BC90163E070E00E948F1B1350CF
|
||||||
|
:10146000160F812F80958370810F0E94890581114D
|
||||||
|
:10147000ECCF80EA898B1A8B62E0CE0141960E9404
|
||||||
|
:101480006B098111E2CF60E1C7010E946B098111F4
|
||||||
|
:10149000DCCF81E062960FB6F894DEBF0FBECDBF01
|
||||||
|
:1014A000DF91CF911F91FF90EF90089540E1B70138
|
||||||
|
:1014B000812F0E94C809EECF9F92AF92BF92CF9228
|
||||||
|
:1014C000DF92EF92FF920F931F93CF93DF93A82E9B
|
||||||
|
:1014D0007B018A016A01D694C794D694C794B82E2A
|
||||||
|
:1014E000CB2DCA19D0E0CC15DD0518F599249394BD
|
||||||
|
:1014F0009B0C0E94A3008B1568F480E0DF91CF91D4
|
||||||
|
:101500001F910F91FF90EF90DF90CF90BF90AF9021
|
||||||
|
:101510009F900895BE01660F771F660F771F6E0DAF
|
||||||
|
:101520007F1D44E08B2D0E94030A882331F3B92CE0
|
||||||
|
:10153000D7CFC02FC37081E009F30E94A3008B15A1
|
||||||
|
:10154000E0F20C1B1109B701600F711F4C2F8B2D9E
|
||||||
|
:10155000DF91CF911F910F91FF90EF90DF90CF908F
|
||||||
|
:10156000BF90AF909F900C94030AEF92FF920F935D
|
||||||
|
:101570001F93CF93DF93CDB7DEB728970FB6F894BC
|
||||||
|
:10158000DEBF0FBECDBF90911B049923E1F17A011C
|
||||||
|
:101590008B01BE016F5F7F4F98E0FB0111929A951E
|
||||||
|
:1015A000E9F79FEF9B839BE09C838A838091FC01FA
|
||||||
|
:1015B0008D838091FD018E838091FE018F8348E0B1
|
||||||
|
:1015C00050E084E00E945C0A81110EC082E02896FF
|
||||||
|
:1015D0000FB6F894DEBF0FBECDBFDF91CF911F9144
|
||||||
|
:1015E0000F91FF90EF9008950115110551F0E1144E
|
||||||
|
:1015F000F10439F0A701B80186E00E945C0A882353
|
||||||
|
:1016000029F380E0E4CF85E0E2CFEF92FF921F93D1
|
||||||
|
:10161000CF93DF93CDB7DEB763970FB6F894DEBFF5
|
||||||
|
:101620000FBECDBF182F7B010E94A300811748F089
|
||||||
|
:1016300082E18B8B80911B0483508330B0F5133093
|
||||||
|
:1016400010F480E026C0212F2350330BC90163E042
|
||||||
|
:1016500070E00E948F1B1350160F812F80958370AE
|
||||||
|
:10166000810F0E9489058111ECCFAE014D5E5F4F65
|
||||||
|
:10167000BE016F5F7F4F812F0E94B6078111E1CFBE
|
||||||
|
:1016800084E0FE013196D70101900D928A95E1F731
|
||||||
|
:1016900081E063960FB6F894DEBF0FBECDBFDF9139
|
||||||
|
:1016A000CF911F91FF90EF900895AE014D5E5F4F77
|
||||||
|
:1016B000BE016F5F7F4F812F0E94EB078111E0CF4A
|
||||||
|
:1016C000C0CF1F93CF93DF93CDB7DEB728970FB668
|
||||||
|
:1016D000F894DEBF0FBECDBF182FBE016B5F7F4FEA
|
||||||
|
:1016E0000E94050B8823B9F0FE0135969E01275F05
|
||||||
|
:1016F0003F4F91919923D9F019821A821B821C8243
|
||||||
|
:101700000E94A300811788F044E0BE016F5F7F4F05
|
||||||
|
:10171000812F0E94030A28960FB6F894DEBF0FBEF1
|
||||||
|
:10172000CDBFDF91CF911F91089580E0F4CFE217F4
|
||||||
|
:10173000F307F9F6F0CF8F929F92AF92BF92DF92AC
|
||||||
|
:10174000EF92FF920F931F93CF93DF93CDB7DEB746
|
||||||
|
:10175000EA970FB6F894DEBF0FBECDBF2091070207
|
||||||
|
:1017600030910802232B09F4EDC190911B049923B9
|
||||||
|
:1017700009F4E8C1182F8091CF03882309F455C0DC
|
||||||
|
:1017800081E60E94D800812F0E94AF00111133C161
|
||||||
|
:10179000109200028091080190910901A0910A0124
|
||||||
|
:1017A000B0910B018FAB98AFA9AFBAAF8BAB9CAB2D
|
||||||
|
:1017B000ADABBEAB8FA798ABA9ABBAAB8090030221
|
||||||
|
:1017C00090900402A0900502B090060220910A02B7
|
||||||
|
:1017D000B501A401CE01C7960E94A80818AE0E94C8
|
||||||
|
:1017E000A300DD24D394D80E19821A821B821C8296
|
||||||
|
:1017F00080E018E008E00D15F0F4802F8D0D99279A
|
||||||
|
:10180000991F7C01F594E7941E2DBE016F5F7F4FF9
|
||||||
|
:101810008E2D0E94050B882309F494C189818823A9
|
||||||
|
:1018200031F00E1106C00F5FE6CF81EEAACFDE2C9D
|
||||||
|
:10183000E2CF0E2DE0CF81111F5F812F123108F40E
|
||||||
|
:1018400082E126EFF22EF80E0FEF010F0F1508F4CC
|
||||||
|
:101850007BC1BE016F5F7F4F802F0E94050B8823E5
|
||||||
|
:1018600009F470C18981853F79F4B501A401CE01E5
|
||||||
|
:1018700001960E941F09AB01BC014115510561058C
|
||||||
|
:10188000710521F4102F62C10150E0CF20910A02AE
|
||||||
|
:10189000CE018F960E94A80818AAF4CF1F5F1231BC
|
||||||
|
:1018A00009F058C171C10091000220910A02CE01D5
|
||||||
|
:1018B000C3960E94A8081CAA17501093FF01011B91
|
||||||
|
:1018C000009300021BA61CA61DA61EA685E5E82EF9
|
||||||
|
:1018D000E9A69AEAF92EFAA6E0910702F091080229
|
||||||
|
:1018E00000810DA711811EA766E070E0CE018996E8
|
||||||
|
:1018F0000E9413081A8A198A21E029832A832B83DC
|
||||||
|
:101900002C832DEE2D832E832F832887E986FA865C
|
||||||
|
:101910001B861C860D871E879F87888B80910002FF
|
||||||
|
:101920008B8B8F5F8C8B8FA58D8B88A98E8B89A9D4
|
||||||
|
:101930008F8B8AA9888F8BA9898F8CA98A8F8DA973
|
||||||
|
:101940008B8F8EA98C8F8EEE8D8F8E8F8F8F88A32D
|
||||||
|
:101950009FA999A398AD9AA399AD9BA39AAD9CA377
|
||||||
|
:101960008DA38EA38FA388A768E2CE0101960E9463
|
||||||
|
:1019700012018FEF0E94AF008FEF0E94AF008FEF38
|
||||||
|
:101980000E94AF008FEF0E94AF0048E250E060E29B
|
||||||
|
:1019900070E0CE0101960E94F51B64E0CE01019635
|
||||||
|
:1019A0000E94120164E1CE0101960E94120164E1DD
|
||||||
|
:1019B000CE0101960E94120164E0CE0101960E94C0
|
||||||
|
:1019C000120164E2CE0101960E9412010E945B089E
|
||||||
|
:1019D00081E0EA960FB6F894DEBF0FBECDBFDF916F
|
||||||
|
:1019E000CF911F910F91FF90EF90DF90BF90AF903C
|
||||||
|
:1019F0009F908F9008951130E9F544E250E060E245
|
||||||
|
:101A000070E0CE0101960E94F51B60E1CE010196C7
|
||||||
|
:101A10000E94120160E1CE0101960E94120164E26F
|
||||||
|
:101A2000CE0101960E94120164E1CE0101960E944E
|
||||||
|
:101A3000120160E1CE0101960E94120168E0CE0120
|
||||||
|
:101A400001960E94120164E0CE0101960E941201EB
|
||||||
|
:101A500068E0CE0101960E9412018FEF0E94AF0054
|
||||||
|
:101A60008FEF0E94AF008FEF0E94AF008FEF0E94B8
|
||||||
|
:101A7000AF00ACCF0E94A300082F88E0ECE0F1E0BB
|
||||||
|
:101A8000DE01119601900D928A95E1F7E1E0F0E018
|
||||||
|
:101A9000EC0FFD1FE10FF11D10811A5F1295110F60
|
||||||
|
:101AA000107E8091FF01885F180FE12EF12C9FE1DD
|
||||||
|
:101AB000E90EF11C8090080190900901A0900A01A4
|
||||||
|
:101AC000B0900B011E151F0411F00CF07FCF89A6FA
|
||||||
|
:101AD0009AA6ABA6BCA6011778F0BE01615D7F4F48
|
||||||
|
:101AE000812F0E94050B882309F473CF8FA5803FB7
|
||||||
|
:101AF00011F0853F79F41AA689A50E94AF008AA546
|
||||||
|
:101B00000E94AF008BA50E94AF008CA50E94AF0081
|
||||||
|
:101B10001F5FD8CF882381F38AA740910302509199
|
||||||
|
:101B200004026091050270910602CE018F960E9418
|
||||||
|
:101B30001F09AB01BC0120910A02CE0189960E94C7
|
||||||
|
:101B4000A808DACF80E045CF112319F01850109380
|
||||||
|
:101B5000000218E0BE016F5F7F4F812F0E94050BCE
|
||||||
|
:101B6000882381F38981803F09F098CEB501A401D3
|
||||||
|
:101B7000CE0101960E941F09AB01BC014115510520
|
||||||
|
:101B80006105710509F08FCE1092FF019BCE8F92F7
|
||||||
|
:101B9000AF92CF92DF92EF92FF920F931F93CF936A
|
||||||
|
:101BA000DF9300D000D0CDB7DEB780911B0488232F
|
||||||
|
:101BB00049F08CE0E8EFF3E0ACE0B4E001900D9286
|
||||||
|
:101BC0008A95E1F780E589831A82AE014D5F5F4F08
|
||||||
|
:101BD00062E0CE0101960E943304811110C0812C75
|
||||||
|
:101BE000A12CD12CC12CF12CE12C10E000E024E040
|
||||||
|
:101BF000AE014F5F5F4F60E38CE00E94710468E0CC
|
||||||
|
:101C000080E10E94EC039FB7F8948091180288232A
|
||||||
|
:101C100019F081508093180280911802811105C03B
|
||||||
|
:101C20008CB58F7B8CBD10922B029FBF60E08091A2
|
||||||
|
:101C300019040E944F010F900F900F900F90DF91A9
|
||||||
|
:101C4000CF911F910F91FF90EF90DF90CF90AF90C9
|
||||||
|
:101C50008F9008952F923F924F925F926F927F9252
|
||||||
|
:101C60008F929F92AF92BF92CF92DF92EF92FF92AC
|
||||||
|
:101C70000F931F93CF93DF9300D000D000D0CDB748
|
||||||
|
:101C8000DEB769835E834D83452B49F49E838D8344
|
||||||
|
:101C9000893C910520F028EC30E03E832D832C0117
|
||||||
|
:101CA000712C612C9C01A0E4BFE10E94741B28EE02
|
||||||
|
:101CB00033E040E050E00E94A31B49015A0110E0CC
|
||||||
|
:101CC00000E032EB232E30E0332E89818150990BD6
|
||||||
|
:101CD0009B838A83ED81FE816F01F12CE12CA89515
|
||||||
|
:101CE00061E084E00E944F0180910101833041F561
|
||||||
|
:101CF000E6E8F0E0F491FC83F7FDC6C083E00E94C3
|
||||||
|
:101D0000F300FC81FF2309F48EC02C81223009F0FE
|
||||||
|
:101D10009EC08091B100887F82608093B1008CE783
|
||||||
|
:101D20008093B30080921E0290921F02A092200224
|
||||||
|
:101D3000B092210280917000826080937000A4C0F4
|
||||||
|
:101D40008F3F09F0A1C083E080930101E6E8F0E055
|
||||||
|
:101D5000F491FC83FF3F09F497C0F13021F150F07A
|
||||||
|
:101D6000F23009F43EC02C8127FD8EC083E00E9432
|
||||||
|
:101D7000F300CBCF14BC15BC84B5826084BD85B59F
|
||||||
|
:101D8000816085BDEEE9F0E08491E82FF0E0EE0F90
|
||||||
|
:101D9000FF1FE957FF4F85919491F1018491809342
|
||||||
|
:101DA0001D021C82ABCF10928000109281008091A6
|
||||||
|
:101DB00081008860809381008091810081608093A0
|
||||||
|
:101DC0008100EEE9F0E08491E82FF0E0EE0FFF1FD4
|
||||||
|
:101DD000E957FF4F85919491F101849180931C0202
|
||||||
|
:101DE0008DCF1092B0001092B1008091B00082604F
|
||||||
|
:101DF0008093B0008091B10081608093B100EEE9E2
|
||||||
|
:101E0000F0E08491E82FF0E0EE0FFF1FE957FF4F5D
|
||||||
|
:101E10008591949190931B0280931A02F101849111
|
||||||
|
:101E2000809319026BCF85B5887F826085BD8CE772
|
||||||
|
:101E300087BD8092260290922702A0922802B0923B
|
||||||
|
:101E4000290280916E00826080936E001DC03C81EB
|
||||||
|
:101E5000313009F051C080918100887F816080938A
|
||||||
|
:101E6000810087EE93E090938900809388008092B0
|
||||||
|
:101E7000220290922302A0922402B0922502809125
|
||||||
|
:101E80006F00826080936F00C301B2010E94A201C3
|
||||||
|
:101E9000A89560E084E00E944F0160E083E00E942A
|
||||||
|
:101EA0004F01EA81FB810E171F072CF4C701B60111
|
||||||
|
:101EB0000E94A201A8950F5F1F4FF9810F1708F428
|
||||||
|
:101EC0000ECF26960FB6F894DEBF0FBECDBFDF91C2
|
||||||
|
:101ED000CF911F910F91FF90EF90DF90CF90BF9027
|
||||||
|
:101EE000AF909F908F907F906F905F904F903F90BA
|
||||||
|
:101EF0002F90089587EE14CF3C813230D9F3311101
|
||||||
|
:101F0000C3CF87EE95CF50E040E00C942A0ECF93DC
|
||||||
|
:101F1000C82F88E70E944E098C2F0E944F038091A2
|
||||||
|
:101F20001B040E944F030E94150363E084E690E0C7
|
||||||
|
:101F3000CF910C94830F61E084EF91E00C94830FB8
|
||||||
|
:101F4000CF92DF92EF92FF920F931F93CF93DF9385
|
||||||
|
:101F500000D000D0CDB7DEB77C01162F19821A82CF
|
||||||
|
:101F60001B821C8280911B04882309F44BC00E94B1
|
||||||
|
:101F7000A300082F123098F1F7011081818181119F
|
||||||
|
:101F800001C081E0412F480F5527551F0417150642
|
||||||
|
:101F90001CF00FEF010F080F85E60E944E0983E049
|
||||||
|
:101FA0006E0155E0C50ED11C0117D8F0BE016F5F60
|
||||||
|
:101FB0007F4F812F0E94050B882331F1812F0E94D2
|
||||||
|
:101FC0004F03CE0101967C01F70181917F010E94B0
|
||||||
|
:101FD0004F03CE14DF04C1F71F5F80E0E5CF14E0AC
|
||||||
|
:101FE000DBCF882399F00E94870F0F900F900F90FE
|
||||||
|
:101FF0000F90DF91CF911F910F91FF90EF90DF90A5
|
||||||
|
:10200000CF90089585E0EFCF83E0EDCF0E941503D8
|
||||||
|
:102010000E949B0FEACF8F929F92AF92BF92CF9276
|
||||||
|
:10202000DF92EF92FF920F931F93CF93DF9300D035
|
||||||
|
:1020300000D0CDB7DEB780911B04882371F01982E0
|
||||||
|
:102040001A821B821C82BE016F5F7F4F84E00E9458
|
||||||
|
:10205000050B811116C083E001C085E00E94870F47
|
||||||
|
:102060000F900F900F900F90DF91CF911F910F91D4
|
||||||
|
:10207000FF90EF90DF90CF90BF90AF909F908F90A8
|
||||||
|
:10208000089581E60E944E0989810E944F030E94B3
|
||||||
|
:10209000A300082F8C81813009F081C08FEF0E944E
|
||||||
|
:1020A0004F0316E0812C912C5401F12CE12C0117E7
|
||||||
|
:1020B00008F4B1C0BE016F5F7F4F812F0E94050BF6
|
||||||
|
:1020C000882349F28A81298130E0522F4427E11484
|
||||||
|
:1020D000F104D9F4982F907F7A01E92A90E0B0E0DA
|
||||||
|
:1020E000A0E0DC019927882788279927AF70BB27B4
|
||||||
|
:1020F0008B809C80982489249824B12CA12C882A38
|
||||||
|
:10210000992AAA2ABB2A1F5FD2CF482B64E0569592
|
||||||
|
:1021100047956A95E1F7452BB1F3C90134E09595F0
|
||||||
|
:1021200087953A95E1F70E944F03298180E1289F26
|
||||||
|
:10213000900111248A8182958F70822B0E944F0317
|
||||||
|
:102140008A8190E0B0E0A0E0DC0199278827882709
|
||||||
|
:102150009927AF70BB272B813C8132272327322759
|
||||||
|
:10216000A90170E060E0842B952BA62BB72B6701AB
|
||||||
|
:1021700088159905AA05BB0518F480E1C80ED11C85
|
||||||
|
:102180008D2D0E944F038A818F708C290E944F03EE
|
||||||
|
:102190008B810E944F038C810E944F03B4CF8A3001
|
||||||
|
:1021A000D0F18FEF0E944F0316E0F12CE12C0117C4
|
||||||
|
:1021B00090F1BE016F5F7F4F812F0E94050B882336
|
||||||
|
:1021C00009F449CF8981811114C09A81911111C0FC
|
||||||
|
:1021D0008B8190E0B0E0A0E0BA2FA92F982F88273C
|
||||||
|
:1021E0002C81822B9C01232B11F0F82EE92E1F5FEE
|
||||||
|
:1021F000DECF0E944F038A810E944F038E2D0E94E2
|
||||||
|
:102200004F038F2D0E944F038B810E944F038C81BF
|
||||||
|
:102210000E944F03ECCF0E9415030E949B0F20CF1A
|
||||||
|
:10222000CF93C82F89E70E944E0980911B040E941A
|
||||||
|
:102230004F030E941503CC2319F0CF910C949B0FF0
|
||||||
|
:10224000CF910895CF93DF93CDB7DEB728970FB620
|
||||||
|
:10225000F894DEBF0FBECDBFFC0187E06630F0F022
|
||||||
|
:102260009E012D5F3F4F86E0D9011D928A95E9F7C7
|
||||||
|
:102270008181898380818A8382818B8383818D831D
|
||||||
|
:1022800084818E8385818F8348E050E0BE016F5F3B
|
||||||
|
:102290007F4F8CEF0E94B50A882359F00E94870F68
|
||||||
|
:1022A00028960FB6F894DEBF0FBECDBFDF91CF9159
|
||||||
|
:1022B000089581E00E941011F3CF50E040E070E0FB
|
||||||
|
:1022C00060E089EF0E94B50A81110C94870F81E0CC
|
||||||
|
:1022D0000C94101150E040E070E060E08DEF0E943F
|
||||||
|
:1022E000B50A81110C94870F81E00C9410116830AD
|
||||||
|
:1022F00018F487E00C94870F20911B04222351F0DF
|
||||||
|
:10230000BC0148E050E086E00E945C0A811104C0F4
|
||||||
|
:1023100082E0F0CF85E0EECF81E00C9410117F9247
|
||||||
|
:102320008F929F92AF92BF92CF92DF92EF92FF92E5
|
||||||
|
:102330000F931F93CF93DF93CDB7DEB76A970FB696
|
||||||
|
:10234000F894DEBF0FBECDBF8C0187E06E3008F47D
|
||||||
|
:1023500049C080911B04882309F443C089506E3022
|
||||||
|
:1023600009F056C0833008F45FC061E084E00E9449
|
||||||
|
:102370004F010E94A300E82E2DEFF22EF80ED12C73
|
||||||
|
:102380003AE0932E45E0842E52E1752EF5E0FF15DC
|
||||||
|
:1023900008F0E7C08D2D692D0E94831B61E0992311
|
||||||
|
:1023A00039F08D2D682D0E94831B911104C060E0CF
|
||||||
|
:1023B00084E00E944F01D39490911B04992349F02B
|
||||||
|
:1023C000933038F0963008F48AC09950933008F46E
|
||||||
|
:1023D00096C082E00E94870F60E084E00E944F0177
|
||||||
|
:1023E00003C085E00E94870F6A960FB6F894DEBF9F
|
||||||
|
:1023F0000FBECDBFDF91CF911F910F91FF90EF9056
|
||||||
|
:10240000DF90CF90BF90AF909F908F907F90089576
|
||||||
|
:10241000F801E684833008F0A8CF0E94A300F82ECC
|
||||||
|
:1024200084E08F0DE0FC2AC00E94A300F82E80916A
|
||||||
|
:10243000140190911501A0911601B09117018B8B99
|
||||||
|
:102440009C8BAD8BBE8B44E0BE016D5E7F4F84E004
|
||||||
|
:102450008F0D0E94C809882379F019821A821B8285
|
||||||
|
:102460008FEF8C8344E0BE016F5F7F4F82E08F0D62
|
||||||
|
:102470000E94C809811179CF82E0B4CF44E066E0C0
|
||||||
|
:1024800074E00E94C8098823B9F31A8E198E8091CE
|
||||||
|
:102490000A048F8B80910B04888F44E0BE01695E33
|
||||||
|
:1024A0007F4F85E08F0D0E94C809882329F380E8BB
|
||||||
|
:1024B000E1FE80E01B8A1C8A1D8A1E8A8B8B44E009
|
||||||
|
:1024C000BE016D5E7F4F83E08F0D0E94C809882397
|
||||||
|
:1024D00099F219821A821B821C8284E0C2CF93E097
|
||||||
|
:1024E000C92E8C2D8F0D0E94610B882309F471CFAA
|
||||||
|
:1024F000CA942FEFC212F5CFFCEFFF0E47CF7F8AB1
|
||||||
|
:10250000AE01495E5F4FBE016F5F7F4F8F2D0E940E
|
||||||
|
:10251000EB07882309F45DCF5E013DE0A30EB11CFB
|
||||||
|
:1025200083E0C82EF50184E091919923B9F01B8ACC
|
||||||
|
:102530001C8A1D8A1E8A44E0BE016D5E7F4F8F2D6E
|
||||||
|
:102540008C0D0E94C809882309F443CFCA9484E003
|
||||||
|
:10255000A81AB108EFEFCE12E5CFCECF815021F708
|
||||||
|
:10256000F5CF2E2D2550330BC90164E070E00E9499
|
||||||
|
:102570008F1BF82EFF2049F085E08F0D0E94610B24
|
||||||
|
:10258000882309F426CFFA94F5CF60E084E00E9416
|
||||||
|
:102590004F011C821B828BE08C83F8018081898330
|
||||||
|
:1025A00081818A8382818D8383818E8384818F83DD
|
||||||
|
:1025B000858188878681898787818A8780858B87BF
|
||||||
|
:1025C00081858C8782858D8783858E8784858F879B
|
||||||
|
:1025D0008585888B40E150E0BE016F5F7F4F84E0CE
|
||||||
|
:1025E0000E945C0A882309F447CF81E00E94101101
|
||||||
|
:1025F000FBCE643018F487E00C94870F462FBC01A3
|
||||||
|
:1026000050E088EF0E94B50A8111F6CF81E00C946A
|
||||||
|
:102610001011633018F487E00C94870F462FBC012B
|
||||||
|
:1026200050E08FEF0E94B50A8111F6CF81E00C9443
|
||||||
|
:102630001011663018F487E00C94870F462FBC0108
|
||||||
|
:1026400050E08EEF0E94B50A8111F6CF81E00C9424
|
||||||
|
:102650001011CF93DF9300D000D0CDB7DEB761115A
|
||||||
|
:102660000AC087E00E94870F0F900F900F900F9085
|
||||||
|
:10267000DF91CF91089519821A821B821C82FC017E
|
||||||
|
:102680008081898344E050E0BE016F5F7F4F8BEF14
|
||||||
|
:102690000E94B50A8111E6CF81E00E941011E4CFBB
|
||||||
|
:1026A000CF93DF93CDB7DEB728970FB6F894DEBF90
|
||||||
|
:1026B0000FBECDBFFC0187E06630F0F09E012D5FBC
|
||||||
|
:1026C0003F4F86E0D9011D928A95E9F78181898380
|
||||||
|
:1026D00080818A8382818B8383818D8384818E83B1
|
||||||
|
:1026E00085818F8348E050E0BE016F5F7F4F8AEFA6
|
||||||
|
:1026F0000E94B50A882359F00E94870F28960FB6CA
|
||||||
|
:10270000F894DEBF0FBECDBFDF91CF91089580E07A
|
||||||
|
:102710000E94101144EF51E063E084EF91E00E94C9
|
||||||
|
:102720002A0E64EF71E080E090E00E94A20161E077
|
||||||
|
:1027300088EE93E00E94830FE1CF0F931F93CF9316
|
||||||
|
:10274000DF93CDB7DEB763970FB6F894DEBF0FBE49
|
||||||
|
:10275000CDBF811180931A0410921B0410921C04A7
|
||||||
|
:102760001FB7F89480911802811124C0E5EAF0E0C7
|
||||||
|
:102770008491E9EBF0E09491E82FF0E0EE0FFF1F79
|
||||||
|
:10278000EF56FF4FA591B491EC91E92321F461E05C
|
||||||
|
:102790008AE00E944F018AE00E94F3008CB58061BC
|
||||||
|
:1027A0008CBD8CB580648CBD8DE00E94F3008BE005
|
||||||
|
:1027B0000E94F300809118028F5F809318021FBF60
|
||||||
|
:1027C0009091190480911804809304049093050457
|
||||||
|
:1027D0000E94F30061E0809104040E944F01809107
|
||||||
|
:1027E00005040E94F3002091050430E0F901EE5841
|
||||||
|
:1027F000FF4F8491F901E155FF4F0491F901E5562E
|
||||||
|
:10280000FF4F14911123F1F081110E942601E12F55
|
||||||
|
:10281000F0E0EE0FFF1FE859FF4FA591B491EC9146
|
||||||
|
:102820000E2381F06FE082E00E94BF0365E070E05C
|
||||||
|
:1028300080E090E00E94A20182E00E949E0384FD5D
|
||||||
|
:10284000FBCF0BC061E0809105040E944F0165E061
|
||||||
|
:1028500070E080E090E00E94A20160E884E50E94C0
|
||||||
|
:10286000BF0366E486E50E94BF0363E088E50E943B
|
||||||
|
:10287000BF0368EE8AE50E94BF0360E48AE20E941B
|
||||||
|
:10288000BF036DE382E20E94BF030E94FA0363E08C
|
||||||
|
:1028900088E20E94EC0310911A041295107F8CE4D8
|
||||||
|
:1028A0000E949E038077181749F060E78CE40E942D
|
||||||
|
:1028B000EC03612F60778CE40E94DF030E94FA032F
|
||||||
|
:1028C00065E070E080E090E00E94A20182E08B8BE6
|
||||||
|
:1028D000AE014D5E5F4FBE016F5F7F4F86E20E948B
|
||||||
|
:1028E000D5058D7F21F40E941706882391F0ECE036
|
||||||
|
:1028F000F4E08CE0DF011D928A95E9F763960FB64C
|
||||||
|
:10290000F894DEBF0FBECDBFDF91CF911F910F9125
|
||||||
|
:102910000895E0910304EF77E13448F4F0E0E056E5
|
||||||
|
:10292000FE4F80818430F9F028F48330E1F010927A
|
||||||
|
:102930001B04E4CF8530B9F08630C9F782E18B8B78
|
||||||
|
:10294000AE014D5E5F4FBE016F5F7F4F83E00E941F
|
||||||
|
:10295000B6078111ECCF8B818E3341F08D3641F07B
|
||||||
|
:10296000823129F789E080931B04C8CF8AE0FBCF2E
|
||||||
|
:102970008BE0F9CFFF920F931F93CF93DF93EC017E
|
||||||
|
:102980008B01F42E80E00E949D136F2DC801FE0183
|
||||||
|
:102990000995DF91CF911F910F91FF900C94C70D76
|
||||||
|
:1029A0000F931F93CF93DF938C010E945E1BC82F60
|
||||||
|
:1029B000C80101960E945E1BD82FC80102960E9492
|
||||||
|
:1029C0005E1BCD1749F0C81711F0D81380E0DF91D6
|
||||||
|
:1029D000CF911F910F9108958C2FF9CF8F929F92D5
|
||||||
|
:1029E000AF92BF92CF92DF92EF92FF920F931F931D
|
||||||
|
:1029F000CF93DF9300D000D0CDB7DEB780911B041A
|
||||||
|
:102A0000882379F019821A821B821C82BE016F5FB3
|
||||||
|
:102A10007F4F84E00E94050B811114C083E00E9467
|
||||||
|
:102A2000870F0F900F900F900F90DF91CF911F9114
|
||||||
|
:102A30000F91FF90EF90DF90CF90BF90AF909F905D
|
||||||
|
:102A40008F9008958B818F3F61F344E050E06CE9F3
|
||||||
|
:102A500071E0CE0101960E94DF1B892B51F044E00A
|
||||||
|
:102A600050E068E971E0CE0101960E94DF1B892BDE
|
||||||
|
:102A700011F419821A8283E60E944E0989810E940C
|
||||||
|
:102A80004F038A810E944F03BE016F5F7F4F85E035
|
||||||
|
:102A90000E94050B882311F20981CA80DB801C810A
|
||||||
|
:102AA000BE016F5F7F4F86E00E94050B882309F40B
|
||||||
|
:102AB000B5CFCE0101965C014E0195E0890E911CC7
|
||||||
|
:102AC0007501F70181917F010E944F03E814F90419
|
||||||
|
:102AD000C1F7BE016F5F7F4F87E00E94050B88231F
|
||||||
|
:102AE00009F49CCFF50181915F010E944F03AE1460
|
||||||
|
:102AF000BF04C1F70E94A300B82EDC24CD24DC243F
|
||||||
|
:102B0000F12CE12CFE2CED2CDC2CCC24C12A18E07D
|
||||||
|
:102B1000AA24A394A00EB116C8F1BE016F5F7F4F27
|
||||||
|
:102B2000812F0E94050B882309F478CF89818111B8
|
||||||
|
:102B300009C09A81911106C09B81911103C09C81AB
|
||||||
|
:102B4000992321F10E944F038A819B81982789272D
|
||||||
|
:102B50009827B0E0A0E0BA2FA92F982F88272C81C2
|
||||||
|
:102B6000822B8C159D05AE05BF0570F48A2D0E9441
|
||||||
|
:102B70004F038A810E944F038B810E944F038C81F7
|
||||||
|
:102B80000E944F031F5FC7CF802FF1CF0E94150314
|
||||||
|
:102B900048CFCF92DF92EF92FF920F931F93CF9384
|
||||||
|
:102BA000DF93CDB7DEB728970FB6F894DEBF0FBE20
|
||||||
|
:102BB000CDBF1886E2EDF3E080E2DF011D928A9539
|
||||||
|
:102BC000E9F78CE292E00E949002181619060CF0C8
|
||||||
|
:102BD0000AC28CE292E00E9482029091D103981383
|
||||||
|
:102BE00002C260E270E082ED93E00E9425028091D3
|
||||||
|
:102BF000D403482F8D3108F04CE1242F30E0F90147
|
||||||
|
:102C0000EF52FC4F648172E0740FE3EDF3E090E06B
|
||||||
|
:102C100051E0A1919A0F5F5F7517D8F76913E1C171
|
||||||
|
:102C2000E091D303E88710920001E154EB3108F002
|
||||||
|
:102C3000FFC0F0E0E25EF94E0C94C51B39164E164B
|
||||||
|
:102C40005316621667166C167B16801618178516B3
|
||||||
|
:102C5000DF16E416E916F316F81608170D171817FD
|
||||||
|
:102C6000181718171817181718171217EE175816DD
|
||||||
|
:102C70005D1665ED73E080E593E10E94BA14289635
|
||||||
|
:102C80000FB6F894DEBF0FBECDBFDF91CF911F917D
|
||||||
|
:102C90000F91FF90EF90DF90CF90089565ED73E076
|
||||||
|
:102CA00089E293E1EACF65ED73E089E093E1E5CF56
|
||||||
|
:102CB00065ED73E089E193E1E0CF65ED73E089EFC5
|
||||||
|
:102CC00092E1DBCF65ED73E08FE891E1D6CF65ED62
|
||||||
|
:102CD00073E087E791E1D1CF86E60E944E0981E05B
|
||||||
|
:102CE0000E944F038BE00E944F0380E00E944F033D
|
||||||
|
:102CF0000E941503C4CF65ED73E08AE691E1BDCF74
|
||||||
|
:102D000065ED73E08BE090E1B8CF4B7F423021F06E
|
||||||
|
:102D100087E00E94870FB3CF8091D5038250863021
|
||||||
|
:102D200028F48091D603805D893610F088E0F1CFD9
|
||||||
|
:102D3000A90165ED73E089E092E00E94EC1B89E057
|
||||||
|
:102D4000C82E82E0D82E0EEE13E0F601F1906F014E
|
||||||
|
:102D5000C8010E94D014F81671F06F2DC8010E94AE
|
||||||
|
:102D6000661B6F2DC80101960E94661B6F2DC8015E
|
||||||
|
:102D700002960E94661B0D5F1F4F0115F4E01F07AE
|
||||||
|
:102D800021F780910902883008F087E0823008F44A
|
||||||
|
:102D900082E080931A0480910B0280930604809154
|
||||||
|
:102DA0000C028093070480910D02809308048091A7
|
||||||
|
:102DB0000E028093090481E00E94101160CF65ED3E
|
||||||
|
:102DC00073E08EEE94E159CF65ED73E080EA9FE009
|
||||||
|
:102DD00054CF87E60E944E09809109020E944F035A
|
||||||
|
:102DE00080910A0283CF65ED73E082E291E145CFE5
|
||||||
|
:102DF000833008F48DCF8091D5039091D603A091B4
|
||||||
|
:102E0000D7038093FC019093FD01A093FE01D3CFE3
|
||||||
|
:102E100065ED73E08DE591E130CF65ED73E082E61D
|
||||||
|
:102E200099E02BCF63E084E690E00E94830F27CFE8
|
||||||
|
:102E300086E06FCF8CE292E00E948202182F8630EB
|
||||||
|
:102E4000F9F48CE292E00E9411021887FE01389694
|
||||||
|
:102E500081E0809300018885833709F483C008F0FE
|
||||||
|
:102E6000D7C0813609F492C0803709F487C0863014
|
||||||
|
:102E700009F4B2C065E18CE292E00E94C802FFCE84
|
||||||
|
:102E8000823009F0B8C063E070E08DEC92E00E94FF
|
||||||
|
:102E900025028091CE02823051F48091CF0280933E
|
||||||
|
:102EA000CE0261E070E08FEC92E00E942502D090AB
|
||||||
|
:102EB000CE02D7FC20C081E08093CF030FEC12E05C
|
||||||
|
:102EC000780161E070E0C8010E942502D8018D916F
|
||||||
|
:102ED0008D01803151F461E070E0C7010E9425024C
|
||||||
|
:102EE000B3E009351B0761F702C08330C9F7D88604
|
||||||
|
:102EF000EFECF2E0ADCF1092CF030091CF02073894
|
||||||
|
:102F000008F0B8CF10E07801E3E0EE0EF11CA70165
|
||||||
|
:102F100070E060E080ED92E00E94F51BB70180ED6B
|
||||||
|
:102F200092E00E942502F701E553FD4F82818093D4
|
||||||
|
:102F3000CC02F801E553FD4F86818093CB02E090EF
|
||||||
|
:102F4000CB02F090CC02B8016E5F7F4F8EEC92E026
|
||||||
|
:102F50000E941308E816F90609F08CCFD886E0ED38
|
||||||
|
:102F6000F2E076CF83E70E94D80080E00E94AF00B5
|
||||||
|
:102F70006EE088E191E00E94120105C00E94D80035
|
||||||
|
:102F80008DE40E94AF000E945B0879CE108180E042
|
||||||
|
:102F90000E949D13183099F410E0812F0E949B0B22
|
||||||
|
:102FA000882391F0111105C080910002813408F44A
|
||||||
|
:102FB00015E01F5F183089F70E94C70D60CE812F82
|
||||||
|
:102FC0000E949B0B8111F8CF0E94F80863E084E611
|
||||||
|
:102FD00090E00E94830FF0CF0E94F8080E949B0FA0
|
||||||
|
:102FE0004ECE81E096CE8CE292E00E9490021816BE
|
||||||
|
:102FF00019060CF41FCF8CE292E00E949002181682
|
||||||
|
:1030000019060CF03CCE8CE292E00E94110237CE01
|
||||||
|
:10301000813E09F4BBCFC0F4833809F02BCF108177
|
||||||
|
:10302000113808F02CCE018107FF02C000E8011B17
|
||||||
|
:1030300083E80E94D800812F0E94AF00812F90E08A
|
||||||
|
:10304000602F885E9E4F97CF803F09F497CF873FD0
|
||||||
|
:1030500009F010CF8E010F5F1F4F87E0D8011D923E
|
||||||
|
:103060008A95E9F787EF0E94D80067E0C80183CF0F
|
||||||
|
:103070000E949C0281110C94C91508951F920F9211
|
||||||
|
:103080000FB60F9211242F933F938F939F93AF937B
|
||||||
|
:10309000BF938091140290911502A0911602B091F5
|
||||||
|
:1030A000170230910F0226E0230F2D3758F50296B4
|
||||||
|
:1030B000A11DB11D20930F0280931402909315025D
|
||||||
|
:1030C000A0931602B0931702809110029091110202
|
||||||
|
:1030D000A0911202B09113020196A11DB11D80931F
|
||||||
|
:1030E000100290931102A0931202B0931302BF91A9
|
||||||
|
:1030F000AF919F918F913F912F910F900FBE0F90A5
|
||||||
|
:103100001F90189529E8230F0396A11DB11DD2CF5A
|
||||||
|
:103110001F920F920FB60F9211242F933F934F934C
|
||||||
|
:103120005F936F937F938F939F93AF93BF93EF932F
|
||||||
|
:10313000FF9380911E0290911F02A0912002B091F6
|
||||||
|
:103140002102892B8A2B8B2BD1F190911902E091CE
|
||||||
|
:103150001A02F0911B0280818927808380911E02D0
|
||||||
|
:1031600090911F02A0912002B09121021816190619
|
||||||
|
:103170001A061B069CF480911E0290911F02A091DA
|
||||||
|
:103180002002B09121020197A109B10980931E028A
|
||||||
|
:1031900090931F02A0932002B0932102FF91EF9120
|
||||||
|
:1031A000BF91AF919F918F917F916F915F914F915F
|
||||||
|
:1031B0003F912F910F900FBE0F901F901895809107
|
||||||
|
:1031C0000101E6E8F0E0E4919FEF90930101E13026
|
||||||
|
:1031D00051F030F0E23069F060E00E944F01DECF44
|
||||||
|
:1031E00010926E00F9CF90916F009D7F90936F00C9
|
||||||
|
:1031F000F3CF909170009D7F9093700091E0909339
|
||||||
|
:10320000B0009091B100987F94609093B1001092BB
|
||||||
|
:10321000B300E2CF1F920F920FB60F9211242F939B
|
||||||
|
:103220003F934F935F936F937F938F939F93AF934E
|
||||||
|
:10323000BF93EF93FF938CE292E00E94A602FF916E
|
||||||
|
:10324000EF91BF91AF919F918F917F916F915F911E
|
||||||
|
:103250004F913F912F910F900FBE0F901F90189597
|
||||||
|
:103260001F920F920FB60F9211242F938F939F935B
|
||||||
|
:10327000EF93FF93E0913C02F0913D028081E09159
|
||||||
|
:103280004202F091430282FD1BC090818091450271
|
||||||
|
:103290008F5F8F7320914602821741F0E0914502C3
|
||||||
|
:1032A000F0E0E45DFD4F958F80934502FF91EF9133
|
||||||
|
:1032B0009F918F912F910F900FBE0F901F90189597
|
||||||
|
:1032C0008081F4CF1F920F920FB60F9211240F90AE
|
||||||
|
:1032D0000FBE0F901F901895ECE2F2E0138212825D
|
||||||
|
:1032E00088EE93E0A0E0B0E084839583A683B78363
|
||||||
|
:1032F0008EEE91E09183808385EC90E095878487C2
|
||||||
|
:1033000084EC90E09787868780EC90E0918B808BAF
|
||||||
|
:1033100081EC90E0938B828B82EC90E0958B848B98
|
||||||
|
:1033200086EC90E0978B868B118E128E138E148E06
|
||||||
|
:103330008FEF9FEF9093CA028093C902E8EFF3E00A
|
||||||
|
:1033400010A211A212A213A214A2E1EDF3E01082C6
|
||||||
|
:1033500083E081A312A213A214A215A216A2809345
|
||||||
|
:10336000CC031092CE031092CD0381E08093CF0363
|
||||||
|
:103370001092D0030895CF93DF9300D000D0CDB743
|
||||||
|
:10338000DEB7789484B5826084BD84B5816084BDE5
|
||||||
|
:1033900085B5826085BD85B5816085BD80916E00F3
|
||||||
|
:1033A000816080936E001092810080918100826024
|
||||||
|
:1033B0008093810080918100816080938100809161
|
||||||
|
:1033C00080008160809380008091B1008460809350
|
||||||
|
:1033D000B1008091B00081608093B00080917A004C
|
||||||
|
:1033E000846080937A0080917A00826080937A0072
|
||||||
|
:1033F00080917A008E7F80937A0080917A00806835
|
||||||
|
:1034000080937A001092C10084E00E94F30083E070
|
||||||
|
:103410000E94F30089E00E94F3008AE00E94F3001A
|
||||||
|
:1034200060E084E00E944F0160E083E00E944F0171
|
||||||
|
:1034300060E089E00E944F0159E0E52E52E0F52E50
|
||||||
|
:103440000EEE13E0C8010E94D014F70181937F01B2
|
||||||
|
:103450000D5F1F4F0115F4E01F07A1F780910902CE
|
||||||
|
:103460008250863080F084E08093090210920A0234
|
||||||
|
:103470008FEF9FEFDC0180930B0290930C02A093DF
|
||||||
|
:103480000D02B0930E02809109029AE09093180405
|
||||||
|
:1034900099E090931904883008F087E0823008F4AE
|
||||||
|
:1034A00082E080931A0410920B0410920A04809117
|
||||||
|
:1034B0000B028093060480910C0280930704809194
|
||||||
|
:1034C0000D028093080480910E02809309048EEF10
|
||||||
|
:1034D0008093D10380E096E9A0E0B0E08093F4030C
|
||||||
|
:1034E0009093F503A093F603B093F7038AE090E07E
|
||||||
|
:1034F000A0E0B0E08093300290933102A0933202BA
|
||||||
|
:10350000B0933302E0913C02F0913D0282E080836F
|
||||||
|
:10351000E0913802F09139021082E0913A02F09184
|
||||||
|
:103520003B0289E1808310924402E0914002F091D5
|
||||||
|
:10353000410286E08083E0913E02F0913F0280816B
|
||||||
|
:1035400080618083E0913E02F0913F02808188603B
|
||||||
|
:103550008083E0913E02F0913F0280818068808309
|
||||||
|
:10356000E0913E02F0913F0280818F7D808361E097
|
||||||
|
:1035700084E00E944F0162E370E080E090E00E94EE
|
||||||
|
:10358000A20160E084E00E944F0101E012E080911E
|
||||||
|
:103590000001882309F48AC0809109020E949D13CA
|
||||||
|
:1035A00080911B04882309F479C09091F80329EFD6
|
||||||
|
:1035B00033E080E0981709F471C0F90154892F5F56
|
||||||
|
:1035C0003F4F4081541306C08F5FF4CF86EE0E94B8
|
||||||
|
:1035D000D80054C019821A821B821C82BE016F5F00
|
||||||
|
:1035E0007F4F84E00E94050B882309F457C08B812C
|
||||||
|
:1035F0008F3F09F453C08981809301028A818093AF
|
||||||
|
:103600000202BE016F5F7F4F85E00E94050B882399
|
||||||
|
:1036100009F444C0898190E0B0E0A0E0BA2FA92F5E
|
||||||
|
:10362000982F88272A81822BBA2FA92F982F882795
|
||||||
|
:103630002B81822BBA2FA92F982F88272C81822BA0
|
||||||
|
:103640000097A105B10551F11093080200930702FC
|
||||||
|
:103650008093030290930402A0930502B0930602A4
|
||||||
|
:103660008091CF03882309F4B1CF86E60E94D80069
|
||||||
|
:1036700085E50E94AF008AEA0E94AF0080E00E94C8
|
||||||
|
:10368000AF0080E00E94AF00809101020E94AF0075
|
||||||
|
:10369000809102020E94AF000E945B080E94C70D49
|
||||||
|
:1036A00062E370E080E090E00E94A2010E949C0230
|
||||||
|
:1036B000882309F46CCF0E94C91569CFF999FECF10
|
||||||
|
:1036C00092BD81BDF89A992780B50895262FF99962
|
||||||
|
:1036D000FECF1FBA92BD81BD20BD0FB6F894FA9AF5
|
||||||
|
:1036E000F99A0FBE01960895A29FB001B39FC00141
|
||||||
|
:1036F000A39F700D811D1124911DB29F700D811D1E
|
||||||
|
:103700001124911D0895991B79E004C0991F961703
|
||||||
|
:1037100008F0961B881F7A95C9F78095089597FB46
|
||||||
|
:10372000072E16F4009407D077FD09D00E94CB1B1A
|
||||||
|
:1037300007FC05D03EF4909581959F4F08957095B4
|
||||||
|
:1037400061957F4F0895A1E21A2EAA1BBB1BFD01B4
|
||||||
|
:103750000DC0AA1FBB1FEE1FFF1FA217B307E40770
|
||||||
|
:10376000F50720F0A21BB30BE40BF50B661F771FC8
|
||||||
|
:10377000881F991F1A9469F76095709580959095A8
|
||||||
|
:103780009B01AC01BD01CF010895EE0FFF1F059015
|
||||||
|
:10379000F491E02D0994AA1BBB1B51E107C0AA1F9D
|
||||||
|
:1037A000BB1FA617B70710F0A61BB70B881F991FE2
|
||||||
|
:1037B0005A95A9F780959095BC01CD010895FB011C
|
||||||
|
:1037C000DC0104C08D910190801921F441505040DA
|
||||||
|
:1037D000C8F7881B990B0895FB01DC0102C001901A
|
||||||
|
:1037E0000D9241505040D8F70895DC0101C06D930F
|
||||||
|
:0C37F00041505040E0F70895F894FFCFDE
|
||||||
|
:1037FC0001FFFFFFFFFFFFFFEEEEEEEE0001040501
|
||||||
|
:10380C0006070203FFFFFFFF00000001F73632330B
|
||||||
|
:10381C000A0119919780200D4B084EFA280A0119BC
|
||||||
|
:10382C00006DDD0000001804FF03800000000000A4
|
||||||
|
:10383C00000000004D70FFFFFF00C3FF0000000AF6
|
||||||
|
:10384C0000000000FF00EFFF0024FEC0FFFF1999ED
|
||||||
|
:10385C00051E7FF8850C0101A6E06FFFFFFFFFFF3F
|
||||||
|
:10386C00FFFFFFFFFFFFFFFF303030357D203800BA
|
||||||
|
:10387C0000000000FFFFFFFF3005013505100801B7
|
||||||
|
:10388C00000000001C2000780300FE000103A00CC7
|
||||||
|
:10389C0006080000FF000000040300000000000008
|
||||||
|
:1038AC0007070000000000000500000000000000F9
|
||||||
|
:1038BC0001000000000000000000000000000000FB
|
||||||
|
:1038CC0000000000000000000000000000000000EC
|
||||||
|
:1038DC00021132622700002781E100000000C802BB
|
||||||
|
:0C38EC00D5010202660390021102820264
|
||||||
|
:00000001FF
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
#include "sportidentprotocol.h"
|
||||||
|
|
||||||
|
void SiTimestamp::fromUnixtime(uint32_t timestamp, int8_t timezone) {
|
||||||
|
if(!timestamp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t localtime = timestamp + (int16_t)timezone*900;
|
||||||
|
uint32_t daysFromEpoch = localtime/86400;
|
||||||
|
uint32_t secsFromMidnight = localtime%86400;
|
||||||
|
uint8_t weekday = (daysFromEpoch + 4)%7;
|
||||||
|
ptd = weekday << 1;
|
||||||
|
ptd |= secsFromMidnight/43200;
|
||||||
|
uint16_t pt = secsFromMidnight%43200;
|
||||||
|
pth = pt >> 8;
|
||||||
|
ptl = pt & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SportidentProtocol::crc16(uint8_t *data, uint16_t len) {
|
||||||
|
if(len < 2) {
|
||||||
|
return 0; // response value is "0" for none or one data byte
|
||||||
|
}
|
||||||
|
uint8_t *p = data;
|
||||||
|
|
||||||
|
uint16_t crc = *p++;
|
||||||
|
crc = (crc << 8) + *p++;
|
||||||
|
|
||||||
|
if(len == 2) {
|
||||||
|
return crc; // response value is CRC for two data bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t val;
|
||||||
|
for(uint16_t i = (int)(len >> 1); i > 0; --i) {
|
||||||
|
if(i > 1) {
|
||||||
|
val = *p++;
|
||||||
|
val = (val << 8) + *p++;
|
||||||
|
} else {
|
||||||
|
if(len & 1) { // odd number of data bytes, complete with "0"
|
||||||
|
val = *p;
|
||||||
|
val = (val << 8);
|
||||||
|
} else {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint8_t j = 0; j<16; ++j) {
|
||||||
|
if(crc & 0x8000) {
|
||||||
|
crc <<= 1;
|
||||||
|
if(val & 0x8000) {
|
||||||
|
++crc;
|
||||||
|
}
|
||||||
|
crc ^= 0x8005;
|
||||||
|
} else {
|
||||||
|
crc <<= 1;
|
||||||
|
if(val & 0x8000) {
|
||||||
|
++crc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SportidentProtocol::start(uint8_t code) {
|
||||||
|
|
||||||
|
serialBuffer[0] = STX;
|
||||||
|
serialBuffer[1] = code;
|
||||||
|
|
||||||
|
const uint16_t station_code = 0x0001;
|
||||||
|
|
||||||
|
// Legacy protocol
|
||||||
|
if(code < 0x80) {
|
||||||
|
baseCmd = true;
|
||||||
|
baseCmdChecksum = 0;
|
||||||
|
serialDataPos = 2;
|
||||||
|
add(station_code & 0xff);
|
||||||
|
} else {
|
||||||
|
baseCmd = false;
|
||||||
|
serialDataPos = 3;
|
||||||
|
add(station_code >> 8);
|
||||||
|
add(station_code & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SportidentProtocol::add(uint8_t dataByte) {
|
||||||
|
if(baseCmd) {
|
||||||
|
if(dataByte < 0x20) {
|
||||||
|
serialBuffer[serialDataPos++] = DLE;
|
||||||
|
}
|
||||||
|
baseCmdChecksum += dataByte;
|
||||||
|
} else if (serialDataPos >= SPORTIDENT_MAX_PACKET_SIZE - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
serialBuffer[serialDataPos++] = dataByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SportidentProtocol::add(const uint8_t *data, uint8_t size) {
|
||||||
|
for(uint8_t i = 0; i < size; ++i) {
|
||||||
|
add(data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SportidentProtocol::send() {
|
||||||
|
if(baseCmd) {
|
||||||
|
if(serialBuffer[1] == BCMD_READ_SI6) {
|
||||||
|
add(baseCmdChecksum & 0xFF);
|
||||||
|
}
|
||||||
|
serialBuffer[serialDataPos++] = ETX;
|
||||||
|
} else {
|
||||||
|
uint8_t dataSize = serialDataPos - 3; // minus start, resp code, datalen
|
||||||
|
|
||||||
|
serialBuffer[2] = dataSize;
|
||||||
|
|
||||||
|
crc.value = SportidentProtocol::crc16(&serialBuffer[1], 2 + dataSize);
|
||||||
|
serialBuffer[serialDataPos++] = crc.b[1];
|
||||||
|
serialBuffer[serialDataPos++] = crc.b[0];
|
||||||
|
serialBuffer[serialDataPos++] = ETX;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < serialDataPos; i++) {
|
||||||
|
Serial.write(serialBuffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SportidentProtocol::error() {
|
||||||
|
Serial.write(NAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *SportidentProtocol::read(bool *error, uint8_t *code, uint8_t *dataSize) {
|
||||||
|
*error = false;
|
||||||
|
if(Serial.available() > 0) {
|
||||||
|
uint8_t b = Serial.peek();
|
||||||
|
if(b == ACK) {
|
||||||
|
Serial.read(); // drop byte
|
||||||
|
*code = ACK;
|
||||||
|
*dataSize = 0;
|
||||||
|
return code;
|
||||||
|
} else if(b == STX) {
|
||||||
|
Serial.readBytes(serialBuffer, 3);
|
||||||
|
if(serialBuffer[1] == STX) {
|
||||||
|
serialBuffer[1] = serialBuffer[2];
|
||||||
|
Serial.readBytes(&serialBuffer[2], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cmd = serialBuffer[1];
|
||||||
|
|
||||||
|
// Legacy protocol
|
||||||
|
if(cmd < 0x80) {
|
||||||
|
legacyMode = true;
|
||||||
|
uint8_t length = 0;
|
||||||
|
for(uint8_t i = 2; i < SPORTIDENT_MAX_PACKET_SIZE; ++i) {
|
||||||
|
Serial.readBytes(&serialBuffer[i], 1);
|
||||||
|
++length;
|
||||||
|
if(serialBuffer[i] == DLE) {
|
||||||
|
Serial.readBytes(&serialBuffer[i], 1);
|
||||||
|
} else if(serialBuffer[i] == ETX) {
|
||||||
|
--length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*code = cmd;
|
||||||
|
*dataSize = length;
|
||||||
|
return &serialBuffer[2];
|
||||||
|
}
|
||||||
|
legacyMode = false;
|
||||||
|
|
||||||
|
uint8_t length = serialBuffer[2];
|
||||||
|
|
||||||
|
if(length > SPORTIDENT_MAX_PACKET_SIZE - 6) {
|
||||||
|
*error = true;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
memset(&serialBuffer[3], 0, length + 3);
|
||||||
|
Serial.readBytes(&serialBuffer[3], length + 3);
|
||||||
|
crc.b[1] = serialBuffer[length + 3];
|
||||||
|
crc.b[0] = serialBuffer[length + 4];
|
||||||
|
|
||||||
|
if(crc.value != SportidentProtocol::crc16(&serialBuffer[1], 2 + length)) {
|
||||||
|
*error = true;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
*code = cmd;
|
||||||
|
*dataSize = length;
|
||||||
|
return &serialBuffer[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
#ifndef SPORTIDENTPROTOCOL_H
|
||||||
|
#define SPORTIDENTPROTOCOL_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#define SPORTIDENT_MAX_PACKET_SIZE 140
|
||||||
|
#define SPORTIDENT_LEGACY_MAX_PACKET_SIZE 255 // It should be enough
|
||||||
|
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint16_t value;
|
||||||
|
byte b[2];
|
||||||
|
} Crc;
|
||||||
|
|
||||||
|
class SiTimestamp {
|
||||||
|
public:
|
||||||
|
void fromUnixtime(uint32_t timestamp, int8_t timezone = 0);
|
||||||
|
|
||||||
|
uint8_t ptd = 0xEE;
|
||||||
|
uint8_t cn = 0xEE;
|
||||||
|
uint8_t pth = 0xEE;
|
||||||
|
uint8_t ptl = 0xEE;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SportidentProtocol {
|
||||||
|
public:
|
||||||
|
enum SpecialBytes {
|
||||||
|
STX = 0x02,
|
||||||
|
ETX = 0x03,
|
||||||
|
ACK = 0x06,
|
||||||
|
DLE = 0x10,
|
||||||
|
NAK = 0x15,
|
||||||
|
WAKEUP = 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Commands {
|
||||||
|
// Base commands
|
||||||
|
BCMD_SI5_DETECTED = 0x46, // SI-card 5 inserted (46 49) or removed (46 4F)
|
||||||
|
BCMD_READ_SI6 = 0x61,
|
||||||
|
BCMD_SI6_DETECTED = 0x66,
|
||||||
|
BCMD_SET_MS = 0x70,
|
||||||
|
BCMD_GET_SYS_VAL = 0x73,
|
||||||
|
|
||||||
|
CMD_SET_MS = 0xF0,
|
||||||
|
CMD_GET_TIME = 0xF7,
|
||||||
|
CMD_GET_SYS_VAL = 0x83,
|
||||||
|
CMD_READ_SI6 = 0xE1, // read out SI-card 6 data block
|
||||||
|
CMD_SI6_DETECTED = 0xE6,
|
||||||
|
CMD_SI_REMOVED = 0xE7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Offsets {
|
||||||
|
O_MODE = 0x71,
|
||||||
|
O_PROTO = 0x74
|
||||||
|
};
|
||||||
|
|
||||||
|
void start(uint8_t code);
|
||||||
|
void add(uint8_t dataByte);
|
||||||
|
void add(const uint8_t *data, uint8_t size);
|
||||||
|
void send();
|
||||||
|
void error();
|
||||||
|
uint8_t *read(bool *error, uint8_t *code, uint8_t *dataSize);
|
||||||
|
bool isLegacyMode() const { return legacyMode; }
|
||||||
|
|
||||||
|
static uint16_t crc16(uint8_t *data, uint16_t len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Crc crc;
|
||||||
|
uint8_t serialBuffer[SPORTIDENT_LEGACY_MAX_PACKET_SIZE];
|
||||||
|
uint8_t serialDataPos = 3;
|
||||||
|
uint16_t baseCmdChecksum = 0;
|
||||||
|
bool legacyMode = true;
|
||||||
|
bool baseCmd = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
:107E000001C0E5C0112484B7882361F0982F9A70CF
|
||||||
|
:107E1000923041F081FF02C097EF94BF282E80E09E
|
||||||
|
:107E2000C1D0EEC085E08093810082E08093C000E5
|
||||||
|
:107E300088E18093C10086E08093C20083E3809351
|
||||||
|
:107E4000C4008EE0AFD0549A86E028E13EEF91E086
|
||||||
|
:107E5000309385002093840096BBB09BFECF4C9A54
|
||||||
|
:107E6000A8954091C00047FD02C0815089F793E07A
|
||||||
|
:107E7000E92EDD24D39425E0C22E31E1B32E86D045
|
||||||
|
:107E8000813479F483D0182F93D0123811F480E024
|
||||||
|
:107E900004C088E0113809F083E071D080E16FD030
|
||||||
|
:107EA000EECF823419F484E18BD0F8CF853411F40D
|
||||||
|
:107EB00085E0FACF853541F469D0C82F67D0D82F37
|
||||||
|
:107EC000CC0FDD1F75D0EACF863519F484E078D069
|
||||||
|
:107ED000DECF843609F034C059D058D0F82E56D0B1
|
||||||
|
:107EE000A82E00E011E048018FEF881A980A4ED0C2
|
||||||
|
:107EF000F80180838401F810F6CF5AD0F5E4AF1270
|
||||||
|
:107F000001C0FFCFFE01E7BEE89507B600FCFDCF3C
|
||||||
|
:107F1000FE01A0E0B1E0CD0102962D913C91090156
|
||||||
|
:107F2000D7BEE89511243296DC01F812F4CFFE0199
|
||||||
|
:107F3000C7BEE89507B600FCFDCFB7BEE895AECF4B
|
||||||
|
:107F4000843771F423D022D0F82E20D031D08E0186
|
||||||
|
:107F5000F80185918F0113D0FA94F110F9CF9ECFDB
|
||||||
|
:107F6000853739F425D08EE10AD085E908D08FE035
|
||||||
|
:107F700094CF813509F0A6CF88E014D0A3CF90919B
|
||||||
|
:107F8000C00095FFFCCF8093C60008958091C0008B
|
||||||
|
:107F900087FFFCCF8091C00084FD01C0A89580912F
|
||||||
|
:107FA000C6000895E0E6F0E098E1908380830895AC
|
||||||
|
:107FB000EDDF803219F088E0F5DFFFCF84E1DFCF1D
|
||||||
|
:107FC000CF93C82FE3DFC150E9F7CF91F1CFFC0188
|
||||||
|
:107FD0000A0167BFE895112407B600FCFDCF667063
|
||||||
|
:0E7FE00029F0452B19F481E187BFE89508953B
|
||||||
|
:027FFE00000879
|
||||||
|
:0400000300007E007B
|
||||||
|
:00000001FF
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
:107E000001C0C9C01F92CDB7DEB7112484B7882343
|
||||||
|
:107E100061F0982F9A70923041F081FF02C097EF85
|
||||||
|
:107E200094BF282E80E0A2D0EBC082E08093C000F7
|
||||||
|
:107E300088E18093C10086E08093C20089E180934D
|
||||||
|
:107E4000C4008EE093D093E0D92ECC24C39425E0D7
|
||||||
|
:107E5000B22E31E1A32E7ED0813469F47BD08983A8
|
||||||
|
:107E60008BD089818238E9F0813811F488E001C033
|
||||||
|
:107E700083E069D065C0823411F484E103C08534A5
|
||||||
|
:107E800019F485E081D05CC0853539F463D0882E43
|
||||||
|
:107E900061D0982E880C991C52C0863521F484E05C
|
||||||
|
:107EA00073D080E0E6CF843609F02DC053D052D095
|
||||||
|
:107EB000F82E50D0E82E00E011E04CD0F80181936C
|
||||||
|
:107EC0008F01FE12FACF58D0F5E4EF1201C0FFCFB8
|
||||||
|
:107ED000F401D7BEE89507B600FCFDCFF401A0E0A1
|
||||||
|
:107EE000B1E08D919D910C01C7BEE89511243296A9
|
||||||
|
:107EF000FA12F7CFF401B7BEE89507B600FCFDCF44
|
||||||
|
:107F0000A7BEE8951DC0843769F424D023D0182F6C
|
||||||
|
:107F100021D032D07401F70185917F0114D0115026
|
||||||
|
:107F2000D1F70EC0853739F427D08EE10CD085E922
|
||||||
|
:107F30000AD08FE09ECF813511F488E017D01CD095
|
||||||
|
:107F400080E101D088CF9091C00095FFFCCF809355
|
||||||
|
:107F5000C60008958091C00087FFFCCF8091C000CB
|
||||||
|
:107F600084FD01C0A8958091C6000895E0E6F0E088
|
||||||
|
:107F700098E1908380830895EDDF803219F088E0E6
|
||||||
|
:107F8000F5DFFFCF84E1DFCFCF93C82FE3DFC15010
|
||||||
|
:107F9000E9F7CF91F1CFFC010A0167BFE895112401
|
||||||
|
:107FA00007B600FCFDCF667029F0452B19F481E17E
|
||||||
|
:067FB00087BFE89508956B
|
||||||
|
:027FFE00000879
|
||||||
|
:0400000300007E007B
|
||||||
|
:00000001FF
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
:107E000001C0E8C011248AEC8093660084B78823FF
|
||||||
|
:107E100061F0982F9A70923041F081FF02C097EF85
|
||||||
|
:107E200094BF282E80E0C1D0EBC085E08093810014
|
||||||
|
:107E300082E08093C00088E18093C10086E0809357
|
||||||
|
:107E4000C20089E18093C4008EE0AFD0549A86E0EE
|
||||||
|
:107E500028E13EEF91E0309385002093840096BBAB
|
||||||
|
:107E6000B09BFECF4C9AA8954091C00047FD02C040
|
||||||
|
:107E7000815089F793E0E92EDD24D39425E0C22ECA
|
||||||
|
:107E800031E1B32E86D0813479F483D0182F93D08A
|
||||||
|
:107E9000123811F480E004C088E0113809F083E062
|
||||||
|
:107EA00071D080E16FD0EECF823419F484E18BD0B1
|
||||||
|
:107EB000F8CF853411F485E0FACF853541F469D0E7
|
||||||
|
:107EC000C82F67D0D82FCC0FDD1F75D0EACF8635ED
|
||||||
|
:107ED00019F484E078D0DECF843609F034C059D06C
|
||||||
|
:107EE00058D0F82E56D0A82E00E011E048018FEFB0
|
||||||
|
:107EF000881A980A4ED0F80180838401F810F6CFD2
|
||||||
|
:107F00005AD0F5E4AF1201C0FFCFFE01E7BEE895FD
|
||||||
|
:107F100007B600FCFDCFFE01A0E0B1E0CD01029666
|
||||||
|
:107F20002D913C910901D7BEE89511243296DC01D0
|
||||||
|
:107F3000F812F4CFFE01C7BEE89507B600FCFDCFEE
|
||||||
|
:107F4000B7BEE895AECF843771F423D022D0F82E97
|
||||||
|
:107F500020D031D08E01F80185918F0113D0FA9491
|
||||||
|
:107F6000F110F9CF9ECF853739F425D08EE10AD0B4
|
||||||
|
:107F700085E908D08FE094CF813509F0A6CF88E05D
|
||||||
|
:107F800014D0A3CF9091C00095FFFCCF8093C60082
|
||||||
|
:107F900008958091C00087FFFCCF8091C00084FDD0
|
||||||
|
:107FA00001C0A8958091C6000895E0E6F0E098E150
|
||||||
|
:107FB000908380830895EDDF803219F088E0F5DF4B
|
||||||
|
:107FC000FFCF84E1DFCFCF93C82FE3DFC150E9F7C4
|
||||||
|
:107FD000CF91F1CFFC010A0167BFE895112407B6E4
|
||||||
|
:107FE00000FCFDCF667029F0452B19F481E187BFB5
|
||||||
|
:047FF000E895089573
|
||||||
|
:027FFE00000879
|
||||||
|
:0400000300007E007B
|
||||||
|
:00000001FF
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
:107E000001C0E5C0112484B7882359F083FF03C063
|
||||||
|
:107E100094B7967F94BF80FD04C0282E80E0C2D026
|
||||||
|
:107E2000EFC085E08093810082E08093C00088E10C
|
||||||
|
:107E30008093C10086E08093C20083E38093C400F6
|
||||||
|
:107E40008FE0B0D0259A86E020E33CEF91E03093BC
|
||||||
|
:107E500085002093840096BBB09BFECF1D9AA89509
|
||||||
|
:107E60004091C00047FD02C0815089F793E0E92EA0
|
||||||
|
:107E7000DD24D39425E0C22E31E1B32E87D0C82F64
|
||||||
|
:107E800089E290D0C13479F481D0C82F91D0C23822
|
||||||
|
:107E900011F480E004C088E0C13809F083E06FD0BD
|
||||||
|
:107EA00080E16DD0EBCF84E1C23419F0C53419F410
|
||||||
|
:107EB00085E086D0F5CFC53541F468D0082F66D06F
|
||||||
|
:107EC000182F000F111F74D0EBCFC63519F484E0C2
|
||||||
|
:107ED00077D0DFCFC43609F033C058D057D0F82E52
|
||||||
|
:107EE00055D0A82EC0E0D1E04E018FEF881A980A35
|
||||||
|
:107EF0004DD08883E401F810F7CF5AD0F5E4AF12E3
|
||||||
|
:107F000001C0FFCFF801E7BEE89507B600FCFDCF42
|
||||||
|
:107F1000F801A0E0B1E0CD0102962D913C9109015C
|
||||||
|
:107F2000D7BEE89511243296DC01F812F4CFF8019F
|
||||||
|
:107F3000C7BEE89507B600FCFDCFB7BEE895B0CF49
|
||||||
|
:107F4000C43771F423D022D0F82E20D031D0E801EC
|
||||||
|
:107F5000FE018591EF0113D0FA94F110F9CFA0CF73
|
||||||
|
:107F6000C53739F425D08EE10AD085E908D08FE0F5
|
||||||
|
:107F700096CFC13509F0A7CF88E014D0A4CF909157
|
||||||
|
:107F8000C00095FFFCCF8093C60008958091C0008B
|
||||||
|
:107F900087FFFCCF8091C00084FD01C0A89580912F
|
||||||
|
:107FA000C6000895E0E6F0E098E1908380830895AC
|
||||||
|
:107FB000EDDF803219F088E0F5DFFFCF84E1DFCF1D
|
||||||
|
:107FC000CF93C82FE3DFC150E9F7CF91F1CFFC0188
|
||||||
|
:107FD0000A0167BFE895112407B600FCFDCF667063
|
||||||
|
:0E7FE00029F0452B19F481E187BFE89508953B
|
||||||
|
:027FFE00000879
|
||||||
|
:0400000300007E007B
|
||||||
|
:00000001FF
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
## Building Optiboot for Base station
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd <Optiboot-local-repo>/optiboot/bootloaders/optiboot
|
||||||
|
|
||||||
|
# Bootloader without LED flashes
|
||||||
|
make AVR_FREQ=8000000L BAUD_RATE=38400 LED_START_FLASHES=0 LED=D4 atmega328
|
||||||
|
mv optiboot_atmega328.hex optiboot_38400_sportiduino.hex
|
||||||
|
|
||||||
|
# Bootloader with LED starting flashes
|
||||||
|
make AVR_FREQ=8000000L BAUD_RATE=38400 LED_START_FLASHES=3 LED=D4 atmega328
|
||||||
|
mv optiboot_atmega328.hex optiboot8_38400_sportiduino_led.hex
|
||||||
|
```
|
||||||
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
sportiduino.name=Sportiduino
|
||||||
|
|
||||||
|
sportiduino.build.mcu=atmega328p
|
||||||
|
sportiduino.build.f_cpu=8000000L
|
||||||
|
sportiduino.build.board=AVR_SPORTIDUINO
|
||||||
|
sportiduino.build.core=arduino
|
||||||
|
sportiduino.build.variant=standard
|
||||||
|
|
||||||
|
sportiduino.upload.tool=avrdude
|
||||||
|
sportiduino.upload.protocol=arduino
|
||||||
|
sportiduino.upload.maximum_size=32256
|
||||||
|
sportiduino.upload.maximum_data_size=2048
|
||||||
|
sportiduino.upload.speed=38400
|
||||||
|
#sportiduino.upload.speed=19200
|
||||||
|
|
||||||
|
sportiduino.bootloader.tool=avrdude
|
||||||
|
sportiduino.bootloader.low_fuses=0xE2
|
||||||
|
sportiduino.bootloader.high_fuses=0xDE
|
||||||
|
sportiduino.bootloader.extended_fuses=0xFF
|
||||||
|
sportiduino.bootloader.unlock_bits=0x3F
|
||||||
|
sportiduino.bootloader.lock_bits=0x0F
|
||||||
|
|
||||||
|
menu.bootloader=Bootloader
|
||||||
|
|
||||||
|
sportiduino.menu.bootloader.optiboot=Optiboot 38400
|
||||||
|
sportiduino.menu.bootloader.optiboot.bootloader.file=optiboot/optiboot8_38400_sportiduino.hex
|
||||||
|
|
||||||
|
sportiduino.menu.bootloader.optiboot_led=Optiboot 38400 with LED
|
||||||
|
sportiduino.menu.bootloader.optiboot_led.bootloader.file=optiboot/optiboot8_38400_sportiduino_led.hex
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
nano.name=Arduino Nano
|
||||||
|
|
||||||
|
nano.upload.tool=avrdude
|
||||||
|
nano.upload.protocol=arduino
|
||||||
|
|
||||||
|
nano.bootloader.tool=avrdude
|
||||||
|
nano.bootloader.unlock_bits=0x3F
|
||||||
|
nano.bootloader.lock_bits=0x0F
|
||||||
|
|
||||||
|
nano.build.f_cpu=8000000L
|
||||||
|
nano.build.board=AVR_NANO
|
||||||
|
nano.build.core=arduino
|
||||||
|
nano.build.variant=eightanaloginputs
|
||||||
|
|
||||||
|
## Arduino Nano w/ ATmega328P (without reset)
|
||||||
|
## --------------------------
|
||||||
|
nano.menu.cpu.atmega328noreset=ATmega328P (without reset)
|
||||||
|
|
||||||
|
nano.menu.cpu.atmega328noreset.upload.maximum_size=30720
|
||||||
|
nano.menu.cpu.atmega328noreset.upload.maximum_data_size=2048
|
||||||
|
nano.menu.cpu.atmega328noreset.upload.speed=38400
|
||||||
|
|
||||||
|
nano.menu.cpu.atmega328noreset.bootloader.low_fuses=0xFF
|
||||||
|
nano.menu.cpu.atmega328noreset.bootloader.high_fuses=0xDA
|
||||||
|
nano.menu.cpu.atmega328noreset.bootloader.extended_fuses=0xFD
|
||||||
|
nano.menu.cpu.atmega328noreset.bootloader.file=optiboot/optiboot8_atmega328_38400_without_reset.hex
|
||||||
|
|
||||||
|
nano.menu.cpu.atmega328noreset.build.mcu=atmega328p
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
#include "Adafruit_SleepyDog.h"
|
||||||
|
|
||||||
|
// Global instance of the main class for sketches to use.
|
||||||
|
WatchdogType Watchdog;
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef ADAFRUIT_SLEEPYDOG_H
|
||||||
|
#define ADAFRUIT_SLEEPYDOG_H
|
||||||
|
|
||||||
|
// Platform-specific code goes below. Each #ifdef should check for the presence
|
||||||
|
// of their platform and pull in the appropriate watchdog implementation type,
|
||||||
|
// then typedef it to WatchdogType so the .cpp file can create a global instance.
|
||||||
|
#if defined(ARDUINO_ARCH_AVR) || defined(__AVR__)
|
||||||
|
#include "utility/WatchdogAVR.h"
|
||||||
|
typedef WatchdogAVR WatchdogType;
|
||||||
|
#elif defined(ARDUINO_ARCH_SAMD)
|
||||||
|
// Arduino Zero / ATSAMD series CPU watchdog support.
|
||||||
|
#include "utility/WatchdogSAMD.h"
|
||||||
|
typedef WatchdogSAMD WatchdogType;
|
||||||
|
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||||
|
// Teensy 3.x watchdog support.
|
||||||
|
#include "utility/WatchdogKinetisK.h"
|
||||||
|
typedef WatchdogKinetisKseries WatchdogType;
|
||||||
|
#elif defined(__MKL26Z64__)
|
||||||
|
// Teensy LC watchdog support.
|
||||||
|
#include "utility/WatchdogKinetisL.h"
|
||||||
|
typedef WatchdogKinetisLseries WatchdogType;
|
||||||
|
#else
|
||||||
|
#error Unsupported platform for the Adafruit Watchdog library!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern WatchdogType Watchdog;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Adafruit Industries
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Adafruit SleepyDog Arduino Library
|
||||||
|
|
||||||
|
Arduino library to use the watchdog timer for system reset and low power sleep.
|
||||||
|
|
||||||
|
Currently supports the following hardware:
|
||||||
|
|
||||||
|
* Arduino Uno or other ATmega328P-based boards.
|
||||||
|
* Arduino Mega or other ATmega2560- or 1280-based boards.
|
||||||
|
* Arduino Zero, Adafruit Feather M0 (ATSAMD21).
|
||||||
|
* Arduino Leonardo or other 32u4-based boards (e.g. Adafruit Feather) WITH CAVEAT: USB Serial connection is clobbered on sleep; if sketch does not require Serial comms, this is not a concern. The example sketches all print to Serial and appear frozen, but the logic does otherwise continue to run. You can restore the USB serial connection after waking up using `USBDevice.attach();` and then reconnect to USB serial from the host machine.
|
||||||
|
* Partial support for Teensy 3.X and LC (watchdog, no sleep).
|
||||||
|
|
||||||
|
Adafruit Trinket and other boards using ATtiny MCUs are NOT supported.
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Adafruit Watchdog Library Basic Usage Example
|
||||||
|
//
|
||||||
|
// Simple example of how to use the watchdog library.
|
||||||
|
//
|
||||||
|
// Author: Tony DiCola
|
||||||
|
|
||||||
|
#include <Adafruit_SleepyDog.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial); // wait for Arduino Serial Monitor (native USB boards)
|
||||||
|
Serial.println("Adafruit Watchdog Library Demo!");
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// First a normal example of using the watchdog timer.
|
||||||
|
// Enable the watchdog by calling Watchdog.enable() as below.
|
||||||
|
// This will turn on the watchdog timer with a ~4 second timeout
|
||||||
|
// before reseting the Arduino. The estimated actual milliseconds
|
||||||
|
// before reset (in milliseconds) is returned.
|
||||||
|
// Make sure to reset the watchdog before the countdown expires or
|
||||||
|
// the Arduino will reset!
|
||||||
|
int countdownMS = Watchdog.enable(4000);
|
||||||
|
Serial.print("Enabled the watchdog with max countdown of ");
|
||||||
|
Serial.print(countdownMS, DEC);
|
||||||
|
Serial.println(" milliseconds!");
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Now loop a few times and periodically reset the watchdog.
|
||||||
|
Serial.println("Looping ten times while resetting the watchdog...");
|
||||||
|
for(int i = 1; i <= 10; ++i) {
|
||||||
|
Serial.print("Loop #"); Serial.println(i, DEC);
|
||||||
|
delay(1000);
|
||||||
|
// Reset watchdog with every loop to make sure the sketch keeps running.
|
||||||
|
// If you comment out this call watch what happens in about 4 iterations!
|
||||||
|
Watchdog.reset();
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Disable the watchdog entirely by calling Watchdog.disable();
|
||||||
|
Watchdog.disable();
|
||||||
|
|
||||||
|
// Finally demonstrate the watchdog resetting by enabling it for a shorter
|
||||||
|
// period of time and waiting a long time without a reset. Notice you can
|
||||||
|
// pass a _maximum_ countdown time (in milliseconds) to the enable call.
|
||||||
|
// The library will try to use that value as the countdown, but it might
|
||||||
|
// pick a smaller value if the hardware doesn't support it. The actual
|
||||||
|
// countdown value will be returned so you can see what it is.
|
||||||
|
countdownMS = Watchdog.enable(4000);
|
||||||
|
Serial.print("Get ready, the watchdog will reset in ");
|
||||||
|
Serial.print(countdownMS, DEC);
|
||||||
|
Serial.println(" milliseconds!");
|
||||||
|
Serial.println();
|
||||||
|
delay(countdownMS+1000);
|
||||||
|
|
||||||
|
// Execution will never get here because the watchdog resets the Arduino!
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// We'll never actually get to the loop because the watchdog will reset in
|
||||||
|
// the setup function.
|
||||||
|
Serial.println("You shouldn't see this message.");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
// Adafruit Watchdog Library Sleep Example
|
||||||
|
//
|
||||||
|
// Simple example of how to do low power sleep with the watchdog timer.
|
||||||
|
//
|
||||||
|
// Author: Tony DiCola
|
||||||
|
|
||||||
|
#include <Adafruit_SleepyDog.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// For boards with "native" USB support (e.g. not using an FTDI chip or
|
||||||
|
// similar serial bridge), Serial connection may be lost on sleep/wake,
|
||||||
|
// and you might not see the "I'm awake" messages. Use the onboard LED
|
||||||
|
// as an alternate indicator -- the code turns it on when awake, off
|
||||||
|
// before going to sleep.
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH); // Show we're awake
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial); // wait for Arduino Serial Monitor (native USB boards)
|
||||||
|
Serial.println("Adafruit Watchdog Library Sleep Demo!");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Serial.println("Going to sleep in one second...");
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// To enter low power sleep mode call Watchdog.sleep() like below
|
||||||
|
// and the watchdog will allow low power sleep for as long as possible.
|
||||||
|
// The actual amount of time spent in sleep will be returned (in
|
||||||
|
// milliseconds).
|
||||||
|
digitalWrite(LED_BUILTIN, LOW); // Show we're asleep
|
||||||
|
int sleepMS = Watchdog.sleep();
|
||||||
|
|
||||||
|
// Alternatively you can provide a millisecond value to specify
|
||||||
|
// how long you'd like the chip to sleep, but the hardware only
|
||||||
|
// supports a limited range of values so the actual sleep time might
|
||||||
|
// be smaller. The time spent in sleep will be returned (in
|
||||||
|
// milliseconds).
|
||||||
|
// int sleepMS = Watchdog.sleep(1000); // Sleep for up to 1 second.
|
||||||
|
|
||||||
|
// Code resumes here on wake.
|
||||||
|
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH); // Show we're awake again
|
||||||
|
|
||||||
|
// Try to reattach USB connection on "native USB" boards (connection is
|
||||||
|
// lost on sleep). Host will also need to reattach to the Serial monitor.
|
||||||
|
// Seems not entirely reliable, hence the LED indicator fallback.
|
||||||
|
#ifdef USBCON
|
||||||
|
USBDevice.attach();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Serial.print("I'm awake now! I slept for ");
|
||||||
|
Serial.print(sleepMS, DEC);
|
||||||
|
Serial.println(" milliseconds.");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
name=Adafruit SleepyDog Library
|
||||||
|
version=1.1.2
|
||||||
|
author=Adafruit
|
||||||
|
maintainer=Adafruit <info@adafruit.com>
|
||||||
|
sentence=Arduino library to use the watchdog timer for system reset and low power sleep.
|
||||||
|
paragraph=Arduino library to use the watchdog timer for system reset and low power sleep.
|
||||||
|
category=Other
|
||||||
|
url=https://github.com/adafruit/Adafruit_SleepyDog
|
||||||
|
architectures=*
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
// Be careful to use a platform-specific conditional include to only make the
|
||||||
|
// code visible for the appropriate platform. Arduino will try to compile and
|
||||||
|
// link all .cpp files regardless of platform.
|
||||||
|
#if defined(ARDUINO_ARCH_AVR) || defined(__AVR__)
|
||||||
|
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/power.h>
|
||||||
|
#include <avr/sleep.h>
|
||||||
|
#include <avr/wdt.h>
|
||||||
|
|
||||||
|
#include "WatchdogAVR.h"
|
||||||
|
|
||||||
|
// Define watchdog timer interrupt.
|
||||||
|
ISR(WDT_vect) {
|
||||||
|
// Nothing needs to be done, however interrupt handler must be defined to
|
||||||
|
// prevent a reset.
|
||||||
|
}
|
||||||
|
|
||||||
|
int WatchdogAVR::enable(int maxPeriodMS) {
|
||||||
|
// Pick the closest appropriate watchdog timer value.
|
||||||
|
int actualMS;
|
||||||
|
_setPeriod(maxPeriodMS, _wdto, actualMS);
|
||||||
|
// Enable the watchdog and return the actual countdown value.
|
||||||
|
wdt_enable(_wdto);
|
||||||
|
return actualMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchdogAVR::reset() {
|
||||||
|
// Reset the watchdog.
|
||||||
|
wdt_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchdogAVR::disable() {
|
||||||
|
// Disable the watchdog and clear any saved watchdog timer value.
|
||||||
|
wdt_disable();
|
||||||
|
_wdto = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WatchdogAVR::sleep(int maxPeriodMS) {
|
||||||
|
// Pick the closest appropriate watchdog timer value.
|
||||||
|
int sleepWDTO, actualMS;
|
||||||
|
_setPeriod(maxPeriodMS, sleepWDTO, actualMS);
|
||||||
|
|
||||||
|
// Build watchdog prescaler register value before timing critical code.
|
||||||
|
uint8_t wdps = ((sleepWDTO & 0x08 ? 1 : 0) << WDP3) |
|
||||||
|
((sleepWDTO & 0x04 ? 1 : 0) << WDP2) |
|
||||||
|
((sleepWDTO & 0x02 ? 1 : 0) << WDP1) |
|
||||||
|
((sleepWDTO & 0x01 ? 1 : 0) << WDP0);
|
||||||
|
|
||||||
|
// The next section is timing critical so interrupts are disabled.
|
||||||
|
cli();
|
||||||
|
// First clear any previous watchdog reset.
|
||||||
|
MCUSR &= ~(1<<WDRF);
|
||||||
|
// Now change the watchdog prescaler and interrupt enable bit so the
|
||||||
|
// watchdog reset only triggers the interrupt (and wakes from deep sleep)
|
||||||
|
// and not a full device reset. This is a timing critical section of
|
||||||
|
// code that must happen in 4 cycles.
|
||||||
|
WDTCSR |= (1<<WDCE) | (1<<WDE); // Set WDCE and WDE to enable changes.
|
||||||
|
WDTCSR = wdps; // Set the prescaler bit values.
|
||||||
|
WDTCSR |= (1<<WDIE); // Enable only watchdog interrupts.
|
||||||
|
// Critical section finished, re-enable interrupts.
|
||||||
|
sei();
|
||||||
|
|
||||||
|
// Disable USB if it exists
|
||||||
|
#ifdef USBCON
|
||||||
|
USBCON |= _BV(FRZCLK); // freeze USB clock
|
||||||
|
PLLCSR &= ~_BV(PLLE); // turn off USB PLL
|
||||||
|
USBCON &= ~_BV(USBE); // disable USB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set full power-down sleep mode and go to sleep.
|
||||||
|
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||||
|
sleep_mode();
|
||||||
|
|
||||||
|
// Chip is now asleep!
|
||||||
|
|
||||||
|
// Once awakened by the watchdog execution resumes here.
|
||||||
|
// Start by disabling sleep.
|
||||||
|
sleep_disable();
|
||||||
|
|
||||||
|
// Check if user had the watchdog enabled before sleep and re-enable it.
|
||||||
|
if(_wdto != -1) wdt_enable(_wdto);
|
||||||
|
|
||||||
|
// Return how many actual milliseconds were spent sleeping.
|
||||||
|
return actualMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchdogAVR::_setPeriod(int maxMS, int &wdto, int &actualMS) {
|
||||||
|
// Note the order of these if statements from highest to lowest is
|
||||||
|
// important so that control flow cascades down to the right value based
|
||||||
|
// on its position in the range of discrete timeouts.
|
||||||
|
if((maxMS >= 8000) || (maxMS == 0)) {
|
||||||
|
wdto = WDTO_8S;
|
||||||
|
actualMS = 8000;
|
||||||
|
} else if(maxMS >= 4000) {
|
||||||
|
wdto = WDTO_4S;
|
||||||
|
actualMS = 4000;
|
||||||
|
} else if(maxMS >= 2000) {
|
||||||
|
wdto = WDTO_2S;
|
||||||
|
actualMS = 2000;
|
||||||
|
} else if(maxMS >= 1000) {
|
||||||
|
wdto = WDTO_1S;
|
||||||
|
actualMS = 1000;
|
||||||
|
} else if(maxMS >= 500) {
|
||||||
|
wdto = WDTO_500MS;
|
||||||
|
actualMS = 500;
|
||||||
|
} else if(maxMS >= 250) {
|
||||||
|
wdto = WDTO_250MS;
|
||||||
|
actualMS = 250;
|
||||||
|
} else if(maxMS >= 120) {
|
||||||
|
wdto = WDTO_120MS;
|
||||||
|
actualMS = 120;
|
||||||
|
} else if(maxMS >= 60) {
|
||||||
|
wdto = WDTO_60MS;
|
||||||
|
actualMS = 60;
|
||||||
|
} else if(maxMS >= 30) {
|
||||||
|
wdto = WDTO_30MS;
|
||||||
|
actualMS = 30;
|
||||||
|
} else {
|
||||||
|
wdto = WDTO_15MS;
|
||||||
|
actualMS = 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef WATCHDOGAVR_H
|
||||||
|
#define WATCHDOGAVR_H
|
||||||
|
|
||||||
|
class WatchdogAVR {
|
||||||
|
public:
|
||||||
|
WatchdogAVR():
|
||||||
|
_wdto(-1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Enable the watchdog timer to reset the machine after a period of time
|
||||||
|
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value.
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||||
|
// returned.
|
||||||
|
int enable(int maxPeriodMS = 0);
|
||||||
|
|
||||||
|
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Completely disable the watchdog timer.
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||||
|
// desired period of time. The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||||
|
// returned.
|
||||||
|
int sleep(int maxPeriodMS = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Pick the closest (but not higher) watchdog timer value from the provided
|
||||||
|
// maximum period. Sets wdto to the chosen period value suitable for
|
||||||
|
// passing to wdt_enable(), and actualMS to the chosen period value in
|
||||||
|
// milliseconds. A max value of 0 will pick the longest value possible.
|
||||||
|
void _setPeriod(int maxMS, int &wdto, int &actualMS);
|
||||||
|
|
||||||
|
// Keep the last selected watchdog timer period so that the watchdog can be
|
||||||
|
// re-enabled at that rate after sleep. A value of -1 means no watchdog
|
||||||
|
// timer was enabled.
|
||||||
|
int _wdto;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
// Be careful to use a platform-specific conditional include to only make the
|
||||||
|
// code visible for the appropriate platform. Arduino will try to compile and
|
||||||
|
// link all .cpp files regardless of platform.
|
||||||
|
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||||
|
|
||||||
|
#include <kinetis.h>
|
||||||
|
#include "WatchdogKinetisK.h"
|
||||||
|
|
||||||
|
static void one_bus_cycle(void) __attribute__((always_inline));
|
||||||
|
static void watchdog_config(int cfg, int val);
|
||||||
|
|
||||||
|
// Enable the watchdog timer to reset the machine after a period of time
|
||||||
|
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value.
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||||
|
// returned.
|
||||||
|
int WatchdogKinetisKseries::enable(int maxPeriodMS)
|
||||||
|
{
|
||||||
|
if (maxPeriodMS < 4) {
|
||||||
|
maxPeriodMS = 8000; // default is 8 seconds
|
||||||
|
}
|
||||||
|
if (setting != maxPeriodMS) {
|
||||||
|
watchdog_config(WDOG_STCTRLH_WDOGEN, maxPeriodMS);
|
||||||
|
setting = maxPeriodMS;
|
||||||
|
}
|
||||||
|
return maxPeriodMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||||
|
void WatchdogKinetisKseries::reset()
|
||||||
|
{
|
||||||
|
__disable_irq();
|
||||||
|
WDOG_REFRESH = 0xA602;
|
||||||
|
WDOG_REFRESH = 0xB480;
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Completely disable the watchdog timer.
|
||||||
|
void WatchdogKinetisKseries::disable()
|
||||||
|
{
|
||||||
|
if (setting > 0) {
|
||||||
|
watchdog_config(0, 4);
|
||||||
|
setting = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter the lowest power sleep mode for the desired period of time. The
|
||||||
|
// passed in period (in milliseconds) is just a suggestion and a lower value
|
||||||
|
// might be picked if the hardware does not support the exact desired value
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||||
|
// returned.
|
||||||
|
int WatchdogKinetisKseries::sleep(int maxPeriodMS)
|
||||||
|
{
|
||||||
|
if (maxPeriodMS <= 0) return 0;
|
||||||
|
// TODO....
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void watchdog_config(int cfg, int val)
|
||||||
|
{
|
||||||
|
__disable_irq();
|
||||||
|
WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
|
||||||
|
WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
|
||||||
|
one_bus_cycle();
|
||||||
|
WDOG_STCTRLH = cfg | WDOG_STCTRLH_ALLOWUPDATE;
|
||||||
|
WDOG_TOVALH = val >> 16;
|
||||||
|
WDOG_TOVALL = val;
|
||||||
|
WDOG_PRESC = 0;
|
||||||
|
__enable_irq();
|
||||||
|
for (int i=0; i < 256; i++) {
|
||||||
|
one_bus_cycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void one_bus_cycle(void)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#if (F_CPU / F_BUS) > 1
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#endif
|
||||||
|
#if (F_CPU / F_BUS) > 2
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#endif
|
||||||
|
#if (F_CPU / F_BUS) > 3
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#endif
|
||||||
|
#if (F_CPU / F_BUS) > 4
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#endif
|
||||||
|
#if (F_CPU / F_BUS) > 5
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#endif
|
||||||
|
#if (F_CPU / F_BUS) > 6
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#endif
|
||||||
|
#if (F_CPU / F_BUS) > 7
|
||||||
|
__asm__ volatile ("nop");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef WATCHDOGKINETISK_H
|
||||||
|
#define WATCHDOGKINETISK_H
|
||||||
|
|
||||||
|
class WatchdogKinetisKseries {
|
||||||
|
public:
|
||||||
|
WatchdogKinetisKseries(): setting(0) {}
|
||||||
|
|
||||||
|
// Enable the watchdog timer to reset the machine after a period of time
|
||||||
|
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value.
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||||
|
// returned.
|
||||||
|
int enable(int maxPeriodMS = 0);
|
||||||
|
|
||||||
|
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Completely disable the watchdog timer.
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||||
|
// desired period of time. The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||||
|
// returned.
|
||||||
|
//
|
||||||
|
// NOTE: This is currently not implemented on the SAMD21!
|
||||||
|
int sleep(int maxPeriodMS = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int setting;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Be careful to use a platform-specific conditional include to only make the
|
||||||
|
// code visible for the appropriate platform. Arduino will try to compile and
|
||||||
|
// link all .cpp files regardless of platform.
|
||||||
|
#if defined(__MKL26Z64__)
|
||||||
|
|
||||||
|
#include <kinetis.h>
|
||||||
|
#include "WatchdogKinetisL.h"
|
||||||
|
|
||||||
|
// Normally the watchdog is disabled at startup. This removes the startup
|
||||||
|
// code. The watchdog will be active with 1024 ms timeout. Hopefully the
|
||||||
|
// user will configure the watchdog and begin resetting it before it causes
|
||||||
|
// a reboot. There is no way to start up without the watchdog and then
|
||||||
|
// enable it later...
|
||||||
|
extern "C" void startup_early_hook(void) {}
|
||||||
|
|
||||||
|
|
||||||
|
// Enable the watchdog timer to reset the machine after a period of time
|
||||||
|
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value.
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||||
|
// returned.
|
||||||
|
int WatchdogKinetisLseries::enable(int maxPeriodMS)
|
||||||
|
{
|
||||||
|
// The watchdog can only be programmed once. Then it's forever
|
||||||
|
// locked to this setting (until the chip reboots).
|
||||||
|
if (maxPeriodMS <= 0 || maxPeriodMS > 256) {
|
||||||
|
SIM_COPC = 12;
|
||||||
|
} else if (maxPeriodMS > 32) {
|
||||||
|
SIM_COPC = 8;
|
||||||
|
} else {
|
||||||
|
SIM_COPC = 4;
|
||||||
|
}
|
||||||
|
// Read the actual setting.
|
||||||
|
int val = SIM_COPC & 12;
|
||||||
|
if (val == 12) return 1024;
|
||||||
|
if (val == 8) return 256;
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||||
|
void WatchdogKinetisLseries::reset()
|
||||||
|
{
|
||||||
|
__disable_irq();
|
||||||
|
SIM_SRVCOP = 0x55;
|
||||||
|
SIM_SRVCOP = 0xAA;
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Completely disable the watchdog timer.
|
||||||
|
void WatchdogKinetisLseries::disable()
|
||||||
|
{
|
||||||
|
// no can do....
|
||||||
|
// The watchdog timer in this chip is write-once.
|
||||||
|
// The chip boots up with the watchdog at 1024 ms.
|
||||||
|
// You only get to configure it once. Then it
|
||||||
|
// remains locked to that setting, until a reboot.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter the lowest power sleep mode for the desired period of time. The
|
||||||
|
// passed in period (in milliseconds) is just a suggestion and a lower value
|
||||||
|
// might be picked if the hardware does not support the exact desired value
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||||
|
// returned.
|
||||||
|
int WatchdogKinetisLseries::sleep(int maxPeriodMS)
|
||||||
|
{
|
||||||
|
if (maxPeriodMS <= 0) return 0;
|
||||||
|
// TODO....
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef WATCHDOGKINETISL_H
|
||||||
|
#define WATCHDOGKINETISL_H
|
||||||
|
|
||||||
|
class WatchdogKinetisLseries {
|
||||||
|
public:
|
||||||
|
WatchdogKinetisLseries() {}
|
||||||
|
|
||||||
|
// Enable the watchdog timer to reset the machine after a period of time
|
||||||
|
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value.
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||||
|
// returned.
|
||||||
|
int enable(int maxPeriodMS = 0);
|
||||||
|
|
||||||
|
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Completely disable the watchdog timer.
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||||
|
// desired period of time. The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware does
|
||||||
|
// not support the exact desired value
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||||
|
// returned.
|
||||||
|
//
|
||||||
|
// NOTE: This is currently not implemented on the SAMD21!
|
||||||
|
int sleep(int maxPeriodMS = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,240 @@
|
||||||
|
// Requires Adafruit_ASFcore library!
|
||||||
|
|
||||||
|
// Be careful to use a platform-specific conditional include to only make the
|
||||||
|
// code visible for the appropriate platform. Arduino will try to compile and
|
||||||
|
// link all .cpp files regardless of platform.
|
||||||
|
#if defined(ARDUINO_ARCH_SAMD)
|
||||||
|
|
||||||
|
#include <sam.h>
|
||||||
|
#include "WatchdogSAMD.h"
|
||||||
|
|
||||||
|
int WatchdogSAMD::enable(int maxPeriodMS, bool isForSleep) {
|
||||||
|
// Enable the watchdog with a period up to the specified max period in
|
||||||
|
// milliseconds.
|
||||||
|
|
||||||
|
// Review the watchdog section from the SAMD21 datasheet section 17:
|
||||||
|
// http://www.atmel.com/images/atmel-42181-sam-d21_datasheet.pdf
|
||||||
|
|
||||||
|
int cycles;
|
||||||
|
uint8_t bits;
|
||||||
|
|
||||||
|
if(!_initialized) _initialize_wdt();
|
||||||
|
|
||||||
|
#if defined(__SAMD51__)
|
||||||
|
WDT->CTRLA.reg = 0; // Disable watchdog for config
|
||||||
|
while(WDT->SYNCBUSY.reg);
|
||||||
|
#else
|
||||||
|
WDT->CTRL.reg = 0; // Disable watchdog for config
|
||||||
|
while(WDT->STATUS.bit.SYNCBUSY);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// You'll see some occasional conversion here compensating between
|
||||||
|
// milliseconds (1000 Hz) and WDT clock cycles (~1024 Hz). The low-
|
||||||
|
// power oscillator used by the WDT ostensibly runs at 32,768 Hz with
|
||||||
|
// a 1:32 prescale, thus 1024 Hz, though probably not super precise.
|
||||||
|
|
||||||
|
if((maxPeriodMS >= 16000) || !maxPeriodMS) {
|
||||||
|
cycles = 16384;
|
||||||
|
bits = 0xB;
|
||||||
|
} else {
|
||||||
|
cycles = (maxPeriodMS * 1024L + 500) / 1000; // ms -> WDT cycles
|
||||||
|
if(cycles >= 8192) {
|
||||||
|
cycles = 8192;
|
||||||
|
bits = 0xA;
|
||||||
|
} else if(cycles >= 4096) {
|
||||||
|
cycles = 4096;
|
||||||
|
bits = 0x9;
|
||||||
|
} else if(cycles >= 2048) {
|
||||||
|
cycles = 2048;
|
||||||
|
bits = 0x8;
|
||||||
|
} else if(cycles >= 1024) {
|
||||||
|
cycles = 1024;
|
||||||
|
bits = 0x7;
|
||||||
|
} else if(cycles >= 512) {
|
||||||
|
cycles = 512;
|
||||||
|
bits = 0x6;
|
||||||
|
} else if(cycles >= 256) {
|
||||||
|
cycles = 256;
|
||||||
|
bits = 0x5;
|
||||||
|
} else if(cycles >= 128) {
|
||||||
|
cycles = 128;
|
||||||
|
bits = 0x4;
|
||||||
|
} else if(cycles >= 64) {
|
||||||
|
cycles = 64;
|
||||||
|
bits = 0x3;
|
||||||
|
} else if(cycles >= 32) {
|
||||||
|
cycles = 32;
|
||||||
|
bits = 0x2;
|
||||||
|
} else if(cycles >= 16) {
|
||||||
|
cycles = 16;
|
||||||
|
bits = 0x1;
|
||||||
|
} else {
|
||||||
|
cycles = 8;
|
||||||
|
bits = 0x0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watchdog timer on SAMD is a slightly different animal than on AVR.
|
||||||
|
// On AVR, the WTD timeout is configured in one register and then an
|
||||||
|
// interrupt can optionally be enabled to handle the timeout in code
|
||||||
|
// (as in waking from sleep) vs resetting the chip. Easy.
|
||||||
|
// On SAMD, when the WDT fires, that's it, the chip's getting reset.
|
||||||
|
// Instead, it has an "early warning interrupt" with a different set
|
||||||
|
// interval prior to the reset. For equivalent behavior to the AVR
|
||||||
|
// library, this requires a slightly different configuration depending
|
||||||
|
// whether we're coming from the sleep() function (which needs the
|
||||||
|
// interrupt), or just enable() (no interrupt, we want the chip reset
|
||||||
|
// unless the WDT is cleared first). In the sleep case, 'windowed'
|
||||||
|
// mode is used in order to allow access to the longest available
|
||||||
|
// sleep interval (about 16 sec); the WDT 'period' (when a reset
|
||||||
|
// occurs) follows this and is always just set to the max, since the
|
||||||
|
// interrupt will trigger first. In the enable case, windowed mode
|
||||||
|
// is not used, the WDT period is set and that's that.
|
||||||
|
// The 'isForSleep' argument determines which behavior is used;
|
||||||
|
// this isn't present in the AVR code, just here. It defaults to
|
||||||
|
// 'false' so existing Arduino code works as normal, while the sleep()
|
||||||
|
// function (later in this file) explicitly passes 'true' to get the
|
||||||
|
// alternate behavior.
|
||||||
|
|
||||||
|
#if defined(__SAMD51__)
|
||||||
|
if(isForSleep) {
|
||||||
|
WDT->INTENSET.bit.EW = 1; // Enable early warning interrupt
|
||||||
|
WDT->CONFIG.bit.PER = 0xB; // Period = max
|
||||||
|
WDT->CONFIG.bit.WINDOW = bits; // Set time of interrupt
|
||||||
|
WDT->CTRLA.bit.WEN = 1; // Enable window mode
|
||||||
|
while(WDT->SYNCBUSY.reg); // Sync CTRL write
|
||||||
|
} else {
|
||||||
|
WDT->INTENCLR.bit.EW = 1; // Disable early warning interrupt
|
||||||
|
WDT->CONFIG.bit.PER = bits; // Set period for chip reset
|
||||||
|
WDT->CTRLA.bit.WEN = 0; // Disable window mode
|
||||||
|
while(WDT->SYNCBUSY.reg); // Sync CTRL write
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(); // Clear watchdog interval
|
||||||
|
WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now!
|
||||||
|
while(WDT->SYNCBUSY.reg);
|
||||||
|
#else
|
||||||
|
if(isForSleep) {
|
||||||
|
WDT->INTENSET.bit.EW = 1; // Enable early warning interrupt
|
||||||
|
WDT->CONFIG.bit.PER = 0xB; // Period = max
|
||||||
|
WDT->CONFIG.bit.WINDOW = bits; // Set time of interrupt
|
||||||
|
WDT->CTRL.bit.WEN = 1; // Enable window mode
|
||||||
|
while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write
|
||||||
|
} else {
|
||||||
|
WDT->INTENCLR.bit.EW = 1; // Disable early warning interrupt
|
||||||
|
WDT->CONFIG.bit.PER = bits; // Set period for chip reset
|
||||||
|
WDT->CTRL.bit.WEN = 0; // Disable window mode
|
||||||
|
while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(); // Clear watchdog interval
|
||||||
|
WDT->CTRL.bit.ENABLE = 1; // Start watchdog now!
|
||||||
|
while(WDT->STATUS.bit.SYNCBUSY);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (cycles * 1000L + 512) / 1024; // WDT cycles -> ms
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchdogSAMD::reset() {
|
||||||
|
// Write the watchdog clear key value (0xA5) to the watchdog
|
||||||
|
// clear register to clear the watchdog timer and reset it.
|
||||||
|
WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
|
||||||
|
#if defined(__SAMD51__)
|
||||||
|
while(WDT->SYNCBUSY.reg);
|
||||||
|
#else
|
||||||
|
while(WDT->STATUS.bit.SYNCBUSY);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchdogSAMD::disable() {
|
||||||
|
#if defined(__SAMD51__)
|
||||||
|
WDT->CTRLA.bit.ENABLE = 0;
|
||||||
|
while(WDT->SYNCBUSY.reg);
|
||||||
|
#else
|
||||||
|
WDT->CTRL.bit.ENABLE = 0;
|
||||||
|
while(WDT->STATUS.bit.SYNCBUSY);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void WDT_Handler(void) {
|
||||||
|
// ISR for watchdog early warning, DO NOT RENAME!
|
||||||
|
#if defined(__SAMD51__)
|
||||||
|
WDT->CTRLA.bit.ENABLE = 0; // Disable watchdog
|
||||||
|
while(WDT->SYNCBUSY.reg);
|
||||||
|
#else
|
||||||
|
WDT->CTRL.bit.ENABLE = 0; // Disable watchdog
|
||||||
|
while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write
|
||||||
|
|
||||||
|
#endif
|
||||||
|
WDT->INTFLAG.bit.EW = 1; // Clear interrupt flag
|
||||||
|
}
|
||||||
|
|
||||||
|
int WatchdogSAMD::sleep(int maxPeriodMS) {
|
||||||
|
|
||||||
|
int actualPeriodMS = enable(maxPeriodMS, true); // true = for sleep
|
||||||
|
|
||||||
|
// Enable standby sleep mode (deepest sleep) and activate.
|
||||||
|
// Insights from Atmel ASF library.
|
||||||
|
#if (SAMD20 || SAMD21)
|
||||||
|
// Don't fully power down flash when in sleep
|
||||||
|
NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;
|
||||||
|
#endif
|
||||||
|
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
|
||||||
|
|
||||||
|
__DSB(); // Data sync to ensure outgoing memory accesses complete
|
||||||
|
__WFI(); // Wait for interrupt (places device in sleep mode)
|
||||||
|
|
||||||
|
// Code resumes here on wake (WDT early warning interrupt).
|
||||||
|
// Bug: the return value assumes the WDT has run its course;
|
||||||
|
// incorrect if the device woke due to an external interrupt.
|
||||||
|
// Without an external RTC there's no way to provide a correct
|
||||||
|
// sleep period in the latter case...but at the very least,
|
||||||
|
// might indicate said condition occurred by returning 0 instead
|
||||||
|
// (assuming we can pin down which interrupt caused the wake).
|
||||||
|
|
||||||
|
return actualPeriodMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchdogSAMD::_initialize_wdt() {
|
||||||
|
// One-time initialization of watchdog timer.
|
||||||
|
// Insights from rickrlh and rbrucemtl in Arduino forum!
|
||||||
|
|
||||||
|
#if defined(__SAMD51__)
|
||||||
|
// SAMD51 WDT uses OSCULP32k as input clock now
|
||||||
|
// section: 20.5.3
|
||||||
|
OSC32KCTRL->OSCULP32K.reg =
|
||||||
|
OSC32KCTRL_OSCULP32K_EN1K | OSC32KCTRL_OSCULP32K_EN32K;
|
||||||
|
|
||||||
|
// Enable WDT early-warning interrupt
|
||||||
|
NVIC_DisableIRQ(WDT_IRQn);
|
||||||
|
NVIC_ClearPendingIRQ(WDT_IRQn);
|
||||||
|
NVIC_SetPriority(WDT_IRQn, 0); // Top priority
|
||||||
|
NVIC_EnableIRQ(WDT_IRQn);
|
||||||
|
|
||||||
|
while(WDT->SYNCBUSY.reg);
|
||||||
|
#else
|
||||||
|
// Generic clock generator 2, divisor = 32 (2^(DIV+1))
|
||||||
|
GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4);
|
||||||
|
// Enable clock generator 2 using low-power 32KHz oscillator.
|
||||||
|
// With /32 divisor above, this yields 1024Hz(ish) clock.
|
||||||
|
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) |
|
||||||
|
GCLK_GENCTRL_GENEN |
|
||||||
|
GCLK_GENCTRL_SRC_OSCULP32K |
|
||||||
|
GCLK_GENCTRL_DIVSEL;
|
||||||
|
while(GCLK->STATUS.bit.SYNCBUSY);
|
||||||
|
// WDT clock = clock gen 2
|
||||||
|
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_WDT |
|
||||||
|
GCLK_CLKCTRL_CLKEN |
|
||||||
|
GCLK_CLKCTRL_GEN_GCLK2;
|
||||||
|
|
||||||
|
// Enable WDT early-warning interrupt
|
||||||
|
NVIC_DisableIRQ(WDT_IRQn);
|
||||||
|
NVIC_ClearPendingIRQ(WDT_IRQn);
|
||||||
|
NVIC_SetPriority(WDT_IRQn, 0); // Top priority
|
||||||
|
NVIC_EnableIRQ(WDT_IRQn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(ARDUINO_ARCH_SAMD)
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef WATCHDOGSAMD_H
|
||||||
|
#define WATCHDOGSAMD_H
|
||||||
|
|
||||||
|
class WatchdogSAMD {
|
||||||
|
public:
|
||||||
|
WatchdogSAMD():
|
||||||
|
_initialized(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Enable the watchdog timer to reset the machine after a period of time
|
||||||
|
// without any calls to reset(). The passed in period (in milliseconds)
|
||||||
|
// is just a suggestion and a lower value might be picked if the hardware
|
||||||
|
// does not support the exact desired value.
|
||||||
|
// User code should NOT set the 'isForSleep' argument either way --
|
||||||
|
// it's used internally by the library, but your sketch should leave this
|
||||||
|
// out when calling enable(), just let the default have its way.
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||||
|
// returned.
|
||||||
|
int enable(int maxPeriodMS = 0, bool isForSleep = false);
|
||||||
|
|
||||||
|
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Completely disable the watchdog timer.
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||||
|
// desired period of time. The passed in period (in milliseconds) is
|
||||||
|
// just a suggestion and a lower value might be picked if the hardware
|
||||||
|
// does not support the exact desired value
|
||||||
|
//
|
||||||
|
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||||
|
// returned.
|
||||||
|
int sleep(int maxPeriodMS = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _initialize_wdt();
|
||||||
|
|
||||||
|
bool _initialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,364 @@
|
||||||
|
PinChangeInterrupt Library 1.2.6
|
||||||
|
================================
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
PinChangeInterrupt library with a resource friendly implementation (API and LowLevel).
|
||||||
|
PinChangeInterrupts are different than normal Interrupts. See detail below.
|
||||||
|
|
||||||
|
##### Features:
|
||||||
|
* PinChangeInterrupt for a lot of pins
|
||||||
|
* Rising, Falling or Change detection for every pin separately
|
||||||
|
* Usable on a lot Arduino compatible boards
|
||||||
|
* Implementation is fast, compact and resource friendly
|
||||||
|
* Ports/Pins can be manually deactivated in the Settings file
|
||||||
|
* API and LowLevel option
|
||||||
|
* Full Port0-3 support
|
||||||
|
* .a linkage optimization (Arduino IDE)
|
||||||
|
|
||||||
|
#### Supported pins for PinChangeInterrupt:
|
||||||
|
See [PCINT pin table](https://github.com/NicoHood/PinChangeInterrupt/#pinchangeinterrupt-table) at the bottom for more details.
|
||||||
|
|
||||||
|
```
|
||||||
|
Arduino Uno/Nano/Mini: All pins are usable
|
||||||
|
Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64),
|
||||||
|
A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)
|
||||||
|
Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI)
|
||||||
|
HoodLoader2: All (broken out 1-7) pins are usable
|
||||||
|
Attiny 24/44/84: All pins are usable
|
||||||
|
Attiny 25/45/85: All pins are usable
|
||||||
|
Attiny 13: All pins are usable
|
||||||
|
Attiny 441/841: All pins are usable
|
||||||
|
ATmega644P/ATmega1284P: All pins are usable
|
||||||
|
```
|
||||||
|
|
||||||
|
Contact information can be found here:
|
||||||
|
|
||||||
|
www.nicohood.de
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Download the zip, extract and remove the "-master" of the folder.
|
||||||
|
Install the library [as described here](http://arduino.cc/en/pmwiki.php?n=Guide/Libraries).
|
||||||
|
|
||||||
|
This library can also be used with the [DMBS AVR Library Collection](https://github.com/NicoHood/avr) and a pure makefile.
|
||||||
|
|
||||||
|
How to use
|
||||||
|
==========
|
||||||
|
|
||||||
|
It is important that you know at least the basic difference between **PinInterrupts** and **PinChangeInterrupts**.
|
||||||
|
I will explain the basics of **PinChangeInterrupts** (PCINTs) based on an Arduino Uno.
|
||||||
|
|
||||||
|
On a standard Arduino Uno Pin 2 and 3 have **PinInterrupts**. Those are exclusively for a single pin and can detect RISING, FALLING and CHANGE.
|
||||||
|
|
||||||
|
**PinChangeInterrupts** instead are used for a whole port (they should have better named them PortChangeInterrupts) and can only detect CHANGE for a whole port.
|
||||||
|
Each pin row (0-7, 8-13, A0-A5) represents a port. If an interrupt (ISR) occurs on one pin of a port
|
||||||
|
it is still unclear what pin of the port caused this interrupt. Therefore this library saves the state of the whole port and compares with the last state.
|
||||||
|
This way we can also see if it was a RISING or FALLING edge instead of only knowing the CHANGE.
|
||||||
|
|
||||||
|
A **PinChangeInterrupt** will only be triggered for the attached pins per port.
|
||||||
|
Meaning if you set PCINT for a pin and another pin on the same port is changing a lot
|
||||||
|
it will not interrupt your code.
|
||||||
|
|
||||||
|
**PinChangeInterrupts** might be a tiny bit slower and not that reliable because of that detection overhead (talking about micro seconds).
|
||||||
|
Make sure to not use longer function calls inside the ISR or Serial print.
|
||||||
|
You have the same issues on normal **PinInterrupts** and interrupts in general.
|
||||||
|
|
||||||
|
The library is coded to get maximum speed and minimum code size. The LowLevel example without the API takes 4uS to enter the interrupt function in the worst case
|
||||||
|
which is pretty good and might be even better than the **PinInterrupt** code from the official Arduino core due to high optimization.
|
||||||
|
If you need very precise interrupts you better use **PinInterrupts** without the Arduino IDE at all.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
To see how the code works just check the Led and TickTock example.
|
||||||
|
The LowLevel example is for advanced users with more optimization and more direct access.
|
||||||
|
The HowItWorks example shows the basic PinChangeInterrupt setup and decoding routine, similar to the library.
|
||||||
|
See the notes in the examples about more details.
|
||||||
|
|
||||||
|
An useful "real use" example of the PinChangeInterrupt library can be found here:
|
||||||
|
https://github.com/NicoHood/IRLremote
|
||||||
|
|
||||||
|
### API Reference
|
||||||
|
|
||||||
|
##### Attach a PinChangeInterrupt
|
||||||
|
```cpp
|
||||||
|
// The pin has to be a PCINT number. Use the makro to convert a pin to a PCINT number.
|
||||||
|
// Enables event functions which need to be defined in the sketch.
|
||||||
|
// Valid interrupt modes are: RISING, FALLING or CHANGE
|
||||||
|
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING);
|
||||||
|
|
||||||
|
// You can also input the PCINT number (see table below)
|
||||||
|
attachPinChangeInterrupt(5, tock, FALLING);
|
||||||
|
|
||||||
|
// PinChangeInterrupt can always be abbreviated with PCINT
|
||||||
|
attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE);
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Detach a PinChangeInterrupt
|
||||||
|
```cpp
|
||||||
|
// Similar usage as the attachPCINT function.
|
||||||
|
// Interrupts will no longer occur.
|
||||||
|
detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
|
||||||
|
detachPinChangeInterrupt(5);
|
||||||
|
detachPCINT(digitalPinToPCINT(pinTock));
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Enable/Disable a PinChangeInterrupt
|
||||||
|
```cpp
|
||||||
|
// Similar usage as the attachPCINT function.
|
||||||
|
// Use this to temporary enable/disable the Interrupt
|
||||||
|
disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
|
||||||
|
disablePinChangeInterrupt(5);
|
||||||
|
disablePCINT(digitalPinToPCINT(pinBlink));
|
||||||
|
|
||||||
|
// Enable the PCINT with the old settings again (function + mode)
|
||||||
|
enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
|
||||||
|
enablePinChangeInterrupt(5);
|
||||||
|
enablePCINT(digitalPinToPCINT(pinBlink));
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Get Trigger on mode CHANGE
|
||||||
|
```cpp
|
||||||
|
// Differenciate between RISING and FALLING on mode CHANGE.
|
||||||
|
// Only use this in the attached interrupt function.
|
||||||
|
uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(pinTick));
|
||||||
|
if(trigger == RISING)
|
||||||
|
// Do something
|
||||||
|
else if(trigger == FALLING)
|
||||||
|
// Do something
|
||||||
|
else
|
||||||
|
// Wrong usage (trigger == CHANGE)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### LowLevel API
|
||||||
|
See [LowLevel example](examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino) for more details.
|
||||||
|
```cpp
|
||||||
|
// Use the attach function as you are used to, just leave out the function name
|
||||||
|
attachPinChangeInterrupt(interruptBlink, CHANGE);
|
||||||
|
|
||||||
|
// LowLevel function that is called when an interrupt occurs for a specific PCINT.
|
||||||
|
// It is required to know the exact PCINT number, no Arduino pin number will work here.
|
||||||
|
void PinChangeInterruptEvent(5)(void) {
|
||||||
|
// Do something
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
PinchangeInterrupt Table
|
||||||
|
========================
|
||||||
|
Pins with * are not broken out/deactivated by default.
|
||||||
|
You may activate them in the setting file (advanced).
|
||||||
|
|
||||||
|
Each row section represents a port(0-3).
|
||||||
|
Not all MCUs have all Ports/Pins physically available.
|
||||||
|
|
||||||
|
#### Official Arduinos
|
||||||
|
```
|
||||||
|
| PCINT | Uno/Nano/Mini | Mega/2560 | Leonardo/Micro | HL2 (8/16/32u2) |
|
||||||
|
| ----- | --------------- | -------------- | -------------- | --------------- |
|
||||||
|
| 0 | 8 (PB0) | 53 SS (PB0) | SS (PB0)* | 0 SS (PB0)* |
|
||||||
|
| 1 | 9 (PB1) | 52 SCK (PB1) | SCK (PB1) | 1 SCK (PB1) |
|
||||||
|
| 2 | 10 SS (PB2) | 51 MOSI (PB2) | MOSI (PB2) | 2 MOSI (PB2) |
|
||||||
|
| 3 | 11 MISO (PB3) | 50 MISO (PB3) | MISO (PB3) | 3 MISO (PB3) |
|
||||||
|
| 4 | 12 MOSI (PB4) | 10 (PB4) | 8/A8 (PB4) | 4 (PB4) |
|
||||||
|
| 5 | 13 SCK (PB5) | 11 (PB5) | 9/A9 (PB5) | 5 (PB5) |
|
||||||
|
| 6 | XTAL1 (PB6)* | 12 (PB6) | 10/A10 (PB6) | 6 (PB6) |
|
||||||
|
| 7 | XTAL2 (PB7)* | 13 (PB7) | 11 (PB7) | 7 (PB7) |
|
||||||
|
| ----- | --------------- | -------------- | -------------- | --------------- |
|
||||||
|
| 8 | A0 (PC0) | 0 RX (PE0)* | | (PC6)* |
|
||||||
|
| 9 | A1 (PC1) | 15 RX3 (PJ0)* | | (PC5)* |
|
||||||
|
| 10 | A2 (PC2) | 14 TX3 (PJ1)* | | (PC4)* |
|
||||||
|
| 11 | A3 (PC3) | NC (PJ2)* | | (PC2)* |
|
||||||
|
| 12 | A4 SDA (PC4) | NC (PJ3)* | | (PD5)* |
|
||||||
|
| 13 | A5 SDC (PC5) | NC (PJ4)* | | |
|
||||||
|
| 14 | RST (PC6)* | NC (PJ5)* | | |
|
||||||
|
| 15 | | NC (PJ6)* | | |
|
||||||
|
| ----- | --------------- | -------------- | -------------- | --------------- |
|
||||||
|
| 16 | 0 RX (PD0) | A8 (PK0) | | |
|
||||||
|
| 17 | 1 TX (PD1) | A9 (PK1) | | |
|
||||||
|
| 18 | 2 INT0 (PD2) | A10 (PK2) | | |
|
||||||
|
| 19 | 3 INT1 (PD3) | A11 (PK3) | | |
|
||||||
|
| 20 | 4 (PD4) | A12 (PK4) | | |
|
||||||
|
| 21 | 5 (PD5) | A13 (PK5) | | |
|
||||||
|
| 22 | 6 (PD6) | A14 (PK6) | | |
|
||||||
|
| 23 | 7 (PD7) | A15 (PK7) | | |
|
||||||
|
| ----- | --------------- | -------------- | -------------- | --------------- |
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Atmel Attinys
|
||||||
|
```
|
||||||
|
| PCINT | Attiny13 | Attiny x4 | Attiny x5 | Attiny x41 |
|
||||||
|
| ----- | ------------ | --------------- | ------------- | ------------------- |
|
||||||
|
| 0 | 0 MOSI (PB0) | 0 (PA0) | 0 MOSI (PB0) | A0/D0 (PA0) |
|
||||||
|
| 1 | 1 MISO (PB1) | 1 (PA1) | 1 MISO (PB1) | A1/D1 (PA1) |
|
||||||
|
| 2 | 2 SCK (PB2) | 2 (PA2) | 2 SCK (PB2) | A2/D2 (PA2) |
|
||||||
|
| 3 | 3 (PB3) | 3 (PA3) | 3 XTAL1 (PB3) | A3/D3 (PA3) |
|
||||||
|
| 4 | 4 (PB4) | 4 SCK (PA4) | 4 XTAL2 (PB4) | A4/D4 (PA4) |
|
||||||
|
| 5 | 5 RST (PB5) | 5 MISO (PA5) | 5 RST (PB5) | A5/D5 PWM (PA5) |
|
||||||
|
| 6 | | 6 MOSI (PA6) | | A7/D7 PWM (PA6) |
|
||||||
|
| 7 | | 7 (PA7) | | A6/D6 PWM (PA7) |
|
||||||
|
| ----- | ------------ | --------------- | ------------- | ------------------- |
|
||||||
|
| 8 | | 10 XTAL1 (PB0)* | | A10/D10 XTAL1 (PB0) |
|
||||||
|
| 9 | | 9 XTAL2 (PB1)* | | A9/D9 XTAL2 (PB1) |
|
||||||
|
| 10 | | 8 INT0 (PB2)* | | A8/D8 PWM (PB2) |
|
||||||
|
| 11 | | RST (PB3)* | | RST (PB3) |
|
||||||
|
| 12 | | | | |
|
||||||
|
| 13 | | | | |
|
||||||
|
| 14 | | | | |
|
||||||
|
| 15 | | | | |
|
||||||
|
| ----- | ------------ | --------------- | ------------- | ------------------- |
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Other Atmel MCUs
|
||||||
|
```
|
||||||
|
| PCINT | ATmega644P/1284P |
|
||||||
|
| ----- | ----------------- |
|
||||||
|
| 0 | A0/D24 (PA0) |
|
||||||
|
| 1 | A1/D25 (PA1) |
|
||||||
|
| 2 | A2/D26 (PA2) |
|
||||||
|
| 3 | A3/D27 (PA3) |
|
||||||
|
| 4 | A4/D28 (PA4) |
|
||||||
|
| 5 | A5/D29 (PA5) |
|
||||||
|
| 6 | A6/D30 (PA6) |
|
||||||
|
| 7 | A7/D31 (PA7) |
|
||||||
|
| ----- | ----------------- |
|
||||||
|
| 8 | 0 (PB0) |
|
||||||
|
| 9 | 1 (PB1) |
|
||||||
|
| 10 | 2 INT2 (PB2) |
|
||||||
|
| 11 | 3 PWM (PB3) |
|
||||||
|
| 12 | 4 SS/PWM (PB4) |
|
||||||
|
| 13 | 5 MOSI/PWM (PB5) |
|
||||||
|
| 14 | 6 MISO/PWM (PB6) |
|
||||||
|
| 15 | 7 SCK (PB7) |
|
||||||
|
| ----- | ----------------- |
|
||||||
|
| 16 | 16 SCL (PC0) |
|
||||||
|
| 17 | 17 SDA (PC1) |
|
||||||
|
| 18 | 18 TCK (PC2) |
|
||||||
|
| 19 | 19 TMS (PC3) |
|
||||||
|
| 20 | 20 TDO (PC4) |
|
||||||
|
| 21 | 21 TDI (PC5) |
|
||||||
|
| 22 | 22 (PC6) |
|
||||||
|
| 23 | 23 (PC7) |
|
||||||
|
| ----- | ----------------- |
|
||||||
|
| 24 | 8 RX0 (PD0) |
|
||||||
|
| 25 | 9 TX0 (PD1) |
|
||||||
|
| 26 | 10 RX1/INT0 (PD2) |
|
||||||
|
| 27 | 11 TX1/INT1 (PD3) |
|
||||||
|
| 28 | 12 PWM (PD4) |
|
||||||
|
| 29 | 13 PWM (PD5) |
|
||||||
|
| 30 | 14 PWM (PD6) |
|
||||||
|
| 31 | 15 PWM (PD7) |
|
||||||
|
| ----- | ----------------- |
|
||||||
|
```
|
||||||
|
|
||||||
|
Developer Information
|
||||||
|
=====================
|
||||||
|
If a PinChangeInterrupt occurs it will determine the triggered pin(s).
|
||||||
|
The library uses weak callback functions that are called for the triggered pins(s).
|
||||||
|
This way we can easily skip not triggered pins (I looked at the assembler) and also implement a fast LowLevel version.
|
||||||
|
|
||||||
|
Also the order of the function execution is (normally) ordered from the lower pin number to the higher.
|
||||||
|
Meaning pin 8 will be checked faster as pin 13 (Arduino Uno). Talking about micro seconds here! You can change the order in the settings.
|
||||||
|
For example by default pin 0-3 have a low priority order than pin 4-7 (Arduino Uno). Because they are used for Serial and normal PinInterrupts.
|
||||||
|
I don't expect anyone to use those pins at all with PCINT but at least the priority is lowered compared to the other pins.
|
||||||
|
|
||||||
|
The API takes those weak functions and just overwrites all of them and call the function pointers of the attached functions instead.
|
||||||
|
This way the function can be changed at runtime and its also easier to integrate into other libraries.
|
||||||
|
The function pointers take a bit flash though (LowLevel: 1526/18, API: 1790/58 for Led example).
|
||||||
|
|
||||||
|
You can get better performance and less code size if you deactivate the not used pins/ports manually in the settings file.
|
||||||
|
This way only the needed pins get compiled and the code is optimized by the preprocessor.
|
||||||
|
For a bit more comfortable/automatic optimization you can [install the library into the core](https://github.com/NicoHood/PinChangeInterrupt/#optional-installation)
|
||||||
|
to get use of the .a linkage. This way only the used ports get compiled.
|
||||||
|
So if you only use pins on a single port (eg 8-13) then only this port gets compiled. This only works with the core installation.
|
||||||
|
|
||||||
|
|
||||||
|
That's it! I hope you like the library. I tried to make it as simple and small as possible.
|
||||||
|
Keep in mind that PCINTs are not useful for every project but in most cases
|
||||||
|
the new PinChangeInterrupts may help you a lot.
|
||||||
|
|
||||||
|
|
||||||
|
Version History
|
||||||
|
===============
|
||||||
|
```
|
||||||
|
1.2.6 Release (10.02.2018)
|
||||||
|
* Fix makefile compilation problems
|
||||||
|
|
||||||
|
1.2.5 Release (02.09.2017)
|
||||||
|
* Fixed makefile compilation
|
||||||
|
* Added support to disable pcint/port via -DPCINT_DISABLE_PORT0 etc.
|
||||||
|
* Added ATtinyX313 support
|
||||||
|
* Fix ATmega1284P
|
||||||
|
|
||||||
|
1.2.4 Release (16.04.2016)
|
||||||
|
* Fixed Attinyx4/x5 Issue #8
|
||||||
|
|
||||||
|
1.2.3 Release (24.12.2015)
|
||||||
|
* Added Attiny441/841 support
|
||||||
|
|
||||||
|
1.2.2 Release (05.12.2015)
|
||||||
|
* Fixed initial value when enabled issue
|
||||||
|
* Enabled official dot_a_linkage
|
||||||
|
* Added Attiny13 support Issue #4
|
||||||
|
* Updated documentation
|
||||||
|
* Improved detaching function
|
||||||
|
* Improved attaching and enabling
|
||||||
|
|
||||||
|
1.2.1 Release (24.05.2015)
|
||||||
|
* Fix Attiny Issue #1
|
||||||
|
* Added enable/disable function
|
||||||
|
* Added getPinChangeInterruptTrigger() function
|
||||||
|
* Added to Arduino IDE library manager
|
||||||
|
|
||||||
|
1.2 Release (19.04.2015)
|
||||||
|
* Added weak interrupt function
|
||||||
|
* Improved interrupt function calls
|
||||||
|
* Fixed attach/detach array position when ports are deactivated
|
||||||
|
* Improved manual PCINT deactivation by user
|
||||||
|
* Improved definitions for different boards
|
||||||
|
* HoodLoader2 definition fixes
|
||||||
|
* Improved speed
|
||||||
|
* Improved specific boards
|
||||||
|
* Moved attach function to .cpp file
|
||||||
|
* Updated examples
|
||||||
|
* Added API and LowLevel
|
||||||
|
* Added Port3 support (ATmega644P/ATmega1284P)
|
||||||
|
* Added PCINT_VERSION definition
|
||||||
|
|
||||||
|
1.1 Release (06.12.2014)
|
||||||
|
* Added port deactivation
|
||||||
|
* Ram usage improvements for AVRs with <3 PCINT ports
|
||||||
|
|
||||||
|
1.0 Release (04.12.2014)
|
||||||
|
* Added general PinChangeInterrupt functions
|
||||||
|
* Added support for most Arduino boards
|
||||||
|
* Added basic example
|
||||||
|
* Added an example with IRLremote
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
License and Copyright
|
||||||
|
=====================
|
||||||
|
If you use this library for any cool project let me know!
|
||||||
|
|
||||||
|
```
|
||||||
|
Copyright (c) 2014-2018 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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.
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
PinChangeInterrupt_HowItWorks
|
||||||
|
Shows how to manually setup a single PCINT function with a few helper functions.
|
||||||
|
|
||||||
|
Connect a button/cable to pin 7 and ground.
|
||||||
|
The led will change its state if pin 7 changes.
|
||||||
|
|
||||||
|
PinChangeInterrupts are different than normal Interrupts.
|
||||||
|
See readme for more information.
|
||||||
|
Dont use Serial or delay inside interrupts!
|
||||||
|
This library is not compatible with SoftSerial.
|
||||||
|
|
||||||
|
The following pins are usable for PinChangeInterrupt:
|
||||||
|
Arduino Uno/Nano/Mini: All pins are usable
|
||||||
|
Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64),
|
||||||
|
A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)
|
||||||
|
Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI)
|
||||||
|
HoodLoader2: All (broken out 1-7) pins are usable
|
||||||
|
Attiny 24/44/84: All pins are usable
|
||||||
|
Attiny 25/45/85: All pins are usable
|
||||||
|
Attiny 13: All pins are usable
|
||||||
|
Attiny 441/841: All pins are usable
|
||||||
|
ATmega644P/ATmega1284P: All pins are usable
|
||||||
|
*/
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// User Settings
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// choose a valid PinChangeInterrupt pin of your Arduino board
|
||||||
|
#define PCINT_PIN 7
|
||||||
|
#define PCINT_MODE CHANGE
|
||||||
|
#define PCINT_FUNCTION blinkLed
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
// set pins to input with a pullup, led to output
|
||||||
|
pinMode(PCINT_PIN, INPUT_PULLUP);
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
|
// attach the new PinChangeInterrupt
|
||||||
|
attachPinChangeInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void blinkLed(void) {
|
||||||
|
// switch Led state
|
||||||
|
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// PCINT Definitions
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
#define PCMSK *digitalPinToPCMSK(PCINT_PIN)
|
||||||
|
#define PCINT digitalPinToPCMSKbit(PCINT_PIN)
|
||||||
|
#define PCIE digitalPinToPCICRbit(PCINT_PIN)
|
||||||
|
#define PCPIN *portInputRegister(digitalPinToPort(PCINT_PIN))
|
||||||
|
|
||||||
|
#if (PCIE == 0)
|
||||||
|
#define PCINT_vect PCINT0_vect
|
||||||
|
#elif (PCIE == 1)
|
||||||
|
#define PCINT_vect PCINT1_vect
|
||||||
|
#elif (PCIE == 2)
|
||||||
|
#define PCINT_vect PCINT2_vect
|
||||||
|
#else
|
||||||
|
#error This board doesnt support PCINT ?
|
||||||
|
#endif
|
||||||
|
|
||||||
|
volatile uint8_t oldPort = 0x00;
|
||||||
|
|
||||||
|
void attachPinChangeInterrupt(void) {
|
||||||
|
// update the old state to the actual state
|
||||||
|
oldPort = PCPIN;
|
||||||
|
|
||||||
|
// pin change mask registers decide which pins are enabled as triggers
|
||||||
|
PCMSK |= (1 << PCINT);
|
||||||
|
|
||||||
|
// PCICR: Pin Change Interrupt Control Register - enables interrupt vectors
|
||||||
|
PCICR |= (1 << PCIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void detachPinChangeInterrupt(void) {
|
||||||
|
// disable the mask.
|
||||||
|
PCMSK &= ~(1 << PCINT);
|
||||||
|
|
||||||
|
// if that's the last one, disable the interrupt.
|
||||||
|
if (PCMSK == 0)
|
||||||
|
PCICR &= ~(0x01 << PCIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(PCINT_vect) {
|
||||||
|
// get the new and old pin states for port
|
||||||
|
uint8_t newPort = PCPIN;
|
||||||
|
|
||||||
|
// compare with the old value to detect a rising or falling
|
||||||
|
uint8_t change = newPort ^ oldPort;
|
||||||
|
|
||||||
|
// check which pins are triggered, compared with the settings
|
||||||
|
uint8_t trigger = 0x00;
|
||||||
|
#if (PCINT_MODE == RISING) || (PCINT_MODE == CHANGE)
|
||||||
|
uint8_t rising = change & newPort;
|
||||||
|
trigger |= (rising & (1 << PCINT));
|
||||||
|
#endif
|
||||||
|
#if (PCINT_MODE == FALLING) || (PCINT_MODE == CHANGE)
|
||||||
|
uint8_t falling = change & oldPort;
|
||||||
|
trigger |= (falling & (1 << PCINT));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// save the new state for next comparison
|
||||||
|
oldPort = newPort;
|
||||||
|
|
||||||
|
// if our needed pin has changed, call the IRL interrupt function
|
||||||
|
if (trigger & (1 << PCINT))
|
||||||
|
PCINT_FUNCTION();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
PinChangeInterrupt_TickTock
|
||||||
|
Demonstrates how to use the library
|
||||||
|
|
||||||
|
Connect a button/cable to pin 7 and ground.
|
||||||
|
The Led state will change if the pin state does.
|
||||||
|
|
||||||
|
PinChangeInterrupts are different than normal Interrupts.
|
||||||
|
See readme for more information.
|
||||||
|
Dont use Serial or delay inside interrupts!
|
||||||
|
This library is not compatible with SoftSerial.
|
||||||
|
|
||||||
|
The following pins are usable for PinChangeInterrupt:
|
||||||
|
Arduino Uno/Nano/Mini: All pins are usable
|
||||||
|
Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64),
|
||||||
|
A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)
|
||||||
|
Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI)
|
||||||
|
HoodLoader2: All (broken out 1-7) pins are usable
|
||||||
|
Attiny 24/44/84: All pins are usable
|
||||||
|
Attiny 25/45/85: All pins are usable
|
||||||
|
Attiny 13: All pins are usable
|
||||||
|
Attiny 441/841: All pins are usable
|
||||||
|
ATmega644P/ATmega1284P: All pins are usable
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
// Choose a valid PinChangeInterrupt pin of your Arduino board
|
||||||
|
#define pinBlink 7
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// set pin to input with a pullup, led to output
|
||||||
|
pinMode(pinBlink, INPUT_PULLUP);
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
|
// Manually blink once to test if LED is functional
|
||||||
|
blinkLed();
|
||||||
|
delay(1000);
|
||||||
|
blinkLed();
|
||||||
|
|
||||||
|
// Attach the new PinChangeInterrupt and enable event function below
|
||||||
|
attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blinkLed(void) {
|
||||||
|
// Switch Led state
|
||||||
|
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Nothing to do here
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
PinChangeInterrupt_LowLevel
|
||||||
|
Demonstrates how to use the library without the API
|
||||||
|
|
||||||
|
Make sure to comment "//#define PCINT_API" in the settings file.
|
||||||
|
|
||||||
|
To maximize speed and size also uncomment all not used pins above.
|
||||||
|
Then you could also uncomment "#define PCINT_COMPILE_ENABLED_ISR"
|
||||||
|
to get away the .a linkage overhead.
|
||||||
|
|
||||||
|
Connect a button/cable to pin 7 and ground (Uno).
|
||||||
|
Strong overwritten callback functions are called when an interrupt occurs.
|
||||||
|
The Led state will change if the pin state does.
|
||||||
|
|
||||||
|
PinChangeInterrupts are different than normal Interrupts.
|
||||||
|
See readme for more information.
|
||||||
|
Dont use Serial or delay inside interrupts!
|
||||||
|
This library is not compatible with SoftSerial.
|
||||||
|
|
||||||
|
The following pins are usable for PinChangeInterrupt:
|
||||||
|
Arduino Uno/Nano/Mini: All pins are usable
|
||||||
|
Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64),
|
||||||
|
A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)
|
||||||
|
Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI)
|
||||||
|
HoodLoader2: All (broken out 1-7) pins are usable
|
||||||
|
Attiny 24/44/84: All pins are usable
|
||||||
|
Attiny 25/45/85: All pins are usable
|
||||||
|
Attiny 13: All pins are usable
|
||||||
|
Attiny 441/841: All pins are usable
|
||||||
|
ATmega644P/ATmega1284P: All pins are usable
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
// choose a valid PinChangeInterrupt pin of your Arduino board
|
||||||
|
// manually defined pcint number
|
||||||
|
#define pinBlink 7
|
||||||
|
#define interruptBlink 23
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
// set pin to input with a pullup, led to output
|
||||||
|
pinMode(pinBlink, INPUT_PULLUP);
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
|
// attach the new PinChangeInterrupts and enable event functions below
|
||||||
|
attachPinChangeInterrupt(interruptBlink, CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinChangeInterruptEvent(interruptBlink)(void) {
|
||||||
|
// switch Led state
|
||||||
|
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
PinChangeInterrupt_TickTock
|
||||||
|
Demonstrates how to use the library
|
||||||
|
|
||||||
|
Connect a button/cable to pin 10/11 and ground.
|
||||||
|
The value printed on the serial port will increase
|
||||||
|
if pin 10 is rising and decrease if pin 11 is falling.
|
||||||
|
|
||||||
|
PinChangeInterrupts are different than normal Interrupts.
|
||||||
|
See readme for more information.
|
||||||
|
Dont use Serial or delay inside interrupts!
|
||||||
|
This library is not compatible with SoftSerial.
|
||||||
|
|
||||||
|
The following pins are usable for PinChangeInterrupt:
|
||||||
|
Arduino Uno/Nano/Mini: All pins are usable
|
||||||
|
Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64),
|
||||||
|
A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)
|
||||||
|
Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI)
|
||||||
|
HoodLoader2: All (broken out 1-7) pins are usable
|
||||||
|
Attiny 24/44/84: All pins are usable
|
||||||
|
Attiny 25/45/85: All pins are usable
|
||||||
|
Attiny 13: All pins are usable
|
||||||
|
Attiny 441/841: All pins are usable
|
||||||
|
ATmega644P/ATmega1284P: All pins are usable
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
// choose a valid PinChangeInterrupt pin of your Arduino board
|
||||||
|
#define pinTick 10
|
||||||
|
#define pinTock 11
|
||||||
|
|
||||||
|
volatile long ticktocks = 0;
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
// start serial debug output
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println(F("Startup"));
|
||||||
|
|
||||||
|
// set pins to input with a pullup
|
||||||
|
pinMode(pinTick, INPUT_PULLUP);
|
||||||
|
pinMode(pinTock, INPUT_PULLUP);
|
||||||
|
|
||||||
|
// attach the new PinChangeInterrupts and enable event functions below
|
||||||
|
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING);
|
||||||
|
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock), tock, FALLING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// integer to count the number of prints
|
||||||
|
static int i = 0;
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// print values
|
||||||
|
Serial.print(i, DEC);
|
||||||
|
Serial.print(F(" "));
|
||||||
|
Serial.println(ticktocks);
|
||||||
|
|
||||||
|
// abort if we printed 100 times
|
||||||
|
if (i >= 100) {
|
||||||
|
Serial.println(F("Detaching Interrupts."));
|
||||||
|
detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
|
||||||
|
detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
|
||||||
|
// Temporary pause interrupts
|
||||||
|
if (ticktocks > 500) {
|
||||||
|
Serial.println(F("Disabling Tick Interrupt."));
|
||||||
|
disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
|
||||||
|
enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock));
|
||||||
|
}
|
||||||
|
else if (ticktocks < -500) {
|
||||||
|
Serial.println(F("Disabling Tock Interrupt."));
|
||||||
|
disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock));
|
||||||
|
enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
|
||||||
|
enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tick(void) {
|
||||||
|
// increase value
|
||||||
|
ticktocks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tock(void) {
|
||||||
|
// decrease value
|
||||||
|
ticktocks--;
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
|
|
@ -0,0 +1,32 @@
|
||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For PinChangeInterrupt
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
attachPinChangeInterrupt KEYWORD2
|
||||||
|
detachPinChangeInterrupt KEYWORD2
|
||||||
|
attachPCINT KEYWORD2
|
||||||
|
detachPCINT KEYWORD2
|
||||||
|
PinChangeInterruptEvent KEYWORD2
|
||||||
|
PCINTEvent KEYWORD2
|
||||||
|
enablePCINT KEYWORD2
|
||||||
|
enablePinChangeInterrupt KEYWORD2
|
||||||
|
disablePCINT KEYWORD2
|
||||||
|
disablePinChangeInterrupt KEYWORD2
|
||||||
|
getPCINTTrigger KEYWORD2
|
||||||
|
getPinChangeInterruptTrigger KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Instances (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
name=PinChangeInterrupt
|
||||||
|
version=1.2.6
|
||||||
|
author=NicoHood
|
||||||
|
maintainer=NicoHood <blog@NicoHood.de>
|
||||||
|
sentence=A simple & compact PinChangeInterrupt library for Arduino.
|
||||||
|
paragraph=PinChangeInterrupt library with a resource friendly implementation (API and LowLevel). PinChangeInterrupts are different than normal Interrupts. See readme for more information.
|
||||||
|
category=Signal Input/Output
|
||||||
|
url=https://github.com/NicoHood/PinChangeInterrupt
|
||||||
|
architectures=avr
|
||||||
|
dot_a_linkage=true
|
||||||
|
|
@ -0,0 +1,332 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
// manually include cpp files here to save flash if only 1 ISR is present
|
||||||
|
// or if the user knows he just wants to compile all enabled ports.
|
||||||
|
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
#define PCINT_INCLUDE_FROM_CPP
|
||||||
|
#include "PinChangeInterrupt0.cpp"
|
||||||
|
#include "PinChangeInterrupt1.cpp"
|
||||||
|
#include "PinChangeInterrupt2.cpp"
|
||||||
|
#include "PinChangeInterrupt3.cpp"
|
||||||
|
#else
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Weak Callbacks
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// create all weak functions which are all (if not used) alias of the pcint_null_callback above
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("void PinChangeInterruptEventPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("(void) __attribute__((weak, alias(\"pcint_null_callback\")));");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void PinChangeInterruptEventPCINT0(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT1(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT2(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT3(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT4(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT5(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT6(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT7(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT8(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT9(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT10(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT11(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT12(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT13(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT14(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT15(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT16(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT17(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT18(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT19(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT20(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT21(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT22(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT23(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT24(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT25(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT26(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT27(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT28(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT29(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT30(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
void PinChangeInterruptEventPCINT31(void) __attribute__((weak, alias("pcint_null_callback")));
|
||||||
|
|
||||||
|
#endif // PCINT_INCLUDE_FROM_CPP
|
||||||
|
|
||||||
|
// useless function for weak implemented/not used functions, extern c needed for the alias
|
||||||
|
extern "C" {
|
||||||
|
void pcint_null_callback(void) {
|
||||||
|
// useless
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// PinChangeInterrupt User Functions
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// variables to save the last port states and the interrupt settings
|
||||||
|
uint8_t oldPorts[PCINT_NUM_USED_PORTS] = { 0 };
|
||||||
|
uint8_t fallingPorts[PCINT_NUM_USED_PORTS] = { 0 };
|
||||||
|
uint8_t risingPorts[PCINT_NUM_USED_PORTS] = { 0 };
|
||||||
|
|
||||||
|
void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos){
|
||||||
|
// Update the old state to the actual state
|
||||||
|
switch(pcintPort){
|
||||||
|
#ifdef PCINT_INPUT_PORT0_USED
|
||||||
|
case 0:
|
||||||
|
oldPorts[arrayPos] = PCINT_INPUT_PORT0;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT_INPUT_PORT1_USED
|
||||||
|
case 1:
|
||||||
|
oldPorts[arrayPos] = PCINT_INPUT_PORT1;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT_INPUT_PORT2_USED
|
||||||
|
case 2:
|
||||||
|
oldPorts[arrayPos] = PCINT_INPUT_PORT2;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT_INPUT_PORT3_USED
|
||||||
|
case 3:
|
||||||
|
oldPorts[arrayPos] = PCINT_INPUT_PORT3;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pin change mask registers decide which pins are ENABLE as triggers
|
||||||
|
#ifdef PCMSK0
|
||||||
|
#ifdef PCMSK1
|
||||||
|
#ifdef PCMSK3
|
||||||
|
// Special case for ATmega1284P where PCMSK3 is not directly after PCMSK2
|
||||||
|
if(false){
|
||||||
|
#else
|
||||||
|
// Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other
|
||||||
|
if(&PCMSK1 - &PCMSK0 == 1){
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
*(&PCMSK0 + pcintPort) |= pcintMask;
|
||||||
|
#ifdef PCMSK1
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
switch(pcintPort){
|
||||||
|
case 0:
|
||||||
|
PCMSK0 |= pcintMask;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
PCMSK1 |= pcintMask;
|
||||||
|
break;
|
||||||
|
#ifdef PCMSK2
|
||||||
|
case 2:
|
||||||
|
PCMSK2 |= pcintMask;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef PCMSK3
|
||||||
|
case 3:
|
||||||
|
PCMSK3 |= pcintMask;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#elif defined(PCMSK)
|
||||||
|
*(&PCMSK + pcintPort) |= pcintMask;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// PCICR: Pin Change Interrupt Control Register - enables interrupt vectors
|
||||||
|
#ifdef PCICR
|
||||||
|
PCICR |= (1 << (pcintPort + PCIE0));
|
||||||
|
#elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */
|
||||||
|
GIMSK |= (1 << (pcintPort + PCIE0));
|
||||||
|
#elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */
|
||||||
|
GIMSK |= (1 << (pcintPort + PCIE));
|
||||||
|
#else
|
||||||
|
#error MCU has no such a register
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask) {
|
||||||
|
bool disable = false;
|
||||||
|
#ifdef PCMSK0
|
||||||
|
#ifdef PCMSK1
|
||||||
|
// Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other
|
||||||
|
if(&PCMSK1 - &PCMSK0 == 1){
|
||||||
|
#endif
|
||||||
|
// disable the mask.
|
||||||
|
*(&PCMSK0 + pcintPort) &= ~pcintMask;
|
||||||
|
|
||||||
|
// if that's the last one, disable the interrupt.
|
||||||
|
if (*(&PCMSK0 + pcintPort) == 0)
|
||||||
|
disable = true;
|
||||||
|
#ifdef PCMSK1
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
switch(pcintPort){
|
||||||
|
case 0:
|
||||||
|
// disable the mask.
|
||||||
|
PCMSK0 &= ~pcintMask;
|
||||||
|
|
||||||
|
// if that's the last one, disable the interrupt.
|
||||||
|
if (!PCMSK0)
|
||||||
|
disable = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// disable the mask.
|
||||||
|
PCMSK1 &= ~pcintMask;
|
||||||
|
|
||||||
|
// if that's the last one, disable the interrupt.
|
||||||
|
if (!PCMSK1)
|
||||||
|
disable = true;
|
||||||
|
break;
|
||||||
|
#ifdef PCMSK2
|
||||||
|
case 2:
|
||||||
|
// disable the mask.
|
||||||
|
PCMSK2 &= ~pcintMask;
|
||||||
|
|
||||||
|
// if that's the last one, disable the interrupt.
|
||||||
|
if (!PCMSK2)
|
||||||
|
disable = true;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef PCMSK3
|
||||||
|
case 3:
|
||||||
|
// disable the mask.
|
||||||
|
PCMSK3 &= ~pcintMask;
|
||||||
|
|
||||||
|
// if that's the last one, disable the interrupt.
|
||||||
|
if (!PCMSK3)
|
||||||
|
disable = true;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#elif defined(PCMSK)
|
||||||
|
// disable the mask.
|
||||||
|
*(&PCMSK + pcintPort) &= ~pcintMask;
|
||||||
|
|
||||||
|
// if that's the last one, disable the interrupt.
|
||||||
|
if (*(&PCMSK + pcintPort) == 0)
|
||||||
|
disable = true;
|
||||||
|
#endif
|
||||||
|
if(disable)
|
||||||
|
{
|
||||||
|
#ifdef PCICR
|
||||||
|
PCICR &= ~(1 << (pcintPort + PCIE0));
|
||||||
|
#elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */
|
||||||
|
GIMSK &= ~(1 << (pcintPort + PCIE0));
|
||||||
|
#elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */
|
||||||
|
GIMSK &= ~(1 << (pcintPort + PCIE));
|
||||||
|
#else
|
||||||
|
#error MCU has no such a register
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
asm output (nothing to optimize here)
|
||||||
|
|
||||||
|
ISR(PCINT0_vect) {
|
||||||
|
push r1
|
||||||
|
push r0
|
||||||
|
in r0, 0x3f ; 63
|
||||||
|
push r0
|
||||||
|
eor r1, r1
|
||||||
|
push r18
|
||||||
|
push r19
|
||||||
|
push r20
|
||||||
|
push r21
|
||||||
|
push r22
|
||||||
|
push r23
|
||||||
|
push r24
|
||||||
|
push r25
|
||||||
|
push r26
|
||||||
|
push r27
|
||||||
|
push r28
|
||||||
|
push r30
|
||||||
|
push r31
|
||||||
|
|
||||||
|
// get the new and old pin states for port
|
||||||
|
// uint8_t newPort = pinChangeInterruptPortToInput(port);
|
||||||
|
in r24, 0x03; 3 //(1) loads byte into newPort from I/O register
|
||||||
|
|
||||||
|
// loads old port and high + low setting
|
||||||
|
lds r18, 0x011E //(1 or 2) loads oldPorts into register
|
||||||
|
lds r28, 0x011B //(1 or 2) loads fallingPorts into register
|
||||||
|
lds r25, 0x0118 //(1 or 2) loads risingPorts into register
|
||||||
|
|
||||||
|
and r28, r18 // oldPorts & fallingPorts
|
||||||
|
and r25, r24 // newPort & risingPorts
|
||||||
|
or r28, r25 // (oldPorts & fallingPorts) | (newPort & risingPorts)
|
||||||
|
eor r18, r24 // oldPorts^newPort
|
||||||
|
and r28, r18 // ((oldPorts & fallingPorts) | (newPort & risingPorts)) & (oldPorts^newPort)
|
||||||
|
|
||||||
|
// save the new state for next comparison
|
||||||
|
// oldPorts[arrayPos] = newPort;
|
||||||
|
sts 0x011E, r24
|
||||||
|
|
||||||
|
// Execute all functions that should be triggered
|
||||||
|
sbrc r28, 0
|
||||||
|
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
|
||||||
|
sbrc r28, 1
|
||||||
|
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
|
||||||
|
sbrc r28, 2
|
||||||
|
call 0x318 ; 0x318 <_Z20PinChangeInterruptEventPCINT2v>
|
||||||
|
sbrc r28, 3
|
||||||
|
call 0x340 ; 0x340 <_Z20PinChangeInterruptEventPCINT3v>
|
||||||
|
sbrc r28, 4
|
||||||
|
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
|
||||||
|
sbrc r28, 5
|
||||||
|
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
|
||||||
|
sbrc r28, 6
|
||||||
|
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
|
||||||
|
sbrc r28, 7
|
||||||
|
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
|
||||||
|
|
||||||
|
pop r31
|
||||||
|
pop r30
|
||||||
|
pop r28
|
||||||
|
pop r27
|
||||||
|
pop r26
|
||||||
|
pop r25
|
||||||
|
pop r24
|
||||||
|
pop r23
|
||||||
|
pop r22
|
||||||
|
pop r21
|
||||||
|
pop r20
|
||||||
|
pop r19
|
||||||
|
pop r18
|
||||||
|
pop r0
|
||||||
|
out 0x3f, r0 ; 63
|
||||||
|
pop r0
|
||||||
|
pop r1
|
||||||
|
reti
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,898 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2018 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 Guard
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Software Version
|
||||||
|
#define PCINT_VERSION 126
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#ifndef ARDUINO_ARCH_AVR
|
||||||
|
#error This library can only be used with AVR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifndef LOW
|
||||||
|
#define LOW 0x0
|
||||||
|
#endif
|
||||||
|
#ifndef CHANGE
|
||||||
|
#define CHANGE 0x1
|
||||||
|
#endif
|
||||||
|
#ifndef FALLING
|
||||||
|
#define FALLING 0x2
|
||||||
|
#endif
|
||||||
|
#ifndef RISING
|
||||||
|
#define RISING 0x3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// General Helper Definitions and Mappings
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// Settings and Board definitions are seperated to get an better overview.
|
||||||
|
// The order and position of the inclusion is important!
|
||||||
|
#include "PinChangeInterruptSettings.h"
|
||||||
|
#include "PinChangeInterruptBoards.h"
|
||||||
|
#include "PinChangeInterruptPins.h"
|
||||||
|
|
||||||
|
#if !PCINT_NUM_USED_PORTS
|
||||||
|
#error Please enable at least one PCINT port and pin!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// manually include cpp files to save flash if only 1 ISR is present
|
||||||
|
// it includes all ISR files but only the 1 available ISR will/can be compiled
|
||||||
|
#if (PCINT_NUM_USED_PORTS == 1)
|
||||||
|
#ifndef PCINT_COMPILE_ENABLED_ISR
|
||||||
|
#define PCINT_COMPILE_ENABLED_ISR
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Makro Definitions
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// generates the callback for easier reordering in Settings
|
||||||
|
#define PCINT_MACRO_BRACKETS ()
|
||||||
|
#define PCINT_MACRO_TRUE == true)
|
||||||
|
#define PCINT_CALLBACK(bit, pcint) \
|
||||||
|
if (PCINT_USE_PCINT ## pcint PCINT_MACRO_TRUE \
|
||||||
|
if (trigger & (1 << bit)) \
|
||||||
|
PinChangeInterruptEventPCINT ## pcint PCINT_MACRO_BRACKETS
|
||||||
|
|
||||||
|
// definition used by the user to create custom LowLevel PCINT Events
|
||||||
|
#define PinChangeInterruptEvent_Wrapper(n) PinChangeInterruptEventPCINT ## n
|
||||||
|
#define PinChangeInterruptEvent(n) PinChangeInterruptEvent_Wrapper(n)
|
||||||
|
|
||||||
|
// missing 1.0.6 definition workaround
|
||||||
|
#ifndef NOT_AN_INTERRUPT
|
||||||
|
#define NOT_AN_INTERRUPT -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// convert a normal pin to its PCINT number (0 - max 23), used by the user
|
||||||
|
// calculates the pin by the Arduino definitions
|
||||||
|
#if defined(PCIE0)
|
||||||
|
#define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE0)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT)
|
||||||
|
#elif defined(PCIE)
|
||||||
|
#define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT)
|
||||||
|
#else
|
||||||
|
#error MCU has no such a register
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// alias for shorter writing
|
||||||
|
#define PCINTEvent(n) PinChangeInterruptEvent_Wrapper(n)
|
||||||
|
#define digitalPinToPCINT digitalPinToPinChangeInterrupt
|
||||||
|
#define attachPCINT attachPinChangeInterrupt
|
||||||
|
#define enablePCINT enablePinChangeInterrupt
|
||||||
|
#define detachPCINT detachPinChangeInterrupt
|
||||||
|
#define disablePCINT disablePinChangeInterrupt
|
||||||
|
#define getPCINTTrigger getPinChangeInterruptTrigger
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Function Prototypes + Variables
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// typedef for our callback function pointers
|
||||||
|
typedef void(*callback)(void);
|
||||||
|
|
||||||
|
// useless function for weak implemented/not used functions, extern c needed for the alias
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void pcint_null_callback(void);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PinChangeInterruptEventPCINT0(void);
|
||||||
|
void PinChangeInterruptEventPCINT1(void);
|
||||||
|
void PinChangeInterruptEventPCINT2(void);
|
||||||
|
void PinChangeInterruptEventPCINT3(void);
|
||||||
|
void PinChangeInterruptEventPCINT4(void);
|
||||||
|
void PinChangeInterruptEventPCINT5(void);
|
||||||
|
void PinChangeInterruptEventPCINT6(void);
|
||||||
|
void PinChangeInterruptEventPCINT7(void);
|
||||||
|
void PinChangeInterruptEventPCINT8(void);
|
||||||
|
void PinChangeInterruptEventPCINT9(void);
|
||||||
|
void PinChangeInterruptEventPCINT10(void);
|
||||||
|
void PinChangeInterruptEventPCINT11(void);
|
||||||
|
void PinChangeInterruptEventPCINT12(void);
|
||||||
|
void PinChangeInterruptEventPCINT13(void);
|
||||||
|
void PinChangeInterruptEventPCINT14(void);
|
||||||
|
void PinChangeInterruptEventPCINT15(void);
|
||||||
|
void PinChangeInterruptEventPCINT16(void);
|
||||||
|
void PinChangeInterruptEventPCINT17(void);
|
||||||
|
void PinChangeInterruptEventPCINT18(void);
|
||||||
|
void PinChangeInterruptEventPCINT19(void);
|
||||||
|
void PinChangeInterruptEventPCINT20(void);
|
||||||
|
void PinChangeInterruptEventPCINT21(void);
|
||||||
|
void PinChangeInterruptEventPCINT22(void);
|
||||||
|
void PinChangeInterruptEventPCINT23(void);
|
||||||
|
void PinChangeInterruptEventPCINT24(void);
|
||||||
|
void PinChangeInterruptEventPCINT25(void);
|
||||||
|
void PinChangeInterruptEventPCINT26(void);
|
||||||
|
void PinChangeInterruptEventPCINT27(void);
|
||||||
|
void PinChangeInterruptEventPCINT28(void);
|
||||||
|
void PinChangeInterruptEventPCINT29(void);
|
||||||
|
void PinChangeInterruptEventPCINT30(void);
|
||||||
|
void PinChangeInterruptEventPCINT31(void);
|
||||||
|
|
||||||
|
extern uint8_t oldPorts[PCINT_NUM_USED_PORTS];
|
||||||
|
extern uint8_t fallingPorts[PCINT_NUM_USED_PORTS];
|
||||||
|
extern uint8_t risingPorts[PCINT_NUM_USED_PORTS];
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint8_t getArrayPosPCINT(uint8_t pcintPort) __attribute__((always_inline));
|
||||||
|
uint8_t getArrayPosPCINT(uint8_t pcintPort) {
|
||||||
|
/*
|
||||||
|
Maps the port to the array.
|
||||||
|
This is needed since you can deactivate ports
|
||||||
|
and the array will dynamically resize to save ram.
|
||||||
|
|
||||||
|
The function does not need that much flash since the if and else
|
||||||
|
are known at compile time, so the compiler removes all the complex logic.
|
||||||
|
The return is is the input if all pins are activated for example.
|
||||||
|
That's why the function is inline.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (PCINT_NUM_USED_PORTS == 1) {
|
||||||
|
// only the first element is used for a single port
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (PCINT_NUM_USED_PORTS == PCINT_NUM_PORTS) {
|
||||||
|
// use all ports and down remap the array position.
|
||||||
|
return pcintPort;
|
||||||
|
}
|
||||||
|
else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 1) {
|
||||||
|
// one port is not used
|
||||||
|
if (PCINT_USE_PORT0 == 0) {
|
||||||
|
// first port is not used, decrease all port numbers
|
||||||
|
return (pcintPort - 1);
|
||||||
|
}
|
||||||
|
else if (PCINT_HAS_PORT3 == 0) {
|
||||||
|
// 3 ports (standard)
|
||||||
|
if (PCINT_USE_PORT2 == 0) {
|
||||||
|
// last port not used, no mapping needed
|
||||||
|
return pcintPort;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// worst case, port in the middle not used, remap
|
||||||
|
return ((pcintPort >> 1) & 0x01);
|
||||||
|
//if (pcintPort == 0) return 0;
|
||||||
|
//else return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 4 ports (special case for a few AVRs)
|
||||||
|
if (PCINT_USE_PORT3 == 0) {
|
||||||
|
// last port not used, no mapping needed
|
||||||
|
return pcintPort;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// worst case, one of two ports in the middle not used, remap
|
||||||
|
if (PCINT_USE_PORT1 == 0) {
|
||||||
|
// port1 not used, mapping needed
|
||||||
|
if (pcintPort == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return pcintPort - 1;
|
||||||
|
}
|
||||||
|
else if (PCINT_USE_PORT2 == 0) {
|
||||||
|
// port2 not used, mapping needed
|
||||||
|
if (pcintPort == 3)
|
||||||
|
return 2;
|
||||||
|
else
|
||||||
|
return pcintPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use all ports and down remap the array position.
|
||||||
|
return pcintPort;
|
||||||
|
}
|
||||||
|
else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 2) {
|
||||||
|
if (PCINT_USE_PORT2 == 0 && PCINT_USE_PORT3 == 0) {
|
||||||
|
// no need for mapping
|
||||||
|
return pcintPort;
|
||||||
|
}
|
||||||
|
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT3 == 0) {
|
||||||
|
// 1 offset
|
||||||
|
return (pcintPort - 1);
|
||||||
|
}
|
||||||
|
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT1 == 0) {
|
||||||
|
// 2 offset
|
||||||
|
return (pcintPort - 2);
|
||||||
|
}
|
||||||
|
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT2 == 0) {
|
||||||
|
// 2 -> 1
|
||||||
|
return (pcintPort >> 1);
|
||||||
|
}
|
||||||
|
else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT2 == 0) {
|
||||||
|
// 3 -> 1
|
||||||
|
return (pcintPort >> 1);
|
||||||
|
}
|
||||||
|
else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT3 == 0) {
|
||||||
|
// 3 -> 1, 1 -> 0
|
||||||
|
return (pcintPort >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Attach Function (partly inlined)
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos);
|
||||||
|
void attachPinChangeInterrupt0(void);
|
||||||
|
void attachPinChangeInterrupt1(void);
|
||||||
|
void attachPinChangeInterrupt2(void);
|
||||||
|
void attachPinChangeInterrupt3(void);
|
||||||
|
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if (PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" == true)");
|
||||||
|
Serial.print("extern volatile callback callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(";");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if (PCINT_USE_PCINT0 == true)
|
||||||
|
extern volatile callback callbackPCINT0;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT1 == true)
|
||||||
|
extern volatile callback callbackPCINT1;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT2 == true)
|
||||||
|
extern volatile callback callbackPCINT2;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT3 == true)
|
||||||
|
extern volatile callback callbackPCINT3;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT4 == true)
|
||||||
|
extern volatile callback callbackPCINT4;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT5 == true)
|
||||||
|
extern volatile callback callbackPCINT5;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT6 == true)
|
||||||
|
extern volatile callback callbackPCINT6;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT7 == true)
|
||||||
|
extern volatile callback callbackPCINT7;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT8 == true)
|
||||||
|
extern volatile callback callbackPCINT8;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT9 == true)
|
||||||
|
extern volatile callback callbackPCINT9;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT10 == true)
|
||||||
|
extern volatile callback callbackPCINT10;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT11 == true)
|
||||||
|
extern volatile callback callbackPCINT11;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT12 == true)
|
||||||
|
extern volatile callback callbackPCINT12;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT13 == true)
|
||||||
|
extern volatile callback callbackPCINT13;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT14 == true)
|
||||||
|
extern volatile callback callbackPCINT14;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT15 == true)
|
||||||
|
extern volatile callback callbackPCINT15;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT16 == true)
|
||||||
|
extern volatile callback callbackPCINT16;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT17 == true)
|
||||||
|
extern volatile callback callbackPCINT17;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT18 == true)
|
||||||
|
extern volatile callback callbackPCINT18;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT19 == true)
|
||||||
|
extern volatile callback callbackPCINT19;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT20 == true)
|
||||||
|
extern volatile callback callbackPCINT20;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT21 == true)
|
||||||
|
extern volatile callback callbackPCINT21;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT22 == true)
|
||||||
|
extern volatile callback callbackPCINT22;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT23 == true)
|
||||||
|
extern volatile callback callbackPCINT23;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT24 == true)
|
||||||
|
extern volatile callback callbackPCINT24;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT25 == true)
|
||||||
|
extern volatile callback callbackPCINT25;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT26 == true)
|
||||||
|
extern volatile callback callbackPCINT26;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT27 == true)
|
||||||
|
extern volatile callback callbackPCINT27;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT28 == true)
|
||||||
|
extern volatile callback callbackPCINT28;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT29 == true)
|
||||||
|
extern volatile callback callbackPCINT29;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT30 == true)
|
||||||
|
extern volatile callback callbackPCINT30;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT31 == true)
|
||||||
|
extern volatile callback callbackPCINT31;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if (PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" == true)");
|
||||||
|
Serial.print("if (pcintNum == ");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(")");
|
||||||
|
Serial.print("callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" = userFunc;");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// API attach function
|
||||||
|
static inline void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) __attribute__((always_inline));
|
||||||
|
void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) {
|
||||||
|
#else // no API attach function
|
||||||
|
static inline void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) __attribute__((always_inline));
|
||||||
|
void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) {
|
||||||
|
#endif // PCINT_API
|
||||||
|
|
||||||
|
// check if pcint is a valid pcint, exclude deactivated ports
|
||||||
|
uint8_t pcintPort = pcintNum / 8;
|
||||||
|
uint8_t pcintBit = pcintNum % 8;
|
||||||
|
|
||||||
|
// port 0
|
||||||
|
if (pcintPort == 0 && PCINT_USE_PORT0 == true) {
|
||||||
|
// use fake functions to make the ISRs compile with .a linkage
|
||||||
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
attachPinChangeInterrupt0();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT0 == true)
|
||||||
|
if (pcintNum == 0)
|
||||||
|
callbackPCINT0 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT1 == true)
|
||||||
|
if (pcintNum == 1)
|
||||||
|
callbackPCINT1 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT2 == true)
|
||||||
|
if (pcintNum == 2)
|
||||||
|
callbackPCINT2 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT3 == true)
|
||||||
|
if (pcintNum == 3)
|
||||||
|
callbackPCINT3 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT4 == true)
|
||||||
|
if (pcintNum == 4)
|
||||||
|
callbackPCINT4 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT5 == true)
|
||||||
|
if (pcintNum == 5)
|
||||||
|
callbackPCINT5 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT6 == true)
|
||||||
|
if (pcintNum == 6)
|
||||||
|
callbackPCINT6 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT7 == true)
|
||||||
|
if (pcintNum == 7)
|
||||||
|
callbackPCINT7 = userFunc;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
|
||||||
|
// port 1
|
||||||
|
else if (pcintPort == 1 && PCINT_USE_PORT1 == true) {
|
||||||
|
// use fake functions to make the ISRs compile with .a linkage
|
||||||
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
attachPinChangeInterrupt1();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT8 == true)
|
||||||
|
if (pcintNum == 8)
|
||||||
|
callbackPCINT8 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT9 == true)
|
||||||
|
if (pcintNum == 9)
|
||||||
|
callbackPCINT9 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT10 == true)
|
||||||
|
if (pcintNum == 10)
|
||||||
|
callbackPCINT10 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT11 == true)
|
||||||
|
if (pcintNum == 11)
|
||||||
|
callbackPCINT11 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT12 == true)
|
||||||
|
if (pcintNum == 12)
|
||||||
|
callbackPCINT12 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT13 == true)
|
||||||
|
if (pcintNum == 13)
|
||||||
|
callbackPCINT13 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT14 == true)
|
||||||
|
if (pcintNum == 14)
|
||||||
|
callbackPCINT14 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT15 == true)
|
||||||
|
if (pcintNum == 15)
|
||||||
|
callbackPCINT15 = userFunc;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
|
||||||
|
// port 2
|
||||||
|
else if (pcintPort == 2 && PCINT_USE_PORT2 == true) {
|
||||||
|
// use fake functions to make the ISRs compile with .a linkage
|
||||||
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
attachPinChangeInterrupt2();
|
||||||
|
#endif
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT16 == true)
|
||||||
|
if (pcintNum == 16)
|
||||||
|
callbackPCINT16 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT17 == true)
|
||||||
|
if (pcintNum == 17)
|
||||||
|
callbackPCINT17 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT18 == true)
|
||||||
|
if (pcintNum == 18)
|
||||||
|
callbackPCINT18 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT19 == true)
|
||||||
|
if (pcintNum == 19)
|
||||||
|
callbackPCINT19 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT20 == true)
|
||||||
|
if (pcintNum == 20)
|
||||||
|
callbackPCINT20 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT21 == true)
|
||||||
|
if (pcintNum == 21)
|
||||||
|
callbackPCINT21 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT22 == true)
|
||||||
|
if (pcintNum == 22)
|
||||||
|
callbackPCINT22 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT23 == true)
|
||||||
|
if (pcintNum == 23)
|
||||||
|
callbackPCINT23 = userFunc;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
|
||||||
|
// port 3
|
||||||
|
else if (pcintPort == 3 && PCINT_USE_PORT3 == true) {
|
||||||
|
// use fake functions to make the ISRs compile with .a linkage
|
||||||
|
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
attachPinChangeInterrupt3();
|
||||||
|
#endif
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT24 == true)
|
||||||
|
if (pcintNum == 24)
|
||||||
|
callbackPCINT24 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT25 == true)
|
||||||
|
if (pcintNum == 25)
|
||||||
|
callbackPCINT25 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT26 == true)
|
||||||
|
if (pcintNum == 26)
|
||||||
|
callbackPCINT26 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT27 == true)
|
||||||
|
if (pcintNum == 27)
|
||||||
|
callbackPCINT27 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT28 == true)
|
||||||
|
if (pcintNum == 28)
|
||||||
|
callbackPCINT28 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT29 == true)
|
||||||
|
if (pcintNum == 29)
|
||||||
|
callbackPCINT29 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT30 == true)
|
||||||
|
if (pcintNum == 30)
|
||||||
|
callbackPCINT30 = userFunc;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT31 == true)
|
||||||
|
if (pcintNum == 31)
|
||||||
|
callbackPCINT31 = userFunc;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
|
||||||
|
// get bitmask and array position
|
||||||
|
uint8_t pcintMask = (1 << pcintBit);
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
||||||
|
|
||||||
|
// save settings related to mode and registers
|
||||||
|
if (mode == CHANGE || mode == RISING)
|
||||||
|
risingPorts[arrayPos] |= pcintMask;
|
||||||
|
if (mode == CHANGE || mode == FALLING)
|
||||||
|
fallingPorts[arrayPos] |= pcintMask;
|
||||||
|
|
||||||
|
// call the actual hardware attach function
|
||||||
|
enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable interrupt again if temporary disabled
|
||||||
|
static inline void enablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline));
|
||||||
|
void enablePinChangeInterrupt(const uint8_t pcintNum) {
|
||||||
|
// get PCINT registers
|
||||||
|
uint8_t pcintPort = pcintNum / 8;
|
||||||
|
uint8_t pcintBit = pcintNum % 8;
|
||||||
|
|
||||||
|
// check if pcint is a valid pcint, exclude deactivated ports
|
||||||
|
if (pcintPort == 0) {
|
||||||
|
if (PCINT_USE_PORT0 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 1) {
|
||||||
|
if (PCINT_USE_PORT1 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 2) {
|
||||||
|
if (PCINT_USE_PORT2 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 3) {
|
||||||
|
if (PCINT_USE_PORT3 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
|
||||||
|
// call the actual hardware attach function
|
||||||
|
uint8_t pcintMask = (1 << pcintBit);
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
||||||
|
enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Detach Function (partly inlined)
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask);
|
||||||
|
static inline void detachPinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline));
|
||||||
|
|
||||||
|
void detachPinChangeInterrupt(const uint8_t pcintNum) {
|
||||||
|
// get PCINT registers
|
||||||
|
uint8_t pcintPort = pcintNum / 8;
|
||||||
|
uint8_t pcintBit = pcintNum % 8;
|
||||||
|
|
||||||
|
// check if pcint is a valid pcint, exclude deactivated ports
|
||||||
|
// port 0
|
||||||
|
if (pcintPort == 0 && PCINT_USE_PORT0 == true) {
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT0 == true)
|
||||||
|
if (pcintNum == 0)
|
||||||
|
callbackPCINT0 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT1 == true)
|
||||||
|
if (pcintNum == 1)
|
||||||
|
callbackPCINT1 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT2 == true)
|
||||||
|
if (pcintNum == 2)
|
||||||
|
callbackPCINT2 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT3 == true)
|
||||||
|
if (pcintNum == 3)
|
||||||
|
callbackPCINT3 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT4 == true)
|
||||||
|
if (pcintNum == 4)
|
||||||
|
callbackPCINT4 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT5 == true)
|
||||||
|
if (pcintNum == 5)
|
||||||
|
callbackPCINT5 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT6 == true)
|
||||||
|
if (pcintNum == 6)
|
||||||
|
callbackPCINT6 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT7 == true)
|
||||||
|
if (pcintNum == 7)
|
||||||
|
callbackPCINT7 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
|
||||||
|
// port 1
|
||||||
|
else if (pcintPort == 1 && PCINT_USE_PORT1 == true) {
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT8 == true)
|
||||||
|
if (pcintNum == 8)
|
||||||
|
callbackPCINT8 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT9 == true)
|
||||||
|
if (pcintNum == 9)
|
||||||
|
callbackPCINT9 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT10 == true)
|
||||||
|
if (pcintNum == 10)
|
||||||
|
callbackPCINT10 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT11 == true)
|
||||||
|
if (pcintNum == 11)
|
||||||
|
callbackPCINT11 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT12 == true)
|
||||||
|
if (pcintNum == 12)
|
||||||
|
callbackPCINT12 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT13 == true)
|
||||||
|
if (pcintNum == 13)
|
||||||
|
callbackPCINT13 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT14 == true)
|
||||||
|
if (pcintNum == 14)
|
||||||
|
callbackPCINT14 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT15 == true)
|
||||||
|
if (pcintNum == 15)
|
||||||
|
callbackPCINT15 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
|
||||||
|
// port 2
|
||||||
|
else if (pcintPort == 2 && PCINT_USE_PORT2 == true) {
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT16 == true)
|
||||||
|
if (pcintNum == 16)
|
||||||
|
callbackPCINT16 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT17 == true)
|
||||||
|
if (pcintNum == 17)
|
||||||
|
callbackPCINT17 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT18 == true)
|
||||||
|
if (pcintNum == 18)
|
||||||
|
callbackPCINT18 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT19 == true)
|
||||||
|
if (pcintNum == 19)
|
||||||
|
callbackPCINT19 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT20 == true)
|
||||||
|
if (pcintNum == 20)
|
||||||
|
callbackPCINT20 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT21 == true)
|
||||||
|
if (pcintNum == 21)
|
||||||
|
callbackPCINT21 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT22 == true)
|
||||||
|
if (pcintNum == 22)
|
||||||
|
callbackPCINT22 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT23 == true)
|
||||||
|
if (pcintNum == 23)
|
||||||
|
callbackPCINT23 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
|
||||||
|
// port 3
|
||||||
|
else if (pcintPort == 3 && PCINT_USE_PORT3 == true) {
|
||||||
|
// attache the function pointers for the API
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
#if (PCINT_USE_PCINT24 == true)
|
||||||
|
if (pcintNum == 24)
|
||||||
|
callbackPCINT24 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT25 == true)
|
||||||
|
if (pcintNum == 25)
|
||||||
|
callbackPCINT25 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT26 == true)
|
||||||
|
if (pcintNum == 26)
|
||||||
|
callbackPCINT26 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT27 == true)
|
||||||
|
if (pcintNum == 27)
|
||||||
|
callbackPCINT27 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT28 == true)
|
||||||
|
if (pcintNum == 28)
|
||||||
|
callbackPCINT28 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT29 == true)
|
||||||
|
if (pcintNum == 29)
|
||||||
|
callbackPCINT29 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT30 == true)
|
||||||
|
if (pcintNum == 30)
|
||||||
|
callbackPCINT30 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT31 == true)
|
||||||
|
if (pcintNum == 31)
|
||||||
|
callbackPCINT31 = pcint_null_callback;
|
||||||
|
#endif
|
||||||
|
#endif // PCINT_API
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
|
||||||
|
// get bitmask and array position
|
||||||
|
uint8_t pcintMask = (1 << pcintBit);
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
||||||
|
|
||||||
|
// delete setting
|
||||||
|
risingPorts[arrayPos] &= ~pcintMask;
|
||||||
|
fallingPorts[arrayPos] &= ~pcintMask;
|
||||||
|
|
||||||
|
// call the actual hardware disable function
|
||||||
|
disablePinChangeInterruptHelper(pcintPort, pcintMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void disablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline));
|
||||||
|
void disablePinChangeInterrupt(const uint8_t pcintNum) {
|
||||||
|
// get PCINT registers
|
||||||
|
uint8_t pcintPort = pcintNum / 8;
|
||||||
|
uint8_t pcintBit = pcintNum % 8;
|
||||||
|
|
||||||
|
// check if pcint is a valid pcint, exclude deactivated ports
|
||||||
|
if (pcintPort == 0) {
|
||||||
|
if (PCINT_USE_PORT0 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 1) {
|
||||||
|
if (PCINT_USE_PORT1 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 2) {
|
||||||
|
if (PCINT_USE_PORT2 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 3) {
|
||||||
|
if (PCINT_USE_PORT3 == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
|
||||||
|
// get bitmask
|
||||||
|
uint8_t pcintMask = (1 << pcintBit);
|
||||||
|
|
||||||
|
// Do not delete mode settings nor detach the user function
|
||||||
|
// Just turn off interrupts
|
||||||
|
|
||||||
|
// call the actual hardware disable function
|
||||||
|
disablePinChangeInterruptHelper(pcintPort, pcintMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// getTrigger Function (inlined)
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
static inline uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) __attribute__((always_inline));
|
||||||
|
uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) {
|
||||||
|
// get PCINT registers
|
||||||
|
uint8_t pcintPort = pcintNum / 8;
|
||||||
|
uint8_t pcintBit = pcintNum % 8;
|
||||||
|
|
||||||
|
// check if pcint is a valid pcint, exclude deactivated ports
|
||||||
|
if (pcintPort == 0) {
|
||||||
|
if (PCINT_USE_PORT0 == false)
|
||||||
|
return CHANGE;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 1) {
|
||||||
|
if (PCINT_USE_PORT1 == false)
|
||||||
|
return CHANGE;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 2) {
|
||||||
|
if (PCINT_USE_PORT2 == false)
|
||||||
|
return CHANGE;
|
||||||
|
}
|
||||||
|
else if (pcintPort == 3) {
|
||||||
|
if (PCINT_USE_PORT3 == false)
|
||||||
|
return CHANGE;
|
||||||
|
}
|
||||||
|
else return CHANGE;
|
||||||
|
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
|
||||||
|
|
||||||
|
// Check if no mode was set, return an error
|
||||||
|
if(!(risingPorts[arrayPos] & (1 << pcintBit)) && !(fallingPorts[arrayPos] & (1 << pcintBit)))
|
||||||
|
return CHANGE;
|
||||||
|
|
||||||
|
// specify the CHANGE mode
|
||||||
|
if (oldPorts[arrayPos] & (1 << pcintBit))
|
||||||
|
return RISING;
|
||||||
|
else
|
||||||
|
return FALLING;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Interrupt Handler
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// prevent compilation twice if included from the .cpp to force compile all ISRs
|
||||||
|
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|
||||||
|
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
|
||||||
|
#if (PCINT_USE_PORT0 == true)
|
||||||
|
|
||||||
|
void attachPinChangeInterrupt0(void) {
|
||||||
|
// fake function to make the IDE link this file
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(PCINT0_vect) {
|
||||||
|
// get the new and old pin states for port
|
||||||
|
uint8_t newPort = PCINT_INPUT_PORT0;
|
||||||
|
|
||||||
|
// compare with the old value to detect a rising or falling
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(0);
|
||||||
|
uint8_t change = newPort ^ oldPorts[arrayPos];
|
||||||
|
uint8_t rising = change & newPort;
|
||||||
|
uint8_t falling = change & oldPorts[arrayPos];
|
||||||
|
|
||||||
|
// check which pins are triggered, compared with the settings
|
||||||
|
uint8_t risingTrigger = rising & risingPorts[arrayPos];
|
||||||
|
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
|
||||||
|
uint8_t trigger = risingTrigger | fallingTrigger;
|
||||||
|
|
||||||
|
// save the new state for next comparison
|
||||||
|
oldPorts[arrayPos] = newPort;
|
||||||
|
|
||||||
|
// Execute all functions that should be triggered
|
||||||
|
// This way we can exclude a single function
|
||||||
|
// and the calling is also much faster
|
||||||
|
// We may also reorder the pins for different priority
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT0)
|
||||||
|
PCINT_CALLBACK(0, 0);
|
||||||
|
PCINT_CALLBACK(1, 1);
|
||||||
|
PCINT_CALLBACK(2, 2);
|
||||||
|
PCINT_CALLBACK(3, 3);
|
||||||
|
PCINT_CALLBACK(4, 4);
|
||||||
|
PCINT_CALLBACK(5, 5);
|
||||||
|
PCINT_CALLBACK(6, 6);
|
||||||
|
PCINT_CALLBACK(7, 7);
|
||||||
|
#else
|
||||||
|
PCINT_CALLBACK_PORT0
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if (PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" == true)");
|
||||||
|
Serial.print("volatile callback callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" = pcint_null_callback;");
|
||||||
|
Serial.print("void PinChangeInterruptEventPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("(void){");
|
||||||
|
Serial.print(" callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("();");
|
||||||
|
Serial.println("}");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if (PCINT_USE_PCINT0 == true)
|
||||||
|
volatile callback callbackPCINT0 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT0(void) {
|
||||||
|
callbackPCINT0();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT1 == true)
|
||||||
|
volatile callback callbackPCINT1 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT1(void) {
|
||||||
|
callbackPCINT1();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT2 == true)
|
||||||
|
volatile callback callbackPCINT2 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT2(void) {
|
||||||
|
callbackPCINT2();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT3 == true)
|
||||||
|
volatile callback callbackPCINT3 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT3(void) {
|
||||||
|
callbackPCINT3();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT4 == true)
|
||||||
|
volatile callback callbackPCINT4 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT4(void) {
|
||||||
|
callbackPCINT4();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT5 == true)
|
||||||
|
volatile callback callbackPCINT5 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT5(void) {
|
||||||
|
callbackPCINT5();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT6 == true)
|
||||||
|
volatile callback callbackPCINT6 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT6(void) {
|
||||||
|
callbackPCINT6();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT7 == true)
|
||||||
|
volatile callback callbackPCINT7 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT7(void) {
|
||||||
|
callbackPCINT7();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PCINT_API
|
||||||
|
|
||||||
|
#endif // PCINT_USE_PORT0
|
||||||
|
|
||||||
|
#endif // PCINT_INCLUDE_FROM_CPP
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Interrupt Handler
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// prevent compilation twice if included from the .cpp to force compile all ISRs
|
||||||
|
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|
||||||
|
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
|
||||||
|
#if (PCINT_USE_PORT1 == true)
|
||||||
|
|
||||||
|
void attachPinChangeInterrupt1(void) {
|
||||||
|
// fake function to make the IDE link this file
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(PCINT1_vect) {
|
||||||
|
// get the new and old pin states for port
|
||||||
|
uint8_t newPort = PCINT_INPUT_PORT1;
|
||||||
|
|
||||||
|
// compare with the old value to detect a rising or falling
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(1);
|
||||||
|
uint8_t change = newPort ^ oldPorts[arrayPos];
|
||||||
|
uint8_t rising = change & newPort;
|
||||||
|
uint8_t falling = change & oldPorts[arrayPos];
|
||||||
|
|
||||||
|
// check which pins are triggered, compared with the settings
|
||||||
|
uint8_t risingTrigger = rising & risingPorts[arrayPos];
|
||||||
|
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
|
||||||
|
uint8_t trigger = risingTrigger | fallingTrigger;
|
||||||
|
|
||||||
|
// save the new state for next comparison
|
||||||
|
oldPorts[arrayPos] = newPort;
|
||||||
|
|
||||||
|
// Execute all functions that should be triggered
|
||||||
|
// This way we can exclude a single function
|
||||||
|
// and the calling is also much faster
|
||||||
|
// We may also reorder the pins for different priority
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT1)
|
||||||
|
PCINT_CALLBACK(0, 8);
|
||||||
|
PCINT_CALLBACK(1, 9);
|
||||||
|
PCINT_CALLBACK(2, 10);
|
||||||
|
PCINT_CALLBACK(3, 11);
|
||||||
|
PCINT_CALLBACK(4, 12);
|
||||||
|
PCINT_CALLBACK(5, 13);
|
||||||
|
PCINT_CALLBACK(6, 14);
|
||||||
|
PCINT_CALLBACK(7, 15);
|
||||||
|
#else
|
||||||
|
PCINT_CALLBACK_PORT1
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if (PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" == true)");
|
||||||
|
Serial.print("volatile callback callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" = pcint_null_callback;");
|
||||||
|
Serial.print("void PinChangeInterruptEventPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("(void){");
|
||||||
|
Serial.print(" callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("();");
|
||||||
|
Serial.println("}");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if (PCINT_USE_PCINT8 == true)
|
||||||
|
volatile callback callbackPCINT8 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT8(void) {
|
||||||
|
callbackPCINT8();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT9 == true)
|
||||||
|
volatile callback callbackPCINT9 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT9(void) {
|
||||||
|
callbackPCINT9();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT10 == true)
|
||||||
|
volatile callback callbackPCINT10 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT10(void) {
|
||||||
|
callbackPCINT10();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT11 == true)
|
||||||
|
volatile callback callbackPCINT11 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT11(void) {
|
||||||
|
callbackPCINT11();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT12 == true)
|
||||||
|
volatile callback callbackPCINT12 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT12(void) {
|
||||||
|
callbackPCINT12();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT13 == true)
|
||||||
|
volatile callback callbackPCINT13 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT13(void) {
|
||||||
|
callbackPCINT13();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT14 == true)
|
||||||
|
volatile callback callbackPCINT14 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT14(void) {
|
||||||
|
callbackPCINT14();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT15 == true)
|
||||||
|
volatile callback callbackPCINT15 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT15(void) {
|
||||||
|
callbackPCINT15();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PCINT_API
|
||||||
|
|
||||||
|
#endif // PCINT_USE_PORT1
|
||||||
|
|
||||||
|
#endif // PCINT_INCLUDE_FROM_CPP
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Interrupt Handler
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// prevent compilation twice if included from the .cpp to force compile all ISRs
|
||||||
|
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|
||||||
|
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
|
||||||
|
#if (PCINT_USE_PORT2 == true)
|
||||||
|
|
||||||
|
void attachPinChangeInterrupt2(void) {
|
||||||
|
// fake function to make the IDE link this file
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(PCINT2_vect) {
|
||||||
|
// get the new and old pin states for port
|
||||||
|
uint8_t newPort = PCINT_INPUT_PORT2;
|
||||||
|
|
||||||
|
// compare with the old value to detect a rising or falling
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(2);
|
||||||
|
uint8_t change = newPort ^ oldPorts[arrayPos];
|
||||||
|
uint8_t rising = change & newPort;
|
||||||
|
uint8_t falling = change & oldPorts[arrayPos];
|
||||||
|
|
||||||
|
// check which pins are triggered, compared with the settings
|
||||||
|
uint8_t risingTrigger = rising & risingPorts[arrayPos];
|
||||||
|
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
|
||||||
|
uint8_t trigger = risingTrigger | fallingTrigger;
|
||||||
|
|
||||||
|
// save the new state for next comparison
|
||||||
|
oldPorts[arrayPos] = newPort;
|
||||||
|
|
||||||
|
// Execute all functions that should be triggered
|
||||||
|
// This way we can exclude a single function
|
||||||
|
// and the calling is also much faster
|
||||||
|
// We may also reorder the pins for different priority
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT2)
|
||||||
|
PCINT_CALLBACK(0, 16);
|
||||||
|
PCINT_CALLBACK(1, 17);
|
||||||
|
PCINT_CALLBACK(2, 18);
|
||||||
|
PCINT_CALLBACK(3, 19);
|
||||||
|
PCINT_CALLBACK(4, 20);
|
||||||
|
PCINT_CALLBACK(5, 21);
|
||||||
|
PCINT_CALLBACK(6, 22);
|
||||||
|
PCINT_CALLBACK(7, 23);
|
||||||
|
#else
|
||||||
|
PCINT_CALLBACK_PORT2
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if (PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" == true)");
|
||||||
|
Serial.print("volatile callback callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" = pcint_null_callback;");
|
||||||
|
Serial.print("void PinChangeInterruptEventPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("(void){");
|
||||||
|
Serial.print(" callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("();");
|
||||||
|
Serial.println("}");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if (PCINT_USE_PCINT16 == true)
|
||||||
|
volatile callback callbackPCINT16 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT16(void) {
|
||||||
|
callbackPCINT16();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT17 == true)
|
||||||
|
volatile callback callbackPCINT17 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT17(void) {
|
||||||
|
callbackPCINT17();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT18 == true)
|
||||||
|
volatile callback callbackPCINT18 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT18(void) {
|
||||||
|
callbackPCINT18();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT19 == true)
|
||||||
|
volatile callback callbackPCINT19 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT19(void) {
|
||||||
|
callbackPCINT19();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT20 == true)
|
||||||
|
volatile callback callbackPCINT20 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT20(void) {
|
||||||
|
callbackPCINT20();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT21 == true)
|
||||||
|
volatile callback callbackPCINT21 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT21(void) {
|
||||||
|
callbackPCINT21();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT22 == true)
|
||||||
|
volatile callback callbackPCINT22 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT22(void) {
|
||||||
|
callbackPCINT22();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT23 == true)
|
||||||
|
volatile callback callbackPCINT23 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT23(void) {
|
||||||
|
callbackPCINT23();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PCINT_API
|
||||||
|
|
||||||
|
#endif // PCINT_USE_PORT2
|
||||||
|
|
||||||
|
#endif // PCINT_INCLUDE_FROM_CPP
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 "PinChangeInterrupt.h"
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Interrupt Handler
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// prevent compilation twice if included from the .cpp to force compile all ISRs
|
||||||
|
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|
||||||
|
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
|
||||||
|
|
||||||
|
#if (PCINT_USE_PORT3 == true)
|
||||||
|
|
||||||
|
void attachPinChangeInterrupt3(void) {
|
||||||
|
// fake function to make the IDE link this file
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(PCINT3_vect) {
|
||||||
|
// get the new and old pin states for port
|
||||||
|
uint8_t newPort = PCINT_INPUT_PORT3;
|
||||||
|
|
||||||
|
// compare with the old value to detect a rising or falling
|
||||||
|
uint8_t arrayPos = getArrayPosPCINT(3);
|
||||||
|
uint8_t change = newPort ^ oldPorts[arrayPos];
|
||||||
|
uint8_t rising = change & newPort;
|
||||||
|
uint8_t falling = change & oldPorts[arrayPos];
|
||||||
|
|
||||||
|
// check which pins are triggered, compared with the settings
|
||||||
|
uint8_t risingTrigger = rising & risingPorts[arrayPos];
|
||||||
|
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
|
||||||
|
uint8_t trigger = risingTrigger | fallingTrigger;
|
||||||
|
|
||||||
|
// save the new state for next comparison
|
||||||
|
oldPorts[arrayPos] = newPort;
|
||||||
|
|
||||||
|
// Execute all functions that should be triggered
|
||||||
|
// This way we can exclude a single function
|
||||||
|
// and the calling is also much faster
|
||||||
|
// We may also reorder the pins for different priority
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT3)
|
||||||
|
PCINT_CALLBACK(0, 24);
|
||||||
|
PCINT_CALLBACK(1, 25);
|
||||||
|
PCINT_CALLBACK(2, 26);
|
||||||
|
PCINT_CALLBACK(3, 27);
|
||||||
|
PCINT_CALLBACK(4, 28);
|
||||||
|
PCINT_CALLBACK(5, 29);
|
||||||
|
PCINT_CALLBACK(6, 30);
|
||||||
|
PCINT_CALLBACK(7, 31);
|
||||||
|
#else
|
||||||
|
PCINT_CALLBACK_PORT3
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PCINT_API)
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if (PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" == true)");
|
||||||
|
Serial.print("volatile callback callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" = pcint_null_callback;");
|
||||||
|
Serial.print("void PinChangeInterruptEventPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("(void){");
|
||||||
|
Serial.print(" callbackPCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println("();");
|
||||||
|
Serial.println("}");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if (PCINT_USE_PCINT24 == true)
|
||||||
|
volatile callback callbackPCINT24 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT24(void) {
|
||||||
|
callbackPCINT24();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT25 == true)
|
||||||
|
volatile callback callbackPCINT25 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT25(void) {
|
||||||
|
callbackPCINT25();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT26 == true)
|
||||||
|
volatile callback callbackPCINT26 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT26(void) {
|
||||||
|
callbackPCINT26();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT27 == true)
|
||||||
|
volatile callback callbackPCINT27 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT27(void) {
|
||||||
|
callbackPCINT27();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT28 == true)
|
||||||
|
volatile callback callbackPCINT28 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT28(void) {
|
||||||
|
callbackPCINT28();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT29 == true)
|
||||||
|
volatile callback callbackPCINT29 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT29(void) {
|
||||||
|
callbackPCINT29();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT30 == true)
|
||||||
|
volatile callback callbackPCINT30 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT30(void) {
|
||||||
|
callbackPCINT30();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if (PCINT_USE_PCINT31 == true)
|
||||||
|
volatile callback callbackPCINT31 = pcint_null_callback;
|
||||||
|
void PinChangeInterruptEventPCINT31(void) {
|
||||||
|
callbackPCINT31();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PCINT_API
|
||||||
|
|
||||||
|
#endif // PCINT_USE_PORT3
|
||||||
|
|
||||||
|
#endif // PCINT_INCLUDE_FROM_CPP
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 guard
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Board Definitions
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// Microcontroller specific definitions
|
||||||
|
|
||||||
|
#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega88__)
|
||||||
|
// Arduino Uno
|
||||||
|
#define PCINT_INPUT_PORT0 PINB
|
||||||
|
#define PCINT_INPUT_PORT1 PINC
|
||||||
|
#define PCINT_INPUT_PORT2 PIND
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega640__)
|
||||||
|
// Arduino Mega/Mega2560
|
||||||
|
#define PCINT_INPUT_PORT0 PINB
|
||||||
|
#define PCINT_INPUT_PORT2 PINK
|
||||||
|
|
||||||
|
// special Port1 case, pins are on 2 HW Pin Ports (E,J)
|
||||||
|
#if defined(PCINT_ENABLE_PCINT16) // PortE
|
||||||
|
#if defined(PCINT_ENABLE_PCINT17) || defined(PCINT_ENABLE_PCINT18) \
|
||||||
|
|| defined(PCINT_ENABLE_PCINT19) || defined(PCINT_ENABLE_PCINT20) \
|
||||||
|
|| defined(PCINT_ENABLE_PCINT21) || defined(PCINT_ENABLE_PCINT22) \
|
||||||
|
|| defined(PCINT_ENABLE_PCINT23) // PortJ
|
||||||
|
// PortE and PortJ selected
|
||||||
|
#define PCINT_INPUT_PORT1 ((PINE & 0x01) | (PINJ << 1))
|
||||||
|
#else
|
||||||
|
// PortE only selected
|
||||||
|
#define PCINT_INPUT_PORT1 PINE
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// PortJ only selected
|
||||||
|
// we still have to do the shift because the attach
|
||||||
|
// function is not designed for this optimization
|
||||||
|
#define PCINT_INPUT_PORT1 (PINJ << 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
|
||||||
|
// Arduino Leonardo/Micro
|
||||||
|
#define PCINT_INPUT_PORT0 PINB
|
||||||
|
|
||||||
|
#elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
|
||||||
|
// u2 Series/HoodLoader2
|
||||||
|
// u2 Series has crappy pin mappings for port 1
|
||||||
|
#define PCINT_INPUT_PORT0 PINB
|
||||||
|
#define PCINT_INPUT_PORT1 (((PINC >> 6) & (1 << 0)) | ((PINC >> 4) & (1 << 1)) | ((PINC >> 2) & (1 << 2)) | ((PINC << 1) & (1 << 3)) | ((PIND >> 1) & (1 << 4)))
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||||
|
// Attiny x5
|
||||||
|
#define PCINT_INPUT_PORT0 PINB
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATtiny13__)
|
||||||
|
// Attiny 13A
|
||||||
|
#define PCINT_INPUT_PORT0 PINB
|
||||||
|
#ifndef portInputRegister
|
||||||
|
#define portInputRegister(P) ( (volatile uint8_t *)(PINB) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||||
|
// Attiny x4
|
||||||
|
#define PCINT_INPUT_PORT0 PINA
|
||||||
|
#define PCINT_INPUT_PORT1 PINB
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||||
|
// 1284p and 644p, special 4 port case
|
||||||
|
#define PCINT_INPUT_PORT0 PINA
|
||||||
|
#define PCINT_INPUT_PORT1 PINB
|
||||||
|
#define PCINT_INPUT_PORT2 PINC
|
||||||
|
#define PCINT_INPUT_PORT3 PIND
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATtinyX41__) || defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__)
|
||||||
|
// Attiny x41
|
||||||
|
#define PCINT_INPUT_PORT0 PINA
|
||||||
|
#define PCINT_INPUT_PORT1 PINB
|
||||||
|
|
||||||
|
// "iotn841.h" is missing those definitions, so we add them here
|
||||||
|
#define PCINT0 0
|
||||||
|
#define PCINT1 1
|
||||||
|
#define PCINT2 2
|
||||||
|
#define PCINT3 3
|
||||||
|
#define PCINT4 4
|
||||||
|
#define PCINT5 5
|
||||||
|
#define PCINT6 6
|
||||||
|
#define PCINT7 7
|
||||||
|
|
||||||
|
#define PCINT8 0
|
||||||
|
#define PCINT9 1
|
||||||
|
#define PCINT10 2
|
||||||
|
#define PCINT11 3
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATtinyX313__)
|
||||||
|
// ATtiny x313, PORT A is almost useless, left out here
|
||||||
|
#define PCINT_INPUT_PORT1 PINB
|
||||||
|
#define PCINT_INPUT_PORT2 PIND
|
||||||
|
|
||||||
|
#else // Microcontroller not supported
|
||||||
|
#error PinChangeInterrupt library does not support this MCU.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Add missing definitions
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// add fakes if ports are not used
|
||||||
|
#ifndef PCINT_INPUT_PORT0
|
||||||
|
#define PCINT_INPUT_PORT0 0
|
||||||
|
#else
|
||||||
|
#define PCINT_INPUT_PORT0_USED
|
||||||
|
#endif
|
||||||
|
#ifndef PCINT_INPUT_PORT1
|
||||||
|
#define PCINT_INPUT_PORT1 0
|
||||||
|
#else
|
||||||
|
#define PCINT_INPUT_PORT1_USED
|
||||||
|
#endif
|
||||||
|
#ifndef PCINT_INPUT_PORT2
|
||||||
|
#define PCINT_INPUT_PORT2 0
|
||||||
|
#else
|
||||||
|
#define PCINT_INPUT_PORT2_USED
|
||||||
|
#endif
|
||||||
|
#ifndef PCINT_INPUT_PORT3
|
||||||
|
#define PCINT_INPUT_PORT3 0
|
||||||
|
#else
|
||||||
|
#define PCINT_INPUT_PORT3_USED
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,926 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2017 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 guard
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
The strategy in this file:
|
||||||
|
|
||||||
|
0. Makefile optimization:
|
||||||
|
To disable PCINT/PORTs via makefile use -DPCINT_DISABLE_PORT0 etc.
|
||||||
|
This will undef a previously defined PCINT_ENABLE_PORT0.
|
||||||
|
|
||||||
|
1. Reduce the user settings to the enabled pins.
|
||||||
|
If the whole port is deactivated, also disable all pins on this port.
|
||||||
|
|
||||||
|
2. Define the hardware available pins/ports.
|
||||||
|
|
||||||
|
3. Compare the hardware definition with the enabled pin definitions.
|
||||||
|
If the pin is available and enabled, create a makro to use the pin.
|
||||||
|
|
||||||
|
4. Count all used pins (for each port).
|
||||||
|
|
||||||
|
5. If there are no pins used on a port, do not use the port
|
||||||
|
|
||||||
|
6. Finally we have a clear defintion of the used pins/ports like this:
|
||||||
|
PCINT_USE_PCINT0 (true/false)
|
||||||
|
PCINT_USE_PORT0 (true/false)
|
||||||
|
|
||||||
|
Other definitions that can be used:
|
||||||
|
PCINT_HAS_PORT0 (true/false)
|
||||||
|
PCINT_HAS_PCINT0 (true/false)
|
||||||
|
PCINT_NUM_PINS_PORT0 (0-8)
|
||||||
|
PCINT_NUM_USED_PINS_PORT0 (0-8)
|
||||||
|
EXTERNAL_NUM_PINCHANGEINTERRUPT (0-24)
|
||||||
|
EXTERNAL_NUM_USED_PINCHANGEINTERRUPT (0-24)
|
||||||
|
PCINT_NUM_PORTS (0-3)
|
||||||
|
PCINT_NUM_USED_PORTS (0-3)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Disabled Pins
|
||||||
|
//================================================================================
|
||||||
|
/*
|
||||||
|
for (int port = 0; port < 4; port++) {
|
||||||
|
Serial.print("#if defined(PCINT_ENABLE_PORT");
|
||||||
|
Serial.print(port);
|
||||||
|
Serial.print(") && defined(PCINT_DISABLE_PORT");
|
||||||
|
Serial.print(port);
|
||||||
|
Serial.println(")");
|
||||||
|
Serial.print("#undef PCINT_ENABLE_PORT");
|
||||||
|
Serial.println(port);
|
||||||
|
Serial.println("#endif");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if defined(PCINT_ENABLE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(") && defined(PCINT_DISABLE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(")");
|
||||||
|
Serial.print("#undef PCINT_ENABLE_PCINT");
|
||||||
|
Serial.println(i);
|
||||||
|
Serial.println("#endif");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if defined(PCINT_ENABLE_PORT0) && defined(PCINT_DISABLE_PORT0)
|
||||||
|
#undef PCINT_ENABLE_PORT0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PORT1) && defined(PCINT_DISABLE_PORT1)
|
||||||
|
#undef PCINT_ENABLE_PORT1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PORT2) && defined(PCINT_DISABLE_PORT2)
|
||||||
|
#undef PCINT_ENABLE_PORT2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PORT3) && defined(PCINT_DISABLE_PORT3)
|
||||||
|
#undef PCINT_ENABLE_PORT3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT0) && defined(PCINT_DISABLE_PCINT0)
|
||||||
|
#undef PCINT_ENABLE_PCINT0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT1) && defined(PCINT_DISABLE_PCINT1)
|
||||||
|
#undef PCINT_ENABLE_PCINT1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT2) && defined(PCINT_DISABLE_PCINT2)
|
||||||
|
#undef PCINT_ENABLE_PCINT2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT3) && defined(PCINT_DISABLE_PCINT3)
|
||||||
|
#undef PCINT_ENABLE_PCINT3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT4) && defined(PCINT_DISABLE_PCINT4)
|
||||||
|
#undef PCINT_ENABLE_PCINT4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT5) && defined(PCINT_DISABLE_PCINT5)
|
||||||
|
#undef PCINT_ENABLE_PCINT5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT6) && defined(PCINT_DISABLE_PCINT6)
|
||||||
|
#undef PCINT_ENABLE_PCINT6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT7) && defined(PCINT_DISABLE_PCINT7)
|
||||||
|
#undef PCINT_ENABLE_PCINT7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT8) && defined(PCINT_DISABLE_PCINT8)
|
||||||
|
#undef PCINT_ENABLE_PCINT8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT9) && defined(PCINT_DISABLE_PCINT9)
|
||||||
|
#undef PCINT_ENABLE_PCINT9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT10) && defined(PCINT_DISABLE_PCINT10)
|
||||||
|
#undef PCINT_ENABLE_PCINT10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT11) && defined(PCINT_DISABLE_PCINT11)
|
||||||
|
#undef PCINT_ENABLE_PCINT11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT12) && defined(PCINT_DISABLE_PCINT12)
|
||||||
|
#undef PCINT_ENABLE_PCINT12
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT13) && defined(PCINT_DISABLE_PCINT13)
|
||||||
|
#undef PCINT_ENABLE_PCINT13
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT14) && defined(PCINT_DISABLE_PCINT14)
|
||||||
|
#undef PCINT_ENABLE_PCINT14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT15) && defined(PCINT_DISABLE_PCINT15)
|
||||||
|
#undef PCINT_ENABLE_PCINT15
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT16) && defined(PCINT_DISABLE_PCINT16)
|
||||||
|
#undef PCINT_ENABLE_PCINT16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT17) && defined(PCINT_DISABLE_PCINT17)
|
||||||
|
#undef PCINT_ENABLE_PCINT17
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT18) && defined(PCINT_DISABLE_PCINT18)
|
||||||
|
#undef PCINT_ENABLE_PCINT18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT19) && defined(PCINT_DISABLE_PCINT19)
|
||||||
|
#undef PCINT_ENABLE_PCINT19
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT20) && defined(PCINT_DISABLE_PCINT20)
|
||||||
|
#undef PCINT_ENABLE_PCINT20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT21) && defined(PCINT_DISABLE_PCINT21)
|
||||||
|
#undef PCINT_ENABLE_PCINT21
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT22) && defined(PCINT_DISABLE_PCINT22)
|
||||||
|
#undef PCINT_ENABLE_PCINT22
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT23) && defined(PCINT_DISABLE_PCINT23)
|
||||||
|
#undef PCINT_ENABLE_PCINT23
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT24) && defined(PCINT_DISABLE_PCINT24)
|
||||||
|
#undef PCINT_ENABLE_PCINT24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT25) && defined(PCINT_DISABLE_PCINT25)
|
||||||
|
#undef PCINT_ENABLE_PCINT25
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT26) && defined(PCINT_DISABLE_PCINT26)
|
||||||
|
#undef PCINT_ENABLE_PCINT26
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT27) && defined(PCINT_DISABLE_PCINT27)
|
||||||
|
#undef PCINT_ENABLE_PCINT27
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT28) && defined(PCINT_DISABLE_PCINT28)
|
||||||
|
#undef PCINT_ENABLE_PCINT28
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT29) && defined(PCINT_DISABLE_PCINT29)
|
||||||
|
#undef PCINT_ENABLE_PCINT29
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT30) && defined(PCINT_DISABLE_PCINT30)
|
||||||
|
#undef PCINT_ENABLE_PCINT30
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PCINT_ENABLE_PCINT31) && defined(PCINT_DISABLE_PCINT31)
|
||||||
|
#undef PCINT_ENABLE_PCINT31
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Enabled Pins
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
/* Disable all pins on a port, if port is deactivated
|
||||||
|
We could then check every pin -> port definition
|
||||||
|
But that'd be a mess and doesnt help
|
||||||
|
Users who deactivate stuff should know
|
||||||
|
what the are doing.
|
||||||
|
So we use the enabled pins for all next definitions*/
|
||||||
|
/*
|
||||||
|
for (int port = 0; port < 4; port++) {
|
||||||
|
Serial.print("#if !defined(PCINT_ENABLE_PORT");
|
||||||
|
Serial.print(port);
|
||||||
|
Serial.println(")");
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
Serial.print("#if defined(PCINT_ENABLE_PCINT");
|
||||||
|
Serial.print(port * 8 + i);
|
||||||
|
Serial.println(")");
|
||||||
|
Serial.print("#undef PCINT_ENABLE_PCINT");
|
||||||
|
Serial.println(port * 8 + i);
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
Serial.println("#endif");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if !defined(PCINT_ENABLE_PORT0)
|
||||||
|
#if defined(PCINT_ENABLE_PCINT0)
|
||||||
|
#undef PCINT_ENABLE_PCINT0
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT1)
|
||||||
|
#undef PCINT_ENABLE_PCINT1
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT2)
|
||||||
|
#undef PCINT_ENABLE_PCINT2
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT3)
|
||||||
|
#undef PCINT_ENABLE_PCINT3
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT4)
|
||||||
|
#undef PCINT_ENABLE_PCINT4
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT5)
|
||||||
|
#undef PCINT_ENABLE_PCINT5
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT6)
|
||||||
|
#undef PCINT_ENABLE_PCINT6
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT7)
|
||||||
|
#undef PCINT_ENABLE_PCINT7
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(PCINT_ENABLE_PORT1)
|
||||||
|
#if defined(PCINT_ENABLE_PCINT8)
|
||||||
|
#undef PCINT_ENABLE_PCINT8
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT9)
|
||||||
|
#undef PCINT_ENABLE_PCINT9
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT10)
|
||||||
|
#undef PCINT_ENABLE_PCINT10
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT11)
|
||||||
|
#undef PCINT_ENABLE_PCINT11
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT12)
|
||||||
|
#undef PCINT_ENABLE_PCINT12
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT13)
|
||||||
|
#undef PCINT_ENABLE_PCINT13
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT14)
|
||||||
|
#undef PCINT_ENABLE_PCINT14
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT15)
|
||||||
|
#undef PCINT_ENABLE_PCINT15
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(PCINT_ENABLE_PORT2)
|
||||||
|
#if defined(PCINT_ENABLE_PCINT16)
|
||||||
|
#undef PCINT_ENABLE_PCINT16
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT17)
|
||||||
|
#undef PCINT_ENABLE_PCINT17
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT18)
|
||||||
|
#undef PCINT_ENABLE_PCINT18
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT19)
|
||||||
|
#undef PCINT_ENABLE_PCINT19
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT20)
|
||||||
|
#undef PCINT_ENABLE_PCINT20
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT21)
|
||||||
|
#undef PCINT_ENABLE_PCINT21
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT22)
|
||||||
|
#undef PCINT_ENABLE_PCINT22
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT23)
|
||||||
|
#undef PCINT_ENABLE_PCINT23
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(PCINT_ENABLE_PORT3)
|
||||||
|
#if defined(PCINT_ENABLE_PCINT24)
|
||||||
|
#undef PCINT_ENABLE_PCINT24
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT25)
|
||||||
|
#undef PCINT_ENABLE_PCINT25
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT26)
|
||||||
|
#undef PCINT_ENABLE_PCINT26
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT27)
|
||||||
|
#undef PCINT_ENABLE_PCINT27
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT28)
|
||||||
|
#undef PCINT_ENABLE_PCINT28
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT29)
|
||||||
|
#undef PCINT_ENABLE_PCINT29
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT30)
|
||||||
|
#undef PCINT_ENABLE_PCINT30
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT31)
|
||||||
|
#undef PCINT_ENABLE_PCINT31
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Hardware Definitions
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
#if defined(PCINT0_vect)
|
||||||
|
#define PCINT_HAS_PORT0 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PORT0 false
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT1_vect)
|
||||||
|
#define PCINT_HAS_PORT1 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PORT1 false
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT2_vect)
|
||||||
|
#define PCINT_HAS_PORT2 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PORT2 false
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT3_vect)
|
||||||
|
#define PCINT_HAS_PORT3 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PORT3 false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// number of available ports
|
||||||
|
#define PCINT_NUM_PORTS ( \
|
||||||
|
PCINT_HAS_PORT0 + \
|
||||||
|
PCINT_HAS_PORT1 + \
|
||||||
|
PCINT_HAS_PORT2 + \
|
||||||
|
PCINT_HAS_PORT3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#ifdef PCINT");
|
||||||
|
Serial.println(i);
|
||||||
|
Serial.print("#define PCINT_HAS_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" true");
|
||||||
|
Serial.println("#else");
|
||||||
|
Serial.print("#define PCINT_HAS_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" false");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#ifdef PCINT0
|
||||||
|
#define PCINT_HAS_PCINT0 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT0 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT1
|
||||||
|
#define PCINT_HAS_PCINT1 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT1 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT2
|
||||||
|
#define PCINT_HAS_PCINT2 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT2 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT3
|
||||||
|
#define PCINT_HAS_PCINT3 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT3 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT4
|
||||||
|
#define PCINT_HAS_PCINT4 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT4 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT5
|
||||||
|
#define PCINT_HAS_PCINT5 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT5 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT6
|
||||||
|
#define PCINT_HAS_PCINT6 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT6 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT7
|
||||||
|
#define PCINT_HAS_PCINT7 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT7 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT8
|
||||||
|
#define PCINT_HAS_PCINT8 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT8 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT9
|
||||||
|
#define PCINT_HAS_PCINT9 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT9 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT10
|
||||||
|
#define PCINT_HAS_PCINT10 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT10 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT11
|
||||||
|
#define PCINT_HAS_PCINT11 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT11 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT12
|
||||||
|
#define PCINT_HAS_PCINT12 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT12 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT13
|
||||||
|
#define PCINT_HAS_PCINT13 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT13 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT14
|
||||||
|
#define PCINT_HAS_PCINT14 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT14 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT15
|
||||||
|
#define PCINT_HAS_PCINT15 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT15 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT16
|
||||||
|
#define PCINT_HAS_PCINT16 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT16 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT17
|
||||||
|
#define PCINT_HAS_PCINT17 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT17 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT18
|
||||||
|
#define PCINT_HAS_PCINT18 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT18 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT19
|
||||||
|
#define PCINT_HAS_PCINT19 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT19 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT20
|
||||||
|
#define PCINT_HAS_PCINT20 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT20 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT21
|
||||||
|
#define PCINT_HAS_PCINT21 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT21 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT22
|
||||||
|
#define PCINT_HAS_PCINT22 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT22 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT23
|
||||||
|
#define PCINT_HAS_PCINT23 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT23 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT24
|
||||||
|
#define PCINT_HAS_PCINT24 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT24 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT25
|
||||||
|
#define PCINT_HAS_PCINT25 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT25 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT26
|
||||||
|
#define PCINT_HAS_PCINT26 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT26 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT27
|
||||||
|
#define PCINT_HAS_PCINT27 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT27 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT28
|
||||||
|
#define PCINT_HAS_PCINT28 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT28 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT29
|
||||||
|
#define PCINT_HAS_PCINT29 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT29 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT30
|
||||||
|
#define PCINT_HAS_PCINT30 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT30 false
|
||||||
|
#endif
|
||||||
|
#ifdef PCINT31
|
||||||
|
#define PCINT_HAS_PCINT31 true
|
||||||
|
#else
|
||||||
|
#define PCINT_HAS_PCINT31 false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// count numbers of available pins on each port
|
||||||
|
/*
|
||||||
|
for (int port = 0; port < 4; port++) {
|
||||||
|
Serial.print("#define PCINT_NUM_PINS_PORT");
|
||||||
|
Serial.print(port);
|
||||||
|
Serial.println(" ( \\");
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
Serial.print("PCINT_HAS_PCINT");
|
||||||
|
Serial.print(port * 8 + i);
|
||||||
|
if (i != 7)
|
||||||
|
Serial.println(" + \\");
|
||||||
|
}
|
||||||
|
Serial.println(")");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#define PCINT_NUM_PINS_PORT0 ( \
|
||||||
|
PCINT_HAS_PCINT0 + \
|
||||||
|
PCINT_HAS_PCINT1 + \
|
||||||
|
PCINT_HAS_PCINT2 + \
|
||||||
|
PCINT_HAS_PCINT3 + \
|
||||||
|
PCINT_HAS_PCINT4 + \
|
||||||
|
PCINT_HAS_PCINT5 + \
|
||||||
|
PCINT_HAS_PCINT6 + \
|
||||||
|
PCINT_HAS_PCINT7)
|
||||||
|
|
||||||
|
#define PCINT_NUM_PINS_PORT1 ( \
|
||||||
|
PCINT_HAS_PCINT8 + \
|
||||||
|
PCINT_HAS_PCINT9 + \
|
||||||
|
PCINT_HAS_PCINT10 + \
|
||||||
|
PCINT_HAS_PCINT11 + \
|
||||||
|
PCINT_HAS_PCINT12 + \
|
||||||
|
PCINT_HAS_PCINT13 + \
|
||||||
|
PCINT_HAS_PCINT14 + \
|
||||||
|
PCINT_HAS_PCINT15)
|
||||||
|
|
||||||
|
#define PCINT_NUM_PINS_PORT2 ( \
|
||||||
|
PCINT_HAS_PCINT16 + \
|
||||||
|
PCINT_HAS_PCINT17 + \
|
||||||
|
PCINT_HAS_PCINT18 + \
|
||||||
|
PCINT_HAS_PCINT19 + \
|
||||||
|
PCINT_HAS_PCINT20 + \
|
||||||
|
PCINT_HAS_PCINT21 + \
|
||||||
|
PCINT_HAS_PCINT22 + \
|
||||||
|
PCINT_HAS_PCINT23)
|
||||||
|
|
||||||
|
#define PCINT_NUM_PINS_PORT3 ( \
|
||||||
|
PCINT_HAS_PCINT24 + \
|
||||||
|
PCINT_HAS_PCINT25 + \
|
||||||
|
PCINT_HAS_PCINT26 + \
|
||||||
|
PCINT_HAS_PCINT27 + \
|
||||||
|
PCINT_HAS_PCINT28 + \
|
||||||
|
PCINT_HAS_PCINT29 + \
|
||||||
|
PCINT_HAS_PCINT30 + \
|
||||||
|
PCINT_HAS_PCINT31)
|
||||||
|
|
||||||
|
|
||||||
|
// number of available hardware pins
|
||||||
|
#define EXTERNAL_NUM_PINCHANGEINTERRUPT ( \
|
||||||
|
PCINT_NUM_PINS_PORT0 + \
|
||||||
|
PCINT_NUM_PINS_PORT1 + \
|
||||||
|
PCINT_NUM_PINS_PORT2 + \
|
||||||
|
PCINT_NUM_PINS_PORT3)
|
||||||
|
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Used Pins
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// check if pins are physically available and enabled
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
Serial.print("#if (PCINT_HAS_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(" == true) && defined(PCINT_ENABLE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(")");
|
||||||
|
Serial.print("#define PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" true");
|
||||||
|
Serial.println("#else");
|
||||||
|
Serial.print("#define PCINT_USE_PCINT");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.println(" false");
|
||||||
|
Serial.println("#endif");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if (PCINT_HAS_PCINT0 == true) && defined(PCINT_ENABLE_PCINT0)
|
||||||
|
#define PCINT_USE_PCINT0 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT0 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT1 == true) && defined(PCINT_ENABLE_PCINT1)
|
||||||
|
#define PCINT_USE_PCINT1 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT1 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT2 == true) && defined(PCINT_ENABLE_PCINT2)
|
||||||
|
#define PCINT_USE_PCINT2 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT2 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT3 == true) && defined(PCINT_ENABLE_PCINT3)
|
||||||
|
#define PCINT_USE_PCINT3 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT3 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT4 == true) && defined(PCINT_ENABLE_PCINT4)
|
||||||
|
#define PCINT_USE_PCINT4 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT4 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT5 == true) && defined(PCINT_ENABLE_PCINT5)
|
||||||
|
#define PCINT_USE_PCINT5 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT5 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT6 == true) && defined(PCINT_ENABLE_PCINT6)
|
||||||
|
#define PCINT_USE_PCINT6 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT6 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT7 == true) && defined(PCINT_ENABLE_PCINT7)
|
||||||
|
#define PCINT_USE_PCINT7 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT7 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT8 == true) && defined(PCINT_ENABLE_PCINT8)
|
||||||
|
#define PCINT_USE_PCINT8 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT8 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT9 == true) && defined(PCINT_ENABLE_PCINT9)
|
||||||
|
#define PCINT_USE_PCINT9 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT9 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT10 == true) && defined(PCINT_ENABLE_PCINT10)
|
||||||
|
#define PCINT_USE_PCINT10 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT10 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT11 == true) && defined(PCINT_ENABLE_PCINT11)
|
||||||
|
#define PCINT_USE_PCINT11 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT11 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT12 == true) && defined(PCINT_ENABLE_PCINT12)
|
||||||
|
#define PCINT_USE_PCINT12 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT12 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT13 == true) && defined(PCINT_ENABLE_PCINT13)
|
||||||
|
#define PCINT_USE_PCINT13 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT13 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT14 == true) && defined(PCINT_ENABLE_PCINT14)
|
||||||
|
#define PCINT_USE_PCINT14 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT14 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT15 == true) && defined(PCINT_ENABLE_PCINT15)
|
||||||
|
#define PCINT_USE_PCINT15 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT15 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT16 == true) && defined(PCINT_ENABLE_PCINT16)
|
||||||
|
#define PCINT_USE_PCINT16 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT16 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT17 == true) && defined(PCINT_ENABLE_PCINT17)
|
||||||
|
#define PCINT_USE_PCINT17 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT17 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT18 == true) && defined(PCINT_ENABLE_PCINT18)
|
||||||
|
#define PCINT_USE_PCINT18 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT18 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT19 == true) && defined(PCINT_ENABLE_PCINT19)
|
||||||
|
#define PCINT_USE_PCINT19 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT19 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT20 == true) && defined(PCINT_ENABLE_PCINT20)
|
||||||
|
#define PCINT_USE_PCINT20 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT20 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT21 == true) && defined(PCINT_ENABLE_PCINT21)
|
||||||
|
#define PCINT_USE_PCINT21 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT21 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT22 == true) && defined(PCINT_ENABLE_PCINT22)
|
||||||
|
#define PCINT_USE_PCINT22 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT22 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT23 == true) && defined(PCINT_ENABLE_PCINT23)
|
||||||
|
#define PCINT_USE_PCINT23 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT23 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT24 == true) && defined(PCINT_ENABLE_PCINT24)
|
||||||
|
#define PCINT_USE_PCINT24 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT24 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT25 == true) && defined(PCINT_ENABLE_PCINT25)
|
||||||
|
#define PCINT_USE_PCINT25 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT25 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT26 == true) && defined(PCINT_ENABLE_PCINT26)
|
||||||
|
#define PCINT_USE_PCINT26 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT26 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT27 == true) && defined(PCINT_ENABLE_PCINT27)
|
||||||
|
#define PCINT_USE_PCINT27 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT27 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT28 == true) && defined(PCINT_ENABLE_PCINT28)
|
||||||
|
#define PCINT_USE_PCINT28 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT28 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT29 == true) && defined(PCINT_ENABLE_PCINT29)
|
||||||
|
#define PCINT_USE_PCINT29 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT29 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT30 == true) && defined(PCINT_ENABLE_PCINT30)
|
||||||
|
#define PCINT_USE_PCINT30 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT30 false
|
||||||
|
#endif
|
||||||
|
#if (PCINT_HAS_PCINT31 == true) && defined(PCINT_ENABLE_PCINT31)
|
||||||
|
#define PCINT_USE_PCINT31 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PCINT31 false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Number Used Pins
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// count numbers of used pins on each port
|
||||||
|
/*
|
||||||
|
for (int port = 0; port < 4; port++) {
|
||||||
|
Serial.print("#define PCINT_NUM_USED_PINS_PORT");
|
||||||
|
Serial.print(port);
|
||||||
|
Serial.println(" ( \\");
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
Serial.print("PCINT_USE_PCINT");
|
||||||
|
Serial.print(port * 8 + i);
|
||||||
|
if (i != 7)
|
||||||
|
Serial.println(" + \\");
|
||||||
|
}
|
||||||
|
Serial.println(")");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#define PCINT_NUM_USED_PINS_PORT0 ( \
|
||||||
|
PCINT_USE_PCINT0 + \
|
||||||
|
PCINT_USE_PCINT1 + \
|
||||||
|
PCINT_USE_PCINT2 + \
|
||||||
|
PCINT_USE_PCINT3 + \
|
||||||
|
PCINT_USE_PCINT4 + \
|
||||||
|
PCINT_USE_PCINT5 + \
|
||||||
|
PCINT_USE_PCINT6 + \
|
||||||
|
PCINT_USE_PCINT7)
|
||||||
|
|
||||||
|
#define PCINT_NUM_USED_PINS_PORT1 ( \
|
||||||
|
PCINT_USE_PCINT8 + \
|
||||||
|
PCINT_USE_PCINT9 + \
|
||||||
|
PCINT_USE_PCINT10 + \
|
||||||
|
PCINT_USE_PCINT11 + \
|
||||||
|
PCINT_USE_PCINT12 + \
|
||||||
|
PCINT_USE_PCINT13 + \
|
||||||
|
PCINT_USE_PCINT14 + \
|
||||||
|
PCINT_USE_PCINT15)
|
||||||
|
|
||||||
|
#define PCINT_NUM_USED_PINS_PORT2 ( \
|
||||||
|
PCINT_USE_PCINT16 + \
|
||||||
|
PCINT_USE_PCINT17 + \
|
||||||
|
PCINT_USE_PCINT18 + \
|
||||||
|
PCINT_USE_PCINT19 + \
|
||||||
|
PCINT_USE_PCINT20 + \
|
||||||
|
PCINT_USE_PCINT21 + \
|
||||||
|
PCINT_USE_PCINT22 + \
|
||||||
|
PCINT_USE_PCINT23)
|
||||||
|
|
||||||
|
#define PCINT_NUM_USED_PINS_PORT3 ( \
|
||||||
|
PCINT_USE_PCINT24 + \
|
||||||
|
PCINT_USE_PCINT25 + \
|
||||||
|
PCINT_USE_PCINT26 + \
|
||||||
|
PCINT_USE_PCINT27 + \
|
||||||
|
PCINT_USE_PCINT28 + \
|
||||||
|
PCINT_USE_PCINT29 + \
|
||||||
|
PCINT_USE_PCINT30 + \
|
||||||
|
PCINT_USE_PCINT31)
|
||||||
|
|
||||||
|
|
||||||
|
// number of used hardware pins
|
||||||
|
#define EXTERNAL_NUM_USED_PINCHANGEINTERRUPT ( \
|
||||||
|
PCINT_NUM_USED_PINS_PORT0 + \
|
||||||
|
PCINT_NUM_USED_PINS_PORT1 + \
|
||||||
|
PCINT_NUM_USED_PINS_PORT2 + \
|
||||||
|
PCINT_NUM_USED_PINS_PORT3)
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Used Ports
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// check if ports are used
|
||||||
|
#if PCINT_NUM_USED_PINS_PORT0
|
||||||
|
#define PCINT_USE_PORT0 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PORT0 false
|
||||||
|
#endif
|
||||||
|
#if PCINT_NUM_USED_PINS_PORT1
|
||||||
|
#define PCINT_USE_PORT1 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PORT1 false
|
||||||
|
#endif
|
||||||
|
#if PCINT_NUM_USED_PINS_PORT2
|
||||||
|
#define PCINT_USE_PORT2 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PORT2 false
|
||||||
|
#endif
|
||||||
|
#if PCINT_NUM_USED_PINS_PORT3
|
||||||
|
#define PCINT_USE_PORT3 true
|
||||||
|
#else
|
||||||
|
#define PCINT_USE_PORT3 false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// number of used ports
|
||||||
|
#define PCINT_NUM_USED_PORTS ( \
|
||||||
|
PCINT_USE_PORT0 + \
|
||||||
|
PCINT_USE_PORT1 + \
|
||||||
|
PCINT_USE_PORT2 + \
|
||||||
|
PCINT_USE_PORT3)
|
||||||
|
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
See the readme for credit to other people.
|
||||||
|
|
||||||
|
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 guard
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// General Settings
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
/* Settings to de/activate ports/pins
|
||||||
|
This will save you flash and ram because the arrays
|
||||||
|
are managed dynamically with the definitions below.
|
||||||
|
Make sure you still have all needed ports activated.
|
||||||
|
Each deactivated port saves 3 bytes of ram.
|
||||||
|
If you deactivate the whole port,
|
||||||
|
you dont need to deactivate the pins.
|
||||||
|
Same for the port if you deactivate all 8 pins.
|
||||||
|
You dont have to deactivate pins/ports that dont exist.
|
||||||
|
That is done by the macros. */
|
||||||
|
|
||||||
|
#ifndef PCINT_ENABLE_MANUAL
|
||||||
|
|
||||||
|
#define PCINT_ENABLE_PORT0
|
||||||
|
#define PCINT_ENABLE_PORT1
|
||||||
|
#define PCINT_ENABLE_PORT2
|
||||||
|
#define PCINT_ENABLE_PORT3
|
||||||
|
|
||||||
|
#define PCINT_ENABLE_PCINT0
|
||||||
|
#define PCINT_ENABLE_PCINT1
|
||||||
|
#define PCINT_ENABLE_PCINT2
|
||||||
|
#define PCINT_ENABLE_PCINT3
|
||||||
|
#define PCINT_ENABLE_PCINT4
|
||||||
|
#define PCINT_ENABLE_PCINT5
|
||||||
|
#define PCINT_ENABLE_PCINT6
|
||||||
|
#define PCINT_ENABLE_PCINT7
|
||||||
|
#define PCINT_ENABLE_PCINT8
|
||||||
|
#define PCINT_ENABLE_PCINT9
|
||||||
|
#define PCINT_ENABLE_PCINT10
|
||||||
|
#define PCINT_ENABLE_PCINT11
|
||||||
|
#define PCINT_ENABLE_PCINT12
|
||||||
|
#define PCINT_ENABLE_PCINT13
|
||||||
|
#define PCINT_ENABLE_PCINT14
|
||||||
|
#define PCINT_ENABLE_PCINT15
|
||||||
|
#define PCINT_ENABLE_PCINT16
|
||||||
|
#define PCINT_ENABLE_PCINT17
|
||||||
|
#define PCINT_ENABLE_PCINT18
|
||||||
|
#define PCINT_ENABLE_PCINT19
|
||||||
|
#define PCINT_ENABLE_PCINT20
|
||||||
|
#define PCINT_ENABLE_PCINT21
|
||||||
|
#define PCINT_ENABLE_PCINT22
|
||||||
|
#define PCINT_ENABLE_PCINT23
|
||||||
|
#define PCINT_ENABLE_PCINT24
|
||||||
|
#define PCINT_ENABLE_PCINT25
|
||||||
|
#define PCINT_ENABLE_PCINT26
|
||||||
|
#define PCINT_ENABLE_PCINT27
|
||||||
|
#define PCINT_ENABLE_PCINT28
|
||||||
|
#define PCINT_ENABLE_PCINT29
|
||||||
|
#define PCINT_ENABLE_PCINT30
|
||||||
|
#define PCINT_ENABLE_PCINT31
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
// use API with function pointers (better optimized with .a linkage)
|
||||||
|
#define PCINT_API
|
||||||
|
|
||||||
|
// is the library compiled via .a file?
|
||||||
|
// see readme for more information
|
||||||
|
#define PCINT_ALINKAGE
|
||||||
|
|
||||||
|
// force compile all enabled port ISRs (with .a linkage)
|
||||||
|
//#define PCINT_COMPILE_ENABLED_ISR
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// Suggested Settings
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
// Arduino Uno (328)
|
||||||
|
#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega88__)
|
||||||
|
/* Reordering interrupt callbacks priority
|
||||||
|
Port0 has SPI on higher pins, ordering is fine
|
||||||
|
Port1 has I2C on higher pins, ordering is fine
|
||||||
|
Port2 has USART and Pin Interrupt on lower pins,
|
||||||
|
move the priority down
|
||||||
|
Its more likely the user will use pin 4-7
|
||||||
|
*/
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT2)
|
||||||
|
#define PCINT_CALLBACK_PORT2 \
|
||||||
|
PCINT_CALLBACK(4, 20); \
|
||||||
|
PCINT_CALLBACK(5, 21); \
|
||||||
|
PCINT_CALLBACK(6, 22); \
|
||||||
|
PCINT_CALLBACK(7, 23); \
|
||||||
|
PCINT_CALLBACK(0, 16); /* USART RX */ \
|
||||||
|
PCINT_CALLBACK(1, 17); /* USART TX */ \
|
||||||
|
PCINT_CALLBACK(2, 18); /* Pin Interrupt 0 */ \
|
||||||
|
PCINT_CALLBACK(3, 19); /* Pin Interrupt 1 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// deactivate crystal and reset pins by default
|
||||||
|
#if defined(PCINT_ENABLE_PCINT6)
|
||||||
|
#undef PCINT_ENABLE_PCINT6 // crystal
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT7)
|
||||||
|
#undef PCINT_ENABLE_PCINT7 // crystal
|
||||||
|
#endif
|
||||||
|
#if defined(PCINT_ENABLE_PCINT14)
|
||||||
|
#undef PCINT_ENABLE_PCINT14 // reset
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Arduino Mega (2560)
|
||||||
|
#if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_MEGA)
|
||||||
|
/* Port1 is structured a bit more complicated
|
||||||
|
Also only 3 pins are connected on standard boards
|
||||||
|
Seeeduino Mega has these pins optional!
|
||||||
|
Disabling Port1 gives more speed and uses less flash
|
||||||
|
Pins: 0(RX0), 14(TX3), 15(RX3) */
|
||||||
|
#if defined(PCINT_ENABLE_PORT1)
|
||||||
|
#undef PCINT_ENABLE_PORT1 // better performence
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Reordering interrupt callbacks priority
|
||||||
|
Port2 has SPI on lower pins, move the priority down
|
||||||
|
Its more likely the user will use pin 10-13
|
||||||
|
Port1 by default deactivated, ordering is fine
|
||||||
|
Port2 only has ADCs, ordering is fine
|
||||||
|
*/
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT0)
|
||||||
|
#define PCINT_CALLBACK_PORT0 \
|
||||||
|
PCINT_CALLBACK(4, 4); \
|
||||||
|
PCINT_CALLBACK(5, 5); \
|
||||||
|
PCINT_CALLBACK(6, 6); \
|
||||||
|
PCINT_CALLBACK(7, 7); \
|
||||||
|
PCINT_CALLBACK(0, 0); /* SPI SS */ \
|
||||||
|
PCINT_CALLBACK(1, 1); /* SPI SCK */ \
|
||||||
|
PCINT_CALLBACK(2, 2); /* SPI MISO */ \
|
||||||
|
PCINT_CALLBACK(3, 3); /* SPI MOSI */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Arduino Leonardo/Micro (32u4)
|
||||||
|
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
|
||||||
|
/* Reordering interrupt callbacks priority
|
||||||
|
Port0 has SPI on lower pins, move the priority down
|
||||||
|
Its more likely the user will use pin 8-11 */
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT0)
|
||||||
|
#define PCINT_CALLBACK_PORT0 \
|
||||||
|
PCINT_CALLBACK(4, 4); \
|
||||||
|
PCINT_CALLBACK(5, 5); \
|
||||||
|
PCINT_CALLBACK(6, 6); \
|
||||||
|
PCINT_CALLBACK(7, 7); \
|
||||||
|
PCINT_CALLBACK(0, 0); /* SPI SS / RX LED */ \
|
||||||
|
PCINT_CALLBACK(1, 1); /* SPI SCK */ \
|
||||||
|
PCINT_CALLBACK(2, 2); /* SPI MISO */ \
|
||||||
|
PCINT_CALLBACK(3, 3); /* SPI MOSI */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RX LED on normal leonardo/micro
|
||||||
|
#if defined(PCINT_ENABLE_PCINT0) && (defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_MICRO))
|
||||||
|
#undef PCINT_ENABLE_PCINT0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Hoodloader2 (u2 Series)
|
||||||
|
#if defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
|
||||||
|
#if defined(ARDUINO_HOODLOADER2)
|
||||||
|
// on HoodLoader2 Arduino boards only PB1-7 (port0) is broken out, save this flash
|
||||||
|
#if defined(PCINT_ENABLE_PORT1)
|
||||||
|
#undef PCINT_ENABLE_PORT1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SS (PB0) is not connected on normal Arduino boards
|
||||||
|
#if defined(PCINT_ENABLE_PCINT0)
|
||||||
|
#undef PCINT_ENABLE_PCINT0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Reordering interrupt callbacks priority
|
||||||
|
Port0 has SPI on lower pins, move the priority down
|
||||||
|
Its more likely the user will use PB4-7
|
||||||
|
Pretend the User has not soldered the 4 Pinheader
|
||||||
|
so only do this for non Arduino boards. */
|
||||||
|
#else
|
||||||
|
#if !defined(PCINT_CALLBACK_PORT0)
|
||||||
|
#define PCINT_CALLBACK_PORT0 \
|
||||||
|
PCINT_CALLBACK(4, 4); \
|
||||||
|
PCINT_CALLBACK(5, 5); \
|
||||||
|
PCINT_CALLBACK(6, 6); \
|
||||||
|
PCINT_CALLBACK(7, 7); \
|
||||||
|
PCINT_CALLBACK(0, 0); /* SPI SS */ \
|
||||||
|
PCINT_CALLBACK(1, 1); /* SPI SCK */ \
|
||||||
|
PCINT_CALLBACK(2, 2); /* SPI MISO */ \
|
||||||
|
PCINT_CALLBACK(3, 3); /* SPI MOSI */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Attiny 25/45/85 only has a very few pins
|
||||||
|
activate all by default
|
||||||
|
The order is also okay. */
|
||||||
|
|
||||||
|
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||||
|
// Port1 is connected to reset, crystal and Pin Interrupt 0
|
||||||
|
// Deactivate it by default
|
||||||
|
#if defined(PCINT_ENABLE_PORT1)
|
||||||
|
#undef PCINT_ENABLE_PORT1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
MFRC522.zip
|
||||||
|
|
||||||
|
# ignore IDE files
|
||||||
|
.idea
|
||||||
|
cmake
|
||||||
|
CMakeLists.txt
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- "2.7"
|
||||||
|
|
||||||
|
# Cache PlatformIO packages using Travis CI container-based infrastructure
|
||||||
|
sudo: false
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- "~/.platformio"
|
||||||
|
|
||||||
|
env:
|
||||||
|
# add examples here and define which boards should be tested (only compile test)
|
||||||
|
- PLATFORMIO_CI_SRC=examples/ChangeUID/ChangeUID.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/DumpInfo/DumpInfo.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/firmware_check/firmware_check.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/FixBrickedUID/FixBrickedUID.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/MifareClassicValueBlock/MifareClassicValueBlock.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/MinimalInterrupt/MinimalInterrupt.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/ReadAndWrite/ReadAndWrite.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/ReadUidMultiReader/ReadUidMultiReader.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/rfid_default_keys/rfid_default_keys.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/rfid_write_personal_data/rfid_write_personal_data.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/Ntag216_AUTH/Ntag216_AUTH.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/ReadNUID/ReadNUID.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
- PLATFORMIO_CI_SRC=examples/servo_motor/servo_motor.ino TESTBOARD=arduino_avr,teensy
|
||||||
|
- PLATFORMIO_CI_SRC=examples/RFID-Cloner/RFID-Cloner.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp
|
||||||
|
|
||||||
|
install:
|
||||||
|
- pip install -U platformio
|
||||||
|
|
||||||
|
script:
|
||||||
|
# short the string comparison
|
||||||
|
- stringContain() { [ -z "${2##*$1*}" ]; }
|
||||||
|
# selectable board tests @Rotzbua
|
||||||
|
# prints only warnings and errors, to show all remove "1>/dev/null"
|
||||||
|
- board="arduino_avr"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=uno --board=megaatmega1280 1>/dev/null; else echo "skip board test of $board"; fi
|
||||||
|
- board="arduino_arm"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=due --board=zero 1>/dev/null; else echo "skip board test of $board"; fi
|
||||||
|
- board="teensy"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=teensy20 --board=teensy31 1>/dev/null; else echo "skip board test of $board"; fi
|
||||||
|
- board="esp"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=d1_mini 1>/dev/null; else echo "skip board test of $board"; fi
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,430 @@
|
||||||
|
/**
|
||||||
|
* MFRC522.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT.
|
||||||
|
* Based on code Dr.Leong ( WWW.B2CQSHOP.COM )
|
||||||
|
* Created by Miguel Balboa (circuitito.com), Jan, 2012.
|
||||||
|
* Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.)
|
||||||
|
* Extended by Tom Clement with functionality to write to sector 0 of UID changeable Mifare cards.
|
||||||
|
* Released into the public domain.
|
||||||
|
*
|
||||||
|
* Please read this file for an overview and then MFRC522.cpp for comments on the specific functions.
|
||||||
|
* Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board.
|
||||||
|
*
|
||||||
|
* There are three hardware components involved:
|
||||||
|
* 1) The micro controller: An Arduino
|
||||||
|
* 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC
|
||||||
|
* 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203.
|
||||||
|
*
|
||||||
|
* The microcontroller and card reader uses SPI for communication.
|
||||||
|
* The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf
|
||||||
|
*
|
||||||
|
* The card reader and the tags communicate using a 13.56MHz electromagnetic field.
|
||||||
|
* The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision".
|
||||||
|
* A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf
|
||||||
|
* Details are found in chapter 6, Type A – Initialization and anticollision.
|
||||||
|
*
|
||||||
|
* If only the PICC UID is wanted, the above documents has all the needed information.
|
||||||
|
* To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected.
|
||||||
|
* The MIFARE Classic chips and protocol is described in the datasheets:
|
||||||
|
* 1K: http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf
|
||||||
|
* 4K: http://datasheet.octopart.com/MF1S7035DA4,118-NXP-Semiconductors-datasheet-11046188.pdf
|
||||||
|
* Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf
|
||||||
|
* The MIFARE Ultralight chip and protocol is described in the datasheets:
|
||||||
|
* Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf
|
||||||
|
* Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf
|
||||||
|
*
|
||||||
|
* MIFARE Classic 1K (MF1S503x):
|
||||||
|
* Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes.
|
||||||
|
* The blocks are numbered 0-63.
|
||||||
|
* Block 3 in each sector is the Sector Trailer. See http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf sections 8.6 and 8.7:
|
||||||
|
* Bytes 0-5: Key A
|
||||||
|
* Bytes 6-8: Access Bits
|
||||||
|
* Bytes 9: User data
|
||||||
|
* Bytes 10-15: Key B (or user data)
|
||||||
|
* Block 0 is read-only manufacturer data.
|
||||||
|
* To access a block, an authentication using a key from the block's sector must be performed first.
|
||||||
|
* Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11).
|
||||||
|
* All keys are set to FFFFFFFFFFFFh at chip delivery.
|
||||||
|
* Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked.
|
||||||
|
* To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns.
|
||||||
|
* MIFARE Classic 4K (MF1S703x):
|
||||||
|
* Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes.
|
||||||
|
* The blocks are numbered 0-255.
|
||||||
|
* The last block in each sector is the Sector Trailer like above.
|
||||||
|
* MIFARE Classic Mini (MF1 IC S20):
|
||||||
|
* Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes.
|
||||||
|
* The blocks are numbered 0-19.
|
||||||
|
* The last block in each sector is the Sector Trailer like above.
|
||||||
|
*
|
||||||
|
* MIFARE Ultralight (MF0ICU1):
|
||||||
|
* Has 16 pages of 4 bytes = 64 bytes.
|
||||||
|
* Pages 0 + 1 is used for the 7-byte UID.
|
||||||
|
* Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
|
||||||
|
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0.
|
||||||
|
* Pages 4-15 are read/write unless blocked by the lock bytes in page 2.
|
||||||
|
* MIFARE Ultralight C (MF0ICU2):
|
||||||
|
* Has 48 pages of 4 bytes = 192 bytes.
|
||||||
|
* Pages 0 + 1 is used for the 7-byte UID.
|
||||||
|
* Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
|
||||||
|
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0.
|
||||||
|
* Pages 4-39 are read/write unless blocked by the lock bytes in page 2.
|
||||||
|
* Page 40 Lock bytes
|
||||||
|
* Page 41 16 bit one way counter
|
||||||
|
* Pages 42-43 Authentication configuration
|
||||||
|
* Pages 44-47 Authentication key
|
||||||
|
*/
|
||||||
|
#ifndef MFRC522_h
|
||||||
|
#define MFRC522_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
// Firmware data for self-test
|
||||||
|
// Reference values based on firmware version
|
||||||
|
// Hint: if needed, you can remove unused self-test data to save flash memory
|
||||||
|
//
|
||||||
|
// Version 0.0 (0x90)
|
||||||
|
// Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August 2005; 16.1 self-test
|
||||||
|
const byte MFRC522_firmware_referenceV0_0[] PROGMEM = {
|
||||||
|
0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19,
|
||||||
|
0xBF, 0x22, 0x30, 0x49, 0x59, 0x63, 0xAD, 0xCA,
|
||||||
|
0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E, 0x49, 0x50,
|
||||||
|
0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E,
|
||||||
|
0x75, 0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78,
|
||||||
|
0x32, 0xFF, 0x58, 0x3B, 0x7C, 0xE9, 0x00, 0x94,
|
||||||
|
0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29, 0xDF,
|
||||||
|
0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D
|
||||||
|
};
|
||||||
|
// Version 1.0 (0x91)
|
||||||
|
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 self-test
|
||||||
|
const byte MFRC522_firmware_referenceV1_0[] PROGMEM = {
|
||||||
|
0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C,
|
||||||
|
0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73,
|
||||||
|
0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1, 0x3E, 0x5A,
|
||||||
|
0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E,
|
||||||
|
0x64, 0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC,
|
||||||
|
0x22, 0xBC, 0xD3, 0x72, 0x35, 0xCD, 0xAA, 0x41,
|
||||||
|
0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02,
|
||||||
|
0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79
|
||||||
|
};
|
||||||
|
// Version 2.0 (0x92)
|
||||||
|
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 self-test
|
||||||
|
const byte MFRC522_firmware_referenceV2_0[] PROGMEM = {
|
||||||
|
0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95,
|
||||||
|
0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE,
|
||||||
|
0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B, 0x89, 0x82,
|
||||||
|
0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49,
|
||||||
|
0x7C, 0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81,
|
||||||
|
0x5D, 0x48, 0x76, 0xD5, 0x71, 0x61, 0x21, 0xA9,
|
||||||
|
0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D,
|
||||||
|
0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F
|
||||||
|
};
|
||||||
|
// Clone
|
||||||
|
// Fudan Semiconductor FM17522 (0x88)
|
||||||
|
const byte FM17522_firmware_reference[] PROGMEM = {
|
||||||
|
0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18,
|
||||||
|
0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B,
|
||||||
|
0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7,
|
||||||
|
0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B,
|
||||||
|
0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7,
|
||||||
|
0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E,
|
||||||
|
0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB,
|
||||||
|
0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62
|
||||||
|
};
|
||||||
|
|
||||||
|
class MFRC522 {
|
||||||
|
public:
|
||||||
|
// MFRC522 registers. Described in chapter 9 of the datasheet.
|
||||||
|
// When using SPI all addresses are shifted one bit left in the "SPI address byte" (section 8.1.2.3)
|
||||||
|
enum PCD_Register {
|
||||||
|
// Page 0: Command and status
|
||||||
|
// 0x00 // reserved for future use
|
||||||
|
CommandReg = 0x01 << 1, // starts and stops command execution
|
||||||
|
ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits
|
||||||
|
DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits
|
||||||
|
ComIrqReg = 0x04 << 1, // interrupt request bits
|
||||||
|
DivIrqReg = 0x05 << 1, // interrupt request bits
|
||||||
|
ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed
|
||||||
|
Status1Reg = 0x07 << 1, // communication status bits
|
||||||
|
Status2Reg = 0x08 << 1, // receiver and transmitter status bits
|
||||||
|
FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer
|
||||||
|
FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer
|
||||||
|
WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning
|
||||||
|
ControlReg = 0x0C << 1, // miscellaneous control registers
|
||||||
|
BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames
|
||||||
|
CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface
|
||||||
|
// 0x0F // reserved for future use
|
||||||
|
|
||||||
|
// Page 1: Command
|
||||||
|
// 0x10 // reserved for future use
|
||||||
|
ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving
|
||||||
|
TxModeReg = 0x12 << 1, // defines transmission data rate and framing
|
||||||
|
RxModeReg = 0x13 << 1, // defines reception data rate and framing
|
||||||
|
TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2
|
||||||
|
TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation
|
||||||
|
TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver
|
||||||
|
RxSelReg = 0x17 << 1, // selects internal receiver settings
|
||||||
|
RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder
|
||||||
|
DemodReg = 0x19 << 1, // defines demodulator settings
|
||||||
|
// 0x1A // reserved for future use
|
||||||
|
// 0x1B // reserved for future use
|
||||||
|
MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters
|
||||||
|
MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters
|
||||||
|
// 0x1E // reserved for future use
|
||||||
|
SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface
|
||||||
|
|
||||||
|
// Page 2: Configuration
|
||||||
|
// 0x20 // reserved for future use
|
||||||
|
CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation
|
||||||
|
CRCResultRegL = 0x22 << 1,
|
||||||
|
// 0x23 // reserved for future use
|
||||||
|
ModWidthReg = 0x24 << 1, // controls the ModWidth setting?
|
||||||
|
// 0x25 // reserved for future use
|
||||||
|
RFCfgReg = 0x26 << 1, // configures the receiver gain
|
||||||
|
GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation
|
||||||
|
CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation
|
||||||
|
ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation
|
||||||
|
TModeReg = 0x2A << 1, // defines settings for the internal timer
|
||||||
|
TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
|
||||||
|
TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value
|
||||||
|
TReloadRegL = 0x2D << 1,
|
||||||
|
TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value
|
||||||
|
TCounterValueRegL = 0x2F << 1,
|
||||||
|
|
||||||
|
// Page 3: Test Registers
|
||||||
|
// 0x30 // reserved for future use
|
||||||
|
TestSel1Reg = 0x31 << 1, // general test signal configuration
|
||||||
|
TestSel2Reg = 0x32 << 1, // general test signal configuration
|
||||||
|
TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7
|
||||||
|
TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus
|
||||||
|
TestBusReg = 0x35 << 1, // shows the status of the internal test bus
|
||||||
|
AutoTestReg = 0x36 << 1, // controls the digital self-test
|
||||||
|
VersionReg = 0x37 << 1, // shows the software version
|
||||||
|
AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2
|
||||||
|
TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1
|
||||||
|
TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2
|
||||||
|
TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels
|
||||||
|
// 0x3C // reserved for production tests
|
||||||
|
// 0x3D // reserved for production tests
|
||||||
|
// 0x3E // reserved for production tests
|
||||||
|
// 0x3F // reserved for production tests
|
||||||
|
};
|
||||||
|
|
||||||
|
// MFRC522 commands. Described in chapter 10 of the datasheet.
|
||||||
|
enum PCD_Command {
|
||||||
|
PCD_Idle = 0x00, // no action, cancels current command execution
|
||||||
|
PCD_Mem = 0x01, // stores 25 bytes into the internal buffer
|
||||||
|
PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number
|
||||||
|
PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self-test
|
||||||
|
PCD_Transmit = 0x04, // transmits data from the FIFO buffer
|
||||||
|
PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
|
||||||
|
PCD_Receive = 0x08, // activates the receiver circuits
|
||||||
|
PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
|
||||||
|
PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader
|
||||||
|
PCD_SoftReset = 0x0F // resets the MFRC522
|
||||||
|
};
|
||||||
|
|
||||||
|
// MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD).
|
||||||
|
// Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf
|
||||||
|
enum PCD_RxGain {
|
||||||
|
RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum
|
||||||
|
RxGain_23dB = 0x01 << 4, // 001b - 23 dB
|
||||||
|
RxGain_18dB_2 = 0x02 << 4, // 010b - 18 dB, it seems 010b is a duplicate for 000b
|
||||||
|
RxGain_23dB_2 = 0x03 << 4, // 011b - 23 dB, it seems 011b is a duplicate for 001b
|
||||||
|
RxGain_33dB = 0x04 << 4, // 100b - 33 dB, average, and typical default
|
||||||
|
RxGain_38dB = 0x05 << 4, // 101b - 38 dB
|
||||||
|
RxGain_43dB = 0x06 << 4, // 110b - 43 dB
|
||||||
|
RxGain_48dB = 0x07 << 4, // 111b - 48 dB, maximum
|
||||||
|
RxGain_min = 0x00 << 4, // 000b - 18 dB, minimum, convenience for RxGain_18dB
|
||||||
|
RxGain_avg = 0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB
|
||||||
|
RxGain_max = 0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB
|
||||||
|
};
|
||||||
|
|
||||||
|
// Commands sent to the PICC.
|
||||||
|
enum PICC_Command {
|
||||||
|
// The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
|
||||||
|
PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
|
||||||
|
PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
|
||||||
|
PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision.
|
||||||
|
PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1
|
||||||
|
PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2
|
||||||
|
PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3
|
||||||
|
PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
|
||||||
|
// The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9)
|
||||||
|
// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
|
||||||
|
// The read/write commands can also be used for MIFARE Ultralight.
|
||||||
|
PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A
|
||||||
|
PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B
|
||||||
|
PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
|
||||||
|
PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
|
||||||
|
PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register.
|
||||||
|
PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register.
|
||||||
|
PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register.
|
||||||
|
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block.
|
||||||
|
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
|
||||||
|
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
|
||||||
|
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC.
|
||||||
|
};
|
||||||
|
|
||||||
|
// MIFARE constants that does not fit anywhere else
|
||||||
|
enum MIFARE_Misc {
|
||||||
|
MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK.
|
||||||
|
MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes.
|
||||||
|
};
|
||||||
|
|
||||||
|
// PICC types we can detect. Remember to update PICC_GetTypeName() if you add more.
|
||||||
|
// last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered
|
||||||
|
enum PICC_Type : byte {
|
||||||
|
PICC_TYPE_UNKNOWN ,
|
||||||
|
PICC_TYPE_ISO_14443_4 , // PICC compliant with ISO/IEC 14443-4
|
||||||
|
PICC_TYPE_ISO_18092 , // PICC compliant with ISO/IEC 18092 (NFC)
|
||||||
|
PICC_TYPE_MIFARE_MINI , // MIFARE Classic protocol, 320 bytes
|
||||||
|
PICC_TYPE_MIFARE_1K , // MIFARE Classic protocol, 1KB
|
||||||
|
PICC_TYPE_MIFARE_4K , // MIFARE Classic protocol, 4KB
|
||||||
|
PICC_TYPE_MIFARE_UL , // MIFARE Ultralight or Ultralight C
|
||||||
|
PICC_TYPE_MIFARE_PLUS , // MIFARE Plus
|
||||||
|
PICC_TYPE_TNP3XXX , // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure
|
||||||
|
PICC_TYPE_NOT_COMPLETE = 0xff // SAK indicates UID is not complete.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more.
|
||||||
|
// last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered
|
||||||
|
enum StatusCode : byte {
|
||||||
|
STATUS_OK , // Success
|
||||||
|
STATUS_ERROR , // Error in communication
|
||||||
|
STATUS_COLLISION , // Collission detected
|
||||||
|
STATUS_TIMEOUT , // Timeout in communication.
|
||||||
|
STATUS_NO_ROOM , // A buffer is not big enough.
|
||||||
|
STATUS_INTERNAL_ERROR , // Internal error in the code. Should not happen ;-)
|
||||||
|
STATUS_INVALID , // Invalid argument.
|
||||||
|
STATUS_CRC_WRONG , // The CRC_A does not match
|
||||||
|
STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK.
|
||||||
|
};
|
||||||
|
|
||||||
|
// A struct used for passing the UID of a PICC.
|
||||||
|
typedef struct {
|
||||||
|
byte size; // Number of bytes in the UID. 4, 7 or 10.
|
||||||
|
byte uidByte[10];
|
||||||
|
byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
|
||||||
|
} Uid;
|
||||||
|
|
||||||
|
// A struct used for passing a MIFARE Crypto1 key
|
||||||
|
typedef struct {
|
||||||
|
byte keyByte[MF_KEY_SIZE];
|
||||||
|
} MIFARE_Key;
|
||||||
|
|
||||||
|
// Member variables
|
||||||
|
Uid uid; // Used by PICC_ReadCardSerial().
|
||||||
|
|
||||||
|
// Size of the MFRC522 FIFO
|
||||||
|
static const byte FIFO_SIZE = 64; // The FIFO is 64 bytes.
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions for setting up the Arduino
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
MFRC522();
|
||||||
|
MFRC522(byte resetPowerDownPin);
|
||||||
|
MFRC522(byte chipSelectPin, byte resetPowerDownPin);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Basic interface functions for communicating with the MFRC522
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void PCD_WriteRegister(byte reg, byte value);
|
||||||
|
void PCD_WriteRegister(byte reg, byte count, byte *values);
|
||||||
|
byte PCD_ReadRegister(byte reg);
|
||||||
|
void PCD_ReadRegister(byte reg, byte count, byte *values, byte rxAlign = 0);
|
||||||
|
void setBitMask(unsigned char reg, unsigned char mask);
|
||||||
|
void PCD_SetRegisterBitMask(byte reg, byte mask);
|
||||||
|
void PCD_ClearRegisterBitMask(byte reg, byte mask);
|
||||||
|
StatusCode PCD_CalculateCRC(byte *data, byte length, byte *result);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions for manipulating the MFRC522
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void PCD_Init();
|
||||||
|
void PCD_Init(byte resetPowerDownPin);
|
||||||
|
void PCD_Init(byte chipSelectPin, byte resetPowerDownPin);
|
||||||
|
void PCD_Reset();
|
||||||
|
void PCD_AntennaOn();
|
||||||
|
void PCD_AntennaOff();
|
||||||
|
byte PCD_GetAntennaGain();
|
||||||
|
void PCD_SetAntennaGain(byte mask);
|
||||||
|
bool PCD_PerformSelfTest();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions for communicating with PICCs
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
StatusCode PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false);
|
||||||
|
StatusCode PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false);
|
||||||
|
StatusCode PICC_RequestA(byte *bufferATQA, byte *bufferSize);
|
||||||
|
StatusCode PICC_WakeupA(byte *bufferATQA, byte *bufferSize);
|
||||||
|
StatusCode PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize);
|
||||||
|
StatusCode PICC_Select(Uid *uid, byte validBits = 0);
|
||||||
|
StatusCode PICC_HaltA();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions for communicating with MIFARE PICCs
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
StatusCode PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid);
|
||||||
|
void PCD_StopCrypto1();
|
||||||
|
StatusCode MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize);
|
||||||
|
StatusCode MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize);
|
||||||
|
StatusCode MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize);
|
||||||
|
StatusCode MIFARE_Ultralight_KeyCheck(byte *buffer);
|
||||||
|
StatusCode MIFARE_Ultralight_CheckWrite(byte page, byte *buffer, byte bufferSize);
|
||||||
|
StatusCode MIFARE_Ultralight_CheckRewrite();
|
||||||
|
StatusCode MIFARE_Ultralight_Readtime (byte *times);
|
||||||
|
StatusCode MIFARE_Ultralight_Num (byte *newnum);
|
||||||
|
|
||||||
|
StatusCode MIFARE_Decrement(byte blockAddr, long delta);
|
||||||
|
StatusCode MIFARE_Increment(byte blockAddr, long delta);
|
||||||
|
StatusCode MIFARE_Restore(byte blockAddr);
|
||||||
|
StatusCode MIFARE_Transfer(byte blockAddr);
|
||||||
|
StatusCode MIFARE_GetValue(byte blockAddr, long *value);
|
||||||
|
StatusCode MIFARE_SetValue(byte blockAddr, long value);
|
||||||
|
StatusCode PCD_NTAG21x_Auth(byte *passWord, byte pACK[]);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Support functions
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
StatusCode PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false);
|
||||||
|
// old function used too much memory, now name moved to flash; if you need char, copy from flash to memory
|
||||||
|
//const char *GetStatusCodeName(byte code);
|
||||||
|
static const __FlashStringHelper *GetStatusCodeName(StatusCode code);
|
||||||
|
static PICC_Type PICC_GetType(byte sak);
|
||||||
|
// old function used too much memory, now name moved to flash; if you need char, copy from flash to memory
|
||||||
|
//const char *PICC_GetTypeName(byte type);
|
||||||
|
static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type);
|
||||||
|
|
||||||
|
// Support functions for debuging
|
||||||
|
void PCD_DumpVersionToSerial();
|
||||||
|
void PICC_DumpToSerial(Uid *uid);
|
||||||
|
void PICC_DumpDetailsToSerial(Uid *uid);
|
||||||
|
void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key);
|
||||||
|
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector);
|
||||||
|
void PICC_DumpMifareUltralightToSerial();
|
||||||
|
void PICC_DumpMifareUltralightToSerial3();
|
||||||
|
void PICC_DumpMifareUltralightToSerial5(byte *b1, byte *b2, byte *b3, byte *b4);
|
||||||
|
void PICC_DumpMifareUltralightToSerial6(byte page, byte *b);
|
||||||
|
void MIFARE_Ultralight_Key (byte *arr);
|
||||||
|
void PICC_DumpMifareUID();
|
||||||
|
void MIFARE_Ultralight_readpage (byte *buffer, byte page);
|
||||||
|
|
||||||
|
// Advanced functions for MIFARE
|
||||||
|
void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3);
|
||||||
|
bool MIFARE_OpenUidBackdoor(bool logErrors);
|
||||||
|
bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors);
|
||||||
|
bool MIFARE_UnbrickUidSector(bool logErrors);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convenience functions - does not add extra functionality
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool PICC_IsNewCardPresent();
|
||||||
|
bool PICC_ReadCardSerial();
|
||||||
|
|
||||||
|
private:
|
||||||
|
byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low)
|
||||||
|
byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
|
||||||
|
StatusCode MIFARE_TwoStepHelper(byte command, byte blockAddr, long data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Makefile for MFRC522 library
|
||||||
|
#
|
||||||
|
|
||||||
|
all: package
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " clean to clean the project (e.g. remove process files)"
|
||||||
|
@echo " package to package the library (into a zip file)"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm ./MFRC522.zip
|
||||||
|
@echo
|
||||||
|
@echo "Clean finished."
|
||||||
|
|
||||||
|
package:
|
||||||
|
zip -o ./MFRC522.zip ./MFRC522.h ./MFRC522.cpp
|
||||||
|
|
@ -0,0 +1,249 @@
|
||||||
|
MFRC522
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/miguelbalboa/rfid.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/miguelbalboa/rfid
|
||||||
|
|
||||||
|
Arduino library for MFRC522 and other RFID RC522 based modules.
|
||||||
|
|
||||||
|
Read and write different types of Radio-Frequency IDentification (RFID) cards
|
||||||
|
on your Arduino using a RC522 based reader connected via the Serial Peripheral
|
||||||
|
Interface (SPI) interface.
|
||||||
|
|
||||||
|
.. _development:
|
||||||
|
Development
|
||||||
|
----------
|
||||||
|
**The development by owner miguelbalboa has ended**. Further development will be done by community. This library is still maintained by miguelbalboa, so make pull request if you like some new features or fixes. Support/issues should be solved by community.
|
||||||
|
|
||||||
|
.. _what works and not:
|
||||||
|
What works and not?
|
||||||
|
----------
|
||||||
|
|
||||||
|
* **Works**
|
||||||
|
|
||||||
|
#. Communication (Crypto1) with MIFARE Classic (1k, 4k, Mini).
|
||||||
|
#. Communication (Crypto1) with MIFARE Classic compatible PICCs.
|
||||||
|
#. Firmware self check of MFRC522.
|
||||||
|
#. Set the UID, write to sector 0, and unbrick Chinese UID changeable MIFARE cards.
|
||||||
|
|
||||||
|
* **Partial**
|
||||||
|
|
||||||
|
#. Communication with MIFARE Ultralight.
|
||||||
|
#. Other PICCs (Ntag216).
|
||||||
|
|
||||||
|
* **Works not**
|
||||||
|
|
||||||
|
#. MIFARE DESFire, MIFARE DESFire EV1/EV2, not supported by software.
|
||||||
|
#. Communication with 3DES or AES, not supported by software.
|
||||||
|
#. Peer-to-peer (ISO/IEC 18092), not `supported by hardware`_.
|
||||||
|
#. Communication with smart phone, not `supported by hardware`_.
|
||||||
|
#. Card emulation, not `supported by hardware`_.
|
||||||
|
#. Use of IRQ pin. But there is a proof-of-concept example.
|
||||||
|
|
||||||
|
* **Need more?**
|
||||||
|
|
||||||
|
#. If software: code it and make a pull request.
|
||||||
|
#. If hardware: buy a more expensive like PN532 (supports NFC and many more, but costs about $15).
|
||||||
|
|
||||||
|
|
||||||
|
.. _compatible ide:
|
||||||
|
Compatible IDE
|
||||||
|
----------
|
||||||
|
This library works with Arduino IDE 1.6, older versions are **not supported** and will cause compile errors. The built-in library manager is supported.
|
||||||
|
|
||||||
|
If you use your own compiler, you have to enable ``c++11``-support.
|
||||||
|
|
||||||
|
|
||||||
|
.. _compatible boards:
|
||||||
|
Compatible boards
|
||||||
|
----------
|
||||||
|
|
||||||
|
This library is compatible to Teensy and ESP8266, but not all examples are available for every board. Also you have to change pins, see `pin layout`_.
|
||||||
|
|
||||||
|
Note that the main target/support of library is still Arduino.
|
||||||
|
|
||||||
|
|
||||||
|
.. _pin layout:
|
||||||
|
Pin Layout
|
||||||
|
----------
|
||||||
|
|
||||||
|
The following table shows the typical pin layout used:
|
||||||
|
|
||||||
|
+-----------+----------+---------------------------------------------------------------+--------------------------+
|
||||||
|
| | PCD | Arduino | Teensy |
|
||||||
|
| +----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+
|
||||||
|
| | MFRC522 | Uno | Mega | Nano v3 |Leonardo / Micro | Pro Micro | 2.0 | ++ 2.0 | 3.1 |
|
||||||
|
+-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+
|
||||||
|
| Signal | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin |
|
||||||
|
+===========+==========+=============+=========+=========+=================+===========+========+========+========+
|
||||||
|
| RST/Reset | RST | 9 [1]_ | 5 [1]_ | D9 | RESET / ICSP-5 | RST | 7 | 4 | 9 |
|
||||||
|
+-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+
|
||||||
|
| SPI SS | SDA [3]_ | 10 [2]_ | 53 [2]_ | D10 | 10 | 10 | 0 | 20 | 10 |
|
||||||
|
+-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+
|
||||||
|
| SPI MOSI | MOSI | 11 / ICSP-4 | 51 | D11 | ICSP-4 | 16 | 2 | 22 | 11 |
|
||||||
|
+-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+
|
||||||
|
| SPI MISO | MISO | 12 / ICSP-1 | 50 | D12 | ICSP-1 | 14 | 3 | 23 | 12 |
|
||||||
|
+-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+
|
||||||
|
| SPI SCK | SCK | 13 / ICSP-3 | 52 | D13 | ICSP-3 | 15 | 1 | 21 | 13 |
|
||||||
|
+-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+
|
||||||
|
|
||||||
|
.. [1] Configurable, typically defined as RST_PIN in sketch/program.
|
||||||
|
.. [2] Configurable, typically defined as SS_PIN in sketch/program.
|
||||||
|
.. [3] The SDA pin might be labeled SS on some/older MFRC522 boards.
|
||||||
|
|
||||||
|
|
||||||
|
.. _hardware:
|
||||||
|
Hardware
|
||||||
|
--------
|
||||||
|
|
||||||
|
There are three hardware components involved:
|
||||||
|
|
||||||
|
1. **Micro Controller**:
|
||||||
|
|
||||||
|
* An `Arduino`_ or compatible executing the Sketch using this library.
|
||||||
|
|
||||||
|
* Prices vary from USD 7 for clones, to USD 75 for "starter kits" (which
|
||||||
|
might be a good choice if this is your first exposure to Arduino;
|
||||||
|
check if such kit already includes the Arduino, Reader, and some Tags).
|
||||||
|
|
||||||
|
2. **Proximity Coupling Device (PCD)**:
|
||||||
|
|
||||||
|
* The PCD is the actual RFID **Reader** based on `NXP MFRC522`_ Contactless
|
||||||
|
Reader Integrated Circuit).
|
||||||
|
|
||||||
|
* Readers can be found on `eBay`_ for around USD 5: search for *"rc522"*.
|
||||||
|
|
||||||
|
* You can also find them at several web stores, they are often included in
|
||||||
|
*"starter kits"*; so check your favourite electronics provider as well.
|
||||||
|
|
||||||
|
3. **Proximity Integrated Circuit Card (PICC)**:
|
||||||
|
|
||||||
|
* The PICC is the RFID **Card** or **Tag** using the `ISO/IEC 14443A`_
|
||||||
|
interface, for example Mifare or NTAG203.
|
||||||
|
|
||||||
|
* One or two might be included with the Reader or *"starter kit"* already.
|
||||||
|
|
||||||
|
|
||||||
|
.. _protocol:
|
||||||
|
Protocols
|
||||||
|
---------
|
||||||
|
|
||||||
|
1. The micro controller and the reader use SPI for communication.
|
||||||
|
|
||||||
|
* The protocol is described in the `NXP MFRC522`_ datasheet.
|
||||||
|
|
||||||
|
* See the `Pin Layout`_ section for details on connecting the pins.
|
||||||
|
|
||||||
|
2. The reader and the tags communicate using a 13.56 MHz electromagnetic field.
|
||||||
|
|
||||||
|
* The protocol is defined in ISO/IEC 14443-3:2011 Part 3 Type A.
|
||||||
|
|
||||||
|
* Details are found in chapter 6 *"Type A – Initialization and anticollision"*.
|
||||||
|
|
||||||
|
* See http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf for a free version
|
||||||
|
of the final draft (which might be outdated in some areas).
|
||||||
|
|
||||||
|
* The reader does not support ISO/IEC 14443-3 Type B.
|
||||||
|
|
||||||
|
|
||||||
|
.. _security:
|
||||||
|
Security
|
||||||
|
-------
|
||||||
|
This library only supports crypto1-encrypted communication. Crypto1 has been known as `broken`_ for a few years, so it does NOT offer ANY security, it is virtually unencrypted communication. **Do not use it for any security related applications!**
|
||||||
|
|
||||||
|
This library does not offer 3DES or AES authentication used by cards like the Mifare DESFire, it may be possible to be implemented because the datasheet says there is support. We hope for pull requests :).
|
||||||
|
|
||||||
|
|
||||||
|
.. _troubleshooting:
|
||||||
|
Troubleshooting
|
||||||
|
-------
|
||||||
|
|
||||||
|
* **I don't get input from reader** or **WARNING: Communication failure, is the MFRC522 properly connected?**
|
||||||
|
|
||||||
|
#. Check your connection, see `Pin Layout`_ .
|
||||||
|
#. Check voltage. Most breakouts work with 3.3V.
|
||||||
|
#. SPI only works with 3.3V, most breakouts seem 5V tollerant, but try a level shifter.
|
||||||
|
#. According to reports #101, #126 and #131, there may be a problem with the soldering on the MFRC522 breakout. You could fix this on your own.
|
||||||
|
|
||||||
|
|
||||||
|
* **Sometimes I get timeouts** or **sometimes tag/card does not work.**
|
||||||
|
|
||||||
|
#. Try other side of the antenna.
|
||||||
|
#. Try to decrease distance between MFRC522.
|
||||||
|
#. Increase antenna gain per firmware: ``mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);``
|
||||||
|
#. Use better power supply.
|
||||||
|
#. Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller.
|
||||||
|
|
||||||
|
|
||||||
|
* **My tag/card doesn't work.**
|
||||||
|
|
||||||
|
#. Distance between antenna and token too large (>1cm).
|
||||||
|
#. You got the wrong type PICC. Is it really 13.56 MHz? Is it really a Mifare Type A?
|
||||||
|
#. NFC tokens are not supported. Some may work.
|
||||||
|
#. Animal RFID tags are not supported. They use a different frequency (125 kHz).
|
||||||
|
#. Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller.
|
||||||
|
#. Newer versions of Mifare cards like DESFire/Ultralight maybe not work according to missing authentification, see `security`_ or different `protocol`_.
|
||||||
|
|
||||||
|
|
||||||
|
* **My mobile phone doesn't recognize the MFRC522** or **my MFRC522 can't read data from other MFRC522**
|
||||||
|
|
||||||
|
#. Card simmulation is not supported.
|
||||||
|
#. Communication with mobile phones is not supported.
|
||||||
|
#. Peer to peer communication is not supported.
|
||||||
|
|
||||||
|
|
||||||
|
* **I need more features.**
|
||||||
|
|
||||||
|
#. If software: code it and make a pull request.
|
||||||
|
#. If hardware: buy a more expensive like PN532 (supports NFC and many more, but costs about $15)
|
||||||
|
|
||||||
|
|
||||||
|
.. _license:
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
For more information, please refer to http://unlicense.org/
|
||||||
|
|
||||||
|
|
||||||
|
History
|
||||||
|
-------
|
||||||
|
|
||||||
|
The MFRC522 library was first created in Jan 2012 by Miguel Balboa (from
|
||||||
|
http://circuitito.com) based on code by Dr. Leong (from http://B2CQSHOP.com)
|
||||||
|
for *"Arduino RFID module Kit 13.56 Mhz with Tags SPI W and R By COOQRobot"*.
|
||||||
|
|
||||||
|
It was translated into English and rewritten/refactored in the fall of 2013
|
||||||
|
by Søren Thing Andersen (from http://access.thing.dk).
|
||||||
|
|
||||||
|
It has been extended with functionality to alter sector 0 on Chinese UID changeable MIFARE card in Oct 2014 by Tom Clement (from http://tomclement.nl).
|
||||||
|
|
||||||
|
|
||||||
|
.. _arduino: https://arduino.cc/
|
||||||
|
.. _ebay: http://www.ebay.com/
|
||||||
|
.. _iso/iec 14443a: https://en.wikipedia.org/wiki/ISO/IEC_14443
|
||||||
|
.. _iso/iec 14443-3\:2011 part 3:
|
||||||
|
.. _nxp mfrc522: http://www.nxp.com/documents/data_sheet/MFRC522.pdf
|
||||||
|
.. _broken: http://eprint.iacr.org/2008/166
|
||||||
|
.. _supported by hardware: https://web.archive.org/web/20151210045625/http://www.nxp.com/documents/leaflet/939775017564.pdf
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------------------------------------------------------------
|
||||||
|
* Example sketch/program showing how to read data from a PICC to serial.
|
||||||
|
* --------------------------------------------------------------------------------------------------------------------
|
||||||
|
* This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid
|
||||||
|
*
|
||||||
|
* Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID
|
||||||
|
* Reader on the Arduino SPI interface.
|
||||||
|
*
|
||||||
|
* When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE
|
||||||
|
* then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When
|
||||||
|
* you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output
|
||||||
|
* will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages
|
||||||
|
* when removing the PICC from reading distance too early.
|
||||||
|
*
|
||||||
|
* If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading).
|
||||||
|
* So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all
|
||||||
|
* details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so
|
||||||
|
* keep the PICCs at reading distance until complete.
|
||||||
|
*
|
||||||
|
* @license Released into the public domain.
|
||||||
|
*
|
||||||
|
* Typical pin layout used:
|
||||||
|
* -----------------------------------------------------------------------------------------
|
||||||
|
* MFRC522 Arduino Arduino Arduino Arduino Arduino
|
||||||
|
* Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro
|
||||||
|
* Signal Pin Pin Pin Pin Pin Pin
|
||||||
|
* -----------------------------------------------------------------------------------------
|
||||||
|
* RST/Reset RST 9 5 D9 RESET/ICSP-5 RST
|
||||||
|
* SPI SS SDA(SS) 10 53 D10 10 10
|
||||||
|
* SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16
|
||||||
|
* SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14
|
||||||
|
* SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15
|
||||||
|
*/
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <MFRC522.h>
|
||||||
|
|
||||||
|
#define RST_PIN 9 // Configurable, see typical pin layout above
|
||||||
|
#define SS_PIN 10 // Configurable, see typical pin layout above
|
||||||
|
|
||||||
|
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
for (uint16_t a = 0; a <1024; a++){
|
||||||
|
EEPROM.write(a,0);
|
||||||
|
delay(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.begin(9600); // Initialize serial communications with the PC
|
||||||
|
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
|
||||||
|
SPI.begin(); // Init SPI bus
|
||||||
|
mfrc522.PCD_Init(); // Init MFRC522
|
||||||
|
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
|
||||||
|
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Look for new cards
|
||||||
|
if ( ! mfrc522.PICC_IsNewCardPresent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select one of the cards
|
||||||
|
if ( ! mfrc522.PICC_ReadCardSerial()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump debug info about the card; PICC_HaltA() is automatically called
|
||||||
|
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map for library MFRC522
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# KEYWORD1 Classes, datatypes, and C++ keywords
|
||||||
|
#######################################
|
||||||
|
MFRC522 KEYWORD1
|
||||||
|
PCD_Register KEYWORD1
|
||||||
|
PCD_Command KEYWORD1
|
||||||
|
PCD_RxGain KEYWORD1
|
||||||
|
PICC_Command KEYWORD1
|
||||||
|
MIFARE_Misc KEYWORD1
|
||||||
|
PICC_Type KEYWORD1
|
||||||
|
StatusCode KEYWORD1
|
||||||
|
Uid KEYWORD1
|
||||||
|
MIFARE_Key KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# KEYWORD2 Methods and functions
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
# Basic interface functions for communicating with the MFRC522
|
||||||
|
PCD_WriteRegister KEYWORD2
|
||||||
|
PCD_WriteRegister KEYWORD2
|
||||||
|
PCD_ReadRegister KEYWORD2
|
||||||
|
PCD_ReadRegister KEYWORD2
|
||||||
|
setBitMask KEYWORD2
|
||||||
|
PCD_SetRegisterBitMask KEYWORD2
|
||||||
|
PCD_ClearRegisterBitMask KEYWORD2
|
||||||
|
PCD_CalculateCRC KEYWORD2
|
||||||
|
|
||||||
|
# Functions for manipulating the MFRC522
|
||||||
|
PCD_Init KEYWORD2
|
||||||
|
PCD_Reset KEYWORD2
|
||||||
|
PCD_AntennaOn KEYWORD2
|
||||||
|
PCD_AntennaOff KEYWORD2
|
||||||
|
PCD_GetAntennaGain KEYWORD2
|
||||||
|
PCD_SetAntennaGain KEYWORD2
|
||||||
|
PCD_PerformSelfTest KEYWORD2
|
||||||
|
|
||||||
|
# Functions for communicating with PICCs
|
||||||
|
PCD_TransceiveData KEYWORD2
|
||||||
|
PCD_CommunicateWithPICC KEYWORD2
|
||||||
|
PICC_RequestA KEYWORD2
|
||||||
|
PICC_WakeupA KEYWORD2
|
||||||
|
PICC_REQA_or_WUPA KEYWORD2
|
||||||
|
PICC_Select KEYWORD2
|
||||||
|
PICC_HaltA KEYWORD2
|
||||||
|
|
||||||
|
# Functions for communicating with MIFARE PICCs
|
||||||
|
PCD_Authenticate KEYWORD2
|
||||||
|
PCD_StopCrypto1 KEYWORD2
|
||||||
|
MIFARE_Read KEYWORD2
|
||||||
|
MIFARE_Write KEYWORD2
|
||||||
|
MIFARE_Increment KEYWORD2
|
||||||
|
MIFARE_Ultralight_Write KEYWORD2
|
||||||
|
MIFARE_GetValue KEYWORD2
|
||||||
|
MIFARE_SetValue KEYWORD2
|
||||||
|
PCD_NTAG216_AUTH KEYWORD2
|
||||||
|
|
||||||
|
# Support functions
|
||||||
|
PCD_MIFARE_Transceive KEYWORD2
|
||||||
|
GetStatusCodeName KEYWORD2
|
||||||
|
PICC_GetType KEYWORD2
|
||||||
|
PICC_GetTypeName KEYWORD2
|
||||||
|
|
||||||
|
# Support functions for debuging
|
||||||
|
PCD_DumpVersionToSerial KEYWORD2
|
||||||
|
PICC_DumpToSerial KEYWORD2
|
||||||
|
PICC_DumpDetailsToSerial KEYWORD2
|
||||||
|
PICC_DumpMifareClassicToSerial KEYWORD2
|
||||||
|
PICC_DumpMifareClassicSectorToSerial KEYWORD2
|
||||||
|
PICC_DumpMifareUltralightToSerial KEYWORD2
|
||||||
|
|
||||||
|
# Advanced functions for MIFARE
|
||||||
|
MIFARE_SetAccessBits KEYWORD2
|
||||||
|
MIFARE_OpenUidBackdoor KEYWORD2
|
||||||
|
MIFARE_SetUid KEYWORD2
|
||||||
|
MIFARE_UnbrickUidSector KEYWORD2
|
||||||
|
|
||||||
|
# Convenience functions - does not add extra functionality
|
||||||
|
PICC_IsNewCardPresent KEYWORD2
|
||||||
|
PICC_ReadCardSerial KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# KEYWORD3 setup and loop functions, as well as the Serial keywords
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
LITERAL1 Constants
|
||||||
|
#######################################
|
||||||
|
CommandReg LITERAL1
|
||||||
|
ComIEnReg LITERAL1
|
||||||
|
DivIEnReg LITERAL1
|
||||||
|
ComIrqReg LITERAL1
|
||||||
|
DivIrqReg LITERAL1
|
||||||
|
ErrorReg LITERAL1
|
||||||
|
Status1Reg LITERAL1
|
||||||
|
Status2Reg LITERAL1
|
||||||
|
FIFODataReg LITERAL1
|
||||||
|
FIFOLevelReg LITERAL1
|
||||||
|
WaterLevelReg LITERAL1
|
||||||
|
ControlReg LITERAL1
|
||||||
|
BitFramingReg LITERAL1
|
||||||
|
CollReg LITERAL1
|
||||||
|
ModeReg LITERAL1
|
||||||
|
TxModeReg LITERAL1
|
||||||
|
RxModeReg LITERAL1
|
||||||
|
TxControlReg LITERAL1
|
||||||
|
TxASKReg LITERAL1
|
||||||
|
TxSelReg LITERAL1
|
||||||
|
RxSelReg LITERAL1
|
||||||
|
RxThresholdReg LITERAL1
|
||||||
|
DemodReg LITERAL1
|
||||||
|
MfTxReg LITERAL1
|
||||||
|
MfRxReg LITERAL1
|
||||||
|
SerialSpeedReg LITERAL1
|
||||||
|
CRCResultRegH LITERAL1
|
||||||
|
CRCResultRegL LITERAL1
|
||||||
|
ModWidthReg LITERAL1
|
||||||
|
RFCfgReg LITERAL1
|
||||||
|
GsNReg LITERAL1
|
||||||
|
CWGsPReg LITERAL1
|
||||||
|
ModGsPReg LITERAL1
|
||||||
|
TModeReg LITERAL1
|
||||||
|
TPrescalerReg LITERAL1
|
||||||
|
TReloadRegH LITERAL1
|
||||||
|
TReloadRegL LITERAL1
|
||||||
|
TCounterValueRegH LITERAL1
|
||||||
|
TCounterValueRegL LITERAL1
|
||||||
|
TestSel1Reg LITERAL1
|
||||||
|
TestSel2Reg LITERAL1
|
||||||
|
TestPinEnReg LITERAL1
|
||||||
|
TestPinValueReg LITERAL1
|
||||||
|
TestBusReg LITERAL1
|
||||||
|
AutoTestReg LITERAL1
|
||||||
|
VersionReg LITERAL1
|
||||||
|
AnalogTestReg LITERAL1
|
||||||
|
TestDAC1Reg LITERAL1
|
||||||
|
TestDAC2Reg LITERAL1
|
||||||
|
TestADCReg LITERAL1
|
||||||
|
PCD_Idle LITERAL1
|
||||||
|
PCD_Mem LITERAL1
|
||||||
|
PCD_GenerateRandomID LITERAL1
|
||||||
|
PCD_CalcCRC LITERAL1
|
||||||
|
PCD_Transmit LITERAL1
|
||||||
|
PCD_NoCmdChange LITERAL1
|
||||||
|
PCD_Receive LITERAL1
|
||||||
|
PCD_Transceive LITERAL1
|
||||||
|
PCD_MFAuthent LITERAL1
|
||||||
|
PCD_SoftReset LITERAL1
|
||||||
|
RxGain_18dB LITERAL1
|
||||||
|
RxGain_23dB LITERAL1
|
||||||
|
RxGain_18dB_2 LITERAL1
|
||||||
|
RxGain_23dB_2 LITERAL1
|
||||||
|
RxGain_33dB LITERAL1
|
||||||
|
RxGain_38dB LITERAL1
|
||||||
|
RxGain_43dB LITERAL1
|
||||||
|
RxGain_48dB LITERAL1
|
||||||
|
RxGain_min LITERAL1
|
||||||
|
RxGain_avg LITERAL1
|
||||||
|
RxGain_max LITERAL1
|
||||||
|
PICC_CMD_REQA LITERAL1
|
||||||
|
PICC_CMD_WUPA LITERAL1
|
||||||
|
PICC_CMD_CT LITERAL1
|
||||||
|
PICC_CMD_SEL_CL1 LITERAL1
|
||||||
|
PICC_CMD_SEL_CL2 LITERAL1
|
||||||
|
PICC_CMD_SEL_CL3 LITERAL1
|
||||||
|
PICC_CMD_HLTA LITERAL1
|
||||||
|
PICC_CMD_MF_AUTH_KEY_A LITERAL1
|
||||||
|
PICC_CMD_MF_AUTH_KEY_B LITERAL1
|
||||||
|
PICC_CMD_MF_READ LITERAL1
|
||||||
|
PICC_CMD_MF_WRITE LITERAL1
|
||||||
|
PICC_CMD_MF_DECREMENT LITERAL1
|
||||||
|
PICC_CMD_MF_INCREMENT LITERAL1
|
||||||
|
PICC_CMD_MF_RESTORE LITERAL1
|
||||||
|
PICC_CMD_MF_TRANSFER LITERAL1
|
||||||
|
PICC_CMD_UL_WRITE LITERAL1
|
||||||
|
MF_ACK LITERAL1
|
||||||
|
MF_KEY_SIZE LITERAL1
|
||||||
|
PICC_TYPE_UNKNOWN LITERAL1
|
||||||
|
PICC_TYPE_ISO_14443_4 LITERAL1
|
||||||
|
PICC_TYPE_ISO_18092 LITERAL1
|
||||||
|
PICC_TYPE_MIFARE_MINI LITERAL1
|
||||||
|
PICC_TYPE_MIFARE_1K LITERAL1
|
||||||
|
PICC_TYPE_MIFARE_4K LITERAL1
|
||||||
|
PICC_TYPE_MIFARE_UL LITERAL1
|
||||||
|
PICC_TYPE_MIFARE_PLUS LITERAL1
|
||||||
|
PICC_TYPE_TNP3XXX LITERAL1
|
||||||
|
PICC_TYPE_NOT_COMPLETE LITERAL1
|
||||||
|
STATUS_OK LITERAL1
|
||||||
|
STATUS_ERROR LITERAL1
|
||||||
|
STATUS_COLLISION LITERAL1
|
||||||
|
STATUS_TIMEOUT LITERAL1
|
||||||
|
STATUS_NO_ROOM LITERAL1
|
||||||
|
STATUS_INTERNAL_ERROR LITERAL1
|
||||||
|
STATUS_INVALID LITERAL1
|
||||||
|
STATUS_CRC_WRONG LITERAL1
|
||||||
|
STATUS_MIFARE_NACK LITERAL1
|
||||||
|
FIFO_SIZE LITERAL1
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "MFRC522",
|
||||||
|
"keywords": "rfid, spi",
|
||||||
|
"description": "Read a card using a MFRC522 reader on your SPI interface",
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/miguelbalboa/rfid.git"
|
||||||
|
},
|
||||||
|
"version": "1.1.8",
|
||||||
|
"exclude": "doc",
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": ["atmelavr", "ststm32", "teensy", "espressif"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
name=MFRC522
|
||||||
|
version=1.1.8
|
||||||
|
author=GithubCommunity
|
||||||
|
maintainer=miguelbalboa
|
||||||
|
sentence=Arduino RFID Library for MFRC522 (SPI)
|
||||||
|
paragraph=Read/Write a RFID Card or Tag using the ISO/IEC 14443A/MIFARE interface.
|
||||||
|
category=Communication
|
||||||
|
url=https://github.com/miguelbalboa/rfid
|
||||||
|
architectures=avr,STM32F1,teensy
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder
|
||||||
|
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||||
|
// and James Tichenor <http://www.jamestichenor.net>
|
||||||
|
|
||||||
|
// 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 <Wire.h>
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// I2C Digital Potentiometer
|
||||||
|
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||||
|
// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.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 <Wire.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Wire Master Reader
|
||||||
|
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||||
|
|
||||||
|
// 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 <Wire.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Wire Master Writer
|
||||||
|
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||||
|
|
||||||
|
// 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 <Wire.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Wire Slave Receiver
|
||||||
|
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||||
|
|
||||||
|
// 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 <Wire.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Wire Slave Sender
|
||||||
|
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||||
|
|
||||||
|
// 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 <Wire.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For Wire
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
begin KEYWORD2
|
||||||
|
setClock KEYWORD2
|
||||||
|
beginTransmission KEYWORD2
|
||||||
|
endTransmission KEYWORD2
|
||||||
|
requestFrom KEYWORD2
|
||||||
|
onReceive KEYWORD2
|
||||||
|
onRequest KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Instances (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
Wire KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
name=Wire
|
||||||
|
version=1.0
|
||||||
|
author=Arduino
|
||||||
|
maintainer=Arduino <info@arduino.cc>
|
||||||
|
sentence=This library allows you to communicate with I2C and Two Wire Interface devices.
|
||||||
|
paragraph=It allows the communication with I2C devices like temperature sensors, realtime clocks and many others using SDA (Data Line) and SCL (Clock Line).
|
||||||
|
category=Communication
|
||||||
|
url=http://www.arduino.cc/en/Reference/Wire
|
||||||
|
architectures=avr
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
This is non-blocking implementation of Wire library
|
||||||
|
|
@ -0,0 +1,330 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "utility/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 clock)
|
||||||
|
{
|
||||||
|
twi_setFrequency(clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
uint8_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();
|
||||||
|
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TwoWire_h
|
||||||
|
#define TwoWire_h
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
@ -0,0 +1,591 @@
|
||||||
|
/*
|
||||||
|
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 <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <compat/twi.h>
|
||||||
|
#include "Arduino.h" // for digitalWrite
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
// disable twi module (to allow for reinitialize)
|
||||||
|
TWCR = 0;
|
||||||
|
|
||||||
|
// 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_setClock
|
||||||
|
* Desc sets twi bit rate
|
||||||
|
* Input Clock Frequency
|
||||||
|
* Output none
|
||||||
|
*/
|
||||||
|
void twi_setFrequency(uint32_t frequency)
|
||||||
|
{
|
||||||
|
TWBR = ((F_CPU / frequency) - 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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
twi_tout(1);//Ini TimeOut
|
||||||
|
while(TWI_READY != twi_state){
|
||||||
|
if (twi_tout(0)) break;
|
||||||
|
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 ourselves, 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
|
||||||
|
twi_tout(1);
|
||||||
|
while(TWI_MRX == twi_state){
|
||||||
|
if (twi_tout(0)) break;
|
||||||
|
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
|
||||||
|
twi_tout(1);
|
||||||
|
while(TWI_READY != twi_state){
|
||||||
|
if (twi_tout(0)) return 5;
|
||||||
|
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
|
||||||
|
twi_tout(1);
|
||||||
|
while(wait && (TWI_MTX == twi_state)){
|
||||||
|
if (twi_tout(0)) return 5;
|
||||||
|
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 < (twi_txBufferLength+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
|
||||||
|
for(i = 0; i < length; ++i){
|
||||||
|
twi_txBuffer[twi_txBufferLength+i] = data[i];
|
||||||
|
}
|
||||||
|
twi_txBufferLength += length;
|
||||||
|
|
||||||
|
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!
|
||||||
|
twi_tout(1);
|
||||||
|
while(TWCR & _BV(TWSTO)){
|
||||||
|
if (twi_tout(0)) return;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Nirea. Time Out
|
||||||
|
static volatile uint8_t twi_toutc;
|
||||||
|
uint8_t twi_tout(uint8_t ini)
|
||||||
|
{
|
||||||
|
if (ini) twi_toutc=0; else twi_toutc++;
|
||||||
|
if (twi_toutc>=1000) {
|
||||||
|
twi_toutc=0;
|
||||||
|
twi_init();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef twi_h
|
||||||
|
#define twi_h
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
//#define ATMEGA8
|
||||||
|
|
||||||
|
#ifndef CPU_FREQ
|
||||||
|
#define CPU_FREQ 16000000L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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);
|
||||||
|
void twi_setFrequency(uint32_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);
|
||||||
|
uint8_t twi_tout(uint8_t);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
DS3231 library for the Arduino.
|
||||||
|
|
||||||
|
This library implements the following features:
|
||||||
|
|
||||||
|
- read/write of current time, both of the alarms,
|
||||||
|
control/status registers, aging register
|
||||||
|
- read of the temperature register, and of any address from the chip.
|
||||||
|
|
||||||
|
Author: Petre Rodan <petre.rodan@simplex.ro>
|
||||||
|
Available from: https://github.com/rodan/ds3231
|
||||||
|
License: GNU GPLv3
|
||||||
|
|
||||||
|
The DS3231 is a low-cost, extremely accurate I2C real-time clock
|
||||||
|
(RTC) with an integrated temperature-compensated crystal oscillator
|
||||||
|
(TCXO) and crystal.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef __config_h_
|
||||||
|
#define __config_h_
|
||||||
|
|
||||||
|
// comment this out if you need unixtime support
|
||||||
|
// this will add about 324bytes to your firmware
|
||||||
|
//#define CONFIG_UNIXTIME
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,418 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
DS3231 library for the Arduino.
|
||||||
|
|
||||||
|
This library implements the following features:
|
||||||
|
|
||||||
|
- read/write of current time, both of the alarms,
|
||||||
|
control/status registers, aging register
|
||||||
|
- read of the temperature register, and of any address from the chip.
|
||||||
|
|
||||||
|
Author: Petre Rodan <petre.rodan@simplex.ro>
|
||||||
|
Available from: https://github.com/rodan/ds3231
|
||||||
|
|
||||||
|
The DS3231 is a low-cost, extremely accurate I2C real-time clock
|
||||||
|
(RTC) with an integrated temperature-compensated crystal oscillator
|
||||||
|
(TCXO) and crystal.
|
||||||
|
|
||||||
|
GNU GPLv3 license:
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ds3231.h"
|
||||||
|
|
||||||
|
#ifdef __AVR__
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
// Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
|
||||||
|
#ifdef PROGMEM
|
||||||
|
#undef PROGMEM
|
||||||
|
#define PROGMEM __attribute__((section(".progmem.data")))
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define PROGMEM
|
||||||
|
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* control register 0Eh/8Eh
|
||||||
|
bit7 EOSC Enable Oscillator (1 if oscillator must be stopped when on battery)
|
||||||
|
bit6 BBSQW Battery Backed Square Wave
|
||||||
|
bit5 CONV Convert temperature (1 forces a conversion NOW)
|
||||||
|
bit4 RS2 Rate select - frequency of square wave output
|
||||||
|
bit3 RS1 Rate select
|
||||||
|
bit2 INTCN Interrupt control (1 for use of the alarms and to disable square wave)
|
||||||
|
bit1 A2IE Alarm2 interrupt enable (1 to enable)
|
||||||
|
bit0 A1IE Alarm1 interrupt enable (1 to enable)
|
||||||
|
*/
|
||||||
|
|
||||||
|
void DS3231_init(const uint8_t ctrl_reg)
|
||||||
|
{
|
||||||
|
DS3231_set_creg(ctrl_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS3231_set(struct ts t)
|
||||||
|
{
|
||||||
|
uint8_t i, century;
|
||||||
|
|
||||||
|
if (t.year > 2000) {
|
||||||
|
century = 0x80;
|
||||||
|
t.year_s = t.year - 2000;
|
||||||
|
} else {
|
||||||
|
century = 0;
|
||||||
|
t.year_s = t.year - 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TimeDate[7] = { t.sec, t.min, t.hour, t.wday, t.mday, t.mon, t.year_s };
|
||||||
|
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(DS3231_TIME_CAL_ADDR);
|
||||||
|
for (i = 0; i <= 6; i++) {
|
||||||
|
TimeDate[i] = dectobcd(TimeDate[i]);
|
||||||
|
if (i == 5)
|
||||||
|
TimeDate[5] += century;
|
||||||
|
Wire.write(TimeDate[i]);
|
||||||
|
}
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DS3231_get(struct ts *t)
|
||||||
|
{
|
||||||
|
memset(t, 0, sizeof(ts));
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(DS3231_TIME_CAL_ADDR);
|
||||||
|
Wire.endTransmission();
|
||||||
|
|
||||||
|
Wire.requestFrom(DS3231_I2C_ADDR, 7);
|
||||||
|
|
||||||
|
uint8_t TimeDate[7]; // second,minute,hour,dow,day,month,year
|
||||||
|
uint8_t century = 0;
|
||||||
|
uint8_t b = 0xff;
|
||||||
|
for (uint8_t i = 0; i <= 6; i++) {
|
||||||
|
uint8_t n = Wire.read();
|
||||||
|
b &= n;
|
||||||
|
if (i == 5) {
|
||||||
|
TimeDate[5] = bcdtodec(n & 0x1F);
|
||||||
|
century = (n & 0x80) >> 7;
|
||||||
|
} else {
|
||||||
|
TimeDate[i] = bcdtodec(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (b == 0xff) {
|
||||||
|
// DS3231 not connected
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t year_full;
|
||||||
|
if (century == 1) {
|
||||||
|
year_full = 2000 + TimeDate[6];
|
||||||
|
} else {
|
||||||
|
year_full = 1900 + TimeDate[6];
|
||||||
|
}
|
||||||
|
|
||||||
|
t->sec = TimeDate[0];
|
||||||
|
t->min = TimeDate[1];
|
||||||
|
t->hour = TimeDate[2];
|
||||||
|
t->mday = TimeDate[4];
|
||||||
|
t->mon = TimeDate[5];
|
||||||
|
t->year = year_full;
|
||||||
|
t->wday = TimeDate[3];
|
||||||
|
t->year_s = TimeDate[6];
|
||||||
|
t->unixtime = get_unixtime(*t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS3231_set_addr(const uint8_t addr, const uint8_t val)
|
||||||
|
{
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(addr);
|
||||||
|
Wire.write(val);
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DS3231_get_addr(const uint8_t addr)
|
||||||
|
{
|
||||||
|
uint8_t rv;
|
||||||
|
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(addr);
|
||||||
|
Wire.endTransmission();
|
||||||
|
|
||||||
|
Wire.requestFrom(DS3231_I2C_ADDR, 1);
|
||||||
|
rv = Wire.read();
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// control register
|
||||||
|
|
||||||
|
void DS3231_set_creg(const uint8_t val)
|
||||||
|
{
|
||||||
|
DS3231_set_addr(DS3231_CONTROL_ADDR, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// status register 0Fh/8Fh
|
||||||
|
|
||||||
|
/*
|
||||||
|
bit7 OSF Oscillator Stop Flag (if 1 then oscillator has stopped and date might be innacurate)
|
||||||
|
bit3 EN32kHz Enable 32kHz output (1 if needed)
|
||||||
|
bit2 BSY Busy with TCXO functions
|
||||||
|
bit1 A2F Alarm 2 Flag - (1 if alarm2 was triggered)
|
||||||
|
bit0 A1F Alarm 1 Flag - (1 if alarm1 was triggered)
|
||||||
|
*/
|
||||||
|
|
||||||
|
void DS3231_set_sreg(const uint8_t val)
|
||||||
|
{
|
||||||
|
DS3231_set_addr(DS3231_STATUS_ADDR, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DS3231_get_sreg(void)
|
||||||
|
{
|
||||||
|
uint8_t rv;
|
||||||
|
rv = DS3231_get_addr(DS3231_STATUS_ADDR);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// aging register
|
||||||
|
|
||||||
|
void DS3231_set_aging(const int8_t val)
|
||||||
|
{
|
||||||
|
uint8_t reg;
|
||||||
|
|
||||||
|
if (val >= 0)
|
||||||
|
reg = val;
|
||||||
|
else
|
||||||
|
reg = ~(-val) + 1; // 2C
|
||||||
|
|
||||||
|
DS3231_set_addr(DS3231_AGING_OFFSET_ADDR, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t DS3231_get_aging(void)
|
||||||
|
{
|
||||||
|
uint8_t reg;
|
||||||
|
int8_t rv;
|
||||||
|
|
||||||
|
reg = DS3231_get_addr(DS3231_AGING_OFFSET_ADDR);
|
||||||
|
|
||||||
|
if ((reg & 0x80) != 0)
|
||||||
|
rv = reg | ~((1 << 8) - 1); // if negative get two's complement
|
||||||
|
else
|
||||||
|
rv = reg;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// temperature register
|
||||||
|
|
||||||
|
float DS3231_get_treg()
|
||||||
|
{
|
||||||
|
float rv;
|
||||||
|
uint8_t temp_msb, temp_lsb;
|
||||||
|
int8_t nint;
|
||||||
|
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(DS3231_TEMPERATURE_ADDR);
|
||||||
|
Wire.endTransmission();
|
||||||
|
|
||||||
|
Wire.requestFrom(DS3231_I2C_ADDR, 2);
|
||||||
|
temp_msb = Wire.read();
|
||||||
|
temp_lsb = Wire.read() >> 6;
|
||||||
|
|
||||||
|
if ((temp_msb & 0x80) != 0)
|
||||||
|
nint = temp_msb | ~((1 << 8) - 1); // if negative get two's complement
|
||||||
|
else
|
||||||
|
nint = temp_msb;
|
||||||
|
|
||||||
|
rv = 0.25 * temp_lsb + nint;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// alarms
|
||||||
|
|
||||||
|
// flags are: A1M1 (seconds), A1M2 (minutes), A1M3 (hour),
|
||||||
|
// A1M4 (day) 0 to enable, 1 to disable, DY/DT (dayofweek == 1/dayofmonth == 0)
|
||||||
|
void DS3231_set_a1(const uint8_t s, uint8_t mi, uint8_t h, uint8_t d, const uint8_t * flags)
|
||||||
|
{
|
||||||
|
uint8_t t[4] = { s, mi, h, d };
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(DS3231_ALARM1_ADDR);
|
||||||
|
|
||||||
|
for (i = 0; i <= 3; i++) {
|
||||||
|
if (i == 3) {
|
||||||
|
Wire.write(dectobcd(t[3]) | (flags[3] << 7) | (flags[4] << 6));
|
||||||
|
} else
|
||||||
|
Wire.write(dectobcd(t[i]) | (flags[i] << 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS3231_get_a1(struct ts *td)
|
||||||
|
{
|
||||||
|
uint8_t n[4];
|
||||||
|
uint8_t t[4]; // second,minute,hour,day
|
||||||
|
//uint8_t f[5]; // flags
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
memset(td, 0, sizeof(ts));
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(DS3231_ALARM1_ADDR);
|
||||||
|
Wire.endTransmission();
|
||||||
|
|
||||||
|
Wire.requestFrom(DS3231_I2C_ADDR, 4);
|
||||||
|
|
||||||
|
for (i = 0; i <= 3; i++) {
|
||||||
|
n[i] = Wire.read();
|
||||||
|
//f[i] = (n[i] & 0x80) >> 7;
|
||||||
|
t[i] = bcdtodec(n[i] & 0x7F);
|
||||||
|
}
|
||||||
|
|
||||||
|
//f[4] = (n[3] & 0x40) >> 6;
|
||||||
|
t[3] = bcdtodec(n[3] & 0x3F);
|
||||||
|
td->sec = t[0];
|
||||||
|
td->min = t[1];
|
||||||
|
td->hour = t[2];
|
||||||
|
td->mday = t[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// when the alarm flag is cleared the pulldown on INT is also released
|
||||||
|
void DS3231_clear_a1f(void)
|
||||||
|
{
|
||||||
|
uint8_t reg_val;
|
||||||
|
|
||||||
|
reg_val = DS3231_get_sreg() & ~DS3231_A1F;
|
||||||
|
DS3231_set_sreg(reg_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DS3231_triggered_a1(void)
|
||||||
|
{
|
||||||
|
return DS3231_get_sreg() & DS3231_A1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flags are: A2M2 (minutes), A2M3 (hour), A2M4 (day) 0 to enable, 1 to disable, DY/DT (dayofweek == 1/dayofmonth == 0) -
|
||||||
|
void DS3231_set_a2(uint8_t mi, const uint8_t h, const uint8_t d, const uint8_t * flags)
|
||||||
|
{
|
||||||
|
uint8_t t[3] = { mi, h, d };
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(DS3231_ALARM2_ADDR);
|
||||||
|
|
||||||
|
for (i = 0; i <= 2; i++) {
|
||||||
|
if (i == 2) {
|
||||||
|
Wire.write(dectobcd(t[2]) | (flags[2] << 7) | (flags[3] << 6));
|
||||||
|
} else
|
||||||
|
Wire.write(dectobcd(t[i]) | (flags[i] << 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS3231_get_a2(char *buf, const uint8_t len)
|
||||||
|
{
|
||||||
|
uint8_t n[3];
|
||||||
|
uint8_t t[3]; //second,minute,hour,day
|
||||||
|
uint8_t f[4]; // flags
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
Wire.beginTransmission(DS3231_I2C_ADDR);
|
||||||
|
Wire.write(DS3231_ALARM2_ADDR);
|
||||||
|
Wire.endTransmission();
|
||||||
|
|
||||||
|
Wire.requestFrom(DS3231_I2C_ADDR, 3);
|
||||||
|
|
||||||
|
for (i = 0; i <= 2; i++) {
|
||||||
|
n[i] = Wire.read();
|
||||||
|
f[i] = (n[i] & 0x80) >> 7;
|
||||||
|
t[i] = bcdtodec(n[i] & 0x7F);
|
||||||
|
}
|
||||||
|
|
||||||
|
f[3] = (n[2] & 0x40) >> 6;
|
||||||
|
t[2] = bcdtodec(n[2] & 0x3F);
|
||||||
|
|
||||||
|
snprintf(buf, len, "m%02d h%02d d%02d fm%d h%d d%d wm%d %d %d %d", t[0],
|
||||||
|
t[1], t[2], f[0], f[1], f[2], f[3], n[0], n[1], n[2]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// when the alarm flag is cleared the pulldown on INT is also released
|
||||||
|
void DS3231_clear_a2f(void)
|
||||||
|
{
|
||||||
|
uint8_t reg_val;
|
||||||
|
|
||||||
|
reg_val = DS3231_get_sreg() & ~DS3231_A2F;
|
||||||
|
DS3231_set_sreg(reg_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DS3231_triggered_a2(void)
|
||||||
|
{
|
||||||
|
return DS3231_get_sreg() & DS3231_A2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t days_in_month [12] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||||
|
|
||||||
|
// returns the number of seconds since 01.01.1970 00:00:00 UTC, valid for 2000..FIXME
|
||||||
|
uint32_t get_unixtime(struct ts t)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint16_t d;
|
||||||
|
int16_t y;
|
||||||
|
uint32_t rv;
|
||||||
|
|
||||||
|
if (t.year >= 2000) {
|
||||||
|
y = t.year - 2000;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = t.mday - 1;
|
||||||
|
for (i=1; i<t.mon; i++) {
|
||||||
|
d += pgm_read_byte(days_in_month + i - 1);
|
||||||
|
}
|
||||||
|
if (t.mon > 2 && y % 4 == 0) {
|
||||||
|
d++;
|
||||||
|
}
|
||||||
|
// count leap days
|
||||||
|
d += (365 * y + (y + 3) / 4);
|
||||||
|
rv = ((d * 24UL + t.hour) * 60 + t.min) * 60 + t.sec + SECONDS_FROM_1970_TO_2000;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t dectobcd(const uint8_t val)
|
||||||
|
{
|
||||||
|
return ((val / 10 * 16) + (val % 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bcdtodec(const uint8_t val)
|
||||||
|
{
|
||||||
|
return ((val / 16 * 10) + (val % 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inp2toi(char *cmd, const uint16_t seek)
|
||||||
|
{
|
||||||
|
uint8_t rv;
|
||||||
|
rv = (cmd[seek] - 48) * 10 + cmd[seek + 1] - 48;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
#ifndef __ds3231_h_
|
||||||
|
#define __ds3231_h_
|
||||||
|
|
||||||
|
//#if ARDUINO >= 100
|
||||||
|
#include <Arduino.h>
|
||||||
|
//#else
|
||||||
|
//#include <WProgram.h>
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define SECONDS_FROM_1970_TO_2000 946684800
|
||||||
|
|
||||||
|
// i2c slave address of the DS3231 chip
|
||||||
|
#define DS3231_I2C_ADDR 0x68
|
||||||
|
|
||||||
|
// timekeeping registers
|
||||||
|
#define DS3231_TIME_CAL_ADDR 0x00
|
||||||
|
#define DS3231_ALARM1_ADDR 0x07
|
||||||
|
#define DS3231_ALARM2_ADDR 0x0B
|
||||||
|
#define DS3231_CONTROL_ADDR 0x0E
|
||||||
|
#define DS3231_STATUS_ADDR 0x0F
|
||||||
|
#define DS3231_AGING_OFFSET_ADDR 0x10
|
||||||
|
#define DS3231_TEMPERATURE_ADDR 0x11
|
||||||
|
|
||||||
|
// control register bits
|
||||||
|
#define DS3231_A1IE 0x1
|
||||||
|
#define DS3231_A2IE 0x2
|
||||||
|
#define DS3231_INTCN 0x4
|
||||||
|
|
||||||
|
// status register bits
|
||||||
|
#define DS3231_A1F 0x1
|
||||||
|
#define DS3231_A2F 0x2
|
||||||
|
#define DS3231_OSF 0x80
|
||||||
|
|
||||||
|
|
||||||
|
struct ts {
|
||||||
|
uint8_t sec; /* seconds */
|
||||||
|
uint8_t min; /* minutes */
|
||||||
|
uint8_t hour; /* hours */
|
||||||
|
uint8_t mday; /* day of the month */
|
||||||
|
uint8_t mon; /* month */
|
||||||
|
int16_t year; /* year */
|
||||||
|
uint8_t wday; /* day of the week */
|
||||||
|
uint8_t yday; /* day in the year */
|
||||||
|
uint8_t isdst; /* daylight saving time */
|
||||||
|
uint8_t year_s; /* year in short notation*/
|
||||||
|
uint32_t unixtime; /* seconds since 01.01.1970 00:00:00 UTC*/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void DS3231_init(const uint8_t creg);
|
||||||
|
void DS3231_set(struct ts t);
|
||||||
|
bool DS3231_get(struct ts *t);
|
||||||
|
|
||||||
|
void DS3231_set_addr(const uint8_t addr, const uint8_t val);
|
||||||
|
uint8_t DS3231_get_addr(const uint8_t addr);
|
||||||
|
|
||||||
|
// control/status register
|
||||||
|
void DS3231_set_creg(const uint8_t val);
|
||||||
|
void DS3231_set_sreg(const uint8_t val);
|
||||||
|
uint8_t DS3231_get_sreg(void);
|
||||||
|
|
||||||
|
// aging offset register
|
||||||
|
void DS3231_set_aging(const int8_t val);
|
||||||
|
int8_t DS3231_get_aging(void);
|
||||||
|
|
||||||
|
// temperature register
|
||||||
|
float DS3231_get_treg(void);
|
||||||
|
|
||||||
|
// alarms
|
||||||
|
void DS3231_set_a1(const uint8_t s, const uint8_t mi, const uint8_t h, const uint8_t d,
|
||||||
|
const uint8_t * flags);
|
||||||
|
void DS3231_get_a1(struct ts *td);
|
||||||
|
void DS3231_clear_a1f(void);
|
||||||
|
uint8_t DS3231_triggered_a1(void);
|
||||||
|
|
||||||
|
void DS3231_set_a2(const uint8_t mi, const uint8_t h, const uint8_t d, const uint8_t * flags);
|
||||||
|
void DS3231_get_a2(char *buf, const uint8_t len);
|
||||||
|
void DS3231_clear_a2f(void);
|
||||||
|
uint8_t DS3231_triggered_a2(void);
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
uint32_t get_unixtime(struct ts t);
|
||||||
|
uint8_t dectobcd(const uint8_t val);
|
||||||
|
uint8_t bcdtodec(const uint8_t val);
|
||||||
|
uint8_t inp2toi(char *cmd, const uint16_t seek);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
# Board settings.
|
||||||
|
#BOARD = atmega328
|
||||||
|
#BOARD = pro5v328
|
||||||
|
|
||||||
|
MON_SPEED = 9600
|
||||||
|
|
||||||
|
# Where to find header files and libraries.
|
||||||
|
LIB_DIRS = ../../ /local/arduino-100/libraries/Wire/ /local/arduino-100/libraries/Wire/utility/
|
||||||
|
|
||||||
|
include ../../../Makefile.master
|
||||||
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include "ds3231.h"
|
||||||
|
|
||||||
|
#define BUFF_MAX 128
|
||||||
|
|
||||||
|
uint8_t time[8];
|
||||||
|
char recv[BUFF_MAX];
|
||||||
|
unsigned int recv_size = 0;
|
||||||
|
unsigned long prev, interval = 5000;
|
||||||
|
|
||||||
|
void parse_cmd(char *cmd, int cmdsize);
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(9600);
|
||||||
|
Wire.begin();
|
||||||
|
DS3231_init(DS3231_INTCN);
|
||||||
|
memset(recv, 0, BUFF_MAX);
|
||||||
|
Serial.println("GET time");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
char in;
|
||||||
|
char buff[BUFF_MAX];
|
||||||
|
unsigned long now = millis();
|
||||||
|
struct ts t;
|
||||||
|
|
||||||
|
// show time once in a while
|
||||||
|
if ((now - prev > interval) && (Serial.available() <= 0)) {
|
||||||
|
DS3231_get(&t);
|
||||||
|
|
||||||
|
// there is a compile time option in the library to include unixtime support
|
||||||
|
#ifdef CONFIG_UNIXTIME
|
||||||
|
snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d %ld", t.year,
|
||||||
|
t.mon, t.mday, t.hour, t.min, t.sec, t.unixtime);
|
||||||
|
#else
|
||||||
|
snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year,
|
||||||
|
t.mon, t.mday, t.hour, t.min, t.sec);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Serial.println(buff);
|
||||||
|
prev = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Serial.available() > 0) {
|
||||||
|
in = Serial.read();
|
||||||
|
|
||||||
|
if ((in == 10 || in == 13) && (recv_size > 0)) {
|
||||||
|
parse_cmd(recv, recv_size);
|
||||||
|
recv_size = 0;
|
||||||
|
recv[0] = 0;
|
||||||
|
} else if (in < 48 || in > 122) {; // ignore ~[0-9A-Za-z]
|
||||||
|
} else if (recv_size > BUFF_MAX - 2) { // drop lines that are too long
|
||||||
|
// drop
|
||||||
|
recv_size = 0;
|
||||||
|
recv[0] = 0;
|
||||||
|
} else if (recv_size < BUFF_MAX - 2) {
|
||||||
|
recv[recv_size] = in;
|
||||||
|
recv[recv_size + 1] = 0;
|
||||||
|
recv_size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_cmd(char *cmd, int cmdsize)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t reg_val;
|
||||||
|
char buff[BUFF_MAX];
|
||||||
|
struct ts t;
|
||||||
|
|
||||||
|
//snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);
|
||||||
|
//Serial.print(buff);
|
||||||
|
|
||||||
|
// TssmmhhWDDMMYYYY aka set time
|
||||||
|
if (cmd[0] == 84 && cmdsize == 16) {
|
||||||
|
//T355720619112011
|
||||||
|
t.sec = inp2toi(cmd, 1);
|
||||||
|
t.min = inp2toi(cmd, 3);
|
||||||
|
t.hour = inp2toi(cmd, 5);
|
||||||
|
t.wday = cmd[7] - 48;
|
||||||
|
t.mday = inp2toi(cmd, 8);
|
||||||
|
t.mon = inp2toi(cmd, 10);
|
||||||
|
t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);
|
||||||
|
DS3231_set(t);
|
||||||
|
Serial.println("OK");
|
||||||
|
} else if (cmd[0] == 49 && cmdsize == 1) { // "1" get alarm 1
|
||||||
|
DS3231_get_a1(&buff[0], 59);
|
||||||
|
Serial.println(buff);
|
||||||
|
} else if (cmd[0] == 50 && cmdsize == 1) { // "2" get alarm 1
|
||||||
|
DS3231_get_a2(&buff[0], 59);
|
||||||
|
Serial.println(buff);
|
||||||
|
} else if (cmd[0] == 51 && cmdsize == 1) { // "3" get aging register
|
||||||
|
Serial.print("aging reg is ");
|
||||||
|
Serial.println(DS3231_get_aging(), DEC);
|
||||||
|
} else if (cmd[0] == 65 && cmdsize == 9) { // "A" set alarm 1
|
||||||
|
DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
|
||||||
|
//ASSMMHHDD
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd
|
||||||
|
}
|
||||||
|
uint8_t flags[5] = { 0, 0, 0, 0, 0 };
|
||||||
|
DS3231_set_a1(time[0], time[1], time[2], time[3], flags);
|
||||||
|
DS3231_get_a1(&buff[0], 59);
|
||||||
|
Serial.println(buff);
|
||||||
|
} else if (cmd[0] == 66 && cmdsize == 7) { // "B" Set Alarm 2
|
||||||
|
DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
|
||||||
|
//BMMHHDD
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd
|
||||||
|
}
|
||||||
|
uint8_t flags[5] = { 0, 0, 0, 0 };
|
||||||
|
DS3231_set_a2(time[0], time[1], time[2], flags);
|
||||||
|
DS3231_get_a2(&buff[0], 59);
|
||||||
|
Serial.println(buff);
|
||||||
|
} else if (cmd[0] == 67 && cmdsize == 1) { // "C" - get temperature register
|
||||||
|
Serial.print("temperature reg is ");
|
||||||
|
Serial.println(DS3231_get_treg(), DEC);
|
||||||
|
} else if (cmd[0] == 68 && cmdsize == 1) { // "D" - reset status register alarm flags
|
||||||
|
reg_val = DS3231_get_sreg();
|
||||||
|
reg_val &= B11111100;
|
||||||
|
DS3231_set_sreg(reg_val);
|
||||||
|
} else if (cmd[0] == 70 && cmdsize == 1) { // "F" - custom fct
|
||||||
|
reg_val = DS3231_get_addr(0x5);
|
||||||
|
Serial.print("orig ");
|
||||||
|
Serial.print(reg_val,DEC);
|
||||||
|
Serial.print("month is ");
|
||||||
|
Serial.println(bcdtodec(reg_val & 0x1F),DEC);
|
||||||
|
} else if (cmd[0] == 71 && cmdsize == 1) { // "G" - set aging status register
|
||||||
|
DS3231_set_aging(0);
|
||||||
|
} else if (cmd[0] == 83 && cmdsize == 1) { // "S" - get status register
|
||||||
|
Serial.print("status reg is ");
|
||||||
|
Serial.println(DS3231_get_sreg(), DEC);
|
||||||
|
} else {
|
||||||
|
Serial.print("unknown command prefix ");
|
||||||
|
Serial.println(cmd[0]);
|
||||||
|
Serial.println(cmd[0], DEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef SPORTIDUINO_DEBUG_H
|
||||||
|
#define SPORTIDUINO_DEBUG_H
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DEBUG_PRINTLN(x) Serial.println(x)
|
||||||
|
#define DEBUG_PRINT(x) Serial.print(x)
|
||||||
|
#define DEBUG_PRINTLN_FORMAT(x, format) Serial.println(x, format)
|
||||||
|
#define DEBUG_PRINT_FORMAT(x, format) Serial.print(x, format)
|
||||||
|
#else
|
||||||
|
#define DEBUG_PRINTLN(x)
|
||||||
|
#define DEBUG_PRINT(x)
|
||||||
|
#define DEBUG_PRINTLN_FORMAT(x, format)
|
||||||
|
#define DEBUG_PRINT_FORMAT(x, format)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,532 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "rfid.h"
|
||||||
|
|
||||||
|
void Rfid::init(uint8_t ssPin, uint8_t rstPin, uint8_t newAntennaGain) {
|
||||||
|
rfidSsPin = ssPin;
|
||||||
|
rfidRstPin = rstPin;
|
||||||
|
antennaGain = constrain(newAntennaGain, MIN_ANTENNA_GAIN, MAX_ANTENNA_GAIN);
|
||||||
|
memset(authPwd.pass, 0xFF, 4);
|
||||||
|
memset(authPwd.pack, 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rfid::clearLastCardUid() {
|
||||||
|
memset(&lastCardUid, 0, sizeof(lastCardUid));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rfid::setAntennaGain(uint8_t newAntennaGain) {
|
||||||
|
antennaGain = constrain(newAntennaGain, MIN_ANTENNA_GAIN, MAX_ANTENNA_GAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rfid::setAuthPassword(uint8_t* password) {
|
||||||
|
if(!password) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
|
authPwd.pass[i] = password[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rfid::begin(uint8_t newAntennaGain) {
|
||||||
|
if(newAntennaGain) {
|
||||||
|
antennaGain = newAntennaGain;
|
||||||
|
}
|
||||||
|
cardType = CardType::UNKNOWN;
|
||||||
|
authenticated = false;
|
||||||
|
|
||||||
|
SPI.begin();
|
||||||
|
mfrc522.PCD_Init(rfidSsPin, rfidRstPin);
|
||||||
|
mfrc522.PCD_AntennaOff();
|
||||||
|
mfrc522.PCD_SetAntennaGain(antennaGain<<4);
|
||||||
|
mfrc522.PCD_AntennaOn();
|
||||||
|
|
||||||
|
delay(5);
|
||||||
|
|
||||||
|
if(!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
|
||||||
|
clearLastCardUid();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto piccType = MFRC522::PICC_GetType(mfrc522.uid.sak);
|
||||||
|
switch(piccType) {
|
||||||
|
case MFRC522::PICC_TYPE_MIFARE_MINI:
|
||||||
|
cardType = CardType::MIFARE_MINI;
|
||||||
|
return;
|
||||||
|
case MFRC522::PICC_TYPE_MIFARE_1K:
|
||||||
|
cardType = CardType::MIFARE_1K;
|
||||||
|
return;
|
||||||
|
case MFRC522::PICC_TYPE_MIFARE_4K:
|
||||||
|
cardType = CardType::MIFARE_4K;
|
||||||
|
return;
|
||||||
|
case MFRC522::PICC_TYPE_MIFARE_UL: {
|
||||||
|
byte pageData[18];
|
||||||
|
byte dataSize = sizeof(pageData);
|
||||||
|
if(ntagCard4PagesRead(3, pageData, &dataSize)) {
|
||||||
|
switch(pageData[2]) {
|
||||||
|
case 0x12:
|
||||||
|
cardType = CardType::NTAG213;
|
||||||
|
return;
|
||||||
|
case 0x3e:
|
||||||
|
cardType = CardType::NTAG215;
|
||||||
|
return;
|
||||||
|
case 0x6d:
|
||||||
|
cardType = CardType::NTAG216;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cardType = CardType::UNKNOWN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rfid::end() {
|
||||||
|
if(isCardDetected()) {
|
||||||
|
memcpy(&lastCardUid, &mfrc522.uid, sizeof(lastCardUid));
|
||||||
|
}
|
||||||
|
|
||||||
|
mfrc522.PICC_HaltA();
|
||||||
|
mfrc522.PCD_StopCrypto1();
|
||||||
|
SPI.end();
|
||||||
|
digitalWrite(rfidRstPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::isCardDetected() {
|
||||||
|
if(cardType != CardType::UNKNOWN) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::isNewCardDetected() {
|
||||||
|
if(isCardDetected()) {
|
||||||
|
for(uint8_t i = 0; i < mfrc522.uid.size; i++) {
|
||||||
|
if(lastCardUid.uidByte[i] != mfrc522.uid.uidByte[i]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN("Same UID");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MFRC522::MIFARE_Key defaultMifareKey = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
|
||||||
|
bool Rfid::mifareCardPageRead(uint8_t pageAdr, byte *data, byte *size) {
|
||||||
|
// data size should be at least 18 bytes!
|
||||||
|
|
||||||
|
if(pageAdr < 3 || *size < 18) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte blockAddr = pageAdr-3 + ((pageAdr-3)/3);
|
||||||
|
byte trailerBlock = blockAddr + (3-blockAddr%4);
|
||||||
|
|
||||||
|
auto status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &defaultMifareKey, &(mfrc522.uid));
|
||||||
|
|
||||||
|
if(status != MFRC522::STATUS_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = mfrc522.MIFARE_Read(blockAddr, data, size);
|
||||||
|
|
||||||
|
if(status != MFRC522::STATUS_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::mifareCardPageWrite(uint8_t pageAdr, byte *data, byte size) {
|
||||||
|
// data size should be 16 bytes!
|
||||||
|
|
||||||
|
if(pageAdr < 3 || size < 16) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte blockAddr = pageAdr-3 + ((pageAdr-3)/3);
|
||||||
|
byte trailerBlock = blockAddr + (3-blockAddr%4);
|
||||||
|
|
||||||
|
auto status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &defaultMifareKey, &(mfrc522.uid));
|
||||||
|
|
||||||
|
if(status != MFRC522::STATUS_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = mfrc522.MIFARE_Write(blockAddr, data, size);
|
||||||
|
|
||||||
|
if(status != MFRC522::STATUS_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::ntagSetPassword(NtagAuthPassword *password, bool readAndWrite, uint8_t negAuthAttemptsLim, uint8_t startPage) {
|
||||||
|
if(negAuthAttemptsLim > 7) {
|
||||||
|
negAuthAttemptsLim = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t maxPage = getCardMaxPage();
|
||||||
|
if(!ntagCardPageWrite(maxPage + PAGE_PWD_OFFSET, password->pass, 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t packPageData[4] = {password->pack[0], password->pack[1], 0, 0};
|
||||||
|
if(!ntagCardPageWrite(maxPage + PAGE_PACK_OFFSET, packPageData, 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//uint8_t pageData[18];
|
||||||
|
//uint8_t dataSize = sizeof(pageData);
|
||||||
|
//if(!ntagCard4PagesRead(maxPage + PAGE_CFG1_OFFSET, pageData, &dataSize)) {
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
uint8_t accessByteData = readAndWrite ? 0x80 : 0x00;
|
||||||
|
accessByteData |= negAuthAttemptsLim & 0x07;
|
||||||
|
uint8_t cfg1PageData[4] = {accessByteData, 0, 0, 0};
|
||||||
|
if(!ntagCardPageWrite(maxPage + PAGE_CFG1_OFFSET, cfg1PageData, 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set start page to enable the password verification at the end of the procedure
|
||||||
|
uint8_t cfg0PageData[4] = {0, 0, 0, startPage};
|
||||||
|
if(!ntagCardPageWrite(maxPage + PAGE_CFG0_OFFSET, cfg0PageData, 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::ntagDisableAuthentication() {
|
||||||
|
DEBUG_PRINTLN("ntagDisableAuthentication");
|
||||||
|
uint8_t maxPage = getCardMaxPage();
|
||||||
|
|
||||||
|
uint8_t defaultPassword[4] = {0xff, 0xff, 0xff, 0xff};
|
||||||
|
// Reset password
|
||||||
|
if(!ntagCardPageWrite(maxPage + PAGE_PWD_OFFSET, defaultPassword, 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cfg0PageData[4] = {0, 0, 0, 0xff};
|
||||||
|
if(!ntagCardPageWrite(maxPage + PAGE_CFG0_OFFSET, cfg0PageData, 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::ntagAuth(NtagAuthPassword *password) {
|
||||||
|
if(!password) {
|
||||||
|
DEBUG_PRINTLN(F("ntagAuth password is null"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isCardDetected()) {
|
||||||
|
DEBUG_PRINTLN(F("ntagAuth card is not detected"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_PRINTLN(F("Authenticating..."));
|
||||||
|
DEBUG_PRINT(F("Password: "));
|
||||||
|
for(uint8_t i = 0; i < 4; i++) {
|
||||||
|
DEBUG_PRINT_FORMAT(password->pass[i], HEX);
|
||||||
|
DEBUG_PRINT(F(" "));
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN("");
|
||||||
|
DEBUG_PRINT(F("Pack: "));
|
||||||
|
for(uint8_t i = 0; i < 2; i++) {
|
||||||
|
DEBUG_PRINT_FORMAT(password->pack[i], HEX);
|
||||||
|
DEBUG_PRINT(F(" "));
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
uint8_t packReturn[2] = {0, 0};
|
||||||
|
auto status = (MFRC522::StatusCode)mfrc522.PCD_NTAG21x_Auth(&password->pass[0], packReturn);
|
||||||
|
DEBUG_PRINT(F("Pack from card: 0x"));
|
||||||
|
DEBUG_PRINT_FORMAT(packReturn[0], HEX);
|
||||||
|
DEBUG_PRINT(F(" 0x"));
|
||||||
|
DEBUG_PRINTLN_FORMAT(packReturn[1], HEX);
|
||||||
|
|
||||||
|
if(status != MFRC522::STATUS_OK) {
|
||||||
|
DEBUG_PRINT(F("Auth failed, status: 0x"));
|
||||||
|
DEBUG_PRINTLN_FORMAT(status, HEX);
|
||||||
|
if (status == MFRC522::STATUS_TIMEOUT) {
|
||||||
|
byte atqa_answer[2];
|
||||||
|
byte atqa_size = 2;
|
||||||
|
mfrc522.PICC_WakeupA(atqa_answer, &atqa_size);
|
||||||
|
|
||||||
|
if (!mfrc522.PICC_ReadCardSerial()) {
|
||||||
|
DEBUG_PRINTLN(F("ReadCardSerial failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::ntagTryAuth(bool ignoreAuthError) {
|
||||||
|
if(authPwd.pass[0] != 0xFF || authPwd.pass[1] != 0xFF || authPwd.pass[2] != 0xFF || authPwd.pass[3] != 0xFF) {
|
||||||
|
if(!ntagAuth(&authPwd)) {
|
||||||
|
if(!ignoreAuthError) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN(F("ignore auth error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authenticated = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::ntagCard4PagesRead(uint8_t pageAdr, byte *data, byte *size, bool ignoreAuthError) {
|
||||||
|
if(*size < 18) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pageAdr >= CARD_PAGE_INIT && !authenticated) {
|
||||||
|
if (!ntagTryAuth(ignoreAuthError)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(pageAdr, data, size);
|
||||||
|
|
||||||
|
if(status != MFRC522::STATUS_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::ntagCardPageWrite(uint8_t pageAdr, byte *data, byte size, bool ignoreAuthError) {
|
||||||
|
DEBUG_PRINT(F("ntagCardPageWrite pageAdr: "));
|
||||||
|
DEBUG_PRINT(pageAdr);
|
||||||
|
DEBUG_PRINT(F(" size: "));
|
||||||
|
DEBUG_PRINTLN(size);
|
||||||
|
if(pageAdr < 2 || size < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!authenticated || !ignoreAuthError) {
|
||||||
|
if(!ntagTryAuth(ignoreAuthError)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto status = (MFRC522::StatusCode)mfrc522.MIFARE_Ultralight_Write(pageAdr, data, size);
|
||||||
|
|
||||||
|
if(status != MFRC522::STATUS_OK) {
|
||||||
|
DEBUG_PRINT(F("ntagCardPageWrite failed, status: 0x"));
|
||||||
|
DEBUG_PRINTLN_FORMAT(status, HEX);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Rfid::getCardMaxPage() {
|
||||||
|
switch(cardType) {
|
||||||
|
case CardType::MIFARE_MINI:
|
||||||
|
return 17;
|
||||||
|
case CardType::MIFARE_1K:
|
||||||
|
return 50;
|
||||||
|
case CardType::MIFARE_4K:
|
||||||
|
return 98;
|
||||||
|
case CardType::MIFARE_UL:
|
||||||
|
return 39;
|
||||||
|
case CardType::NTAG216:
|
||||||
|
return 225;
|
||||||
|
case CardType::NTAG215:
|
||||||
|
return 129;
|
||||||
|
case CardType::NTAG213:
|
||||||
|
return 39;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CardType Rfid::getCardType() {
|
||||||
|
return cardType;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardPageRead(uint8_t pageAdr, byte *data, uint8_t size, bool ignoreAuthError) {
|
||||||
|
uint8_t maxPage = getCardMaxPage();
|
||||||
|
|
||||||
|
if(pageAdr > maxPage) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
byte pageData[18];
|
||||||
|
byte dataSize = sizeof(pageData);
|
||||||
|
switch(cardType) {
|
||||||
|
case CardType::MIFARE_MINI:
|
||||||
|
case CardType::MIFARE_1K:
|
||||||
|
case CardType::MIFARE_4K:
|
||||||
|
result = mifareCardPageRead(pageAdr, pageData, &dataSize);
|
||||||
|
break;
|
||||||
|
case CardType::MIFARE_UL:
|
||||||
|
case CardType::NTAG213:
|
||||||
|
case CardType::NTAG215:
|
||||||
|
case CardType::NTAG216:
|
||||||
|
default:
|
||||||
|
result = ntagCard4PagesRead(pageAdr, pageData, &dataSize, ignoreAuthError);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result) {
|
||||||
|
memcpy(data, pageData, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardPageWrite(uint8_t pageAdr, const byte *data, uint8_t size, bool ignoreAuthError) {
|
||||||
|
uint8_t maxPage = getCardMaxPage();
|
||||||
|
|
||||||
|
if(pageAdr > maxPage) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte pageData[16];
|
||||||
|
memset(pageData, 0, sizeof(pageData));
|
||||||
|
memcpy(pageData, data, size);
|
||||||
|
|
||||||
|
switch(cardType) {
|
||||||
|
case CardType::MIFARE_MINI:
|
||||||
|
case CardType::MIFARE_1K:
|
||||||
|
case CardType::MIFARE_4K:
|
||||||
|
return mifareCardPageWrite(pageAdr, pageData, sizeof(pageData));
|
||||||
|
case CardType::MIFARE_UL:
|
||||||
|
case CardType::NTAG213:
|
||||||
|
case CardType::NTAG215:
|
||||||
|
case CardType::NTAG216:
|
||||||
|
default:
|
||||||
|
return ntagCardPageWrite(pageAdr, pageData, sizeof(pageData), ignoreAuthError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardPageWrite(uint8_t pageAdr, uint32_t value) {
|
||||||
|
byte data[4];
|
||||||
|
data[0] = (value >> 24) & 0xFF;
|
||||||
|
data[1] = (value >> 16) & 0xFF;
|
||||||
|
data[2] = (value >> 8) & 0xFF;
|
||||||
|
data[3] = value & 0xFF;
|
||||||
|
return cardPageWrite(pageAdr, data, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardWrite(uint8_t startPageAdr, const byte *data, uint16_t size) {
|
||||||
|
uint8_t pageAddr = startPageAdr;
|
||||||
|
for(uint8_t i = 0; i < size/4; ++i) {
|
||||||
|
if(!cardPageWrite(pageAddr++, data + i*4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tailSize = size%4;
|
||||||
|
if(tailSize > 0) {
|
||||||
|
if(!cardPageWrite(pageAddr, data + size - tailSize, tailSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardErase(uint8_t beginPageAddr, uint8_t endPageAddr) {
|
||||||
|
for(uint8_t pageAddr = endPageAddr; pageAddr >= beginPageAddr; --pageAddr) {
|
||||||
|
if(!cardPageErase(pageAddr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardPageErase(uint8_t pageAddr) {
|
||||||
|
DEBUG_PRINT(F("Erasing page "));
|
||||||
|
DEBUG_PRINTLN(pageAddr);
|
||||||
|
byte pageData[4];
|
||||||
|
if(!cardPageRead(pageAddr, pageData)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < 4; ++i) {
|
||||||
|
if(pageData[i] != 0) {
|
||||||
|
const byte emptyBlock[] = {0,0,0,0};
|
||||||
|
return cardPageWrite(pageAddr, emptyBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardErase4Pages(uint8_t pageAddr) {
|
||||||
|
if (!isCardDetected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch(cardType) {
|
||||||
|
case CardType::MIFARE_MINI:
|
||||||
|
case CardType::MIFARE_1K:
|
||||||
|
case CardType::MIFARE_4K: {
|
||||||
|
for(uint8_t i = 0; i < 4; ++i) {
|
||||||
|
if(!cardPageErase(pageAddr + 3 - i)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case CardType::NTAG213:
|
||||||
|
case CardType::NTAG215:
|
||||||
|
case CardType::NTAG216: {
|
||||||
|
DEBUG_PRINT(F("Checking pages at "));
|
||||||
|
DEBUG_PRINTLN(pageAddr);
|
||||||
|
byte pageData[18];
|
||||||
|
byte dataSize = sizeof(pageData);
|
||||||
|
if(!ntagCard4PagesRead(pageAddr, pageData, &dataSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < 4; ++i) {
|
||||||
|
for(uint8_t j = 0; j < 4; ++j) {
|
||||||
|
uint8_t offset = (3 - i);
|
||||||
|
if(pageData[offset*4 + j] != 0) {
|
||||||
|
const byte emptyBlock[] = {0,0,0,0};
|
||||||
|
if(!ntagCardPageWrite(pageAddr + offset, emptyBlock, sizeof(emptyBlock))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rfid::cardEnableDisableAuthentication(bool writeProtection, bool readProtection) {
|
||||||
|
if (!isCardDetected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch(cardType) {
|
||||||
|
case CardType::MIFARE_MINI:
|
||||||
|
case CardType::MIFARE_1K:
|
||||||
|
case CardType::MIFARE_4K: {
|
||||||
|
// TODO: not implemented yet
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case CardType::NTAG213:
|
||||||
|
case CardType::NTAG215:
|
||||||
|
case CardType::NTAG216: {
|
||||||
|
if(!writeProtection) {
|
||||||
|
return ntagDisableAuthentication();
|
||||||
|
}
|
||||||
|
// Enable authentication from page 4 and with unlimited negative password verification attempts
|
||||||
|
return ntagSetPassword(&authPwd, readProtection, 0, CARD_PAGE_INIT);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
#ifndef SPORTIDUINO_RFID_H
|
||||||
|
#define SPORTIDUINO_RFID_H
|
||||||
|
|
||||||
|
#include <MFRC522.h>
|
||||||
|
|
||||||
|
#define MIN_ANTENNA_GAIN 2
|
||||||
|
#define MAX_ANTENNA_GAIN 7
|
||||||
|
|
||||||
|
#define DEFAULT_ANTENNA_GAIN 4
|
||||||
|
|
||||||
|
#define CARD_PAGE_INIT 4
|
||||||
|
#define CARD_PAGE_INIT_TIME 5
|
||||||
|
#define CARD_PAGE_LAST_RECORD_INFO 6
|
||||||
|
#define CARD_PAGE_INFO1 6
|
||||||
|
#define CARD_PAGE_INFO2 7
|
||||||
|
#define CARD_PAGE_START 8
|
||||||
|
|
||||||
|
#define CARD_PAGE_PASS 5
|
||||||
|
#define CARD_PAGE_DATE 6
|
||||||
|
#define CARD_PAGE_TIME 7
|
||||||
|
#define CARD_PAGE_STATION_NUM 6
|
||||||
|
#define CARD_PAGE_BACKUP_START 6
|
||||||
|
|
||||||
|
#define PAGE_CFG0_OFFSET 2
|
||||||
|
#define PAGE_CFG1_OFFSET 3
|
||||||
|
#define PAGE_PWD_OFFSET 4
|
||||||
|
#define PAGE_PACK_OFFSET 5
|
||||||
|
|
||||||
|
enum class CardType : byte {
|
||||||
|
UNKNOWN = 0,
|
||||||
|
ISO_14443_4 = 1,
|
||||||
|
ISO_18092 = 2,
|
||||||
|
MIFARE_MINI = 3,
|
||||||
|
MIFARE_1K = 4,
|
||||||
|
MIFARE_4K = 5,
|
||||||
|
MIFARE_UL = 6,
|
||||||
|
MIFARE_PLUS = 7,
|
||||||
|
TNP3XXX = 8,
|
||||||
|
NTAG213 = 9,
|
||||||
|
NTAG215 = 10,
|
||||||
|
NTAG216 = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
byte pass[4];
|
||||||
|
byte pack[2];
|
||||||
|
} NtagAuthPassword;
|
||||||
|
|
||||||
|
class Rfid {
|
||||||
|
public:
|
||||||
|
void init(uint8_t ssPin, uint8_t rstPin, uint8_t newAntennaGain = DEFAULT_ANTENNA_GAIN);
|
||||||
|
|
||||||
|
void clearLastCardUid();
|
||||||
|
|
||||||
|
void setAntennaGain(uint8_t newAntennaGain);
|
||||||
|
void setAuthPassword(uint8_t *password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begins to work with RFID module
|
||||||
|
* Turn on RC522, detect a card and return the card type if a new one has presented else return 0 if the same card has presented or 0xFF if no any card
|
||||||
|
*/
|
||||||
|
void begin(uint8_t newAntennaGain = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops to work with RFID module
|
||||||
|
*/
|
||||||
|
void end();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if any card has been detected by RFID module
|
||||||
|
*/
|
||||||
|
bool isCardDetected();
|
||||||
|
|
||||||
|
bool isNewCardDetected();
|
||||||
|
|
||||||
|
bool cardWrite(uint8_t startPageAdr, const byte *data, uint16_t size);
|
||||||
|
|
||||||
|
bool cardErase(uint8_t beginPageAddr, uint8_t endPageAddr);
|
||||||
|
|
||||||
|
bool cardPageErase(uint8_t pageAddr);
|
||||||
|
|
||||||
|
bool cardErase4Pages(uint8_t pageAddr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads data from a card page. Buffer size should be 4 bytes!
|
||||||
|
*/
|
||||||
|
bool cardPageRead(uint8_t pageAdr, byte *data, uint8_t size = 4, bool ignoreAuthError = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes data to a card page. Buffer size should be 4 bytes!
|
||||||
|
*/
|
||||||
|
bool cardPageWrite(uint8_t pageAdr, const byte *data, uint8_t size = 4, bool ignoreAuthError = true);
|
||||||
|
|
||||||
|
bool cardPageWrite(uint8_t pageAdr, uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns max page address of the presented card
|
||||||
|
*/
|
||||||
|
uint8_t getCardMaxPage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns type of the card
|
||||||
|
*/
|
||||||
|
CardType getCardType();
|
||||||
|
|
||||||
|
bool cardEnableDisableAuthentication(bool writeProtection, bool readProtection = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// data buffer size should be greater 18 bytes
|
||||||
|
bool mifareCardPageRead(uint8_t pageAdr, byte *data, byte *size);
|
||||||
|
// data buffer size should be greater 16 bytes
|
||||||
|
bool mifareCardPageWrite(uint8_t pageAdr, byte *data, byte size);
|
||||||
|
// data buffer size should be greater 18 bytes
|
||||||
|
bool ntagCard4PagesRead(uint8_t pageAdr, byte *data, byte *size, bool ignoreAuthError = true);
|
||||||
|
bool ntagTryAuth(bool ignoreAuthError);
|
||||||
|
bool ntagAuth(NtagAuthPassword *password);
|
||||||
|
bool ntagSetPassword(NtagAuthPassword *password, bool readAndWrite, uint8_t negAuthAttemptsLim, uint8_t startPage);
|
||||||
|
bool ntagDisableAuthentication();
|
||||||
|
// data buffer size should be greater 4 bytes
|
||||||
|
bool ntagCardPageWrite(uint8_t pageAdr, byte *data, byte size, bool ignoreAuthError = true);
|
||||||
|
|
||||||
|
MFRC522 mfrc522;
|
||||||
|
NtagAuthPassword authPwd;
|
||||||
|
MFRC522::Uid lastCardUid;
|
||||||
|
uint8_t rfidSsPin = 0;
|
||||||
|
uint8_t rfidRstPin = 0;
|
||||||
|
uint8_t antennaGain = 0;
|
||||||
|
CardType cardType = CardType::UNKNOWN;
|
||||||
|
bool authenticated = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPORTIDUINO_RFID_H
|
||||||
|
|
||||||
|
|
@ -0,0 +1,259 @@
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <Adafruit_SleepyDog.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "sportiduino.h"
|
||||||
|
|
||||||
|
#define SERIAL_DATA_MAX_SIZE 28
|
||||||
|
#define SERIAL_TIMEOUT 10
|
||||||
|
|
||||||
|
void majEepromWrite(uint16_t adr, uint8_t val) {
|
||||||
|
uint8_t oldVal = majEepromRead(adr);
|
||||||
|
if(val != oldVal) {
|
||||||
|
for(uint16_t i = 0; i < 3; i++) {
|
||||||
|
EEPROM.write(adr + i, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t majEepromRead(uint16_t adr) {
|
||||||
|
uint8_t val1 = EEPROM.read(adr);
|
||||||
|
uint8_t val2 = EEPROM.read(adr + 1);
|
||||||
|
uint8_t val3 = EEPROM.read(adr + 2);
|
||||||
|
|
||||||
|
if(val1 == val2 || val1 == val3) {
|
||||||
|
return val1;
|
||||||
|
} else if(val2 == val3) {
|
||||||
|
return val2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void beep_w(const uint8_t ledPin, const uint8_t buzPin, uint16_t freq, uint16_t ms, uint8_t n, uint16_t pause) {
|
||||||
|
if (pause == 0) {
|
||||||
|
pause = (ms > 200) ? 200 : ms;
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < n; i++) {
|
||||||
|
Watchdog.reset();
|
||||||
|
|
||||||
|
digitalWrite(ledPin, HIGH);
|
||||||
|
#if !defined(SILENT_BEEP)
|
||||||
|
if(freq > 0) {
|
||||||
|
tone(buzPin, freq, ms);
|
||||||
|
} else {
|
||||||
|
digitalWrite(buzPin, HIGH);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
delay(ms);
|
||||||
|
Watchdog.reset();
|
||||||
|
|
||||||
|
digitalWrite(ledPin, LOW);
|
||||||
|
digitalWrite(buzPin, LOW);
|
||||||
|
|
||||||
|
if(i < n - 1) {
|
||||||
|
delay(pause);
|
||||||
|
Watchdog.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findNewPage(Rfid *rfid, uint8_t *newPage, uint8_t *lastNum) {
|
||||||
|
DEBUG_PRINTLN(F("findNewPage"));
|
||||||
|
uint8_t startPage = CARD_PAGE_START;
|
||||||
|
uint8_t endPage = rfid->getCardMaxPage() + 1; // page after last page
|
||||||
|
uint8_t page = startPage;
|
||||||
|
byte pageData[4] = {0,0,0,0};
|
||||||
|
byte num = 0;
|
||||||
|
|
||||||
|
*newPage = 0;
|
||||||
|
*lastNum = 0;
|
||||||
|
|
||||||
|
while(startPage < endPage) {
|
||||||
|
page = (startPage + endPage)/2;
|
||||||
|
DEBUG_PRINT(F("page: "));
|
||||||
|
DEBUG_PRINTLN(page);
|
||||||
|
|
||||||
|
if(!rfid->cardPageRead(page, pageData)) {
|
||||||
|
DEBUG_PRINTLN(F("page read failed"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = pageData[0];
|
||||||
|
|
||||||
|
if(num == 0) {
|
||||||
|
endPage = page;
|
||||||
|
} else {
|
||||||
|
startPage = (startPage != page)? page : page + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num > 0) {
|
||||||
|
++page;
|
||||||
|
}
|
||||||
|
DEBUG_PRINT(F("new page: "));
|
||||||
|
DEBUG_PRINT(page);
|
||||||
|
DEBUG_PRINT(F(", num: "));
|
||||||
|
DEBUG_PRINTLN(num);
|
||||||
|
|
||||||
|
*newPage = page;
|
||||||
|
*lastNum = num;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pageIsEmpty(const byte *pageData) {
|
||||||
|
return (pageData[0] == 0 && pageData[1] == 0 && pageData[2] == 0 && pageData[3] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uint32ToByteArray(uint32_t value, byte *byteArray) {
|
||||||
|
for(uint8_t i = 0; i < 4; ++i) {
|
||||||
|
byteArray[3 - i] = value & 0xff;
|
||||||
|
value >>= 8;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t byteArrayToUint32(const byte *byteArray) {
|
||||||
|
uint32_t value = 0;
|
||||||
|
for(uint8_t i = 0; i < 4; ++i) {
|
||||||
|
value <<= 8;
|
||||||
|
value |= byteArray[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readConfig(uint8_t *config, uint8_t configSize, uint16_t eepromConfigAddress) {
|
||||||
|
uint16_t eepromAdr = eepromConfigAddress;
|
||||||
|
for(uint8_t i = 0; i < configSize; ++i) {
|
||||||
|
*((uint8_t*)config + i) = majEepromRead(eepromAdr);
|
||||||
|
eepromAdr += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeConfig(uint8_t *newConfig, uint8_t configSize, uint16_t eepromConfigAddress) {
|
||||||
|
uint16_t eepromAdr = eepromConfigAddress;
|
||||||
|
for(uint8_t i = 0; i < configSize; ++i) {
|
||||||
|
majEepromWrite(eepromAdr, *((uint8_t*)newConfig + i));
|
||||||
|
eepromAdr += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SerialProtocol::init(uint8_t _startByte, uint32_t _baudrate) {
|
||||||
|
startByte = _startByte;
|
||||||
|
baudrate = _baudrate;
|
||||||
|
Serial.setTimeout(SERIAL_TIMEOUT);
|
||||||
|
begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::begin() {
|
||||||
|
Serial.begin(baudrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::end() {
|
||||||
|
Serial.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::start(uint8_t code) {
|
||||||
|
serialDataPos = 3;
|
||||||
|
serialPacketCount = 0;
|
||||||
|
memset(serialBuffer, 0, SERIAL_PACKET_SIZE);
|
||||||
|
|
||||||
|
serialBuffer[0] = startByte;
|
||||||
|
serialBuffer[1] = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::send() {
|
||||||
|
uint8_t dataSize = serialDataPos - 3; // minus start, resp code, datalen
|
||||||
|
|
||||||
|
if(dataSize > SERIAL_DATA_MAX_SIZE) {
|
||||||
|
dataSize = serialPacketCount + 0x1E;
|
||||||
|
serialDataPos = SERIAL_PACKET_SIZE - 1;
|
||||||
|
serialPacketCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialBuffer[2] = dataSize;
|
||||||
|
serialBuffer[serialDataPos] = checkSum(serialBuffer, dataSize);
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i <= serialDataPos; i++) {
|
||||||
|
Serial.write(serialBuffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
serialDataPos = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::add(uint8_t dataByte) {
|
||||||
|
if(serialDataPos >= SERIAL_PACKET_SIZE - 1) {
|
||||||
|
serialDataPos++; // to indicate that we going to send packet count
|
||||||
|
send();
|
||||||
|
}
|
||||||
|
|
||||||
|
serialBuffer[serialDataPos] = dataByte;
|
||||||
|
serialDataPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::addUint32(uint32_t data) {
|
||||||
|
uint8_t b[4];
|
||||||
|
uint32ToByteArray(data, b);
|
||||||
|
add(b, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::add(const uint8_t *data, uint8_t size) {
|
||||||
|
for(uint8_t i = 0; i < size; ++i) {
|
||||||
|
add(data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t SerialProtocol::checkSum(uint8_t *buffer, uint8_t dataSize) {
|
||||||
|
// if at dataSize position we have packet count
|
||||||
|
if(dataSize > SERIAL_DATA_MAX_SIZE) {
|
||||||
|
dataSize = SERIAL_DATA_MAX_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t len = dataSize + 2; // + cmd/resp byte + length byte
|
||||||
|
uint8_t sum = 0;
|
||||||
|
for (uint8_t i = 1; i <= len; ++i) {
|
||||||
|
sum += buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *SerialProtocol::read(bool *error, uint8_t *code, uint8_t *dataSize) {
|
||||||
|
*error = false;
|
||||||
|
memset(serialBuffer, 0, SERIAL_PACKET_SIZE);
|
||||||
|
if(Serial.available() > 0) {
|
||||||
|
uint8_t b = Serial.peek();
|
||||||
|
if(b == startByte) {
|
||||||
|
Serial.readBytes(serialBuffer, SERIAL_PACKET_SIZE);
|
||||||
|
|
||||||
|
*dataSize = serialBuffer[2];
|
||||||
|
|
||||||
|
// if at dataSize position we have packet count
|
||||||
|
if(*dataSize > SERIAL_DATA_MAX_SIZE) {
|
||||||
|
*dataSize = SERIAL_DATA_MAX_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(serialBuffer[*dataSize + 3] != checkSum(serialBuffer, *dataSize)) {
|
||||||
|
*error = true;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
*code = serialBuffer[1];
|
||||||
|
return &serialBuffer[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialProtocol::dropByte() {
|
||||||
|
if(Serial.available() > 0) {
|
||||||
|
// Drop byte
|
||||||
|
Serial.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
#ifndef SPORTIDUINO_H
|
||||||
|
#define SPORTIDUINO_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "rfid.h"
|
||||||
|
|
||||||
|
enum StationNum {
|
||||||
|
START_STATION_NUM = 240,
|
||||||
|
FINISH_STATION_NUM = 245,
|
||||||
|
CHECK_STATION_NUM = 248,
|
||||||
|
CLEAR_STATION_NUM = 249
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MasterCard {
|
||||||
|
MASTER_CARD_AUTH_PASSWORD = 248,
|
||||||
|
MASTER_CARD_STATE = 249,
|
||||||
|
MASTER_CARD_SET_TIME = 250,
|
||||||
|
MASTER_CARD_SET_NUMBER = 251,
|
||||||
|
MASTER_CARD_SLEEP = 252,
|
||||||
|
MASTER_CARD_READ_BACKUP = 253,
|
||||||
|
MASTER_CARD_CONFIG = 254,
|
||||||
|
MASTER_CARD_PASSWORD = 255
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MASTER_CARD_SIGN 0xff
|
||||||
|
#define FAST_PUNCH_SIGN 0xaa // page6[3]
|
||||||
|
|
||||||
|
#define SERIAL_PACKET_SIZE 32
|
||||||
|
|
||||||
|
#define MAX_FW_MINOR_VERS 239
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes data with a majority backup in three cells of EEPROM
|
||||||
|
*/
|
||||||
|
void majEepromWrite (uint16_t adr, uint8_t val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads data with a majority backup from EEPROM
|
||||||
|
*/
|
||||||
|
uint8_t majEepromRead(uint16_t adr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn on led and buzzer for given ms n times
|
||||||
|
* @param freq the frequency of your buzzer if you have solded the buzzer without a generator else 0
|
||||||
|
*/
|
||||||
|
void beep_w(const uint8_t ledPin, const uint8_t buzPin, uint16_t freq, uint16_t ms, uint8_t n, uint16_t pause = 0);
|
||||||
|
|
||||||
|
bool findNewPage(Rfid *rfid, uint8_t *newPage, uint8_t *lastNum);
|
||||||
|
bool pageIsEmpty(const byte *pageData);
|
||||||
|
|
||||||
|
bool uint32ToByteArray(uint32_t value, byte *byteArray);
|
||||||
|
uint32_t byteArrayToUint32(const byte *byteArray);
|
||||||
|
bool pageIsEmpty(const byte *pageData);
|
||||||
|
|
||||||
|
bool readConfig(uint8_t *config, uint8_t configSize, uint16_t eepromConfigAddress);
|
||||||
|
bool writeConfig(uint8_t *newConfig, uint8_t configSize, uint16_t eepromConfigAddress);
|
||||||
|
|
||||||
|
|
||||||
|
class SerialProtocol {
|
||||||
|
public:
|
||||||
|
void init(uint8_t _startByte, uint32_t baudrate = 9600);
|
||||||
|
void begin();
|
||||||
|
void end();
|
||||||
|
void start(uint8_t code);
|
||||||
|
void add(uint8_t dataByte);
|
||||||
|
void addUint32(uint32_t data);
|
||||||
|
void add(const uint8_t *data, uint8_t size);
|
||||||
|
void send();
|
||||||
|
uint8_t *read(bool *error, uint8_t *code, uint8_t *dataSize);
|
||||||
|
void dropByte();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t checkSum(uint8_t *buffer, uint8_t dataSize);
|
||||||
|
|
||||||
|
uint8_t startByte = 0;
|
||||||
|
uint8_t serialBuffer[SERIAL_PACKET_SIZE];
|
||||||
|
uint8_t serialDataPos = 3;
|
||||||
|
uint8_t serialPacketCount = 0;
|
||||||
|
uint32_t baudrate = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue