/* * Author: Jon Trulson * Copyright (c) 2015 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #define SM130_DEFAULT_UART 0 #define SM130_DEFAULT_RESET_PIN 13 namespace upm { /** * @brief SM130 RFID Reader Module * @defgroup sm130 libupm-sm130 * @ingroup sparkfun uart gpio rfid */ /** * @library sm130 * @sensor sm130 * @comname RFID Reader * @type rfid * @man sparkfun * @web https://www.sparkfun.com/products/10126 * @con uart gpio * * @brief API for the SM130 RFID Reader Module * * This module defines the SM130 interface for the sm130 RFID library * * This module was developed using an SM130 and a Sparkfun RFID * Evaluation shield using a UART for communications. It should be * fairly trivial to add support for I2C communication in the * future, if you have the correct firmware on the SM130. * * @image html sm130.jpg *
SM130 RFID Reader image provided by SparkFun* under * * CC BY 2.0. * * @snippet sm130.cxx Interesting */ class SM130 { public: // Valid commands typedef enum { CMD_RESET = 0x80, CMD_VERSION = 0x81, CMD_SEEK_TAG = 0x82, CMD_SELECT_TAG = 0x83, CMD_AUTHENTICATE = 0x85, CMD_READ16 = 0x86, CMD_READ_VALUE = 0x87, CMD_WRITE16 = 0x89, CMD_WRITE_VALUE = 0x8a, CMD_WRITE4 = 0x8b, CMD_WRITE_KEY = 0x8c, CMD_INC_VALUE = 0x8d, CMD_DEC_VALUE = 0x8e, CMD_ANTENNA_POWER = 0x90, CMD_READ_PORT = 0x91, CMD_WRITE_PORT = 0x92, CMD_HALT_TAG = 0x93, CMD_SET_BAUD = 0x94, CMD_SLEEP = 0x96 } CMD_T; // valid tag types. typedef enum { TAG_NONE = 0x00, // error/invalid TAG_MIFARE_ULTRALIGHT = 0x01, TAG_MIFARE_1K = 0x02, TAG_MIFARE_4K = 0x03, TAG_UNKNOWN = 0xff } TAG_TYPE_T; // Valid authentication keys typedef enum { KEY_TYPE_EEPROM_A0 = 0x10, KEY_TYPE_EEPROM_A1 = 0x11, KEY_TYPE_EEPROM_A2 = 0x12, KEY_TYPE_EEPROM_A3 = 0x13, KEY_TYPE_EEPROM_A4 = 0x14, KEY_TYPE_EEPROM_A5 = 0x15, KEY_TYPE_EEPROM_A6 = 0x16, KEY_TYPE_EEPROM_A7 = 0x17, KEY_TYPE_EEPROM_A8 = 0x18, KEY_TYPE_EEPROM_A9 = 0x19, KEY_TYPE_EEPROM_A10 = 0x1a, KEY_TYPE_EEPROM_A11 = 0x1b, KEY_TYPE_EEPROM_A12 = 0x1c, KEY_TYPE_EEPROM_A13 = 0x1d, KEY_TYPE_EEPROM_A14 = 0x1e, KEY_TYPE_EEPROM_A15 = 0x1f, KEY_TYPE_EEPROM_B0 = 0x20, KEY_TYPE_EEPROM_B1 = 0x21, KEY_TYPE_EEPROM_B2 = 0x22, KEY_TYPE_EEPROM_B3 = 0x23, KEY_TYPE_EEPROM_B4 = 0x24, KEY_TYPE_EEPROM_B5 = 0x25, KEY_TYPE_EEPROM_B6 = 0x26, KEY_TYPE_EEPROM_B7 = 0x27, KEY_TYPE_EEPROM_B8 = 0x28, KEY_TYPE_EEPROM_B9 = 0x29, KEY_TYPE_EEPROM_B10 = 0x2a, KEY_TYPE_EEPROM_B11 = 0x2b, KEY_TYPE_EEPROM_B12 = 0x2c, KEY_TYPE_EEPROM_B13 = 0x2d, KEY_TYPE_EEPROM_B14 = 0x2e, KEY_TYPE_EEPROM_B15 = 0x2f, KEY_TYPE_A = 0xaa, KEY_TYPE_B = 0xbb, KEY_TYPE_A_AND_TRANSPORT_F = 0xff } KEY_TYPES_T; /** * Instantiates an SM130 object * * @param uart The UART port. Default is 0. * @param reset The Reset pin. Default is 13. */ SM130 (int uart=SM130_DEFAULT_UART, int reset=SM130_DEFAULT_RESET_PIN); /** * SM130 object destructor */ ~SM130 (); /** * Sets the baud rate for the device. The default is 19200. * * @param baud Desired baud rate, default 19200 * @return mraa::Result value */ mraa::Result setBaudRate(int baud=19200); /** * Gets the firmware version string. * * @return The firmware revision */ std::string getFirmwareVersion(); /** * Issues a reset command to the device. * * @return true if successful */ bool reset(); /** * Resets the device using the hardware RESET pin. This is * required if the device has been put to sleep using the sleep() * method. */ void hardwareReset(); /** * Checks to see if a tag is in the RF field, and selects it if * one is present. * * @return true if a tag was detected, false if no tag is present * or an error was detected. */ bool select(); /** * Waits for a tag to enter the RF field for up to 'timeout' * milliseconds. It will call select() every 100ms until 'timeout' * has been exceeded. * * @param timeout The number of milliseconds to wait for a tag to appear * @return true if a tag was detected, false if no tag was * detected within the timeout value, or an error occurred */ bool waitForTag(uint32_t timeout); /** * Set the authentication key for a block. Depending on the * permissions on the tag, the correct key must be authenticated * for that block in order to perform read and write operations. * * @param block The block to authenticate for * @param keyType one of the KEY_TYPE_T values * @param key The 6 byte key to use for Type A and Type B keys * @return true if authentication was successful, false otherwise */ bool authenticate(uint8_t block, KEY_TYPES_T keyType, std::string key=""); /** * Read a 16 byte block. Depending on the tag, authentication of * the block may be required for this method to succeed. * * @param block The block to read * @return The 16 byte block if successful, an empty string otherwise */ std::string readBlock16(uint8_t block); /** * Read a 4 byte value block. Depending on the tag, authentication of * the block may be required for this method to succeed. * * @param block The block to read * @return The 4 byte signed integer value block if successful, 0 otherwise */ int32_t readValueBlock(uint8_t block); /** * Write 16 bytes to a block. Depending on the tag, authentication of * the block may be required for this method to succeed. * * @param block The block to write * @param contents A 16 byte string containing the data to write * @return true if successful, false otherwise */ bool writeBlock16(uint8_t block, std::string contents); /** * Write to a 4 byte value block. Depending on the tag, * authentication of the block may be required for this method to * succeed. * * @param block The block to write * @param value the signed 4 byte integer to write to the value block * @return true if successful, false otherwise */ bool writeValueBlock(uint8_t block, int32_t value); /** * Write 4 bytes to a block. This is typically used for * Ultralight tags. Depending on the tag, authentication of the * block may be required for this method to succeed. * * @param block The block to write * @param contents A 4 byte string containing the data to write * @return true if successful, false otherwise */ bool writeBlock4(uint8_t block, std::string contents); /** * Write a key into one of the 16 EEPROM key slots. This can be a * Type A or Type B key. It is not possible to read these keys * once written. Once stored, the key can be used for * authentication without having to send the key itself. You can * then use the appropriate KEY_TYPE_EEPROM_* keyTypes in a call * to authenticate(). * * @param eepromSector A number between 0 and 15, indicating the * EEPROM sector you want to store the key in * @param keyType Either KEY_TYPE_A or KEY_TYPE_B * @param key The 6 byte key to store in the EEPROM * @return true if successful, false otherwise */ bool writeKey(uint8_t eepromSector, KEY_TYPES_T keyType, std::string key); /** * Increment or decrement a value block. * * @param block The block to adjust * @param value The number to increment or decrement the value block by * @param incr true to increment, false to decrement * @return The contents of the value block after the operation has * completed. */ int32_t adjustValueBlock(uint8_t block, int32_t value, bool incr); /** * Turn the antenna power on or off. The power is on by default * after a reset. If you turn off the antenna, and methods used * for interacting with tags will fail until power is re-enabled. * * @param on true to enable antenna power, false to disable * @return true if successful, false otherwise */ bool setAntennaPower(bool on); /** * Read the status of the 2 onboard GPIO input pins. Bit 0 is for * input 0, bit 1 for input 1. All other bits will be 0. * * @return bitmask of input port status values */ uint8_t readPorts(); /** * Set the output status of the 2 onboard gpio outputs. Bit 0 is for * output 0, bit 1 for output 1. All other bits will be discarded. * * @param val bitmask of output status bits to write * @return true if successful, false otherwise */ bool writePorts(uint8_t val); /** * Halts a tag. Once a tag is halted, it cannot be accessed until * it is removed and reinserted into the RF field and selected. * * @return true if successful, false otherwise */ bool haltTag(); /** * Changes the baud rate of the SM130. WARNING: This is a * potentially dangerous command that could cause you to lose * contact with the device. Once the command is validated and * issued, the host baudrate will be changed to match, and this * method will wait for a response at the new baudrate for up to 1 * second. * * If this response does not arrive, the old baudrate will be * restored, though there is no way to know whether the SM130 * actually succeessfully executed the baudrate change. * * Once the SM130 has changed it's baudrate, the new value will be * stored in it's EEPROM, and any further access to the device * will need to use the new baudrate. This is true even after a * power on reset. * * @param baud The new baud rate to set. Valid values are 9600, * 19200, 38400, 57600, and 115200. * @return true if successful, false otherwise */ bool setSM130BaudRate(int baud); /** * Put the SM130 to sleep. Once the device has been put to sleep, * the only way to wake it is via hardwareReset() or a power * cycle. * * @return true if successful, false otherwise */ bool sleep(); /** * Get the last error that occurred. After a successful * operation, this will be 0. See the datasheet for the various * errors that can occur in various circumstances. * * @return The last error code, or 0 if the last operation succeeded. */ char getLastErrorCode() { return m_lastErrorCode; }; /** * Get the text representation of the last error that occurred. * The returned string is empty if the last operation completed * successfully. * * @return The last error string if an error occurred, or an empty * string if the last operation succeeded. */ std::string getLastErrorString() { return m_lastErrorString; }; /** * Get the UID length of the currently selected tag. * * @return The UID length of the currently selected tag, or 0 if * no tag is currently selected. */ int getUIDLen() { return m_uidLen; }; /** * Get the UID of the currently selected tag. * * @return The UID of the currently selected tag, or an empty string if * no tag is currently selected. */ std::string getUID() { return m_uid; }; /** * Get the tag type of the currently selected tag. * * @return The tag type of the currently selected tag, or TAG_NONE * if no tag is currently selected. */ TAG_TYPE_T getTagType() { return m_tagType; }; /** * Convert the supplied tag type into a human readable string. * * @param tag One of the TAG_TYPE_T values * @return A string representation of the supplied tag type */ std::string tag2String(TAG_TYPE_T tag); /** * This is a convenience function that converts a supplied string * into a space separated hex formatted string. This can be * useful for printing out binary data in a human readable format, * like the UID. * * @param input The string to convert * @return A string representation of the input in space separated * hex values */ std::string string2HexString(std::string input); protected: mraa::Uart m_uart; mraa::Gpio m_gpioReset; std::string sendCommand(CMD_T cmd, std::string data); void initClock(); uint32_t getMillis(); private: int m_uidLen; std::string m_uid; char m_lastErrorCode; std::string m_lastErrorString; TAG_TYPE_T m_tagType; int m_baud; struct timeval m_startTime; void clearError() { m_lastErrorCode = 0; m_lastErrorString.clear(); } }; }