diff --git a/src/m24lr64e/CMakeLists.txt b/src/m24lr64e/CMakeLists.txt index ee9ad3f9..f3d225f2 100644 --- a/src/m24lr64e/CMakeLists.txt +++ b/src/m24lr64e/CMakeLists.txt @@ -1,5 +1,9 @@ -set (libname "m24lr64e") -set (libdescription "upm m24lr64e grove NFC tag") -set (module_src ${libname}.cxx) -set (module_hpp ${libname}.hpp) -upm_module_init() +upm_mixed_module_init (NAME m24lr64e + DESCRIPTION "upm m24lr64esensor module" + C_HDR m24lr64e.h + C_SRC m24lr64e.c + CPP_HDR m24lr64e.hpp + CPP_SRC m24lr64e.cxx + FTI_SRC m24lr64e_fti.c + CPP_WRAPS_C + REQUIRES mraa) diff --git a/src/m24lr64e/m24lr64e.c b/src/m24lr64e/m24lr64e.c new file mode 100644 index 00000000..722ba267 --- /dev/null +++ b/src/m24lr64e/m24lr64e.c @@ -0,0 +1,301 @@ +#include "m24lr64e.h" + +// forward declarations - these were protected methods in original C++ +// code. Might need to expose them? +upm_result_t m24lr64e_eeprom_read_byte(m24lr64e_context dev, + uint32_t address, uint8_t* data); +upm_result_t m24lr64e_eeprom_read_bytes(m24lr64e_context dev, + uint32_t address, + uint8_t* data, int len); +upm_result_t m24lr64e_eeprom_write_byte(m24lr64e_context dev, + uint32_t address, uint8_t data); +upm_result_t m24lr64e_eeprom_write_bytes(m24lr64e_context dev, + uint32_t address, + uint8_t* data, int len); + +m24lr64e_context m24lr64e_init(int bus, m24lr64e_access_mode mode){ + m24lr64e_context dev = + (m24lr64e_context)malloc(sizeof(struct _m24lr64e_context)); + + if (!dev) + return NULL; + + dev->bus = bus; + dev->mode = mode; + + if (dev->mode == M24LR64E_USER_MODE) + dev->address = M24LR64E_DEFAULT_I2C_ADDR; + else + dev->address = M24LR64E_DEFAULT_I2C_ADDR_E2; + + dev->i2c = mraa_i2c_init(dev->bus); + if (mraa_i2c_address(dev->i2c, dev->address) != MRAA_SUCCESS) { + return NULL; + } + + return dev; +} + +void m24lr64e_close(m24lr64e_context dev){ + mraa_i2c_stop(dev->i2c); + free(dev); +} + +upm_result_t m24lr64e_submit_password(m24lr64e_context dev, + uint32_t password){ + // this device actually uses two bytes to address a register + const int pktLen = 11; + uint8_t buf[pktLen]; + + buf[0] = 0x09; + buf[1] = 0x00; + + buf[2] = ((password >> 24) & 0xff); + buf[3] = ((password >> 16) & 0xff); + buf[4] = ((password >> 8) & 0xff); + buf[5] = (password & 0xff); + + buf[6] = 0x09; + + // the password is written twice + buf[7] = ((password >> 24) & 0xff); + buf[8] = ((password >> 16) & 0xff); + buf[9] = ((password >> 8) & 0xff); + buf[10] = (password & 0xff); + + if (mraa_i2c_write(dev->i2c, buf, pktLen) != MRAA_SUCCESS){ + return UPM_ERROR_OPERATION_FAILED; + } + return UPM_SUCCESS; +} + +upm_result_t m24lr64e_write_password(m24lr64e_context dev, uint32_t password){ + const int pktLen = 11; + uint8_t buf[pktLen]; + + buf[0] = 0x09; + buf[1] = 0x00; + + buf[2] = ((password >> 24) & 0xff); + buf[3] = ((password >> 16) & 0xff); + buf[4] = ((password >> 8) & 0xff); + buf[5] = (password & 0xff); + + buf[6] = 0x07; + + // the password is written twice + buf[7] = ((password >> 24) & 0xff); + buf[8] = ((password >> 16) & 0xff); + buf[9] = ((password >> 8) & 0xff); + buf[10] = (password & 0xff); + + if(mraa_i2c_write(dev->i2c, buf, pktLen) != MRAA_SUCCESS){ + return UPM_ERROR_OPERATION_FAILED; + } + return UPM_SUCCESS; +} + +upm_result_t m24lr64e_sector_protect_config(m24lr64e_context dev, + uint32_t sector_number, + bool protect_enable, + sector_access_right access_right, + sector_select_password password){ + if(!protect_enable){ + m24lr64e_write_byte(dev, sector_number, 0x0); + } + else{ + m24lr64e_write_byte(dev, sector_number, + (protect_enable | (access_right << 1) | + (password << 2))); + } + return UPM_SUCCESS; +} + +upm_result_t m24lr64e_clear_sector_protect(m24lr64e_context dev){ + uint8_t buf[64]={0x0}; + return m24lr64e_eeprom_write_bytes(dev, 0, buf, 64); +} + +upm_result_t m24lr64e_sector_write_lock_bit(m24lr64e_context dev, + uint32_t sector_number, + bool sock_enable){ + uint32_t sector_address = M24LR64E_SECTOR_SECURITY_STATUS_BASE_ADDR + + (sector_number/8); + + uint8_t sector_bit = sector_number % 8; + // byte read from the EEPROM into pre_status + uint8_t pre_status; + m24lr64e_eeprom_read_byte(dev, sector_address, &pre_status); + + bool status = (pre_status >> sector_bit) & 0x01; + if(status != sock_enable){ + if(status == true){ + // Call to write byte function + m24lr64e_write_byte(dev, sector_address, pre_status&(~(1<> 8) & 0xff); + buf[1] = (address & 0xff); + buf[2] = data; + + if (mraa_i2c_write(dev->i2c, buf, pkt_len) != MRAA_SUCCESS){ + return UPM_ERROR_OPERATION_FAILED; + } + + upm_delay_us(M24LR64E_I2C_WRITE_TIME*1000); + return UPM_SUCCESS; +} + +upm_result_t m24lr64e_eeprom_write_bytes(m24lr64e_context dev, + uint32_t address, uint8_t* data, + int len){ + uint32_t pkt_len = 2 + len; + uint8_t buf[pkt_len]; + + buf[0] = ((address >> 8) & 0xff); + buf[1] = (address & 0xff); + + int i = 0; + for (i=0; ii2c, buf, pkt_len) != MRAA_SUCCESS){ + return UPM_ERROR_OPERATION_FAILED; + } + upm_delay_us(M24LR64E_I2C_WRITE_TIME*1000); + return UPM_SUCCESS; +} + +upm_result_t m24lr64e_eeprom_read_byte(m24lr64e_context dev, uint32_t address, + uint8_t* data){ + uint32_t pkt_len = 2; + uint8_t buf[pkt_len]; + + buf[0] = ((address >> 8) & 0xff); + buf[1] = (address & 0xff); + + if (mraa_i2c_write(dev->i2c, buf, pkt_len) != MRAA_SUCCESS){ + return UPM_ERROR_OPERATION_FAILED; + } + + pkt_len = 1; + uint8_t abuf[pkt_len]; + abuf[0] = 0; + + if (mraa_i2c_read(dev->i2c, abuf, pkt_len) != pkt_len){ + return UPM_ERROR_OPERATION_FAILED; + } + *data = abuf[0]; + return UPM_SUCCESS; +} + +upm_result_t m24lr64e_eeprom_read_bytes(m24lr64e_context dev, uint32_t address, + uint8_t* data, int len){ + uint32_t pkt_len = 2; + uint8_t buf[pkt_len]; + + buf[0] = ((address >> 8) & 0xff); + buf[1] = (address & 0xff); + + if (mraa_i2c_write(dev->i2c, buf, pkt_len) != MRAA_SUCCESS){ + return UPM_ERROR_OPERATION_FAILED; + } + + if(mraa_i2c_read(dev->i2c, data, len) != len){ + return UPM_ERROR_OPERATION_FAILED; + } + + return UPM_SUCCESS; +} diff --git a/src/m24lr64e/m24lr64e.h b/src/m24lr64e/m24lr64e.h new file mode 100644 index 00000000..f28bad41 --- /dev/null +++ b/src/m24lr64e/m24lr64e.h @@ -0,0 +1,300 @@ +/* + * Author: Jon Trulson + * Abhishek Malik + * Copyright (c) 2016 Intel Corporation. + * + * + * This code was adapted from the Seeed Studio code at: + * https://github.com/Seeed-Studio/NFC_Tag_M24LR6E + * + * Copyright (c) 2014 seeed technology inc. + * Website : www.seeed.cc + * Author : lawliet zou + * Create Time: March 2014 + * + * 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. + */ + +#ifndef M24LR64E_H_ +#define M24LR64E_H_ + +#include "upm.h" +#include "mraa/i2c.h" + +#define M24LR64E_I2C_BUS 0 +#define M24LR64E_DEFAULT_I2C_ADDR 0x53 +#define M24LR64E_DEFAULT_I2C_ADDR_E2 (M24LR64E_DEFAULT_I2C_ADDR | 0x04) + +#define M24LR64E_EEPROM_I2C_LENGTH 8192 +#define M24LR64E_PASSWORD_LENGTH 4 +#define M24LR64E_SECTOR_SECURITY_STATUS_BASE_ADDR 0x800 +#define M24LR64E_LOCK_PROTECT_BIT 0x01 +#define M24LR64E_WRITE_READ_PROTECT_BIT 0x02 +#define M24LR64E_PASSWORD_CTRL_BIT 0x04 + +#define M24LR64E_UID_LENGTH 8 +#define M24LR64E_I2C_WRITE_TIME 5 + +/** + * @brief Grove NFC Tag + * @defgroup m24lr64e libupm-m24lr64e + * @ingroup seeed i2c other + */ + +/** + * @library m24lr64e + * @sensor m24lr64e + * @comname Grove NFC Tag + * @type other + * @man seeed + * @web http://www.seeedstudio.com/wiki/Grove_-_NFC_Tag + * @con i2c + * + * @brief C++ API for the M24LR64E-based Grove NFC Tag + * + * Grove NFC tag is an 8KB electrically erasable programmable read-only memory (EEPROM) + * that can be written to or read from using I2C and NFC-equipped devices. + * + * The user mode (default) allows read and write access to all 8KB + * of space, provided the sector security status (SSS) allows it. + * The root mode allows modification of the SSS data and other + * information, provided the proper password is submitted. The + * default password for a new tag is 0x00000000. See the datasheet + * for more details. + * + * The Seeed Studio* wiki page for this device includes a link to an + * Android* application that can be used to also read and write the + * device via NFC, as well as set NFC passwords, which cannot be + * done via I2C. + * + * @image html m24lr64e.jpg + * @snippet m24lr64e.cxx Interesting + */ + +#include + +typedef enum { + M24LR64E_I2C_PASSWORD_ADDRESS = 2304, + M24LR64E_RF_PASSWORD_1_ADDRESS = 2308, // RF pwds not available in + M24LR64E_RF_PASSWORD_2_ADDRESS = 2312, // I2C access modes + M24LR64E_RF_PASSWORD_3_ADDRESS = 2316, + M24LR64E_DSFID_ADDRESS = 2320, // 1 byte + M24LR64E_AFI_ADDRESS = 2321, // 1 byte + M24LR64E_RESV_ADDRESS = 2322, // 1 bytes + M24LR64E_CONFIG_ADDRESS = 2323, // 1 bytes + M24LR64E_UID_ADDRESS = 2324, // 8 bytes + M24LR64E_MEM_SIZE_ADDRESS = 2332, // 3 bytes + M24LR64E_IC_REF_ADDRESS = 2335, // 1 byte + M24LR64E_PROG_COMP_ENERGY_HARVEST_ADDRESS = 2339 // 1 byte +} M24LR64E_ADDR_T; + +typedef enum { + M24LR64E_USER_MODE = 0x0, // offers simple read/write access right + M24LR64E_ROOT_MODE = 0x1 // offers password change access right +} m24lr64e_access_mode; + +typedef enum { + // ********************************** + // * submit passWd * no submit * + //b2,b1 * Read * Write * Read * Write * + // 00 * 1 1 1 0 * + // 01 * 1 1 1 1 * + // 10 * 1 1 0 0 * + // 11 * 0 1 0 0 * + // ********************************** + m24lr64e_access_1110 = 0, + m24lr64e_access_1111 = 1, + m24lr64e_access_1100 = 2, + m24lr64e_access_0111 = 3, +} sector_access_right; + +typedef enum { + //00 => no passwd protect + //01 => passWd 1 + //10 => passWd 2 + //11 => passwd 3 + m24lr64e_no_password = 0, + m24lr64e_password_1 = 1, + m24lr64e_password_2 = 2, + m24lr64e_password_3 = 3, +} sector_select_password; + +/* + * device context + */ +typedef struct _m24lr64e_context { + mraa_i2c_context i2c; + uint8_t bus; + uint8_t address; + m24lr64e_access_mode mode; +} *m24lr64e_context; + +/** + * M24LR64E Init function + * + * @param bus I2C bus to use + * @param mode Access mode (user or root) to use + */ +m24lr64e_context m24lr64e_init(int bus, m24lr64e_access_mode mode); + +/** + * M24LR64E close function + * + * @param dev void pointer to sensor struct + */ +void m24lr64e_close(m24lr64e_context dev); + +/** + * Submits an I2C access password + * + * @param dev void pointer to sensor struct + * @param passwd 4-byte access password + */ +upm_result_t m24lr64e_submit_password(m24lr64e_context dev, uint32_t password); + +/** + * Writes a new I2C password + * + * @param dev void pointer to sensor struct + * @param passwd 4-byte access password + */ +upm_result_t m24lr64e_write_password(m24lr64e_context dev, uint32_t password); + +/** + * Sets a protection bit for a sector. Must be in the root mode + * + * @param dev void pointer to sensor struct + * @param sectorNumber Sector whose protection you are modifying + * @param protectEnable True if you are enabling protection + * @param accessRight Access rights to set + * @param passwd Password number to enable, if any + */ +upm_result_t m24lr64e_sector_protect_config(m24lr64e_context dev, + uint32_t sector_number, + bool protect_enable, + sector_access_right access_right, + sector_select_password password); + +/** + * Clears sector protection bits. Must be in the root mode. + * + * @param dev void pointer to sensor struct + */ +upm_result_t m24lr64e_clear_sector_protect(m24lr64e_context dev); + +/** + * Sets or clears a sector security status lock bit for a sector. + * Must be in the root mode. + * + * @param dev void pointer to sensor struct + * @param sectorNumber Sector whose SSS you want to modify + * @param sockEnable True to set the bit, false to clear it + */ +upm_result_t m24lr64e_sector_write_lock_bit(m24lr64e_context dev, + uint32_t sector_number, + bool sock_enable); + +/** + * Returns a data storage family identifier (DSFID) + * Must be in the root mode. + * + * @param dev void pointer to sensor struct + * @param dsfid pointer to hold return value + */ +upm_result_t m24lr64e_get_dsfid(m24lr64e_context dev, uint8_t* dsfid); + +/** + * Returns an application family identifier (AFI) + * Must be in the root mode. + * + * @param dev void pointer to sensor struct + * @param afi pointer to hold return value + */ +upm_result_t m24lr64e_get_afi(m24lr64e_context dev, uint8_t* afi); + +/** + * Returns a unique ID. + * Must be in the root mode. + * Maintained to preserve compatibility with older code. + * + * @param dev void pointer to sensor struct + * @param uid pointer to hold return value + */ +upm_result_t m24lr64e_get_uid(m24lr64e_context dev, uint8_t* uid); + +/** + * Returns the memory size + * Must be in the root mode. + * + * @param dev void pointer to sensor struct + * @param memory_size pointer to hold return value + */ +upm_result_t m24lr64e_get_memory_size(m24lr64e_context dev, uint32_t* memory_size); + +/** + * Sets all memory to 0, if permissions allow + * + * @param dev void pointer to sensor struct + */ +upm_result_t m24lr64e_clear_memory(m24lr64e_context dev); + +/** + * Writes a byte to the EEPROM + * + * @param dev void pointer to sensor struct + * @param address Address to write to + * @param data Data to write + */ +upm_result_t m24lr64e_write_byte(m24lr64e_context dev, uint32_t address, + uint8_t data); + +/** + * Writes bytes to the EEPROM + * + * @param dev void pointer to sensor struct + * @param address Address to write to + * @param data Data to write + * @param data Length of the data buffer + */ +upm_result_t m24lr64e_write_bytes(m24lr64e_context dev, uint32_t address, + uint8_t* buffer, int len); + +/** + * Reads a byte from the EEPROM + * + * @param dev void pointer to sensor struct + * @param address Address to read from + * @param data holds return value + */ +upm_result_t m24lr64e_read_byte(m24lr64e_context dev, uint32_t address, + uint8_t* data); + +/** + * Reads multiple bytes from the EEPROM + * + * @param dev void pointer to sensor struct + * @param address Address to read from + * @param buffer Buffer to store data + * @param len Number of bytes to read + */ +upm_result_t m24lr64e_read_bytes(m24lr64e_context dev, uint32_t address, + uint8_t* buffer, int len); + +#endif /* M24LR64E_H_ */ diff --git a/src/m24lr64e/m24lr64e_fti.c b/src/m24lr64e/m24lr64e_fti.c new file mode 100644 index 00000000..eaf3c0d5 --- /dev/null +++ b/src/m24lr64e/m24lr64e_fti.c @@ -0,0 +1,49 @@ +#include "m24lr64e.h" +#include "upm_fti.h" + +/** + * This file implements the Function Table Interface (FTI) for this sensor + */ + +const char upm_m24lr64e_name[] = "M24LR64E"; +const char upm_m24lr64e_description[] = "Grove NFC Tag"; +const upm_protocol_t upm_m24lr64e_protocol[] = {UPM_I2C}; +const upm_sensor_t upm_m24lr64e_category[] = {UPM_NFC}; + +// forward declarations +const void* upm_m24lr64e_get_ft(upm_sensor_t sensor_type); +void* upm_m24lr64e_init_name(); +void upm_m24lr64e_close(void* dev); + +const upm_sensor_descriptor_t upm_m24lr64e_get_descriptor(){ + upm_sensor_descriptor_t usd; + usd.name = upm_m24lr64e_name; + usd.description = upm_m24lr64e_description; + usd.protocol_size = 1; + usd.protocol = upm_m24lr64e_protocol; + usd.category_size = 1; + usd.category = upm_m24lr64e_category; + return usd; +} + +static const upm_sensor_ft ft = +{ + .upm_sensor_init_name = &upm_m24lr64e_init_name, + .upm_sensor_close = &upm_m24lr64e_close, + .upm_sensor_get_descriptor = &upm_m24lr64e_get_descriptor +}; + +const void* upm_m24lr64e_get_ft(upm_sensor_t sensor_type){ + if(sensor_type == UPM_SENSOR){ + return &ft; + } + return NULL; +} + +void* upm_m24lr64e_init_name(){ + return NULL; +} + +void upm_m24lr64e_close(void* dev){ + m24lr64e_close((m24lr64e_context)dev); +}