From dc93988568312bbf8f6c475f46baed414b6ee71c Mon Sep 17 00:00:00 2001 From: Ben Liao Date: Tue, 1 Aug 2023 11:39:54 -0700 Subject: [PATCH 1/3] [MISC] Miscellaneous cleanup changes - Forced the Makefile_defs file to be highlighted as Makefile - Changed tabs to spaces in scripts/test.sh - Fixed formatting error in scripts/format.sh - Removed mode ESTOP from protos, updated protos submodule (#229) --- .gitattributes | 6 +- net_handler/net_handler_message.c | 4 - net_handler/protos | 2 +- scripts/format.sh | 2 +- scripts/test.sh | 120 +++++++++++++++--------------- 5 files changed, 66 insertions(+), 68 deletions(-) diff --git a/.gitattributes b/.gitattributes index 8e0ff3c8..8063783f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ -# in language profile, ignore third-party libraries and protobuf-generated code +# in language profile, ignore third-party libraries used in lowcar lowcar/lib/* linguist-vendored -executor/studentapi.c linguist-generated + +# force the Makefile_defs file to be classified as Makefile and be syntax highlighted as Makefile +Makefile_defs linguist-language=Makefile \ No newline at end of file diff --git a/net_handler/net_handler_message.c b/net_handler/net_handler_message.c index b1f91bac..46fa5085 100644 --- a/net_handler/net_handler_message.c +++ b/net_handler/net_handler_message.c @@ -302,10 +302,6 @@ static int process_run_mode_msg(uint8_t* buf, uint16_t len_pb, robot_desc_field_ log_printf(DEBUG, "entering TELEOP mode"); robot_desc_write(RUN_MODE, TELEOP); break; - case (MODE__ESTOP): - log_printf(DEBUG, "ESTOP RECEIVED! entering IDLE mode"); - robot_desc_write(RUN_MODE, IDLE); - break; default: log_printf(ERROR, "recv_new_msg: requested robot to enter invalid robot mode %s", run_mode_msg->mode); break; diff --git a/net_handler/protos b/net_handler/protos index 9e52c0e5..3525db12 160000 --- a/net_handler/protos +++ b/net_handler/protos @@ -1 +1 @@ -Subproject commit 9e52c0e5cd7ff7b83811145dfc93dbd5ea168f84 +Subproject commit 3525db120e8338cdc13dd021787897d42dea6525 diff --git a/scripts/format.sh b/scripts/format.sh index 7569460a..c16b49a0 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -9,7 +9,7 @@ function clean_up { rm -f diff_output.txt } -# make sure to remove output.txt if Ctrl-C is pressed +# make sure to remove clang_suggestions.txt and diff_output.txt if Ctrl-C is pressed trap 'clean_up' INT # get a list of all runtime files that we could want to check diff --git a/scripts/test.sh b/scripts/test.sh index 4045c692..4bd40b6e 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -2,71 +2,71 @@ # normal clean up function that restores logger config function clean_up { - rm ../logger/logger.config - mv ../logger/logger.config.orig ../logger/logger.config + rm ../logger/logger.config + mv ../logger/logger.config.orig ../logger/logger.config } # sigint handler function sigint_handler { - # if logger/logger.config.orig exists, we need to restore it - if [[ -f ../logger/logger.config.orig ]]; then - clean_up - fi - exit 1 + # if logger/logger.config.orig exists, we need to restore it + if [[ -f ../logger/logger.config.orig ]]; then + clean_up + fi + exit 1 } function run_tests { - local test_exe="" # name of executable for test - local failed=0 # whether tests failed - local failing_tests="" - - echo "Running tests: $@" - - for test in $@; do - # exit if we didn't find the test - if [[ $ALL_TESTS != *"$test"* ]]; then - printf "Could not find specified test $test\n" - clean_up - exit 1 - fi - - # make executable - printf "\nMaking $test\n" - make $test - - # if test failed to compile, set failed to 1 - if [[ $? != 0 ]]; then - failing_tests="$failing_tests $test" # add this test to list of failing tests - failed=1 - continue - fi - - # run test - printf "Running $test...\n" - - if [[ -f bin/integration/$test ]]; then - ./bin/integration/$test - elif [[ -f bin/performance/$test ]]; then - ./bin/performance/$test - else - ./bin/$test - fi - - # if that test failed, set failed to 1 - if [[ $? != 0 ]]; then - failing_tests="$failing_tests $test" # add this test to list of failing tests - failed=1 - fi - done - - clean_up - - # return status - if [[ $failed == "1" ]]; then - printf "\n\n################################################# TESTS FAILED! ##########################################\n\n" - printf "Failing tests: $failing_tests\n\n\n" - exit 1 - fi + local test_exe="" # name of executable for test + local failed=0 # whether tests failed + local failing_tests="" + + echo "Running tests: $@" + + for test in $@; do + # exit if we didn't find the test + if [[ $ALL_TESTS != *"$test"* ]]; then + printf "Could not find specified test $test\n" + clean_up + exit 1 + fi + + # make executable + printf "\nMaking $test\n" + make $test + + # if test failed to compile, set failed to 1 + if [[ $? != 0 ]]; then + failing_tests="$failing_tests $test" # add this test to list of failing tests + failed=1 + continue + fi + + # run test + printf "Running $test...\n" + + if [[ -f bin/integration/$test ]]; then + ./bin/integration/$test + elif [[ -f bin/performance/$test ]]; then + ./bin/performance/$test + else + ./bin/$test + fi + + # if that test failed, set failed to 1 + if [[ $? != 0 ]]; then + failing_tests="$failing_tests $test" # add this test to list of failing tests + failed=1 + fi + done + + clean_up + + # return status + if [[ $failed == "1" ]]; then + printf "\n\n################################################# TESTS FAILED! ##########################################\n\n" + printf "Failing tests: $failing_tests\n\n\n" + exit 1 + fi } ################################################ BEGIN SCRIPT ########################################## @@ -88,13 +88,13 @@ ALL_TESTS="$INT_TESTS $PERF_TESTS" # if no first argument specified, run all the tests if [[ $1 == "" || $1 == "all" ]]; then - input=$ALL_TESTS + input=$ALL_TESTS elif [[ $1 == "int" ]]; then input=$INT_TESTS elif [[ $1 == "perf" ]]; then input=$PERF_TESTS; else - input=$1 + input=$1 fi printf "\n\n################################################ RUNNING TEST SUITE ##########################################\n\n" From d6a76ef34148ce2ce1fc9cb99985eaf25d22c47c Mon Sep 17 00:00:00 2001 From: Ben Liao Date: Tue, 1 Aug 2023 11:53:57 -0700 Subject: [PATCH 2/3] [LOWCAR] Deleted lowcar unused files and old devices --- lowcar/devices/PolarBear/LED.cpp | 58 - lowcar/devices/PolarBear/LED.h | 21 - lowcar/devices/PolarBear/PolarBear.cpp | 102 - lowcar/devices/PolarBear/PolarBear.h | 52 - lowcar/devices/RFID/RFID.cpp | 58 - lowcar/devices/RFID/RFID.h | 39 - lowcar/lib/MFRC522/MFRC522.cpp | 1863 ----------------- lowcar/lib/MFRC522/MFRC522.h | 418 ---- lowcar/lib/SPI/SPI.cpp | 201 -- lowcar/lib/SPI/SPI.h | 324 --- .../BarometricPressureSensor.ino | 143 -- .../BarometricPressureSensor.ino | 143 -- .../DigitalPotControl/DigitalPotControl.ino | 71 - lowcar/lib/SPI/keywords.txt | 36 - lowcar/lib/SevenSeg/SevenSeg.cpp | 1391 ------------ lowcar/lib/SevenSeg/SevenSeg.h | 159 -- lowcar/lib/SevenSeg/keywords.txt | 61 - 17 files changed, 5140 deletions(-) delete mode 100644 lowcar/devices/PolarBear/LED.cpp delete mode 100644 lowcar/devices/PolarBear/LED.h delete mode 100644 lowcar/devices/PolarBear/PolarBear.cpp delete mode 100644 lowcar/devices/PolarBear/PolarBear.h delete mode 100644 lowcar/devices/RFID/RFID.cpp delete mode 100644 lowcar/devices/RFID/RFID.h delete mode 100644 lowcar/lib/MFRC522/MFRC522.cpp delete mode 100644 lowcar/lib/MFRC522/MFRC522.h delete mode 100644 lowcar/lib/SPI/SPI.cpp delete mode 100644 lowcar/lib/SPI/SPI.h delete mode 100644 lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino delete mode 100644 lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor/BarometricPressureSensor.ino delete mode 100644 lowcar/lib/SPI/examples/DigitalPotControl/DigitalPotControl.ino delete mode 100644 lowcar/lib/SPI/keywords.txt delete mode 100644 lowcar/lib/SevenSeg/SevenSeg.cpp delete mode 100644 lowcar/lib/SevenSeg/SevenSeg.h delete mode 100644 lowcar/lib/SevenSeg/keywords.txt diff --git a/lowcar/devices/PolarBear/LED.cpp b/lowcar/devices/PolarBear/LED.cpp deleted file mode 100644 index 114b83f4..00000000 --- a/lowcar/devices/PolarBear/LED.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "LED.h" - -// pins that control the red, yellow, and green LEDs -#define LED_RED 2 -#define LED_YELLOW 3 -#define LED_GREEN 4 - -// decides when the red LED is on -static void ctrl_RED(float duty_cycle, float deadband) { - // red is on when motor is stopped - if ((duty_cycle > deadband * -1.0) && (duty_cycle < deadband)) { - digitalWrite(LED_RED, HIGH); - } else { - digitalWrite(LED_RED, LOW); - } -} - -// decides when the yellow LED is on -static void ctrl_YELLOW(float duty_cycle, float deadband) { - // yellow is on when motor moving backwards - if (duty_cycle < (deadband * -1.0)) { - digitalWrite(LED_YELLOW, HIGH); - } else { - digitalWrite(LED_YELLOW, LOW); - } -} - -// decides when the green LED is on -static void ctrl_GREEN(float duty_cycle, float deadband) { - // green is on when motor moving forwards - if (duty_cycle > deadband) { - digitalWrite(LED_GREEN, HIGH); - } else { - digitalWrite(LED_GREEN, LOW); - } -} - -void ctrl_LEDs(float duty_cycle, float deadband) { - ctrl_RED(duty_cycle, deadband); - ctrl_YELLOW(duty_cycle, deadband); - ctrl_GREEN(duty_cycle, deadband); -} - -void setup_LEDs() { - pinMode(LED_GREEN, OUTPUT); - pinMode(LED_RED, OUTPUT); - pinMode(LED_YELLOW, OUTPUT); - - digitalWrite(LED_GREEN, HIGH); - digitalWrite(LED_RED, HIGH); - digitalWrite(LED_YELLOW, HIGH); - - delay(1000); - - digitalWrite(LED_GREEN, LOW); - digitalWrite(LED_RED, LOW); - digitalWrite(LED_YELLOW, LOW); -} diff --git a/lowcar/devices/PolarBear/LED.h b/lowcar/devices/PolarBear/LED.h deleted file mode 100644 index e484cf97..00000000 --- a/lowcar/devices/PolarBear/LED.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef LED_H -#define LED_H - -#include "Arduino.h" -#include "defs.h" - -/** - * Updates all LEDs based on current duty_cycle - * Arguments: - * duty_cycle: The motor controller duty_cycle - * deadband: The motor controller deadband - */ -void ctrl_LEDs(float duty_cycle, float deadband); - -/** - * Sets the output modes of the three LEDs to OUTPUT - * Blinks them to make sure they work - */ -void setup_LEDs(); - -#endif /* LED_H */ diff --git a/lowcar/devices/PolarBear/PolarBear.cpp b/lowcar/devices/PolarBear/PolarBear.cpp deleted file mode 100644 index 7a4eaa18..00000000 --- a/lowcar/devices/PolarBear/PolarBear.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "PolarBear.h" - -// enumerate the parameters -typedef enum { - DUTY_CYCLE = 0, - MOTOR_CURRENT = 1, - DEADBAND = 2 -} param; - -PolarBear::PolarBear() : Device(DeviceType::POLAR_BEAR, 2) { - this->duty_cycle = 0.0; - this->deadband = 0.05; - - this->dpwm_dt = 255 / 200000; -} - -size_t PolarBear::device_read(uint8_t param, uint8_t* data_buf) { - float* float_buf = (float*) data_buf; - - switch (param) { - case DUTY_CYCLE: - float_buf[0] = this->duty_cycle; - return sizeof(this->duty_cycle); - case MOTOR_CURRENT: - float_buf[0] = (analogRead(FEEDBACK) / 0.0024); - return sizeof(float); - case DEADBAND: - float_buf[0] = this->deadband; - return sizeof(this->deadband); - default: - return 0; - } - return 0; -} - -size_t PolarBear::device_write(uint8_t param, uint8_t* data_buf) { - float* float_buf = (float*) data_buf; - switch (param) { - case DUTY_CYCLE: - // Change duty_cycle only if abs(input) is greater than deadband - if (!(float_buf[0] >= -1.0 * this->deadband && float_buf[0] <= this->deadband)) { - this->duty_cycle = float_buf[0]; - } else { - this->duty_cycle = 0.0; - } - return sizeof(this->duty_cycle); - case MOTOR_CURRENT: - break; - case DEADBAND: - this->deadband = float_buf[0]; - return sizeof(this->deadband); - default: - return 0; - } - return 0; -} - -void PolarBear::device_enable() { - // Start LEDs - setup_LEDs(); - - pinMode(FEEDBACK, INPUT); - pinMode(PWM1, OUTPUT); - pinMode(PWM2, OUTPUT); -} - -void PolarBear::device_disable() { - // Stop motors - this->device_write(DUTY_CYCLE, 0); -} - -void PolarBear::device_actions() { - ctrl_LEDs(this->duty_cycle, this->deadband); - drive(this->duty_cycle); -} - -void PolarBear::drive(float target) { - float direction = (target > 0.0) ? 1.0 : -1.0; // if target == 0.0, direction will be -1 ("backwards") - /* If moving forwards, set pwm1 to 255 (stop), then move pwm2 down - * If moving backwards, set pwm2 to 255, then move pwm1 down - * Make sure that at least one of the pins is set to 255 at all times. - */ - int currpwm1 = 255; - int currpwm2 = 255; - - // Determine how much to move the pins down from 255 - // Sanity check: If |target| == 1, move max speed --> pwm_difference == 255 - // If |target| == 0, stop moving --> pwm_difference == 0 - int pwm_difference = (int) (target * direction * 255.0); // A number between 0 and 255 inclusive (255 is stop; 0 is max speed); - - // We don't catch direction 0.0 because it will be either 1.0 or -1.0. - // If stopped (target == 0.0) then 255 will be written to both drive pins - if (direction > 0.0) { // Moving forwards - currpwm1 -= pwm_difference; - } else if (direction < 0.0) { // Moving backwards - currpwm2 -= pwm_difference; - } - - analogWrite(PWM1, currpwm1); - analogWrite(PWM2, currpwm2); - delayMicroseconds(1 / this->dpwm_dt); // About 784 -} diff --git a/lowcar/devices/PolarBear/PolarBear.h b/lowcar/devices/PolarBear/PolarBear.h deleted file mode 100644 index eec31aab..00000000 --- a/lowcar/devices/PolarBear/PolarBear.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef POLARBEAR_H -#define POLARBEAR_H - -#include "Device.h" -#include "LED.h" -#include "PID.h" -#include "defs.h" - -#define FEEDBACK A3 // pin for getting motor current -#define PWM1 6 // pwm pin 1 -#define PWM2 9 // pwm pin 2 - -class PolarBear : public Device { - public: - PolarBear(); - virtual size_t device_read(uint8_t param, uint8_t* data_buf); - virtual size_t device_write(uint8_t param, uint8_t* data_buf); - - /** - * Setup LEDs, and set FEEDBACk to input and PWM1 & PWM2 to output - */ - virtual void device_enable(); - - /** - * Stops the motors - */ - virtual void device_disable(); - - /** - * Updates LEDs and moves the motor according to this->DUTY_CYCLE - */ - virtual void device_actions(); - - private: - // The "velocity" to move the motor - // (range -1, 1 inclusive, where 1 is max speed forward, -1 is max speed backwards) - // 0 is stop - float duty_cycle; - // The minimum threshold duty_cycle for it to be actually written to in device_write() - float deadband; - float dpwm_dt; - - /** - * Moves the motor given a target "velocity" - * Negative indicates moving backwards; Positive indicates moving forwards. - * Arguments: - * target: value between -1 and 1 inclusive indicating how much to move the motor - */ - void drive(float target); -}; - -#endif diff --git a/lowcar/devices/RFID/RFID.cpp b/lowcar/devices/RFID/RFID.cpp deleted file mode 100644 index 03bd7525..00000000 --- a/lowcar/devices/RFID/RFID.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "RFID.h" - -const int RFID::RST_PIN = 9; -const int RFID::SS_PIN = 10; - -// default constructor simply specifies DeviceID and year to generic constructor and initializes variables -// initializes the msfrc22 object in the initializer list -RFID::RFID() : Device(DeviceType::RFID, 1), tag_detector(RFID::SS_PIN, RFID::RST_PIN) { - this->id_upper = 0; - this->id_lower = 0; - this->tag_detect = 0; - this->delay = FALSE; -} - -size_t RFID::device_read(uint8_t param, uint8_t* data_buf) { - switch ((RFID_Param) param) { // switch the incoming parameter (cast to RFID_Param) - case RFID_Param::ID: - ((int32_t*) data_buf)[0] = this->id; - return sizeof(this->id); - - case RFID_Param::TAG_DETECT: - data_buf[0] = this->tag_detect; - return sizeof(this->tag_detect); - - default: - return 0; - } -} - -void RFID::device_enable() { - SPI.begin(); // begin SPI (what's this?) - this->tag_detector->PCD_Init(); // initialize the RFID object -} - -void RFID::device_actions() { - /* If we either don't sense a card or can't read the UID, we invalidate the data - * The sensor is too slow, so we have to delay the read by one loop - * The delay makes sure that id and tag_detect don't update for - * one cycle of the loop after finding a tag - */ - if (!this->tag_detector->PICC_IsNewCardPresent() || !this->tag_detector->PICC_ReadCardSerial()) { - if (this->delay) { - this->id = 0; // clear the id to invalidate it - this->tag_detect = 0; // no tag detected - } - this->delay = TRUE; - return; // after resetting all our values, we return - } - - // Otherwise, if there is a card that we can read the UID from, we grab the data - // and set tag_detect to 1 to signal that we have a new tag UID - uint32_t uid = (uint32_t) (this->tag_detector->uid.uidByte[2]) << 16 | - (uint32_t) (this->tag_detector->uid.uidByte[1]) << 8 | - (uint32_t) (this->tag_detector->uid.uidByte[0]); - this->id = uid; - this->tag_detect = 1; - this->delay = FALSE; // reset the delay -} diff --git a/lowcar/devices/RFID/RFID.h b/lowcar/devices/RFID/RFID.h deleted file mode 100644 index bd178def..00000000 --- a/lowcar/devices/RFID/RFID.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef RFID_H -#define RFID_H - -#include -#include -#include "Device.h" -#include "defs.h" - -// give params more readable names -enum class RFID_Param : uint8_t { - ID = 0, - TAG_DETECT = 1 // is 1 if we have a tag; 0 otherwise -}; - -class RFID : public Device { - public: - // constructs an RFID; simply calls generic Device constructor with device type and year - // instatiates the mfrc522 private variable, and initializes the other private variables - RFID(); - - // overridden functions from Device class; see descriptions in Device.h - virtual size_t device_read(uint8_t param, uint8_t* data_buf); - virtual void device_enable(); - virtual void device_actions(); - - private: - // Pin definitions - const static int RST_PIN; - const static int SS_PIN; - - MFRC522* tag_detector; // object used to operate the actual RFID tag detector - uint8_t delay; // for delaying the reading of the device - - // Outward facing (read-only) params - uint32_t id; - uint8_t tag_detect; // tag_detect parameter -}; - -#endif diff --git a/lowcar/lib/MFRC522/MFRC522.cpp b/lowcar/lib/MFRC522/MFRC522.cpp deleted file mode 100644 index 273b215a..00000000 --- a/lowcar/lib/MFRC522/MFRC522.cpp +++ /dev/null @@ -1,1863 +0,0 @@ -/* -* MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. -* NOTE: Please also check the comments in MFRC522.h - they provide useful hints and background information. -* Released into the public domain. -*/ - -#include -#include "MFRC522.h" - -///////////////////////////////////////////////////////////////////////////////////// -// Functions for setting up the Arduino -///////////////////////////////////////////////////////////////////////////////////// -/** - * Constructor. - */ -MFRC522::MFRC522() { -} // End constructor - -/** - * Constructor. - * Prepares the output pins. - */ -MFRC522::MFRC522( byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) - ): MFRC522(SS, resetPowerDownPin) { // SS is defined in pins_arduino.h -} // End constructor - -/** - * Constructor. - * Prepares the output pins. - */ -MFRC522::MFRC522( 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) - ) { - _chipSelectPin = chipSelectPin; - _resetPowerDownPin = resetPowerDownPin; -} // End constructor - -///////////////////////////////////////////////////////////////////////////////////// -// Basic interface functions for communicating with the MFRC522 -///////////////////////////////////////////////////////////////////////////////////// - -/** - * Writes a byte to the specified register in the MFRC522 chip. - * The interface is described in the datasheet section 8.1.2. - */ -void MFRC522::PCD_WriteRegister( byte reg, ///< The register to write to. One of the PCD_Register enums. - byte value ///< The value to write. - ) { - SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus - digitalWrite(_chipSelectPin, LOW); // Select slave - SPI.transfer(reg & 0x7E); // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. - SPI.transfer(value); - digitalWrite(_chipSelectPin, HIGH); // Release slave again - SPI.endTransaction(); // Stop using the SPI bus -} // End PCD_WriteRegister() - -/** - * Writes a number of bytes to the specified register in the MFRC522 chip. - * The interface is described in the datasheet section 8.1.2. - */ -void MFRC522::PCD_WriteRegister( byte reg, ///< The register to write to. One of the PCD_Register enums. - byte count, ///< The number of bytes to write to the register - byte *values ///< The values to write. Byte array. - ) { - SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus - digitalWrite(_chipSelectPin, LOW); // Select slave - SPI.transfer(reg & 0x7E); // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. - for (byte index = 0; index < count; index++) { - SPI.transfer(values[index]); - } - digitalWrite(_chipSelectPin, HIGH); // Release slave again - SPI.endTransaction(); // Stop using the SPI bus -} // End PCD_WriteRegister() - -/** - * Reads a byte from the specified register in the MFRC522 chip. - * The interface is described in the datasheet section 8.1.2. - */ -byte MFRC522::PCD_ReadRegister( byte reg ///< The register to read from. One of the PCD_Register enums. - ) { - byte value; - SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus - digitalWrite(_chipSelectPin, LOW); // Select slave - SPI.transfer(0x80 | (reg & 0x7E)); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. - value = SPI.transfer(0); // Read the value back. Send 0 to stop reading. - digitalWrite(_chipSelectPin, HIGH); // Release slave again - SPI.endTransaction(); // Stop using the SPI bus - return value; -} // End PCD_ReadRegister() - -/** - * Reads a number of bytes from the specified register in the MFRC522 chip. - * The interface is described in the datasheet section 8.1.2. - */ -void MFRC522::PCD_ReadRegister( byte reg, ///< The register to read from. One of the PCD_Register enums. - byte count, ///< The number of bytes to read - byte *values, ///< Byte array to store the values in. - byte rxAlign ///< Only bit positions rxAlign..7 in values[0] are updated. - ) { - if (count == 0) { - return; - } - //Serial.print(F("Reading ")); Serial.print(count); Serial.println(F(" bytes from register.")); - byte address = 0x80 | (reg & 0x7E); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. - byte index = 0; // Index in values array. - SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus - digitalWrite(_chipSelectPin, LOW); // Select slave - count--; // One read is performed outside of the loop - SPI.transfer(address); // Tell MFRC522 which address we want to read - while (index < count) { - if (index == 0 && rxAlign) { // Only update bit positions rxAlign..7 in values[0] - // Create bit mask for bit positions rxAlign..7 - byte mask = 0; - for (byte i = rxAlign; i <= 7; i++) { - mask |= (1 << i); - } - // Read value and tell that we want to read the same address again. - byte value = SPI.transfer(address); - // Apply mask to both current value of values[0] and the new data in value. - values[0] = (values[index] & ~mask) | (value & mask); - } - else { // Normal case - values[index] = SPI.transfer(address); // Read value and tell that we want to read the same address again. - } - index++; - } - values[index] = SPI.transfer(0); // Read the final byte. Send 0 to stop reading. - digitalWrite(_chipSelectPin, HIGH); // Release slave again - SPI.endTransaction(); // Stop using the SPI bus -} // End PCD_ReadRegister() - -/** - * Sets the bits given in mask in register reg. - */ -void MFRC522::PCD_SetRegisterBitMask( byte reg, ///< The register to update. One of the PCD_Register enums. - byte mask ///< The bits to set. - ) { - byte tmp; - tmp = PCD_ReadRegister(reg); - PCD_WriteRegister(reg, tmp | mask); // set bit mask -} // End PCD_SetRegisterBitMask() - -/** - * Clears the bits given in mask from register reg. - */ -void MFRC522::PCD_ClearRegisterBitMask( byte reg, ///< The register to update. One of the PCD_Register enums. - byte mask ///< The bits to clear. - ) { - byte tmp; - tmp = PCD_ReadRegister(reg); - PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask -} // End PCD_ClearRegisterBitMask() - - -/** - * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. - byte length, ///< In: The number of bytes to transfer. - byte *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low byte first. - ) { - PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. - PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit - PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization - PCD_WriteRegister(FIFODataReg, length, data); // Write data to the FIFO - PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation - - // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73�s. - word i = 5000; - byte n; - while (1) { - n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved - if (n & 0x04) { // CRCIRq bit set - calculation done - break; - } - if (--i == 0) { // The emergency break. We will eventually terminate on this one after 89ms. Communication with the MFRC522 might be down. - return STATUS_TIMEOUT; - } - } - PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. - - // Transfer the result from the registers to the result buffer - result[0] = PCD_ReadRegister(CRCResultRegL); - result[1] = PCD_ReadRegister(CRCResultRegH); - return STATUS_OK; -} // End PCD_CalculateCRC() - - -///////////////////////////////////////////////////////////////////////////////////// -// Functions for manipulating the MFRC522 -///////////////////////////////////////////////////////////////////////////////////// - -/** - * Initializes the MFRC522 chip. - */ -void MFRC522::PCD_Init() { - // Set the chipSelectPin as digital output, do not select the slave yet - pinMode(_chipSelectPin, OUTPUT); - digitalWrite(_chipSelectPin, HIGH); - - // Set the resetPowerDownPin as digital output, do not reset or power down. - pinMode(_resetPowerDownPin, OUTPUT); - - if (digitalRead(_resetPowerDownPin) == LOW) { //The MFRC522 chip is in power down mode. - digitalWrite(_resetPowerDownPin, HIGH); // Exit power down mode. This triggers a hard reset. - // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74�s. Let us be generous: 50ms. - delay(50); - } - else { // Perform a soft reset - PCD_Reset(); - } - - // When communicating with a PICC we need a timeout if something goes wrong. - // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo]. - // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg. - PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds - PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25�s. - PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. - PCD_WriteRegister(TReloadRegL, 0xE8); - - PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting - PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4) - PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) -} // End PCD_Init() - -/** - * Initializes the MFRC522 chip. - */ -void MFRC522::PCD_Init( byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) - ) { - PCD_Init(SS, resetPowerDownPin); // SS is defined in pins_arduino.h -} // End PCD_Init() - -/** - * Initializes the MFRC522 chip. - */ -void MFRC522::PCD_Init( 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) - ) { - _chipSelectPin = chipSelectPin; - _resetPowerDownPin = resetPowerDownPin; - // Set the chipSelectPin as digital output, do not select the slave yet - PCD_Init(); -} // End PCD_Init() - -/** - * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. - */ -void MFRC522::PCD_Reset() { - PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command. - // The datasheet does not mention how long the SoftRest command takes to complete. - // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) - // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74�s. Let us be generous: 50ms. - delay(50); - // Wait for the PowerDown bit in CommandReg to be cleared - while (PCD_ReadRegister(CommandReg) & (1<<4)) { - // PCD still restarting - unlikely after waiting 50ms, but better safe than sorry. - } -} // End PCD_Reset() - -/** - * Turns the antenna on by enabling pins TX1 and TX2. - * After a reset these pins are disabled. - */ -void MFRC522::PCD_AntennaOn() { - byte value = PCD_ReadRegister(TxControlReg); - if ((value & 0x03) != 0x03) { - PCD_WriteRegister(TxControlReg, value | 0x03); - } -} // End PCD_AntennaOn() - -/** - * Turns the antenna off by disabling pins TX1 and TX2. - */ -void MFRC522::PCD_AntennaOff() { - PCD_ClearRegisterBitMask(TxControlReg, 0x03); -} // End PCD_AntennaOff() - -/** - * Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. - * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf - * NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. - * - * @return Value of the RxGain, scrubbed to the 3 bits used. - */ -byte MFRC522::PCD_GetAntennaGain() { - return PCD_ReadRegister(RFCfgReg) & (0x07<<4); -} // End PCD_GetAntennaGain() - -/** - * Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask. - * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf - * NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. - */ -void MFRC522::PCD_SetAntennaGain(byte mask) { - if (PCD_GetAntennaGain() != mask) { // only bother if there is a change - PCD_ClearRegisterBitMask(RFCfgReg, (0x07<<4)); // clear needed to allow 000 pattern - PCD_SetRegisterBitMask(RFCfgReg, mask & (0x07<<4)); // only set RxGain[2:0] bits - } -} // End PCD_SetAntennaGain() - -/** - * Performs a self-test of the MFRC522 - * See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf - * - * @return Whether or not the test passed. Or false if no firmware reference is available. - */ -bool MFRC522::PCD_PerformSelfTest() { - // This follows directly the steps outlined in 16.1.1 - // 1. Perform a soft reset. - PCD_Reset(); - - // 2. Clear the internal buffer by writing 25 bytes of 00h - byte ZEROES[25] = {0x00}; - PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // flush the FIFO buffer - PCD_WriteRegister(FIFODataReg, 25, ZEROES); // write 25 bytes of 00h to FIFO - PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer - - // 3. Enable self-test - PCD_WriteRegister(AutoTestReg, 0x09); - - // 4. Write 00h to FIFO buffer - PCD_WriteRegister(FIFODataReg, 0x00); - - // 5. Start self-test by issuing the CalcCRC command - PCD_WriteRegister(CommandReg, PCD_CalcCRC); - - // 6. Wait for self-test to complete - word i; - byte n; - for (i = 0; i < 0xFF; i++) { - n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved - if (n & 0x04) { // CRCIRq bit set - calculation done - break; - } - } - PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. - - // 7. Read out resulting 64 bytes from the FIFO buffer. - byte result[64]; - PCD_ReadRegister(FIFODataReg, 64, result, 0); - - // Auto self-test done - // Reset AutoTestReg register to be 0 again. Required for normal operation. - PCD_WriteRegister(AutoTestReg, 0x00); - - // Determine firmware version (see section 9.3.4.8 in spec) - byte version = PCD_ReadRegister(VersionReg); - - // Pick the appropriate reference values - const byte *reference; - switch (version) { - case 0x88: // Fudan Semiconductor FM17522 clone - reference = FM17522_firmware_reference; - break; - case 0x90: // Version 0.0 - reference = MFRC522_firmware_referenceV0_0; - break; - case 0x91: // Version 1.0 - reference = MFRC522_firmware_referenceV1_0; - break; - case 0x92: // Version 2.0 - reference = MFRC522_firmware_referenceV2_0; - break; - default: // Unknown version - return false; // abort test - } - - // Verify that the results match up to our expectations - for (i = 0; i < 64; i++) { - if (result[i] != pgm_read_byte(&(reference[i]))) { - return false; - } - } - - // Test passed; all is good. - return true; -} // End PCD_PerformSelfTest() - -///////////////////////////////////////////////////////////////////////////////////// -// Functions for communicating with PICCs -///////////////////////////////////////////////////////////////////////////////////// - -/** - * Executes the Transceive command. - * CRC validation can only be done if backData and backLen are specified. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PCD_TransceiveData( byte *sendData, ///< Pointer to the data to transfer to the FIFO. - byte sendLen, ///< Number of bytes to transfer to the FIFO. - byte *backData, ///< NULL or pointer to buffer if data should be read back after executing the command. - byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. - byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default NULL. - byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. - ) { - byte waitIRq = 0x30; // RxIRq and IdleIRq - return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC); -} // End PCD_TransceiveData() - -/** - * Transfers data to the MFRC522 FIFO, executes a command, waits for completion and transfers data back from the FIFO. - * CRC validation can only be done if backData and backLen are specified. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The command to execute. One of the PCD_Command enums. - byte waitIRq, ///< The bits in the ComIrqReg register that signals successful completion of the command. - byte *sendData, ///< Pointer to the data to transfer to the FIFO. - byte sendLen, ///< Number of bytes to transfer to the FIFO. - byte *backData, ///< NULL or pointer to buffer if data should be read back after executing the command. - byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. - byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. - byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. - ) { - byte n, _validBits; - unsigned int i; - - // Prepare values for BitFramingReg - byte txLastBits = validBits ? *validBits : 0; - byte bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] - - PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. - PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits - PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization - PCD_WriteRegister(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO - PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments - PCD_WriteRegister(CommandReg, command); // Execute the command - if (command == PCD_Transceive) { - PCD_SetRegisterBitMask(BitFramingReg, 0x80); // StartSend=1, transmission of data starts - } - - // Wait for the command to complete. - // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting. - // Each iteration of the do-while-loop takes 17.86�s. - i = 2000; - while (1) { - n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq - if (n & waitIRq) { // One of the interrupts that signal success has been set. - break; - } - if (n & 0x01) { // Timer interrupt - nothing received in 25ms - return STATUS_TIMEOUT; - } - if (--i == 0) { // The emergency break. If all other conditions fail we will eventually terminate on this one after 35.7ms. Communication with the MFRC522 might be down. - return STATUS_TIMEOUT; - } - } - - // Stop now if any errors except collisions were detected. - byte errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr - if (errorRegValue & 0x13) { // BufferOvfl ParityErr ProtocolErr - return STATUS_ERROR; - } - - // If the caller wants data back, get it from the MFRC522. - if (backData && backLen) { - n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO - if (n > *backLen) { - return STATUS_NO_ROOM; - } - *backLen = n; // Number of bytes returned - PCD_ReadRegister(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO - _validBits = PCD_ReadRegister(ControlReg) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received byte. If this value is 000b, the whole byte is valid. - if (validBits) { - *validBits = _validBits; - } - } - - // Tell about collisions - if (errorRegValue & 0x08) { // CollErr - return STATUS_COLLISION; - } - - // Perform CRC_A validation if requested. - if (backData && backLen && checkCRC) { - // In this case a MIFARE Classic NAK is not OK. - if (*backLen == 1 && _validBits == 4) { - return STATUS_MIFARE_NACK; - } - // We need at least the CRC_A value and all 8 bits of the last byte must be received. - if (*backLen < 2 || _validBits != 0) { - return STATUS_CRC_WRONG; - } - // Verify CRC_A - do our own calculation and store the control in controlBuffer. - byte controlBuffer[2]; - MFRC522::StatusCode status = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]); - if (status != STATUS_OK) { - return status; - } - if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) { - return STATUS_CRC_WRONG; - } - } - - return STATUS_OK; -} // End PCD_CommunicateWithPICC() - -/** - * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. - * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PICC_RequestA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in - byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. - ) { - return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize); -} // End PICC_RequestA() - -/** - * Transmits a 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. - * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PICC_WakeupA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in - byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. - ) { - return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize); -} // End PICC_WakeupA() - -/** - * Transmits REQA or WUPA commands. - * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA - byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in - byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. - ) { - byte validBits; - MFRC522::StatusCode status; - - if (bufferATQA == NULL || *bufferSize < 2) { // The ATQA response is 2 bytes long. - return STATUS_NO_ROOM; - } - PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. - validBits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0] - status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits); - if (status != STATUS_OK) { - return status; - } - if (*bufferSize != 2 || validBits != 0) { // ATQA must be exactly 16 bits. - return STATUS_ERROR; - } - return STATUS_OK; -} // End PICC_REQA_or_WUPA() - -/** - * Transmits SELECT/ANTICOLLISION commands to select a single PICC. - * Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or PICC_WakeupA(). - * On success: - * - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the ISO/IEC 14443-3 draft.) - * - The UID size and value of the chosen PICC is returned in *uid along with the SAK. - * - * A PICC UID consists of 4, 7 or 10 bytes. - * Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: - * UID size Number of UID bytes Cascade levels Example of PICC - * ======== =================== ============== =============== - * single 4 1 MIFARE Classic - * double 7 2 MIFARE Ultralight - * triple 10 3 Not currently in use? - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. - byte validBits ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also supply uid->size. - ) { - bool uidComplete; - bool selectDone; - bool useCascadeTag; - byte cascadeLevel = 1; - MFRC522::StatusCode result; - byte count; - byte index; - byte uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level. - int8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. - byte buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A - byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. - byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. - byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. - byte *responseBuffer; - byte responseLength; - - // Description of buffer structure: - // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 - // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits. - // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag. - // Byte 3: UID-data - // Byte 4: UID-data - // Byte 5: UID-data - // Byte 6: BCC Block Check Character - XOR of bytes 2-5 - // Byte 7: CRC_A - // Byte 8: CRC_A - // The BCC and CRC_A are only transmitted if we know all the UID bits of the current Cascade Level. - // - // Description of bytes 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels) - // UID size Cascade level Byte2 Byte3 Byte4 Byte5 - // ======== ============= ===== ===== ===== ===== - // 4 bytes 1 uid0 uid1 uid2 uid3 - // 7 bytes 1 CT uid0 uid1 uid2 - // 2 uid3 uid4 uid5 uid6 - // 10 bytes 1 CT uid0 uid1 uid2 - // 2 CT uid3 uid4 uid5 - // 3 uid6 uid7 uid8 uid9 - - // Sanity checks - if (validBits > 80) { - return STATUS_INVALID; - } - - // Prepare MFRC522 - PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. - - // Repeat Cascade Level loop until we have a complete UID. - uidComplete = false; - while (!uidComplete) { - // Set the Cascade Level in the SEL byte, find out if we need to use the Cascade Tag in byte 2. - switch (cascadeLevel) { - case 1: - buffer[0] = PICC_CMD_SEL_CL1; - uidIndex = 0; - useCascadeTag = validBits && uid->size > 4; // When we know that the UID has more than 4 bytes - break; - - case 2: - buffer[0] = PICC_CMD_SEL_CL2; - uidIndex = 3; - useCascadeTag = validBits && uid->size > 7; // When we know that the UID has more than 7 bytes - break; - - case 3: - buffer[0] = PICC_CMD_SEL_CL3; - uidIndex = 6; - useCascadeTag = false; // Never used in CL3. - break; - - default: - return STATUS_INTERNAL_ERROR; - break; - } - - // How many UID bits are known in this Cascade Level? - currentLevelKnownBits = validBits - (8 * uidIndex); - if (currentLevelKnownBits < 0) { - currentLevelKnownBits = 0; - } - // Copy the known bits from uid->uidByte[] to buffer[] - index = 2; // destination index in buffer[] - if (useCascadeTag) { - buffer[index++] = PICC_CMD_CT; - } - byte bytesToCopy = currentLevelKnownBits / 8 + (currentLevelKnownBits % 8 ? 1 : 0); // The number of bytes needed to represent the known bits for this level. - if (bytesToCopy) { - byte maxBytes = useCascadeTag ? 3 : 4; // Max 4 bytes in each Cascade Level. Only 3 left if we use the Cascade Tag - if (bytesToCopy > maxBytes) { - bytesToCopy = maxBytes; - } - for (count = 0; count < bytesToCopy; count++) { - buffer[index++] = uid->uidByte[uidIndex + count]; - } - } - // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits - if (useCascadeTag) { - currentLevelKnownBits += 8; - } - - // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. - selectDone = false; - while (!selectDone) { - // Find out how many bits and bytes to send and receive. - if (currentLevelKnownBits >= 32) { // All UID bits in this Cascade Level are known. This is a SELECT. - //Serial.print(F("SELECT: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); - buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole bytes - // Calculate BCC - Block Check Character - buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; - // Calculate CRC_A - result = PCD_CalculateCRC(buffer, 7, &buffer[7]); - if (result != STATUS_OK) { - return result; - } - txLastBits = 0; // 0 => All 8 bits are valid. - bufferUsed = 9; - // Store response in the last 3 bytes of buffer (BCC and CRC_A - not needed after tx) - responseBuffer = &buffer[6]; - responseLength = 3; - } - else { // This is an ANTICOLLISION. - //Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); - txLastBits = currentLevelKnownBits % 8; - count = currentLevelKnownBits / 8; // Number of whole bytes in the UID part. - index = 2 + count; // Number of whole bytes: SEL + NVB + UIDs - buffer[1] = (index << 4) + txLastBits; // NVB - Number of Valid Bits - bufferUsed = index + (txLastBits ? 1 : 0); - // Store response in the unused part of buffer - responseBuffer = &buffer[index]; - responseLength = sizeof(buffer) - index; - } - - // Set bit adjustments - rxAlign = txLastBits; // Having a separate variable is overkill. But it makes the next line easier to read. - PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] - - // Transmit the buffer and receive the response. - result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign); - if (result == STATUS_COLLISION) { // More than one PICC in the field => collision. - byte valueOfCollReg = PCD_ReadRegister(CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] - if (valueOfCollReg & 0x20) { // CollPosNotValid - return STATUS_COLLISION; // Without a valid collision position we cannot continue - } - byte collisionPos = valueOfCollReg & 0x1F; // Values 0-31, 0 means bit 32. - if (collisionPos == 0) { - collisionPos = 32; - } - if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen - return STATUS_INTERNAL_ERROR; - } - // Choose the PICC with the bit set. - currentLevelKnownBits = collisionPos; - count = (currentLevelKnownBits - 1) % 8; // The bit to modify - index = 1 + (currentLevelKnownBits / 8) + (count ? 1 : 0); // First byte is index 0. - buffer[index] |= (1 << count); - } - else if (result != STATUS_OK) { - return result; - } - else { // STATUS_OK - if (currentLevelKnownBits >= 32) { // This was a SELECT. - selectDone = true; // No more anticollision - // We continue below outside the while. - } - else { // This was an ANTICOLLISION. - // We now have all 32 bits of the UID in this Cascade Level - currentLevelKnownBits = 32; - // Run loop again to do the SELECT. - } - } - } // End of while (!selectDone) - - // We do not check the CBB - it was constructed by us above. - - // Copy the found UID bytes from buffer[] to uid->uidByte[] - index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[] - bytesToCopy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; - for (count = 0; count < bytesToCopy; count++) { - uid->uidByte[uidIndex + count] = buffer[index++]; - } - - // Check response SAK (Select Acknowledge) - if (responseLength != 3 || txLastBits != 0) { // SAK must be exactly 24 bits (1 byte + CRC_A). - return STATUS_ERROR; - } - // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those bytes are not needed anymore. - result = PCD_CalculateCRC(responseBuffer, 1, &buffer[2]); - if (result != STATUS_OK) { - return result; - } - if ((buffer[2] != responseBuffer[1]) || (buffer[3] != responseBuffer[2])) { - return STATUS_CRC_WRONG; - } - if (responseBuffer[0] & 0x04) { // Cascade bit set - UID not complete yes - cascadeLevel++; - } - else { - uidComplete = true; - uid->sak = responseBuffer[0]; - } - } // End of while (!uidComplete) - - // Set correct uid->size - uid->size = 3 * cascadeLevel + 1; - - return STATUS_OK; -} // End PICC_Select() - -/** - * Instructs a PICC in state ACTIVE(*) to go to state HALT. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PICC_HaltA() { - MFRC522::StatusCode result; - byte buffer[4]; - - // Build command buffer - buffer[0] = PICC_CMD_HLTA; - buffer[1] = 0; - // Calculate CRC_A - result = PCD_CalculateCRC(buffer, 2, &buffer[2]); - if (result != STATUS_OK) { - return result; - } - - // Send the command. - // The standard says: - // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the - // HLTA command, this response shall be interpreted as 'not acknowledge'. - // We interpret that this way: Only STATUS_TIMEOUT is a success. - result = PCD_TransceiveData(buffer, sizeof(buffer), NULL, 0); - if (result == STATUS_TIMEOUT) { - return STATUS_OK; - } - if (result == STATUS_OK) { // That is ironically NOT ok in this case ;-) - return STATUS_ERROR; - } - return result; -} // End PICC_HaltA() - - -///////////////////////////////////////////////////////////////////////////////////// -// Functions for communicating with MIFARE PICCs -///////////////////////////////////////////////////////////////////////////////////// - -/** - * Executes the MFRC522 MFAuthent command. - * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. - * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. - * For use with MIFARE Classic PICCs. - * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. - * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. - * - * All keys are set to FFFFFFFFFFFFh at chip delivery. - * - * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. - */ -MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B - byte blockAddr, ///< The block number. See numbering in the comments in the .h file. - MIFARE_Key *key, ///< Pointer to the Crypteo1 key to use (6 bytes) - Uid *uid ///< Pointer to Uid struct. The first 4 bytes of the UID is used. - ) { - byte waitIRq = 0x10; // IdleIRq - - // Build command buffer - byte sendData[12]; - sendData[0] = command; - sendData[1] = blockAddr; - for (byte i = 0; i < MF_KEY_SIZE; i++) { // 6 key bytes - sendData[2+i] = key->keyByte[i]; - } - for (byte i = 0; i < 4; i++) { // The first 4 bytes of the UID - sendData[8+i] = uid->uidByte[i]; - } - - // Start the authentication. - return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData)); -} // End PCD_Authenticate() - -/** - * Used to exit the PCD from its authenticated state. - * Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start. - */ -void MFRC522::PCD_StopCrypto1() { - // Clear MFCrypto1On bit - PCD_ClearRegisterBitMask(Status2Reg, 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0] -} // End PCD_StopCrypto1() - -/** - * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. - * - * For MIFARE Classic the sector containing the block must be authenticated before calling this function. - * - * For MIFARE Ultralight only addresses 00h to 0Fh are decoded. - * The MF0ICU1 returns a NAK for higher addresses. - * The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument. - * For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned. - * A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned. - * - * The buffer must be at least 18 bytes because a CRC_A is also returned. - * Checks the CRC_A before returning STATUS_OK. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. - byte *buffer, ///< The buffer to store the data in - byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. - ) { - MFRC522::StatusCode result; - - // Sanity check - if (buffer == NULL || *bufferSize < 18) { - return STATUS_NO_ROOM; - } - - // Build command buffer - buffer[0] = PICC_CMD_MF_READ; - buffer[1] = blockAddr; - // Calculate CRC_A - result = PCD_CalculateCRC(buffer, 2, &buffer[2]); - if (result != STATUS_OK) { - return result; - } - - // Transmit the buffer and receive the response, validate CRC_A. - return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true); -} // End MIFARE_Read() - -/** - * Writes 16 bytes to the active PICC. - * - * For MIFARE Classic the sector containing the block must be authenticated before calling this function. - * - * For MIFARE Ultralight the operation is called "COMPATIBILITY WRITE". - * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) - * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0. - * * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. - byte *buffer, ///< The 16 bytes to write to the PICC - byte bufferSize ///< Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. - ) { - MFRC522::StatusCode result; - - // Sanity check - if (buffer == NULL || bufferSize < 16) { - return STATUS_INVALID; - } - - // Mifare Classic protocol requires two communications to perform a write. - // Step 1: Tell the PICC we want to write to block blockAddr. - byte cmdBuffer[2]; - cmdBuffer[0] = PICC_CMD_MF_WRITE; - cmdBuffer[1] = blockAddr; - result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } - - // Step 2: Transfer the data - result = PCD_MIFARE_Transceive(buffer, bufferSize); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } - - return STATUS_OK; -} // End MIFARE_Write() - -/** - * Writes a 4 byte page to the active MIFARE Ultralight PICC. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page (2-15) to write to. - byte *buffer, ///< The 4 bytes to write to the PICC - byte bufferSize ///< Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. - ) { - MFRC522::StatusCode result; - - // Sanity check - if (buffer == NULL || bufferSize < 4) { - return STATUS_INVALID; - } - - // Build commmand buffer - byte cmdBuffer[6]; - cmdBuffer[0] = PICC_CMD_UL_WRITE; - cmdBuffer[1] = page; - memcpy(&cmdBuffer[2], buffer, 4); - - // Perform the write - result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } - return STATUS_OK; -} // End MIFARE_Ultralight_Write() - -/** - * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. - * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. - * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. - * Use MIFARE_Transfer() to store the result in a block. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_Decrement( byte blockAddr, ///< The block (0-0xff) number. - long delta ///< This number is subtracted from the value of block blockAddr. - ) { - return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta); -} // End MIFARE_Decrement() - -/** - * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. - * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. - * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. - * Use MIFARE_Transfer() to store the result in a block. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_Increment( byte blockAddr, ///< The block (0-0xff) number. - long delta ///< This number is added to the value of block blockAddr. - ) { - return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta); -} // End MIFARE_Increment() - -/** - * MIFARE Restore copies the value of the addressed block into a volatile memory. - * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. - * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. - * Use MIFARE_Transfer() to store the result in a block. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_Restore( byte blockAddr ///< The block (0-0xff) number. - ) { - // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2. - // Doing only a single step does not work, so I chose to transfer 0L in step two. - return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L); -} // End MIFARE_Restore() - -/** - * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper( byte command, ///< The command to use - byte blockAddr, ///< The block (0-0xff) number. - long data ///< The data to transfer in step 2 - ) { - MFRC522::StatusCode result; - byte cmdBuffer[2]; // We only need room for 2 bytes. - - // Step 1: Tell the PICC the command and block address - cmdBuffer[0] = command; - cmdBuffer[1] = blockAddr; - result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } - - // Step 2: Transfer the data - result = PCD_MIFARE_Transceive( (byte *)&data, 4, true); // Adds CRC_A and accept timeout as success. - if (result != STATUS_OK) { - return result; - } - - return STATUS_OK; -} // End MIFARE_TwoStepHelper() - -/** - * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. - * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. - * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0xff) number. - ) { - MFRC522::StatusCode result; - byte cmdBuffer[2]; // We only need room for 2 bytes. - - // Tell the PICC we want to transfer the result into block blockAddr. - cmdBuffer[0] = PICC_CMD_MF_TRANSFER; - cmdBuffer[1] = blockAddr; - result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } - return STATUS_OK; -} // End MIFARE_Transfer() - -/** - * Helper routine to read the current value from a Value Block. - * - * Only for MIFARE Classic and only for blocks in "value block" mode, that - * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing - * the block must be authenticated before calling this function. - * - * @param[in] blockAddr The block (0x00-0xff) number. - * @param[out] value Current value of the Value Block. - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_GetValue(byte blockAddr, long *value) { - MFRC522::StatusCode status; - byte buffer[18]; - byte size = sizeof(buffer); - - // Read the block - status = MIFARE_Read(blockAddr, buffer, &size); - if (status == STATUS_OK) { - // Extract the value - *value = (long(buffer[3])<<24) | (long(buffer[2])<<16) | (long(buffer[1])<<8) | long(buffer[0]); - } - return status; -} // End MIFARE_GetValue() - -/** - * Helper routine to write a specific value into a Value Block. - * - * Only for MIFARE Classic and only for blocks in "value block" mode, that - * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing - * the block must be authenticated before calling this function. - * - * @param[in] blockAddr The block (0x00-0xff) number. - * @param[in] value New value of the Value Block. - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::MIFARE_SetValue(byte blockAddr, long value) { - byte buffer[18]; - - // Translate the long into 4 bytes; repeated 2x in value block - buffer[0] = buffer[ 8] = (value & 0xFF); - buffer[1] = buffer[ 9] = (value & 0xFF00) >> 8; - buffer[2] = buffer[10] = (value & 0xFF0000) >> 16; - buffer[3] = buffer[11] = (value & 0xFF000000) >> 24; - // Inverse 4 bytes also found in value block - buffer[4] = ~buffer[0]; - buffer[5] = ~buffer[1]; - buffer[6] = ~buffer[2]; - buffer[7] = ~buffer[3]; - // Address 2x with inverse address 2x - buffer[12] = buffer[14] = blockAddr; - buffer[13] = buffer[15] = ~blockAddr; - - // Write the whole data block - return MIFARE_Write(blockAddr, buffer, 16); -} // End MIFARE_SetValue() - -/** - * Authenticate with a NTAG216. - * - * Only for NTAG216. First implemented by Gargantuanman. - * - * @param[in] passWord password. - * @param[in] pACK result success???. - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Authenticate with 32bit password -{ - MFRC522::StatusCode result; - byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. - - cmdBuffer[0] = 0x1B; //Comando de autentificacion - - for (byte i = 0; i<4; i++) - cmdBuffer[i+1] = passWord[i]; - - result = PCD_CalculateCRC(cmdBuffer, 5, &cmdBuffer[5]); - - if (result!=STATUS_OK) { - return result; - } - - // Transceive the data, store the reply in cmdBuffer[] - byte waitIRq = 0x30; // RxIRq and IdleIRq - byte cmdBufferSize = sizeof(cmdBuffer); - byte validBits = 0; - byte rxlength = 5; - result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, 7, cmdBuffer, &rxlength, &validBits); - - pACK[0] = cmdBuffer[0]; - pACK[1] = cmdBuffer[1]; - - if (result!=STATUS_OK) { - return result; - } - - return STATUS_OK; -} // End PCD_NTAG216_AUTH() - - -///////////////////////////////////////////////////////////////////////////////////// -// Support functions -///////////////////////////////////////////////////////////////////////////////////// - -/** - * Wrapper for MIFARE protocol communication. - * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. - byte sendLen, ///< Number of bytes in sendData. - bool acceptTimeout ///< True => A timeout is also success - ) { - MFRC522::StatusCode result; - byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. - - // Sanity check - if (sendData == NULL || sendLen > 16) { - return STATUS_INVALID; - } - - // Copy sendData[] to cmdBuffer[] and add CRC_A - memcpy(cmdBuffer, sendData, sendLen); - result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]); - if (result != STATUS_OK) { - return result; - } - sendLen += 2; - - // Transceive the data, store the reply in cmdBuffer[] - byte waitIRq = 0x30; // RxIRq and IdleIRq - byte cmdBufferSize = sizeof(cmdBuffer); - byte validBits = 0; - result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, sendLen, cmdBuffer, &cmdBufferSize, &validBits); - if (acceptTimeout && result == STATUS_TIMEOUT) { - return STATUS_OK; - } - if (result != STATUS_OK) { - return result; - } - // The PICC must reply with a 4 bit ACK - if (cmdBufferSize != 1 || validBits != 4) { - return STATUS_ERROR; - } - if (cmdBuffer[0] != MF_ACK) { - return STATUS_MIFARE_NACK; - } - return STATUS_OK; -} // End PCD_MIFARE_Transceive() - -/** - * Returns a __FlashStringHelper pointer to a status code name. - * - * @return const __FlashStringHelper * - */ -const __FlashStringHelper *MFRC522::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. - ) { - switch (code) { - case STATUS_OK: return F("Success."); - case STATUS_ERROR: return F("Error in communication."); - case STATUS_COLLISION: return F("Collission detected."); - case STATUS_TIMEOUT: return F("Timeout in communication."); - case STATUS_NO_ROOM: return F("A buffer is not big enough."); - case STATUS_INTERNAL_ERROR: return F("Internal error in the code. Should not happen."); - case STATUS_INVALID: return F("Invalid argument."); - case STATUS_CRC_WRONG: return F("The CRC_A does not match."); - case STATUS_MIFARE_NACK: return F("A MIFARE PICC responded with NAK."); - default: return F("Unknown error"); - } -} // End GetStatusCodeName() - -/** - * Translates the SAK (Select Acknowledge) to a PICC type. - * - * @return PICC_Type - */ -MFRC522::PICC_Type MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select(). - ) { - // http://www.nxp.com/documents/application_note/AN10833.pdf - // 3.2 Coding of Select Acknowledge (SAK) - // ignore 8-bit (iso14443 starts with LSBit = bit 1) - // fixes wrong type for manufacturer Infineon (http://nfc-tools.org/index.php?title=ISO14443A) - sak &= 0x7F; - switch (sak) { - case 0x04: return PICC_TYPE_NOT_COMPLETE; // UID not complete - case 0x09: return PICC_TYPE_MIFARE_MINI; - case 0x08: return PICC_TYPE_MIFARE_1K; - case 0x18: return PICC_TYPE_MIFARE_4K; - case 0x00: return PICC_TYPE_MIFARE_UL; - case 0x10: - case 0x11: return PICC_TYPE_MIFARE_PLUS; - case 0x01: return PICC_TYPE_TNP3XXX; - case 0x20: return PICC_TYPE_ISO_14443_4; - case 0x40: return PICC_TYPE_ISO_18092; - default: return PICC_TYPE_UNKNOWN; - } -} // End PICC_GetType() - -/** - * Returns a __FlashStringHelper pointer to the PICC type name. - * - * @return const __FlashStringHelper * - */ -const __FlashStringHelper *MFRC522::PICC_GetTypeName(PICC_Type piccType ///< One of the PICC_Type enums. - ) { - switch (piccType) { - case PICC_TYPE_ISO_14443_4: return F("PICC compliant with ISO/IEC 14443-4"); - case PICC_TYPE_ISO_18092: return F("PICC compliant with ISO/IEC 18092 (NFC)"); - case PICC_TYPE_MIFARE_MINI: return F("MIFARE Mini, 320 bytes"); - case PICC_TYPE_MIFARE_1K: return F("MIFARE 1KB"); - case PICC_TYPE_MIFARE_4K: return F("MIFARE 4KB"); - case PICC_TYPE_MIFARE_UL: return F("MIFARE Ultralight or Ultralight C"); - case PICC_TYPE_MIFARE_PLUS: return F("MIFARE Plus"); - case PICC_TYPE_TNP3XXX: return F("MIFARE TNP3XXX"); - case PICC_TYPE_NOT_COMPLETE: return F("SAK indicates UID is not complete."); - case PICC_TYPE_UNKNOWN: - default: return F("Unknown type"); - } -} // End PICC_GetTypeName() - -/** - * Dumps debug info about the connected PCD to Serial. - * Shows all known firmware versions - */ -void MFRC522::PCD_DumpVersionToSerial() { - // Get the MFRC522 firmware version - byte v = PCD_ReadRegister(VersionReg); - Serial.print(F("Firmware Version: 0x")); - Serial.print(v, HEX); - // Lookup which version - switch(v) { - case 0x88: Serial.println(F(" = (clone)")); break; - case 0x90: Serial.println(F(" = v0.0")); break; - case 0x91: Serial.println(F(" = v1.0")); break; - case 0x92: Serial.println(F(" = v2.0")); break; - default: Serial.println(F(" = (unknown)")); - } - // When 0x00 or 0xFF is returned, communication probably failed - if ((v == 0x00) || (v == 0xFF)) - Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); -} // End PCD_DumpVersionToSerial() - -/** - * Dumps debug info about the selected PICC to Serial. - * On success the PICC is halted after dumping the data. - * For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried. - */ -void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). - ) { - MIFARE_Key key; - - // Dump UID, SAK and Type - PICC_DumpDetailsToSerial(uid); - - // Dump contents - PICC_Type piccType = PICC_GetType(uid->sak); - switch (piccType) { - case PICC_TYPE_MIFARE_MINI: - case PICC_TYPE_MIFARE_1K: - case PICC_TYPE_MIFARE_4K: - // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory. - for (byte i = 0; i < 6; i++) { - key.keyByte[i] = 0xFF; - } - PICC_DumpMifareClassicToSerial(uid, piccType, &key); - break; - - case PICC_TYPE_MIFARE_UL: - PICC_DumpMifareUltralightToSerial(); - break; - - case PICC_TYPE_ISO_14443_4: - case PICC_TYPE_ISO_18092: - case PICC_TYPE_MIFARE_PLUS: - case PICC_TYPE_TNP3XXX: - Serial.println(F("Dumping memory contents not implemented for that PICC type.")); - break; - - case PICC_TYPE_UNKNOWN: - case PICC_TYPE_NOT_COMPLETE: - default: - break; // No memory dump here - } - - Serial.println(); - PICC_HaltA(); // Already done if it was a MIFARE Classic PICC. -} // End PICC_DumpToSerial() - -/** - * Dumps card info (UID,SAK,Type) about the selected PICC to Serial. - */ -void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). - ) { - // UID - Serial.print(F("Card UID:")); - for (byte i = 0; i < uid->size; i++) { - if(uid->uidByte[i] < 0x10) - Serial.print(F(" 0")); - else - Serial.print(F(" ")); - Serial.print(uid->uidByte[i], HEX); - } - Serial.println(); - - // SAK - Serial.print(F("Card SAK: ")); - if(uid->sak < 0x10) - Serial.print(F("0")); - Serial.println(uid->sak, HEX); - - // (suggested) PICC type - PICC_Type piccType = PICC_GetType(uid->sak); - Serial.print(F("PICC type: ")); - Serial.println(PICC_GetTypeName(piccType)); -} // End PICC_DumpDetailsToSerial() - -/** - * Dumps memory contents of a MIFARE Classic PICC. - * On success the PICC is halted after dumping the data. - */ -void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). - PICC_Type piccType, ///< One of the PICC_Type enums. - MIFARE_Key *key ///< Key A used for all sectors. - ) { - byte no_of_sectors = 0; - switch (piccType) { - case PICC_TYPE_MIFARE_MINI: - // Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. - no_of_sectors = 5; - break; - - case PICC_TYPE_MIFARE_1K: - // Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. - no_of_sectors = 16; - break; - - case PICC_TYPE_MIFARE_4K: - // Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. - no_of_sectors = 40; - break; - - default: // Should not happen. Ignore. - break; - } - - // Dump sectors, highest address first. - if (no_of_sectors) { - Serial.println(F("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits")); - for (int8_t i = no_of_sectors - 1; i >= 0; i--) { - PICC_DumpMifareClassicSectorToSerial(uid, key, i); - } - } - PICC_HaltA(); // Halt the PICC before stopping the encrypted session. - PCD_StopCrypto1(); -} // End PICC_DumpMifareClassicToSerial() - -/** - * Dumps memory contents of a sector of a MIFARE Classic PICC. - * Uses PCD_Authenticate(), MIFARE_Read() and PCD_StopCrypto1. - * Always uses PICC_CMD_MF_AUTH_KEY_A because only Key A can always read the sector trailer access bits. - */ -void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). - MIFARE_Key *key, ///< Key A for the sector. - byte sector ///< The sector to dump, 0..39. - ) { - MFRC522::StatusCode status; - byte firstBlock; // Address of lowest address to dump actually last block dumped) - byte no_of_blocks; // Number of blocks in sector - bool isSectorTrailer; // Set to true while handling the "last" (ie highest address) in the sector. - - // The access bits are stored in a peculiar fashion. - // There are four groups: - // g[3] Access bits for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) - // g[2] Access bits for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) - // g[1] Access bits for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) - // g[0] Access bits for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) - // Each group has access bits [C1 C2 C3]. In this code C1 is MSB and C3 is LSB. - // The four CX bits are stored together in a nible cx and an inverted nible cx_. - byte c1, c2, c3; // Nibbles - byte c1_, c2_, c3_; // Inverted nibbles - bool invertedError; // True if one of the inverted nibbles did not match - byte g[4]; // Access bits for each of the four groups. - byte group; // 0-3 - active group for access bits - bool firstInGroup; // True for the first block dumped in the group - - // Determine position and size of sector. - if (sector < 32) { // Sectors 0..31 has 4 blocks each - no_of_blocks = 4; - firstBlock = sector * no_of_blocks; - } - else if (sector < 40) { // Sectors 32-39 has 16 blocks each - no_of_blocks = 16; - firstBlock = 128 + (sector - 32) * no_of_blocks; - } - else { // Illegal input, no MIFARE Classic PICC has more than 40 sectors. - return; - } - - // Dump blocks, highest address first. - byte byteCount; - byte buffer[18]; - byte blockAddr; - isSectorTrailer = true; - for (int8_t blockOffset = no_of_blocks - 1; blockOffset >= 0; blockOffset--) { - blockAddr = firstBlock + blockOffset; - // Sector number - only on first line - if (isSectorTrailer) { - if(sector < 10) - Serial.print(F(" ")); // Pad with spaces - else - Serial.print(F(" ")); // Pad with spaces - Serial.print(sector); - Serial.print(F(" ")); - } - else { - Serial.print(F(" ")); - } - // Block number - if(blockAddr < 10) - Serial.print(F(" ")); // Pad with spaces - else { - if(blockAddr < 100) - Serial.print(F(" ")); // Pad with spaces - else - Serial.print(F(" ")); // Pad with spaces - } - Serial.print(blockAddr); - Serial.print(F(" ")); - // Establish encrypted communications before reading the first block - if (isSectorTrailer) { - status = PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, firstBlock, key, uid); - if (status != STATUS_OK) { - Serial.print(F("PCD_Authenticate() failed: ")); - Serial.println(GetStatusCodeName(status)); - return; - } - } - // Read block - byteCount = sizeof(buffer); - status = MIFARE_Read(blockAddr, buffer, &byteCount); - if (status != STATUS_OK) { - Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); - continue; - } - // Dump data - for (byte index = 0; index < 16; index++) { - if(buffer[index] < 0x10) - Serial.print(F(" 0")); - else - Serial.print(F(" ")); - Serial.print(buffer[index], HEX); - if ((index % 4) == 3) { - Serial.print(F(" ")); - } - } - // Parse sector trailer data - if (isSectorTrailer) { - c1 = buffer[7] >> 4; - c2 = buffer[8] & 0xF; - c3 = buffer[8] >> 4; - c1_ = buffer[6] & 0xF; - c2_ = buffer[6] >> 4; - c3_ = buffer[7] & 0xF; - invertedError = (c1 != (~c1_ & 0xF)) || (c2 != (~c2_ & 0xF)) || (c3 != (~c3_ & 0xF)); - g[0] = ((c1 & 1) << 2) | ((c2 & 1) << 1) | ((c3 & 1) << 0); - g[1] = ((c1 & 2) << 1) | ((c2 & 2) << 0) | ((c3 & 2) >> 1); - g[2] = ((c1 & 4) << 0) | ((c2 & 4) >> 1) | ((c3 & 4) >> 2); - g[3] = ((c1 & 8) >> 1) | ((c2 & 8) >> 2) | ((c3 & 8) >> 3); - isSectorTrailer = false; - } - - // Which access group is this block in? - if (no_of_blocks == 4) { - group = blockOffset; - firstInGroup = true; - } - else { - group = blockOffset / 5; - firstInGroup = (group == 3) || (group != (blockOffset + 1) / 5); - } - - if (firstInGroup) { - // Print access bits - Serial.print(F(" [ ")); - Serial.print((g[group] >> 2) & 1, DEC); Serial.print(F(" ")); - Serial.print((g[group] >> 1) & 1, DEC); Serial.print(F(" ")); - Serial.print((g[group] >> 0) & 1, DEC); - Serial.print(F(" ] ")); - if (invertedError) { - Serial.print(F(" Inverted access bits did not match! ")); - } - } - - if (group != 3 && (g[group] == 1 || g[group] == 6)) { // Not a sector trailer, a value block - long value = (long(buffer[3])<<24) | (long(buffer[2])<<16) | (long(buffer[1])<<8) | long(buffer[0]); - Serial.print(F(" Value=0x")); Serial.print(value, HEX); - Serial.print(F(" Adr=0x")); Serial.print(buffer[12], HEX); - } - Serial.println(); - } - - return; -} // End PICC_DumpMifareClassicSectorToSerial() - -/** - * Dumps memory contents of a MIFARE Ultralight PICC. - */ -void MFRC522::PICC_DumpMifareUltralightToSerial() { - MFRC522::StatusCode status; - byte byteCount; - byte buffer[18]; - byte i; - - Serial.println(F("Page 0 1 2 3")); - // Try the mpages of the original Ultralight. Ultralight C has more pages. - for (byte page = 0; page < 16; page +=4) { // Read returns data for 4 pages at a time. - // Read pages - byteCount = sizeof(buffer); - status = MIFARE_Read(page, buffer, &byteCount); - if (status != STATUS_OK) { - Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); - break; - } - // Dump data - for (byte offset = 0; offset < 4; offset++) { - i = page + offset; - if(i < 10) - Serial.print(F(" ")); // Pad with spaces - else - Serial.print(F(" ")); // Pad with spaces - Serial.print(i); - Serial.print(F(" ")); - for (byte index = 0; index < 4; index++) { - i = 4 * offset + index; - if(buffer[i] < 0x10) - Serial.print(F(" 0")); - else - Serial.print(F(" ")); - Serial.print(buffer[i], HEX); - } - Serial.println(); - } - } -} // End PICC_DumpMifareUltralightToSerial() - -/** - * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tuples C1 is MSB (=4) and C3 is LSB (=1). - */ -void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. - byte g0, ///< Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) - byte g1, ///< Access bits C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) - byte g2, ///< Access bits C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) - byte g3 ///< Access bits C1 C2 C3] for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) - ) { - byte c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2); - byte c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1); - byte c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0); - - accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF); - accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF); - accessBitBuffer[2] = c3 << 4 | c2; -} // End MIFARE_SetAccessBits() - - -/** - * Performs the "magic sequence" needed to get Chinese UID changeable - * Mifare cards to allow writing to sector 0, where the card UID is stored. - * - * Note that you do not need to have selected the card through REQA or WUPA, - * this sequence works immediately when the card is in the reader vicinity. - * This means you can use this method even on "bricked" cards that your reader does - * not recognise anymore (see MFRC522::MIFARE_UnbrickUidSector). - * - * Of course with non-bricked devices, you're free to select them before calling this function. - */ -bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { - // Magic sequence: - // > 50 00 57 CD (HALT + CRC) - // > 40 (7 bits only) - // < A (4 bits only) - // > 43 - // < A (4 bits only) - // Then you can write to sector 0 without authenticating - - PICC_HaltA(); // 50 00 57 CD - - byte cmd = 0x40; - byte validBits = 7; /* Our command is only 7 bits. After receiving card response, - this will contain amount of valid response bits. */ - byte response[32]; // Card's response is written here - byte received; - MFRC522::StatusCode status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 40 - if(status != STATUS_OK) { - if(logErrors) { - Serial.println(F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?")); - Serial.print(F("Error name: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - if (received != 1 || response[0] != 0x0A) { - if (logErrors) { - Serial.print(F("Got bad response on backdoor 0x40 command: ")); - Serial.print(response[0], HEX); - Serial.print(F(" (")); - Serial.print(validBits); - Serial.print(F(" valid bits)\r\n")); - } - return false; - } - - cmd = 0x43; - validBits = 8; - status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 43 - if(status != STATUS_OK) { - if(logErrors) { - Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40")); - Serial.print(F("Error name: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - if (received != 1 || response[0] != 0x0A) { - if (logErrors) { - Serial.print(F("Got bad response on backdoor 0x43 command: ")); - Serial.print(response[0], HEX); - Serial.print(F(" (")); - Serial.print(validBits); - Serial.print(F(" valid bits)\r\n")); - } - return false; - } - - // You can now write to sector 0 without authenticating! - return true; -} // End MIFARE_OpenUidBackdoor() - -/** - * Reads entire block 0, including all manufacturer data, and overwrites - * that block with the new UID, a freshly calculated BCC, and the original - * manufacturer data. - * - * It assumes a default KEY A of 0xFFFFFFFFFFFF. - * Make sure to have selected the card before this function is called. - */ -bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { - - // UID + BCC byte can not be larger than 16 together - if (!newUid || !uidSize || uidSize > 15) { - if (logErrors) { - Serial.println(F("New UID buffer empty, size 0, or size > 15 given")); - } - return false; - } - - // Authenticate for reading - MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - MFRC522::StatusCode status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); - if (status != STATUS_OK) { - - if (status == STATUS_TIMEOUT) { - // We get a read timeout if no card is selected yet, so let's select one - - // Wake the card up again if sleeping -// byte atqa_answer[2]; -// byte atqa_size = 2; -// PICC_WakeupA(atqa_answer, &atqa_size); - - if (!PICC_IsNewCardPresent() || !PICC_ReadCardSerial()) { - Serial.println(F("No card was previously selected, and none are available. Failed to set UID.")); - return false; - } - - status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); - if (status != STATUS_OK) { - // We tried, time to give up - if (logErrors) { - Serial.println(F("Failed to authenticate to card for reading, could not set UID: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - } - else { - if (logErrors) { - Serial.print(F("PCD_Authenticate() failed: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - } - - // Read block 0 - byte block0_buffer[18]; - byte byteCount = sizeof(block0_buffer); - status = MIFARE_Read((byte)0, block0_buffer, &byteCount); - if (status != STATUS_OK) { - if (logErrors) { - Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); - Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?")); - } - return false; - } - - // Write new UID to the data we just read, and calculate BCC byte - byte bcc = 0; - for (int i = 0; i < uidSize; i++) { - block0_buffer[i] = newUid[i]; - bcc ^= newUid[i]; - } - - // Write BCC byte to buffer - block0_buffer[uidSize] = bcc; - - // Stop encrypted traffic so we can send raw bytes - PCD_StopCrypto1(); - - // Activate UID backdoor - if (!MIFARE_OpenUidBackdoor(logErrors)) { - if (logErrors) { - Serial.println(F("Activating the UID backdoor failed.")); - } - return false; - } - - // Write modified block 0 back to card - status = MIFARE_Write((byte)0, block0_buffer, (byte)16); - if (status != STATUS_OK) { - if (logErrors) { - Serial.print(F("MIFARE_Write() failed: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - - // Wake the card up again - byte atqa_answer[2]; - byte atqa_size = 2; - PICC_WakeupA(atqa_answer, &atqa_size); - - return true; -} - -/** - * Resets entire sector 0 to zeroes, so the card can be read again by readers. - */ -bool MFRC522::MIFARE_UnbrickUidSector(bool logErrors) { - MIFARE_OpenUidBackdoor(logErrors); - - byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - // Write modified block 0 back to card - MFRC522::StatusCode status = MIFARE_Write((byte)0, block0_buffer, (byte)16); - if (status != STATUS_OK) { - if (logErrors) { - Serial.print(F("MIFARE_Write() failed: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - return true; -} - -///////////////////////////////////////////////////////////////////////////////////// -// Convenience functions - does not add extra functionality -///////////////////////////////////////////////////////////////////////////////////// - -/** - * Returns true if a PICC responds to PICC_CMD_REQA. - * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. - * - * @return bool - */ -bool MFRC522::PICC_IsNewCardPresent() { - byte bufferATQA[2]; - byte bufferSize = sizeof(bufferATQA); - MFRC522::StatusCode result = PICC_RequestA(bufferATQA, &bufferSize); - return (result == STATUS_OK || result == STATUS_COLLISION); -} // End PICC_IsNewCardPresent() - -/** - * Simple wrapper around PICC_Select. - * Returns true if a UID could be read. - * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. - * The read UID is available in the class variable uid. - * - * @return bool - */ -bool MFRC522::PICC_ReadCardSerial() { - MFRC522::StatusCode result = PICC_Select(&uid); - return (result == STATUS_OK); -} // End diff --git a/lowcar/lib/MFRC522/MFRC522.h b/lowcar/lib/MFRC522/MFRC522.h deleted file mode 100644 index dec7c67a..00000000 --- a/lowcar/lib/MFRC522/MFRC522.h +++ /dev/null @@ -1,418 +0,0 @@ -/** - * 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 -#include - -// 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_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_NTAG216_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(); - - // 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 diff --git a/lowcar/lib/SPI/SPI.cpp b/lowcar/lib/SPI/SPI.cpp deleted file mode 100644 index dd28a5f7..00000000 --- a/lowcar/lib/SPI/SPI.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2010 by Cristian Maglie - * Copyright (c) 2014 by Paul Stoffregen (Transaction API) - * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) - * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) - * SPI Master library for arduino. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ - -#include "SPI.h" - -SPIClass SPI; - -uint8_t SPIClass::initialized = 0; -uint8_t SPIClass::interruptMode = 0; -uint8_t SPIClass::interruptMask = 0; -uint8_t SPIClass::interruptSave = 0; -#ifdef SPI_TRANSACTION_MISMATCH_LED -uint8_t SPIClass::inTransactionFlag = 0; -#endif - -void SPIClass::begin() -{ - uint8_t sreg = SREG; - noInterrupts(); // Protect from a scheduler and prevent transactionBegin - if (!initialized) { - // Set SS to high so a connected chip will be "deselected" by default - uint8_t port = digitalPinToPort(SS); - uint8_t bit = digitalPinToBitMask(SS); - volatile uint8_t *reg = portModeRegister(port); - - // if the SS pin is not already configured as an output - // then set it high (to enable the internal pull-up resistor) - if(!(*reg & bit)){ - digitalWrite(SS, HIGH); - } - - // When the SS pin is set as OUTPUT, it can be used as - // a general purpose output port (it doesn't influence - // SPI operations). - pinMode(SS, OUTPUT); - - // Warning: if the SS pin ever becomes a LOW INPUT then SPI - // automatically switches to Slave, so the data direction of - // the SS pin MUST be kept as OUTPUT. - SPCR |= _BV(MSTR); - SPCR |= _BV(SPE); - - // Set direction register for SCK and MOSI pin. - // MISO pin automatically overrides to INPUT. - // By doing this AFTER enabling SPI, we avoid accidentally - // clocking in a single bit since the lines go directly - // from "input" to SPI control. - // http://code.google.com/p/arduino/issues/detail?id=888 - pinMode(SCK, OUTPUT); - pinMode(MOSI, OUTPUT); - } - initialized++; // reference count - SREG = sreg; -} - -void SPIClass::end() { - uint8_t sreg = SREG; - noInterrupts(); // Protect from a scheduler and prevent transactionBegin - // Decrease the reference counter - if (initialized) - initialized--; - // If there are no more references disable SPI - if (!initialized) { - SPCR &= ~_BV(SPE); - interruptMode = 0; - #ifdef SPI_TRANSACTION_MISMATCH_LED - inTransactionFlag = 0; - #endif - } - SREG = sreg; -} - -// mapping of interrupt numbers to bits within SPI_AVR_EIMSK -#if defined(__AVR_ATmega32U4__) - #define SPI_INT0_MASK (1< - * Copyright (c) 2014 by Paul Stoffregen (Transaction API) - * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) - * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) - * SPI Master library for arduino. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ - -#ifndef _SPI_H_INCLUDED -#define _SPI_H_INCLUDED - -#include - -// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), -// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) -#define SPI_HAS_TRANSACTION 1 - -// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method -#define SPI_HAS_NOTUSINGINTERRUPT 1 - -// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. -// This way when there is a bug fix you can check this define to alert users -// of your code if it uses better version of this library. -// This also implies everything that SPI_HAS_TRANSACTION as documented above is -// available too. -#define SPI_ATOMIC_VERSION 1 - -// Uncomment this line to add detection of mismatched begin/end transactions. -// A mismatch occurs if other libraries fail to use SPI.endTransaction() for -// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn -// on if any mismatch is ever detected. -//#define SPI_TRANSACTION_MISMATCH_LED 5 - -#ifndef LSBFIRST -#define LSBFIRST 0 -#endif -#ifndef MSBFIRST -#define MSBFIRST 1 -#endif - -#define SPI_CLOCK_DIV4 0x00 -#define SPI_CLOCK_DIV16 0x01 -#define SPI_CLOCK_DIV64 0x02 -#define SPI_CLOCK_DIV128 0x03 -#define SPI_CLOCK_DIV2 0x04 -#define SPI_CLOCK_DIV8 0x05 -#define SPI_CLOCK_DIV32 0x06 - -#define SPI_MODE0 0x00 -#define SPI_MODE1 0x04 -#define SPI_MODE2 0x08 -#define SPI_MODE3 0x0C - -#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR -#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR -#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR - -// define SPI_AVR_EIMSK for AVR boards with external interrupt pins -#if defined(EIMSK) - #define SPI_AVR_EIMSK EIMSK -#elif defined(GICR) - #define SPI_AVR_EIMSK GICR -#elif defined(GIMSK) - #define SPI_AVR_EIMSK GIMSK -#endif - -class SPISettings { -public: - SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { - if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); - } else { - init_MightInline(clock, bitOrder, dataMode); - } - } - SPISettings() { - init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); - } -private: - void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); - } - void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) - __attribute__((__always_inline__)) { - // Clock settings are defined as follows. Note that this shows SPI2X - // inverted, so the bits form increasing numbers. Also note that - // fosc/64 appears twice - // SPR1 SPR0 ~SPI2X Freq - // 0 0 0 fosc/2 - // 0 0 1 fosc/4 - // 0 1 0 fosc/8 - // 0 1 1 fosc/16 - // 1 0 0 fosc/32 - // 1 0 1 fosc/64 - // 1 1 0 fosc/64 - // 1 1 1 fosc/128 - - // We find the fastest clock that is less than or equal to the - // given clock rate. The clock divider that results in clock_setting - // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the - // slowest (128 == 2 ^^ 7, so clock_div = 6). - uint8_t clockDiv; - - // When the clock is known at compiletime, use this if-then-else - // cascade, which the compiler knows how to completely optimize - // away. When clock is not known, use a loop instead, which generates - // shorter code. - if (__builtin_constant_p(clock)) { - if (clock >= F_CPU / 2) { - clockDiv = 0; - } else if (clock >= F_CPU / 4) { - clockDiv = 1; - } else if (clock >= F_CPU / 8) { - clockDiv = 2; - } else if (clock >= F_CPU / 16) { - clockDiv = 3; - } else if (clock >= F_CPU / 32) { - clockDiv = 4; - } else if (clock >= F_CPU / 64) { - clockDiv = 5; - } else { - clockDiv = 6; - } - } else { - uint32_t clockSetting = F_CPU / 2; - clockDiv = 0; - while (clockDiv < 6 && clock < clockSetting) { - clockSetting /= 2; - clockDiv++; - } - } - - // Compensate for the duplicate fosc/64 - if (clockDiv == 6) - clockDiv = 7; - - // Invert the SPI2X bit - clockDiv ^= 0x1; - - // Pack into the SPISettings class - spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) | - (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK); - spsr = clockDiv & SPI_2XCLOCK_MASK; - } - uint8_t spcr; - uint8_t spsr; - friend class SPIClass; -}; - - -class SPIClass { -public: - // Initialize the SPI library - static void begin(); - - // If SPI is used from within an interrupt, this function registers - // that interrupt with the SPI library, so beginTransaction() can - // prevent conflicts. The input interruptNumber is the number used - // with attachInterrupt. If SPI is used from a different interrupt - // (eg, a timer), interruptNumber should be 255. - static void usingInterrupt(uint8_t interruptNumber); - // And this does the opposite. - static void notUsingInterrupt(uint8_t interruptNumber); - // Note: the usingInterrupt and notUsingInterrupt functions should - // not to be called from ISR context or inside a transaction. - // For details see: - // https://github.com/arduino/Arduino/pull/2381 - // https://github.com/arduino/Arduino/pull/2449 - - // Before using SPI.transfer() or asserting chip select pins, - // this function is used to gain exclusive access to the SPI bus - // and configure the correct settings. - inline static void beginTransaction(SPISettings settings) { - if (interruptMode > 0) { - uint8_t sreg = SREG; - noInterrupts(); - - #ifdef SPI_AVR_EIMSK - if (interruptMode == 1) { - interruptSave = SPI_AVR_EIMSK; - SPI_AVR_EIMSK &= ~interruptMask; - SREG = sreg; - } else - #endif - { - interruptSave = sreg; - } - } - - #ifdef SPI_TRANSACTION_MISMATCH_LED - if (inTransactionFlag) { - pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); - digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); - } - inTransactionFlag = 1; - #endif - - SPCR = settings.spcr; - SPSR = settings.spsr; - } - - // Write to the SPI bus (MOSI pin) and also receive (MISO pin) - inline static uint8_t transfer(uint8_t data) { - SPDR = data; - /* - * The following NOP introduces a small delay that can prevent the wait - * loop form iterating when running at the maximum speed. This gives - * about 10% more speed, even if it seems counter-intuitive. At lower - * speeds it is unnoticed. - */ - asm volatile("nop"); - while (!(SPSR & _BV(SPIF))) ; // wait - return SPDR; - } - inline static uint16_t transfer16(uint16_t data) { - union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out; - in.val = data; - if (!(SPCR & _BV(DORD))) { - SPDR = in.msb; - asm volatile("nop"); // See transfer(uint8_t) function - while (!(SPSR & _BV(SPIF))) ; - out.msb = SPDR; - SPDR = in.lsb; - asm volatile("nop"); - while (!(SPSR & _BV(SPIF))) ; - out.lsb = SPDR; - } else { - SPDR = in.lsb; - asm volatile("nop"); - while (!(SPSR & _BV(SPIF))) ; - out.lsb = SPDR; - SPDR = in.msb; - asm volatile("nop"); - while (!(SPSR & _BV(SPIF))) ; - out.msb = SPDR; - } - return out.val; - } - inline static void transfer(void *buf, size_t count) { - if (count == 0) return; - uint8_t *p = (uint8_t *)buf; - SPDR = *p; - while (--count > 0) { - uint8_t out = *(p + 1); - while (!(SPSR & _BV(SPIF))) ; - uint8_t in = SPDR; - SPDR = out; - *p++ = in; - } - while (!(SPSR & _BV(SPIF))) ; - *p = SPDR; - } - // After performing a group of transfers and releasing the chip select - // signal, this function allows others to access the SPI bus - inline static void endTransaction(void) { - #ifdef SPI_TRANSACTION_MISMATCH_LED - if (!inTransactionFlag) { - pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); - digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); - } - inTransactionFlag = 0; - #endif - - if (interruptMode > 0) { - #ifdef SPI_AVR_EIMSK - uint8_t sreg = SREG; - #endif - noInterrupts(); - #ifdef SPI_AVR_EIMSK - if (interruptMode == 1) { - SPI_AVR_EIMSK = interruptSave; - SREG = sreg; - } else - #endif - { - SREG = interruptSave; - } - } - } - - // Disable the SPI bus - static void end(); - - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. - inline static void setBitOrder(uint8_t bitOrder) { - if (bitOrder == LSBFIRST) SPCR |= _BV(DORD); - else SPCR &= ~(_BV(DORD)); - } - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. - inline static void setDataMode(uint8_t dataMode) { - SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode; - } - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. - inline static void setClockDivider(uint8_t clockDiv) { - SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK); - SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK); - } - // These undocumented functions should not be used. SPI.transfer() - // polls the hardware flag which is automatically cleared as the - // AVR responds to SPI's interrupt - inline static void attachInterrupt() { SPCR |= _BV(SPIE); } - inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); } - -private: - static uint8_t initialized; - static uint8_t interruptMode; // 0=none, 1=mask, 2=global - static uint8_t interruptMask; // which interrupts to mask - static uint8_t interruptSave; // temp storage, to restore state - #ifdef SPI_TRANSACTION_MISMATCH_LED - static uint8_t inTransactionFlag; - #endif -}; - -extern SPIClass SPI; - -#endif \ No newline at end of file diff --git a/lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino deleted file mode 100644 index 9d77a426..00000000 --- a/lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino +++ /dev/null @@ -1,143 +0,0 @@ -/* - SCP1000 Barometric Pressure Sensor Display - - Shows the output of a Barometric Pressure Sensor on a - Uses the SPI library. For details on the sensor, see: - http://www.sparkfun.com/commerce/product_info.php?products_id=8161 - http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ - - This sketch adapted from Nathan Seidle's SCP1000 example for PIC: - http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip - - Circuit: - SCP1000 sensor attached to pins 6, 7, 10 - 13: - DRDY: pin 6 - CSB: pin 7 - MOSI: pin 11 - MISO: pin 12 - SCK: pin 13 - - created 31 July 2010 - modified 14 August 2010 - by Tom Igoe - */ - -// the sensor communicates using SPI, so include the library: -#include - -//Sensor's memory register addresses: -const int PRESSURE = 0x1F; //3 most significant bits of pressure -const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure -const int TEMPERATURE = 0x21; //16 bit temperature reading -const byte READ = 0b11111100; // SCP1000's read command -const byte WRITE = 0b00000010; // SCP1000's write command - -// pins used for the connection with the sensor -// the other you need are controlled by the SPI library): -const int dataReadyPin = 6; -const int chipSelectPin = 7; - -void setup() { - Serial.begin(9600); - - // start the SPI library: - SPI.begin(); - - // initalize the data ready and chip select pins: - pinMode(dataReadyPin, INPUT); - pinMode(chipSelectPin, OUTPUT); - - //Configure SCP1000 for low noise configuration: - writeRegister(0x02, 0x2D); - writeRegister(0x01, 0x03); - writeRegister(0x03, 0x02); - // give the sensor time to set up: - delay(100); -} - -void loop() { - //Select High Resolution Mode - writeRegister(0x03, 0x0A); - - // don't do anything until the data ready pin is high: - if (digitalRead(dataReadyPin) == HIGH) { - //Read the temperature data - int tempData = readRegister(0x21, 2); - - // convert the temperature to celsius and display it: - float realTemp = (float)tempData / 20.0; - Serial.print("Temp[C]="); - Serial.print(realTemp); - - - //Read the pressure data highest 3 bits: - byte pressure_data_high = readRegister(0x1F, 1); - pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 - - //Read the pressure data lower 16 bits: - unsigned int pressure_data_low = readRegister(0x20, 2); - //combine the two parts into one 19-bit number: - long pressure = ((pressure_data_high << 16) | pressure_data_low)/4; - - // display the temperature: - Serial.println("\tPressure [Pa]=" + String(pressure)); - } -} - -//Read from or write to register from the SCP1000: -unsigned int readRegister(byte thisRegister, int bytesToRead ) { - byte inByte = 0; // incoming byte from the SPI - unsigned int result = 0; // result to return - Serial.print(thisRegister, BIN); - Serial.print("\t"); - // SCP1000 expects the register name in the upper 6 bits - // of the byte. So shift the bits left by two bits: - thisRegister = thisRegister << 2; - // now combine the address and the command into one byte - byte dataToSend = thisRegister & READ; - Serial.println(thisRegister, BIN); - // take the chip select low to select the device: - digitalWrite(chipSelectPin, LOW); - // send the device the register you want to read: - SPI.transfer(dataToSend); - // send a value of 0 to read the first byte returned: - result = SPI.transfer(0x00); - // decrement the number of bytes left to read: - bytesToRead--; - // if you still have another byte to read: - if (bytesToRead > 0) { - // shift the first byte left, then get the second byte: - result = result << 8; - inByte = SPI.transfer(0x00); - // combine the byte you just got with the previous one: - result = result | inByte; - // decrement the number of bytes left to read: - bytesToRead--; - } - // take the chip select high to de-select: - digitalWrite(chipSelectPin, HIGH); - // return the result: - return(result); -} - - -//Sends a write command to SCP1000 - -void writeRegister(byte thisRegister, byte thisValue) { - - // SCP1000 expects the register address in the upper 6 bits - // of the byte. So shift the bits left by two bits: - thisRegister = thisRegister << 2; - // now combine the register address and the command into one byte: - byte dataToSend = thisRegister | WRITE; - - // take the chip select low to select the device: - digitalWrite(chipSelectPin, LOW); - - SPI.transfer(dataToSend); //Send register location - SPI.transfer(thisValue); //Send value to record into register - - // take the chip select high to de-select: - digitalWrite(chipSelectPin, HIGH); -} - diff --git a/lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor/BarometricPressureSensor.ino b/lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor/BarometricPressureSensor.ino deleted file mode 100644 index 9c9c9b6c..00000000 --- a/lowcar/lib/SPI/examples/BarometricPressureSensor/BarometricPressureSensor/BarometricPressureSensor.ino +++ /dev/null @@ -1,143 +0,0 @@ -/* - SCP1000 Barometric Pressure Sensor Display - - Shows the output of a Barometric Pressure Sensor on a - Uses the SPI library. For details on the sensor, see: - http://www.sparkfun.com/commerce/product_info.php?products_id=8161 - http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ - - This sketch adapted from Nathan Seidle's SCP1000 example for PIC: - http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip - - Circuit: - SCP1000 sensor attached to pins 6, 7, 10 - 13: - DRDY: pin 6 - CSB: pin 7 - MOSI: pin 11 - MISO: pin 12 - SCK: pin 13 - - created 31 July 2010 - modified 14 August 2010 - by Tom Igoe - */ - -// the sensor communicates using SPI, so include the library: -#include - -//Sensor's memory register addresses: -const int PRESSURE = 0x1F; //3 most significant bits of pressure -const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure -const int TEMPERATURE = 0x21; //16 bit temperature reading -cont byte READ = 0b00000000; // SCP1000's read command -const byte WRITE = 0b00000010; // SCP1000's write command -// pins used for the connection with the sensor -// the other you need are controlled by the SPI library): -const int dataReadyPin = 6; -const int chipSelectPin = 7; - -void setup() { - Serial.begin(9600); - - // start the SPI library: - SPI.begin(); - - // initalize the data ready and chip select pins: - pinMode(dataReadyPin, INPUT); - pinMode(chipSelectPin, OUTPUT); - - //Configure SCP1000 for low noise configuration: - writeRegister(0x02, 0x2D); - writeRegister(0x01, 0x03); - writeRegister(0x03, 0x02); - // give the sensor time to set up: - delay(100); -} - -void loop() { - //Select High Resolution Mode - writeRegister(0x03, 0x0A); - - // don't do anything until the data ready pin is high: - if (digitalRead(dataReadyPin) == HIGH) { - //Read the temperature data - int tempData = readRegister(0x21, 2); - - // convert the temperature to celsius and display it: - float realTemp = (float)tempData / 20.0; - Serial.print("Temp[C]="); - Serial.print(realTemp); - - - //Read the pressure data highest 3 bits: - byte pressure_data_high = readRegister(0x1F, 1); - pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 - - //Read the pressure data lower 16 bits: - unsigned int pressure_data_low = readRegister(0x20, 2); - //combine the two parts into one 19-bit number: - long pressure = ((pressure_data_high << 16) | pressure_data_low)/4; - - // display the temperature: - Serial.println("\tPressure [Pa]=" + String(pressure)); - } -} - -//Read from or write to register from the SCP1000: -unsigned int readRegister(byte thisRegister, int bytesToRead ) { - byte inByte = 0; // incoming byte from the SPI - unsigned int result = 0; // result to return - - // SCP1000 expects the register name in the upper 6 bits - // of the byte. So shift the bits left by two bits: - thisRegister = thisRegister << 2; - // now combine the address and the command into one byte - dataToSend = thisRegister & READ; - - // take the chip select low to select the device: - digitalWrite(chipSelectPin, LOW); - // send the device the register you want to read: - SPI.transfer(dataToSend); - // send a value of 0 to read the first byte returned: - result = SPI.transfer(0x00); - // decrement the number of bytes left to read: - bytesToRead--; - // if you still have another byte to read: - if (bytesToRead > 0) { - // shift the first byte left, then get the second byte: - result = result << 8; - inByte = SPI.transfer(0x00); - // combine the byte you just got with the previous one: - result = result | inByte; - // decrement the number of bytes left to read: - bytesToRead--; - } - // take the chip select high to de-select: - digitalWrite(chipSelectPin, HIGH); - // return the result: - return(result); -} - - -//Sends a write command to SCP1000 - -void writeRegister(byte thisRegister, byte thisValue) { - - // SCP1000 expects the register address in the upper 6 bits - // of the byte. So shift the bits left by two bits: - thisRegister = thisRegister << 2; - // now combine the register address and the command into one byte: - dataToSend = thisRegister | WRITE; - - // take the chip select low to select the device: - digitalWrite(chipSelectPin, LOW); - - SPI.transfer(dataToSend); //Send register location - SPI.transfer(thisValue); //Send value to record into register - - // take the chip select high to de-select: - digitalWrite(chipSelectPin, HIGH); -} - - - diff --git a/lowcar/lib/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/lowcar/lib/SPI/examples/DigitalPotControl/DigitalPotControl.ino deleted file mode 100644 index adf93a2c..00000000 --- a/lowcar/lib/SPI/examples/DigitalPotControl/DigitalPotControl.ino +++ /dev/null @@ -1,71 +0,0 @@ -/* - Digital Pot Control - - This example controls an Analog Devices AD5206 digital potentiometer. - The AD5206 has 6 potentiometer channels. Each channel's pins are labeled - A - connect this to voltage - W - this is the pot's wiper, which changes when you set it - B - connect this to ground. - - The AD5206 is SPI-compatible,and to command it, you send two bytes, - one with the channel number (0 - 5) and one with the resistance value for the - channel (0 - 255). - - The circuit: - * All A pins of AD5206 connected to +5V - * All B pins of AD5206 connected to ground - * An LED and a 220-ohm resisor in series connected from each W pin to ground - * CS - to digital pin 10 (SS pin) - * SDI - to digital pin 11 (MOSI pin) - * CLK - to digital pin 13 (SCK pin) - - created 10 Aug 2010 - by Tom Igoe - - Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 - -*/ - - -// inslude the SPI library: -#include - - -// set pin 10 as the slave select for the digital pot: -const int slaveSelectPin = 10; - -void setup() { - // set the slaveSelectPin as an output: - pinMode (slaveSelectPin, OUTPUT); - // initialize SPI: - SPI.begin(); -} - -void loop() { - // go through the six channels of the digital pot: - for (int channel = 0; channel < 6; channel++) { - // change the resistance on this channel from min to max: - for (int level = 0; level < 255; level++) { - digitalPotWrite(channel, level); - delay(10); - } - // wait a second at the top: - delay(100); - // change the resistance on this channel from max to min: - for (int level = 0; level < 255; level++) { - digitalPotWrite(channel, 255 - level); - delay(10); - } - } - -} - -void digitalPotWrite(int address, int value) { - // take the SS pin low to select the chip: - digitalWrite(slaveSelectPin,LOW); - // send in the address and value via SPI: - SPI.transfer(address); - SPI.transfer(value); - // take the SS pin high to de-select the chip: - digitalWrite(slaveSelectPin,HIGH); -} diff --git a/lowcar/lib/SPI/keywords.txt b/lowcar/lib/SPI/keywords.txt deleted file mode 100644 index fa761658..00000000 --- a/lowcar/lib/SPI/keywords.txt +++ /dev/null @@ -1,36 +0,0 @@ -####################################### -# Syntax Coloring Map SPI -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -SPI KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### -begin KEYWORD2 -end KEYWORD2 -transfer KEYWORD2 -setBitOrder KEYWORD2 -setDataMode KEYWORD2 -setClockDivider KEYWORD2 - - -####################################### -# Constants (LITERAL1) -####################################### -SPI_CLOCK_DIV4 LITERAL1 -SPI_CLOCK_DIV16 LITERAL1 -SPI_CLOCK_DIV64 LITERAL1 -SPI_CLOCK_DIV128 LITERAL1 -SPI_CLOCK_DIV2 LITERAL1 -SPI_CLOCK_DIV8 LITERAL1 -SPI_CLOCK_DIV32 LITERAL1 -SPI_CLOCK_DIV64 LITERAL1 -SPI_MODE0 LITERAL1 -SPI_MODE1 LITERAL1 -SPI_MODE2 LITERAL1 -SPI_MODE3 LITERAL1 \ No newline at end of file diff --git a/lowcar/lib/SevenSeg/SevenSeg.cpp b/lowcar/lib/SevenSeg/SevenSeg.cpp deleted file mode 100644 index 2dc12346..00000000 --- a/lowcar/lib/SevenSeg/SevenSeg.cpp +++ /dev/null @@ -1,1391 +0,0 @@ -/* - SevenSeg v.1.0 - SevenSeg.h - Library for controlling a 7-segment display - Created by Sigvald Marholm, 02.06.2015. - - http://sim.marebakken.com/SevenSeg.pdf (This links to a pdf that is a later version of SevenSeg) -*/ - -#include -#include "SevenSeg.h" - -// Constructor -SevenSeg::SevenSeg(int A,int B,int C,int D,int E,int F,int G){ - - // Assume Common Anode (user must change this if false) - setCommonAnode(); - - // Set segment pins - _A=A; - _B=B; - _C=C; - _D=D; - _E=E; - _F=F; - _G=G; - _DP=-1; // DP initially not assigned - - // Set all segment pins as outputs - pinMode(_A, OUTPUT); - pinMode(_B, OUTPUT); - pinMode(_C, OUTPUT); - pinMode(_D, OUTPUT); - pinMode(_E, OUTPUT); - pinMode(_F, OUTPUT); - pinMode(_G, OUTPUT); - - // Assume no digit pins are used (i.e. it's only one hardwired digit) - _numOfDigits=0; - - _colonState=_segOff; // default off - _aposState=_segOff; // default off - _colonSegPin=-1; // -1 when not assigned - _colonSegLPin=-1; // -1 when not assigned - _aposSegPin=-1; // -1 when not assigned - _symbDigPin=-1; // -1 when not assigned - - // When no pins are used you need not multiplex the output and the delay is superfluous - // TBD: Needed for duty cycle control. Add option to differentiate between 0 and 1 digit pins - _digitDelay=0; - _digitOnDelay=0; - _digitOffDelay=0; - _dutyCycle=100; - - // Timer data (default values when no timer is assigned) - _timerDigit=0; - _timerPhase=1; - _timerID=-1; - _timerCounter=0; - _timerCounterOnEnd=0; - _timerCounterOffEnd=0; - - _writeInt=0; - _writePoint=0; -// _writeFloat=0; - _writeStr=0; - _writeMode=' '; - - // Clear display - clearDisp(); -} - -void SevenSeg::setTimer(int timerID){ - -/* - Assigns timer0, timer1 or timer2 solely to the task of multiplexing the display (depending on - the value of timerNumber). - - For an example of a 5 digit display with 100Hz refresh rate and able to resolve duty cycle in - 10%-steps a timing of the following resolution is needed: - - 1/( 100Hz * 5 digits * 0.1 ) = 200us - - It is sufficient, but the brightness should be adjustable to more than 10 values. Hence a - resolution of 16us is selected by setting the prescaler to 64 and the compare register to 3: - - interrupt delay = (64*(3+1))/16MHz = 16us - - The timerCounter variable is of type unsigned int having a maximum value of 65535. Incrementing - this at each interrupt and taking action upon timerCounterOnEnd or timerCounterOffEnd yields - a maximum delay for something to happen: - - max delay for something to happen = 16us * (65535+1) = 1.04s - - which should be more than sufficient if you want to be able to look at your display. -*/ - - _timerID = timerID; - -} - -void SevenSeg::clearTimer(){ - - stopTimer(); - _timerID = -1; - -} - -void SevenSeg::startTimer(){ - - cli(); // Temporarily stop interrupts - - // See registers in ATmega328 datasheet - - if(_timerID==0){ - TCCR0A = 0; - TCCR0B = 0; - TCNT0 = 0; // Initialize counter value to 0 - OCR0A = 3; // Set Compare Match Register to 3 - TCCR0A |= (1< (10^_numOfDigits-1) or num < (-10^_(numOfDigits-1)+1) // Store these values in object during digit pin assignment to save computation? - * Display a positive or negative overload - * - * else display can handle number - * - * num = 2468 // example - * digit_0 = num / (10^(_numOfDigits-1)) // 2 - * digit_1 = (num / (10^(_numOfDigits-2)))%10 // 4 - * i_th_digit = (num / (10^(_numOfDigits-1-i)))%10 // 6 and 8 for i=2 and 3 - * - * IMPROVED: - * num = 2468 // exampmle - * digit_0 = num % 10; - * num /= 10; - * digit_1 = num % 10; - * num /= 10; - * - * FIXED POINT: - * write similar to int, but write fp at correct position. - * num=1234, and fp=0 => 1234 (don't show .) - * num=1234, and fp=1 => 123.4 - * num=1234, and fp=4 => 0.123 (option 1, too unpredictable and heavy) - * num=1234, and fp=4 => 1234 (simply don't show fp as it's invalid) - * - */ - -void SevenSeg::writeClock(int ss){ - - writeClock(ss/60,ss%60); - -} - -void SevenSeg::writeClock(int ss, char c){ - - writeClock(ss/60,ss%60,c); - -} - -void SevenSeg::writeClock(int mm, int ss){ - - // Use ':' if assigned, '.' otherwise, or simply nothing if none assigned - - if(_colonSegPin!=-1){ - writeClock(mm,ss,':'); - } else if(_DP!=-1){ - writeClock(mm,ss,'.'); - } else { - writeClock(mm,ss,'_'); - } - -} - -void SevenSeg::writeClock(int mm, int ss, char c){ - - if(_timerID==-1){ // No timer assigned. MUX once. - - int num = mm*100+ss; - - // colon through symbpin? 1 if yes. - int symbColon = (_symbDigPin!=-1); - - for(int i=_numOfDigits-1;i>=0;i--){ - changeDigit(i); - int nextDigit = num % 10; - writeDigit(nextDigit); // Possible future update: don't write insignificant zeroes - if(c==':' && !symbColon) setColon(); - if((c=='.')&&(i==_numOfDigits-3)) setDP(); // Only set "." in the right place - num /= 10; - execDelay(_digitOnDelay); - if(c==':' && !symbColon) clearColon(); - if(c=='.') clearDP(); - writeDigit(' '); - execDelay(_digitOffDelay); - } - - if(symbColon && c==':'){ - changeDigit('s'); - setColon(); - execDelay(_digitOnDelay); - clearColon(); - execDelay(_digitOffDelay); - } - - } else { - - _writeMode=c; - _writeInt=mm*100+ss; - - } - -} - -void SevenSeg::write(int num,int point){ - write((long int)num, point); -} - -void SevenSeg::write(long int num,int point){ - - if(_timerID==-1){ // No timer assigned. MUX once. - - // Compute the maximum positive and negative numbers possible to display - // (TBD: Move this to a computation done on pin assignments?) - long int maxNegNum=1; - for(int i=1;i<=_numOfDigits-1;i++) maxNegNum*=10; - long int maxPosNum=10*maxNegNum-1; - maxNegNum=-maxNegNum+1; - - // TBD: Change to displaying OL (overload) or ---- or similar? - if(num>maxPosNum) num=maxPosNum; - if(num=0;i--){ - changeDigit(i); - int nextDigit = num % 10L; - if(minus&&i==0) writeDigit('-'); - else writeDigit(nextDigit); // TBD: Possible future update: don't write insignificant zeroes - if(point==i) setDP(); - num /= 10; - execDelay(_digitOnDelay); - writeDigit(' '); - clearDP(); - execDelay(_digitOffDelay); - } -*/ - - for(int i=_numOfDigits-1;i>=0;i--){ - changeDigit(i); - int nextDigit = num % 10L; - if(num || i>point-1 || i==_numOfDigits-1){ - writeDigit(nextDigit); - } else if(minus){ - writeDigit('-'); - minus=0; - } else { - writeDigit(' '); - } - if(point==i) setDP(); - num /= 10; - execDelay(_digitOnDelay); - writeDigit(' '); - clearDP(); - execDelay(_digitOffDelay); - } - - } else { // Use timer - - if(point==0){ // Don't display decimal point if zero decimals used - point=_numOfDigits; // value if-sentence won't trigger on - } else { - point=_numOfDigits-point-1; // Map number of decimal points to digit number - } - - _writeMode = 'p'; // Tell interruptAction that write(int,int) was used (fixed point). - _writeInt = iaLimitInt(num); // Tell interruptAction to write this number ... - _writePoint = point; // ... with this fixed point - } - -} - -// Extracts digit number "digit" from "number" for use with ia - interruptAction -char SevenSeg::iaExtractDigit(long int number, int digit, int point){ - -/* OLD VERSION WITHOU ZERO SUPPRESION (v1.0) - if(number<0){ - if(digit==0) return '-'; - number*=-1; - } - for(int i=0;i<_numOfDigits-digit-1;i++) number/=10L; - return (char)((number%10L)+48L); -*/ - - long int old_number = number; - int minus = 0; - if(number<0){ - number*=-1; - minus = 1; - } - - if(digit!=_numOfDigits-1){ - for(int i=0;i<_numOfDigits-digit-1;i++) number/=10L; - } - - if(digit>point-1 || digit==_numOfDigits-1 || number!=0) return (char)((number%10L)+48L); - else { - if(iaExtractDigit(old_number,digit+1,point)!='-' && iaExtractDigit(old_number,digit+1,point)!=' ' && minus) return '-'; - else return ' '; - } - -// else if(iaExtractDigit(old_number,digit+1,point)=='-' && minus) return '-'; -// else if(iaExtractDigit(old_number,digit+1,point)!=' ' && iaExtractDigit(old_number,digit+1,point)!='-' && minus) return '-'; -// else ' '; -/* - else if(iaExtractDigit(number,digit+1,point)=='0'){ - if(minus) return '-'; - else return ' '; - } else return ' '; - */ - -} - -// Limits integer similar to how it's done in write(int,int) -long int SevenSeg::iaLimitInt(long int number){ - - - // Compute the maximum positive and negative numbers possible to display - // (TBD: Move this to a computation done on pin assignments?) - long int maxNegNum=1; - for(int i=1;i<=_numOfDigits-1;i++) maxNegNum*=10; - long int maxPosNum=10*maxNegNum-1; - maxNegNum=-maxNegNum+1; - - // TBD: Change to displaying OL (overload) or ---- or similar? - if(number>maxPosNum) number=maxPosNum; - if(number=0.5 && num>0) intNum++; - if(remainder<=0.5 && num<0) intNum--; - write(intNum,point); -} - -void SevenSeg::write(double num){ - - // Compute the maximum positive and negative numbers possible to display - // (TBD: Move this to a computation done on pin assignments?) - long int maxNegNum=1; - for(int i=1;i<=_numOfDigits-1;i++) maxNegNum*=10; - long int maxPosNum=10*maxNegNum-1; - maxNegNum=-maxNegNum+1; - - if(num>maxPosNum) num=maxPosNum; - if(num-1){ - while(num*100<=maxPosNum && num*100>=maxNegNum && point<_numOfDigits-2){ - num*=10; - point++; - } - if((int)num==0){ - point++; // The minus sign will disappear - } - } else if(num>0&&num<1){ - while(num*100<=maxPosNum && num*100>=maxNegNum && point<_numOfDigits-1){ - num*=10; - point++; - } - } else { - while(num*10<=maxPosNum && num*10>=maxNegNum){ - num*=10; - point++; - } - } - - // Implementing correct round-off - double rest=num; - if(rest<0) rest*=-1; - rest=rest-(long int)rest; - if(rest>=0.5&&num>0) num++; - if(rest>=0.5&&num<0) num--; - - if(_timerID==-1){ - - write((long int)num,point); - - } else { // user timer - - // Adapting to another format - point=point+1-_numOfDigits; - - _writeMode='f'; - _writePoint=-point; - _writeInt=(long int)num; - - } -} - -void SevenSeg::updDelay(){ - - // On-time for each display is total time spent per digit times the duty cycle. The - // off-time is the rest of the cycle for the given display. - - long int temp = _digitDelay; // Stored into long int since temporary variable gets larger than 32767 - temp *= _dutyCycle; // Multiplication in this way to prevent multiplying two "shorter" ints. - temp /= 100; // Division after multiplication to minimize round-off errors. - _digitOnDelay=temp; - _digitOffDelay=_digitDelay-_digitOnDelay; - - if(_timerID!=-1){ - // Artefacts in duty cycle control appeared when these values changed while interrupts happening (A kind of stepping in brightness appeared) - cli(); - _timerCounterOnEnd=(_digitOnDelay/16)-1; - _timerCounterOffEnd=(_digitOffDelay/16)-1; - if(_digitOnDelay==0) _timerCounterOnEnd=0; - if(_digitOffDelay==0) _timerCounterOffEnd=0; - _timerCounter=0; - sei(); - } -} - -void SevenSeg::interruptAction(){ - - // Increment the library's counter - _timerCounter++; - - // Finished with on-part. Turn off digit, and switch to the off-phase (_timerPhase=0) - if((_timerCounter>=_timerCounterOnEnd)&&(_timerPhase==1)){ - _timerCounter=0; - _timerPhase=0; - - writeDigit(' '); - - // If a write mode using . is used it is reasonable to assume that DP exists. Clear it (eventhough it might not be on this digit). - if(_writeMode=='p'||_writeMode=='.'||_writeMode=='s'||_writeMode=='f') clearDP(); - if(_writeMode==':') clearColon(); - - } - - // Finished with the off-part. Switch to next digit and turn it on. - if((_timerCounter>=_timerCounterOffEnd)&&(_timerPhase==0)){ - _timerCounter=0; - _timerPhase=1; - - _timerDigit++; - - //if(_timerDigit>=_numOfDigits) _timerDigit=0; - if(_timerDigit>=_numOfDigits){ - if(_symbDigPin!=-1 && _timerDigit==_numOfDigits){ // Symbol pin in use. Let _timerDigit=_numOfDigits be used for symbol mux. - } else { // Finished muxing symbol digit, or symbol pin not in use - _timerDigit=0; - } - } - - if(_timerDigit==_numOfDigits) changeDigit('s'); - else changeDigit(_timerDigit); -// writeDigit(_timerDigit); - - if(_writeMode=='p'||_writeMode=='f'){ // Fixed point writing (or float) - writeDigit(iaExtractDigit(_writeInt,_timerDigit,_writePoint)); - if(_writePoint==_timerDigit) setDP(); - } - - if(_writeMode=='i'){ // Fixed point writing - writeDigit(iaExtractDigit(_writeInt,_timerDigit,_numOfDigits)); - } - - if(_writeMode==':'||_writeMode=='.'||_writeMode=='_'){ - - // colon through symbpin? 1 if yes. - int symbColon = (_symbDigPin!=-1); - - if(_timerDigit==_numOfDigits){ // Symbol digit - setColon(); - } else { - writeDigit(iaExtractDigit(_writeInt,_timerDigit,_numOfDigits)); - if(_writeMode==':' && !symbColon) setColon(); - if((_writeMode=='.')&&(_timerDigit==_numOfDigits-3)) setDP(); // Only set "." in the right place - } - - } - - if(_writeMode=='s'){ - - // This algorithm must count to the correct letter i in _writeStr for digit j, since the two may be unmatched - // and it is impossible to know which letter to write without counting - int i=0; // which digit - int j=0; // which digit have it counted to - while(_writeStr[i]!='\0' && j<_timerDigit){ - if(_writeStr[i+1]=='.'){ - i++; - } - i++; - j++; - } - writeDigit(_writeStr[i]); - if(_writeStr[i+1]=='.') setDP(); - - } - - if(_writeMode=='o'){ - - // This algorithm must count to the correct letter i in _writeStr for digit j, since the two may be unmatched - // and it is impossible to know which letter to write without counting - int i=0; // which digit - int j=0; // which digit have it counted to - while(i<_writeStrObj.length() && j<_timerDigit){ - if(_writeStrObj[i+1]=='.'){ - i++; - } - i++; - j++; - } - writeDigit(_writeStrObj[i]); - if(_writeStrObj[i+1]=='.') setDP(); - - } - - } - - -/* - // If we're in the on-part of the cycle and has counted as many interrupts corresponding to one on-phase - if((_timerCounter>=_timerCounterOnEnd) && (_timerPhase==1)){ - _timerCounter=0; // Reset the library's counter - _timerPhase=0; // Switch to off-phase - - // Turn off this digit - writeDigit(' '); - - } - - // Similar for the off-phase. - if((_timerCounter>=_timerCounterOffEnd) && (_timerPhase==0)){ - _timerCounter=0; - _timerPhase=1; - - // Turn on the next digit - _timerDigit++; - if(_timerDigit>=_numOfDigits){ - _timerDigit=0; - } - changeDigit(_timerDigit); - writeDigit(_timerDigit); - - } -*/ -} - -/* -void SevenSeg::setDigitPins(int numOfDigits, int *pDigitPins){ - - if(_numOfDigits>0){ -// delete [] _dig; - free(_dig); - } - - _numOfDigits = numOfDigits; - -// _dig = new int[numOfDigits]; - _dig = (int*)malloc(_numOfDigits * sizeof(int)); - -// memcpy(_dig, pDigitPins, numOfDigits); - for(int i=0;i<_numOfDigits;i++){ - _dig[i]=pDigitPins[i]; - } - -} -*/ -void SevenSeg::changeDigit(int digit){ - - - // Turn off all digits/segments first. - // If you swith on a new digit before turning off the segments you will get - // a slight shine of the "old" number in the "new" digit. - clearDisp(); - digitalWrite(_dig[digit], _digOn); - -} - -void SevenSeg::changeDigit(char digit){ - - if(digit=='s'){ - // change to the symbol digit - clearDisp(); - digitalWrite(_symbDigPin, _digOn); - digitalWrite(_colonSegPin, _colonState); - digitalWrite(_colonSegLPin, _colonState); - digitalWrite(_aposSegPin, _aposState); - } - - if(digit=' '){ - clearDisp(); - } - -} - -void SevenSeg::setDPPin(int DPPin){ - - _DP=DPPin; - pinMode(_DP, OUTPUT); - -} - -void SevenSeg::setDP(){ - - digitalWrite(_DP, _segOn); - -} - -void SevenSeg::clearDP(){ - - digitalWrite(_DP, _segOff); - -} -/* - void setDPPin(int); - void setDP(); - void clearDP(); - -Characters: Colon, apostrophe, comma(DP), randomly assignable symbols? -Most symbols can be confined to one character, but colon should be able to assign in two parts (UC and LC). -Yet two colons are also present on some displays. And on some displays, colons and apostorphes are treated as a separate digit using an additional common cathode/anode. - -I've decided to treat the symbols in the following way - - DP is assigned as an eight segment for each digit, as this is the only way I've seen it done. Simple. - I want the functions setDPPin(int), setDP(), clearDP(). DP should be cleared at each changeDigit (i.e. in ClearDisp?) - In the parsing function it should be possible to write "1.2.3.4.". - - Colon are treated in many different ways on many different displays. I want a function setColonPin() that are overloaded - and take most of the case. setColon() and clearColon() should turn it on or off. I'll explain the scenarios, and the syntax: - - Colon may be split in two parts UC (upper colon) and LC (lower colon) or colon may be hardwired as one LED - - 1. Colon has its own cathodes and anodes. Ground the cathode if common cathode or tie anode to supply in case of common anode. - Syntax: setColonPin(segPin) where segPin is the other pin. In this case the colon needs not be multiplexed. If split segment pin - for UC/LC, the user joins them together. setColon()/clearColon() writes directly to segmentPin. - 2. UC/LC is joined together using its own segment pin, and shares common anode/cathode with one of the digits. - Syntax: setColonPin(segPin,digPin). The function will detect at what digit to type the colon based on digitPin, and store this in colonDigU and - colonDigL. If no digit is tied to digitPin issue an error. colonState is a private member variable being set or cleared by setColon()/clearColon(). - writeDigit() checks colonState when on colonDigU or colonDigL digits and writes accordingly. - 3. UC shares common anode/cathode digit pin with one of the digits, while LC shares with another digit. They are the same segment pin. - Syntax: setColonPin(segPin,digLPin,digUPin). This works in the same way as above, except that different values are stored to DigU and DigL. - 4. UC and LC are treated like seperate segments on a new "symbol" digit pin(!). In these cases there is usually also an apostrophe (A) segment. - The UC and LC segments should be joined together into one segment (C). - Syntax: setSymbolPin(SegCPin,SegAPin,digPin) digPin will be stored to symbDigPin, and the multiplexing must occur over one additional digit. - This implies modification to i.e. setRefreshRate, setDigitDelay and maybe other functions. All functions must be checked. - - Members needed in class: - - private: - colonState ; // _segOn or _segOff. - aposState; // _segOn or _segOff. - colonDigU; // Which digits to activate colon at (one digit for UC and one for LC) - colonDigL; // colonDigU==colonDigL==-1 means that it is treated as a separate digit, case 1 or 4. (check negative numbers for int) - symbDigPin; // If the colon is on a separate digit pin the symbol digit pin number is stored here. Otherwise, it is -1. Non-zero values imply more muxing. - colonSegPin; - aposSegPin; - public: - setColonPin(int); - setColonPin(int,int); - setColonPin(int,int,int); - setSymbPin(int,int,int,int); - setColon(); - clearColon(); - setApos(); - clearApos(); - - The parsing function should parse colon to off except when any colon present in string. Same with apostorphe. I.e. "34:07". I initially wanted to have support for two - colons since you need that on a watch. However, I've settled on only one colon since there are almost none display available with two colons. If I find one, and will - use one, I will simply duplicate the colon stuff in my class. - - Actually, cases 1, 2 and 3 can be joined together! The colon can be turned on irrespective of what digits they are on (at least as long as there are only one colon). - This simplifies the class: - - private: - colonState; // _segOn or _segOff. - aposState; // _segOn or _segOff. - symbDigPin; // If the colon is on a separate digit pin the symbol digit pin number is stored here. Otherwise, it is -1. Non-zero values imply more muxing. - colonSegPin; - aposSegPin; - public: - setColonPin(int); - setSymbPin(int,int,int,int); - setColon(); - clearColon(); - setApos(); - clearApos(); - -*/ - -void SevenSeg::setColonPin(int colonPin){ - _colonSegPin=colonPin; - pinMode(_colonSegPin,OUTPUT); - digitalWrite(_colonSegPin, _colonState); -} - -void SevenSeg::setSymbPins(int digPin, int segUCPin, int segLCPin, int segAPin){ - _colonSegPin=segUCPin; - _colonSegLPin=segLCPin; - _aposSegPin=segAPin; - _symbDigPin=digPin; - pinMode(_colonSegPin,OUTPUT); - pinMode(_colonSegLPin,OUTPUT); - pinMode(_aposSegPin,OUTPUT); - pinMode(_symbDigPin,OUTPUT); - digitalWrite(_colonSegPin, _colonState); - digitalWrite(_colonSegLPin, _colonState); - digitalWrite(_aposSegPin, _aposState); -} - -/* -The functions for setColon(), clearColon(), setApos(), clearApos() directly sets or clears the -segment pins if no symbol pin is assigned. Since no symbol pin is assigned colon (apos isn't set) has -a separate segment pin "Colon" and shares a digit pin with one or two other digits -(in case it is split into UC and LC). In this case it makes sense to control it just like other -segments; by setting and clearing the segment pin with setColon() or clearColon() after the correct -digit is selected with changeDigit(). Compare with setDP()/clearDP(). Furthermore, it is not necessary -to identify WHICH digit the colon segments apply for since, if colon is turned on, one may simply switch -on the segment pin for all digits. Nothing will be tied to the colon segment pin for other digits than -those it applies to, hence it is sufficient to initialize this kind of hardware with setColon(int colonPin). -Sometimes, a colon is present as one or two complete stand-alone LEDs. In this case, the can be wired -up into one of these configurations to work. - -In the other main case, a separate symbol pin is assigned for colon and apostrophe. This is actually an -additional digit pin which must be muxed across. The segment pins are shared with other segments such as -A-G. This is a compact way of allowing many symbols (colon and apostrophe) while only adding one more pin. -This configuration is programmed with setSymbPins(int digPin, int segUCPin, int segLCPin, int segAPin), -where digPin is the symbol digit pin and the other pins are the pins used for segment UC, LC and apos. -If colon is present as one segment only, segUCPin and segULPin can be the same value. Sometimes, colon -and apostorphe are present as stand-alone diodes with their own cathodes and anodes not being connected -to anything else. In this case, join their cathodes or anodes (in case of common cathode or anode respectively) -and connect their other terminal to one segment pin each to make the mentioned configuration. -The behaviour set/clear behaviour of these digits are a bit different in this case. The set/clear-funciton -only sets a flag to on or off. In order to type the characters you must mux to the symbol digit by issuing -changeDigit('s'). This function will light up the appropriate symbols in accordance with the flags. -*/ - -void SevenSeg::setColon(){ - _colonState=_segOn; - if(_symbDigPin==-1){ - digitalWrite(_colonSegPin, _segOn); - } -} - -void SevenSeg::clearColon(){ - _colonState=_segOff; - if(_symbDigPin==-1){ - digitalWrite(_colonSegPin, _segOff); - } -} - -void SevenSeg::setApos(){ - _aposState=_segOn; - if(_symbDigPin==-1){ - digitalWrite(_aposSegPin, _segOn); - } -} - -void SevenSeg::clearApos(){ - _aposState=_segOff; - if(_symbDigPin==-1){ - digitalWrite(_aposSegPin, _segOff); - } -} - -void SevenSeg::writeDigit(int digit){ - - // Turn off all LEDs first to avoid running current through too many LEDs at once. - digitalWrite(_A, _segOff); - digitalWrite(_B, _segOff); - digitalWrite(_C, _segOff); - digitalWrite(_D, _segOff); - digitalWrite(_E, _segOff); - digitalWrite(_F, _segOff); - digitalWrite(_G, _segOff); - - if(digit==1){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - } - - if(digit==2){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_G, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_D, _segOn); - } - - if(digit==3){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_G, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - } - - if(digit==4){ - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - } - - if(digit==5){ - digitalWrite(_A, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - } - - if(digit==6){ - digitalWrite(_A, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit==7){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - } - - if(digit==8){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit==9){ - digitalWrite(_G, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - } - - if(digit==0){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - } - -} - -void SevenSeg::writeDigit(char digit){ - - // Turn off all LEDs first. Run writeDigit(' ') to clear digit. - digitalWrite(_A, _segOff); - digitalWrite(_B, _segOff); - digitalWrite(_C, _segOff); - digitalWrite(_D, _segOff); - digitalWrite(_E, _segOff); - digitalWrite(_F, _segOff); - digitalWrite(_G, _segOff); - - if(digit=='-'){ - digitalWrite(_G, _segOn); - } - - if(digit=='\370'){ // ASCII code 248 or degree symbol: '°' - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - // Digits are numbers. Write with writeDigit(int) - if(digit>=48&&digit<=57) writeDigit(digit-48); - - // Digits are small caps letters. Capitalize. - if(digit>=97&&digit<=122) digit-=32; - - if(digit=='A'){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='B'){ - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='C'){ - digitalWrite(_A, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - } - - if(digit=='D'){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='E'){ - digitalWrite(_A, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='F'){ - digitalWrite(_A, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='G'){ -/* - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_G, _segOn); - // TBD: Really write G like a 9, when it can be written as almost G? -*/ - digitalWrite(_A, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - } - - if(digit=='H'){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='I'){ - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - } - - if(digit=='J'){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - } - - if(digit=='K'){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='L'){ - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - } - - if(digit=='M'){ - digitalWrite(_A, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_E, _segOn); - } - - if(digit=='N'){ - digitalWrite(_C, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='O'){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - } - - if(digit=='P'){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='Q'){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='R'){ - digitalWrite(_E, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='S'){ - digitalWrite(_A, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='T'){ - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='U'){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - } - - if(digit=='V'){ - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - } - - if(digit=='W'){ - digitalWrite(_B, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_F, _segOn); - } - - if(digit=='X'){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='Y'){ - digitalWrite(_B, _segOn); - digitalWrite(_C, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_F, _segOn); - digitalWrite(_G, _segOn); - } - - if(digit=='Z'){ - digitalWrite(_A, _segOn); - digitalWrite(_B, _segOn); - digitalWrite(_D, _segOn); - digitalWrite(_E, _segOn); - digitalWrite(_G, _segOn); - } -} - -void SevenSeg::execDelay(int usec){ - - if(usec!=0){ // delay() and delayMicroseconds() don't handle 0 delay - - if(usec<=16383) delayMicroseconds(usec); // maximum value for delayMicroseconds(); - else delay(usec/1000); - - } - -} diff --git a/lowcar/lib/SevenSeg/SevenSeg.h b/lowcar/lib/SevenSeg/SevenSeg.h deleted file mode 100644 index 64da7840..00000000 --- a/lowcar/lib/SevenSeg/SevenSeg.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - SevenSeg v1.1 - SevenSeg.h - Library for controlling a 7-segment LCD - Created by Sigvald Marholm, 02.06.2015. -*/ - -#ifndef SevenSeg_h -#define SevenSeg_h - -#include "Arduino.h" - -class SevenSeg -{ - - public: - - // Constructor - SevenSeg(int,int,int,int,int,int,int); - - // Low level functions for initializing hardware - void setCommonAnode(); - void setCommonCathode(); - void setDigitPins(int,int *); - void setActivePinState(int,int); - void setDPPin(int); - void setColonPin(int); - void setSymbPins(int,int,int,int); - - // Low level functions for printing to display - void clearDisp(); - void changeDigit(int); - void changeDigit(char); - void writeDigit(int); - void writeDigit(char); - void setDP(); - void clearDP(); - void setColon(); - void clearColon(); - void setApos(); - void clearApos(); - - // Low level functions for controlling multiplexing - void setDigitDelay(long int); // Should I have this function? - void setRefreshRate(int); - void setDutyCycle(int); - - // High level functions for printing to display - void write(long int); - void write(int); - void write(long int,int); - void write(int, int); - void write(char*); - void write(String); - void write(double); - void write(double num, int point); - void writeClock(int,int,char); - void writeClock(int,int); - void writeClock(int,char); - void writeClock(int); - - // Timer control functions - void setTimer(int); - void clearTimer(); - void interruptAction(); - void startTimer(); - void stopTimer(); - - // To clean up -// void setPinState(int); // I think this isn't in use. Its called setActivePinState? -// int getDigitDelay(); // How many get-functions should I make? - - private: - - // The pins for each of the seven segments (eight with decimal point) - int _A; - int _B; - int _C; - int _D; - int _E; - int _F; - int _G; - int _DP; // -1 when decimal point not assigned - - // Variables used for colon and apostrophe symbols - int _colonState; // Whether colon is on (_segOn) or off (_segOff). - int _aposState; // Whether apostorphe is on (_segOn) or off (_segOff). - int _colonSegPin; - int _colonSegLPin; - int _aposSegPin; - int _symbDigPin; - - /* The colon/apostrophe handling needs some further explanation: - * - * colonSegPin is the segment pin for colon. I.e. some displays have a separate segment for colon on one of the digits. - * others have colon split across two digits: i.e. the upper part has a separate segment on one digit, whereas the lower - * part has uses the same segment pin but on another digit. It is assumed that this segment pin is only used for colon, - * and it is stored into colonSegPin by setColonPin(int). The functions setColon() and clearColon() turns on/off this pin, - * respectively. - * - * On some displays, colon is one or two separate free-standing LED(s) with its own cathode and anode. In case of common - * cathode, ground the cathod and treat the anode(s) as a segment pin. The other way around in case of common anode. This - * should make the method described above applicable. - * - * On other displays, the upper colon part, the lower colon part, as well as an apostrophe, shares segments with the usual - * segments (i.e. segments A, B and C) but is treated as a separate symbol digit that must be multiplexed along with the - * other digits. In this case the function setSymbPins(int,int,int,int) is used to assign a pin to that digit, stored in - * symbDigPin. The pin corresponding to the upper colon segment is stored in colonSegPin, whereas the lower colon segment - * is stored in colonSegLPin. aposSegPin holds the segment pin for the apostrophe. symbDigPin being unequal to -1 is an - * indication for multiplexing-related functions that it must multiplex over _numOfDigits+1 digit pins. In this case, the - * setColon(), clearColon(), setApos() and clearApos() does not directly influence the pin, but the variable colonState and - * aposState. In this case, the digit must be changed to the symbol digit by issuing changeDigit('s') in order to show the - * symbols. - */ - - // The pins for each of the digits - int *_dig; - int _numOfDigits; - - // Timing variables. Stored in microseconds. - long int _digitDelay; // How much time spent per display during multiplexing. - long int _digitOnDelay; // How much on-time per display (used for dimming), i.e. it could be on only 40% of digitDelay - long int _digitOffDelay; // digitDelay minus digitOnDelay - int _dutyCycle; // The duty cycle (digitOnDelay/digitDelay, here in percent) - // Strictly speaking, _digitOnDelay and _digitOffDelay holds redundant information, but are stored so the computations only - // needs to be made once. There's an internal update function to update them based on the _digitDelay and _dutyCycle - - void updDelay(); - void execDelay(int); // Executes delay in microseconds - char iaExtractDigit(long int,int,int); - long int iaLimitInt(long int); - - // Sets which values (HIGH or LOW) pins should have to turn on/off segments or digits. - // This depends on whether the display is Common Anode or Common Cathode. - int _digOn; - int _digOff; - int _segOn; - int _segOff; - - // Variables used by interrupt service routine to keep track of stuff - int _timerDigit; // What digit interrupt timer should update next time - int _timerPhase; // What phase of the cycle it is to update, i.e. phase 1 (on), or phase 0 (off). Needed for duty cycling. - int _timerID; // Values 0,1,2 corresponds to using timer0, timer1 or timer2. - long int _timerCounter; // Prescaler of 64 is used since this is available on all timers (0, 1 and 2). - // Timer registers are not sufficiently large. This counter variable will extend upon the original timer. - // and increment by one each time. - long int _timerCounterOnEnd; // How far _timerCounter should count to provide a delay approximately equal to _digitOnDelay - long int _timerCounterOffEnd; // How far _timerCounter should count to provide a delay approximately equal to _digitOffDelay - - // What is to be printed by interruptAction is determined by these variables - long int _writeInt; // Holds the number to be written in case of int, fixed point, or clock - int _writePoint; // Holds the number of digits to use as decimals in case of fixed point -// float _writeFloat; // Holds the float to write in case of float. OBSOLETE: Float are converted to fixed point - char *_writeStr; // Holds a pointer to a string to write in case of string - char _writeMode; // 'p' for fixed point, 'i' for integer, 'f' for float, ':'/'.'/'_' for clock with according divisor symbol - String _writeStrObj; - -}; - -#endif diff --git a/lowcar/lib/SevenSeg/keywords.txt b/lowcar/lib/SevenSeg/keywords.txt deleted file mode 100644 index 4316b10f..00000000 --- a/lowcar/lib/SevenSeg/keywords.txt +++ /dev/null @@ -1,61 +0,0 @@ -####################################### -# SevenSeg v1.1 -# keywords.txt - Syntax Coloring Map -# Sascha Bruechert, 05.02.2015 -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### -SevenSeg KEYWORD1 - - -####################################### -# Methods and Functions (KEYWORD2) -####################################### -digitPins KEYWORD2 -numOfDigits KEYWORD2 - -## Low level functions for initializing hardware -setCommonAnode KEYWORD2 -setCommonCathode KEYWORD2 -setDigitPins KEYWORD2 -setActivePinState KEYWORD2 -setDPPin KEYWORD2 -setColonPin KEYWORD2 -setSymbPins KEYWORD2 - -## Low level functions for printing to display -clearDisp KEYWORD2 -changeDigit KEYWORD2 -writeDigit KEYWORD2 -setDP KEYWORD2 -clearDP KEYWORD2 -setColon KEYWORD2 -clearColon KEYWORD2 -setApos KEYWORD2 -clearApos KEYWORD2 - -## Low level functions for controlling multiplexing -setDigitDelay KEYWORD2 -setRefreshRate KEYWORD2 -setDutyCycle KEYWORD2 - -## High level functions for printing to display -write KEYWORD2 -writeClock KEYWORD2 - -## Timer control functions -setTimer KEYWORD2 -clearTimer KEYWORD2 -startTimer KEYWORD2 -stopTimer KEYWORD2 -interruptAction KEYWORD2 - -####################################### -# Instances (KEYWORD2) -####################################### - -####################################### -# Constants (LITERAL1) -####################################### From 87a8348ecfe3be69299a08ae1393fcd9614a3cbc Mon Sep 17 00:00:00 2001 From: Ben Liao Date: Tue, 1 Aug 2023 12:07:57 -0700 Subject: [PATCH 3/3] [MISC] Small changes to .gitattributes - Ignore everything in lowcar/lib for language stats - Ensure that .h files in lowcar/devices classified as C++ --- .gitattributes | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 8063783f..15f14eca 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,8 @@ # in language profile, ignore third-party libraries used in lowcar -lowcar/lib/* linguist-vendored +lowcar/lib/** linguist-vendored + +# force everything in the lowcar/devices directory to be classified as C++ +lowcar/devices/** linguist-language=C++ # force the Makefile_defs file to be classified as Makefile and be syntax highlighted as Makefile Makefile_defs linguist-language=Makefile \ No newline at end of file