diff --git a/.gitignore b/.gitignore index 642d602..bb2fc01 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ BUILD compile_commands.json .clangd .cache +MQTT diff --git a/Codigo_ESP32.ino b/Codigo_ESP32.ino new file mode 100644 index 0000000..1e785d8 --- /dev/null +++ b/Codigo_ESP32.ino @@ -0,0 +1,155 @@ +#include +#include + +WiFiClient esp32Client; +PubSubClient mqttClient(esp32Client); + +const char* ssid = "Telecentro-5401"; +const char* password = "Z2NKJZ3WYJFD"; + +char *server = "192.168.0.43"; +int port = 1883; + +int ledpin = 23; // Nuevo pin para el LED +int mqttStatusPin = 21; // Pin para indicar estado MQTT +int messagePin = 19; // Pin para indicar que se recibión un mensaje y se reenvió por UART +int var = 0; + +#define RXD2 16 +#define TXD2 17 + +void wifiInit() { + Serial.print("Conectándose a "); + Serial.print(ssid); + Serial.print("\n"); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + Serial.print("\n"); + Serial.print("Conectado a WiFi"); + Serial.print("\n"); + Serial.print("Dirección IP: "); + Serial.print(WiFi.localIP()); +} + +void callback(char* topic, byte* payload, unsigned int length) { + char payload_string[length + 1]; + memcpy(payload_string, payload, length); + payload_string[length] = '\0'; + + if (strcmp(topic, "ProyectoTranquera/TestMQTT") == 0) { + int resultI = atoi(payload_string); + var = resultI; + } + + Serial.print("Mensaje recibido ["); + Serial.print(topic); + Serial.print("]: "); + Serial.print(payload_string); + Serial.print("\n"); + + // Reenviar el mensaje por UART + Serial2.print(topic); + Serial2.print(":"); + Serial2.print(payload_string); + Serial2.print("\n"); + + digitalWrite(messagePin, HIGH); + digitalWrite(messagePin, LOW); // Hago un pulso cuando envié un mensaje +} + +void reconnect() { + while (!mqttClient.connected()) { + Serial.print("Intentando conectarse MQTT..."); + Serial.print("\n"); + digitalWrite(mqttStatusPin, LOW); // Indicar que está desconectado + + if (mqttClient.connect("ESP32")) { + Serial.print("Conectado"); + Serial.print("\n"); + digitalWrite(mqttStatusPin, HIGH); // Indicar que está conectado + mqttClient.subscribe("ProyectoTranquera/TestMQTT"); + } else { + Serial.print("Fallo, rc="); + Serial.print(mqttClient.state()); + Serial.print(" intentar de nuevo en 5 segundos"); + Serial.print("\n"); + delay(5000); + } + } +} + +void setup() { + pinMode(ledpin, OUTPUT); + pinMode(mqttStatusPin, OUTPUT); // Configurar el pin de estado MQTT como salida + pinMode(messagePin, OUTPUT); // Configurar el pin de mensaje como salida + Serial.begin(115200); + Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2); // Configuración UART2 a 115200 baudios + delay(10); + wifiInit(); + mqttClient.setServer(server, port); + mqttClient.setCallback(callback); + digitalWrite(mqttStatusPin, LOW); // El Pin empieza en LOW + digitalWrite(messagePin, LOW); // El Pin empieza en LOW +} + +void loop() { + if (!mqttClient.connected()) { + reconnect(); + } else { + digitalWrite(mqttStatusPin, HIGH); // Mantener en HIGH si está conectado + } + mqttClient.loop(); + + if (var == 0) { + digitalWrite(ledpin, LOW); + } else if (var == 1) { + digitalWrite(ledpin, HIGH); + } + + if (Serial2.available()) { + String uartMessage = Serial2.readStringUntil('\n'); // Leer mensaje UART + int separatorIndex = uartMessage.indexOf(':'); + + if (separatorIndex != -1) { + String command = uartMessage.substring(0, separatorIndex); + String argument = uartMessage.substring(separatorIndex + 1); + + if (command == "subscribe") { + mqttClient.subscribe(argument.c_str()); + Serial.print("Suscrito a: "); + Serial.print(argument); + Serial.print("\n"); + Serial2.print("subscribed:"); + Serial2.print(argument); + Serial2.print("\n"); + digitalWrite(messagePin, HIGH); + digitalWrite(messagePin, LOW); // Hago un pulso cuando envié un mensaje + } else if (command == "unsubscribe") { + mqttClient.unsubscribe(argument.c_str()); + Serial.print("Desuscrito de: "); + Serial.print(argument); + Serial.print("\n"); + Serial2.print("unsubscribed:"); + Serial2.print(argument); + Serial2.print("\n"); + digitalWrite(messagePin, HIGH); + digitalWrite(messagePin, LOW); // Hago un pulso cuando envié un mensaje + } else { + // Publicar mensaje en MQTT + mqttClient.publish(command.c_str(), argument.c_str()); + Serial.print("Mensaje enviado: "); + Serial.print("\n"); + Serial.print("Tópico: "); + Serial.print(command); + Serial.print(", Mensaje: "); + Serial.print(argument); + Serial.print("\n"); + } + } + } +} diff --git "a/Esquem\303\241tico.pdf" "b/Esquem\303\241tico.pdf" new file mode 100644 index 0000000..5dd03bd Binary files /dev/null and "b/Esquem\303\241tico.pdf" differ diff --git a/Memoria del Trabajo Final del Seminario de Sistemas Embebidos - Villacampa - 102602.pdf b/Memoria del Trabajo Final del Seminario de Sistemas Embebidos - Villacampa - 102602.pdf new file mode 100644 index 0000000..22c19df Binary files /dev/null and b/Memoria del Trabajo Final del Seminario de Sistemas Embebidos - Villacampa - 102602.pdf differ diff --git a/Proyecto_Tranquera.apk b/Proyecto_Tranquera.apk new file mode 100644 index 0000000..47d4dbf Binary files /dev/null and b/Proyecto_Tranquera.apk differ diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..4c2fc99 --- /dev/null +++ b/README.txt @@ -0,0 +1,19 @@ +En este repositorio se encuentra el desarrollo de un proyecto para el control automático de tranqueras +en mangas. Se incluye en este repositorio todo el firmware desarrollado, un esquemático del hardware +usado, un archivo .apk para la instalación de una aplicación movil necesaria para el uso del sistema, +un video demostrativo del funcionamiento, y una memoria del desarrollo del trabajo. + +Realizado entre abril y julio de 2024 por Augusto Villacampa Horta como trabajo final del seminario +de Sistemas Embebidos de la Facultad de Ingeniería de la Universidad de Buenos Aires. + +Link al video demostrativo del funcionamiento: +https://www.youtube.com/watch?v=cxtm0vdYiug + +Consideraciones: + +- En el archivo mbed_app.json se configura el tamaño de los buffers internos de transmisión y + recepción desde la ESP32, es decir los mensajes que llegan por MQTT y otras configuraciones + +- En el archivo global_defines.h se configuran varios parámetros para el funcionamiento del + sistema o de los módulos. En el ultimo caso, en los distintos módulos se verifica si estos + parámetros fueron definidos, y los define si no lo fueron. Esto como medida de seguridad. diff --git a/main.cpp b/main.cpp index 92bb138..1eedc7f 100644 --- a/main.cpp +++ b/main.cpp @@ -1,13 +1,17 @@ //=====[Libraries]============================================================= -#include "smart_home_system.h" +#include "mbed.h" +#include "arm_book_lib.h" + +#include "system.h" //=====[Main function, the program entry point after power on or reset]======== int main() { - smartHomeSystemInit(); + system_init(); while (true) { - smartHomeSystemUpdate(); + system_update(); } -} \ No newline at end of file +} + diff --git a/mbed_app.json b/mbed_app.json index 9cde318..b912825 100644 --- a/mbed_app.json +++ b/mbed_app.json @@ -1,7 +1,11 @@ { "target_overrides": { "*": { - "target.printf_lib": "std" + "platform.stdio-convert-newlines": 1, + "target.printf_lib": "std", + "drivers.uart-serial-rxbuf-size": 1024, + "drivers.uart-serial-txbuf-size": 256 } } -} \ No newline at end of file +} + diff --git a/modules/MFRC522/MFRC522.cpp b/modules/MFRC522/MFRC522.cpp new file mode 100644 index 0000000..7616bd5 --- /dev/null +++ b/modules/MFRC522/MFRC522.cpp @@ -0,0 +1,1160 @@ +/* +* MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. +* _Please_ see the comments in MFRC522.h - they give useful hints and background. +* Released into the public domain. +*/ + +#include "MFRC522.h" +#include "arm_book_lib.h" + +static const char* const _TypeNamePICC[] = +{ + "Unknown type", + "PICC compliant with ISO/IEC 14443-4", + "PICC compliant with ISO/IEC 18092 (NFC)", + "MIFARE Mini, 320 bytes", + "MIFARE 1KB", + "MIFARE 4KB", + "MIFARE Ultralight or Ultralight C", + "MIFARE Plus", + "MIFARE TNP3XXX", + + /* not complete UID */ + "SAK indicates UID is not complete" +}; + +static const char* const _ErrorMessage[] = +{ + "Unknown error", + "Success", + "Error in communication", + "Collision detected", + "Timeout in communication", + "A buffer is not big enough", + "Internal error in the code, should not happen", + "Invalid argument", + "The CRC_A does not match", + "A MIFARE PICC responded with NAK" +}; + +#define MFRC522_MaxPICCs (sizeof(_TypeNamePICC)/sizeof(_TypeNamePICC[0])) +#define MFRC522_MaxError (sizeof(_ErrorMessage)/sizeof(_ErrorMessage[0])) + +void wait_ms(int ms){ + delay(ms); + return; +} + +///////////////////////////////////////////////////////////////////////////////////// +// Functions for setting up the driver +///////////////////////////////////////////////////////////////////////////////////// + +/** + * Constructor. + * Prepares the output pins. + */ +MFRC522::MFRC522(PinName mosi, + PinName miso, + PinName sclk, + PinName cs, + PinName reset) : m_SPI(mosi, miso, sclk), m_CS(cs), m_RESET(reset) +{ + /* Configure SPI bus */ + m_SPI.format(8, 0); + m_SPI.frequency(8000000); + + /* Release SPI-CS pin */ + m_CS = 1; + + /* Release RESET pin */ + m_RESET = 1; +} // End constructor + + +/** + * Destructor. + */ +MFRC522::~MFRC522() +{ + +} + + +///////////////////////////////////////////////////////////////////////////////////// +// 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(uint8_t reg, uint8_t value) +{ + m_CS = 0; /* Select SPI Chip MFRC522 */ + + // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. + (void) m_SPI.write(reg & 0x7E); + (void) m_SPI.write(value); + + m_CS = 1; /* Release SPI Chip MFRC522 */ +} // 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(uint8_t reg, uint8_t count, uint8_t *values) +{ + m_CS = 0; /* Select SPI Chip MFRC522 */ + + // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. + (void) m_SPI.write(reg & 0x7E); + for (uint8_t index = 0; index < count; index++) + { + (void) m_SPI.write(values[index]); + } + + m_CS = 1; /* Release SPI Chip MFRC522 */ +} // 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. + */ +uint8_t MFRC522::PCD_ReadRegister(uint8_t reg) +{ + uint8_t value; + m_CS = 0; /* Select SPI Chip MFRC522 */ + + // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. + (void) m_SPI.write(0x80 | reg); + + // Read the value back. Send 0 to stop reading. + value = m_SPI.write(0); + + m_CS = 1; /* Release SPI Chip MFRC522 */ + + 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(uint8_t reg, uint8_t count, uint8_t *values, uint8_t rxAlign) +{ + if (count == 0) { return; } + + uint8_t address = 0x80 | reg; // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. + uint8_t index = 0; // Index in values array. + + m_CS = 0; /* Select SPI Chip MFRC522 */ + count--; // One read is performed outside of the loop + (void) m_SPI.write(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 + uint8_t mask = 0; + for (uint8_t i = rxAlign; i <= 7; i++) + { + mask |= (1 << i); + } + + // Read value and tell that we want to read the same address again. + uint8_t value = m_SPI.write(address); + + // Apply mask to both current value of values[0] and the new data in value. + values[0] = (values[index] & ~mask) | (value & mask); + } + else + { + // Read value and tell that we want to read the same address again. + values[index] = m_SPI.write(address); + } + + index++; + } + + values[index] = m_SPI.write(0); // Read the final byte. Send 0 to stop reading. + + m_CS = 1; /* Release SPI Chip MFRC522 */ +} // End PCD_ReadRegister() + +/** + * Sets the bits given in mask in register reg. + */ +void MFRC522::PCD_SetRegisterBits(uint8_t reg, uint8_t mask) +{ + uint8_t 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_ClrRegisterBits(uint8_t reg, uint8_t mask) +{ + uint8_t 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. + */ +uint8_t MFRC522::PCD_CalculateCRC(uint8_t *data, uint8_t length, uint8_t *result) +{ + PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. + PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit + PCD_SetRegisterBits(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.73us. + uint16_t i = 5000; + uint8_t 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; + } + } + + // Stop calculating CRC for new content in the FIFO. + PCD_WriteRegister(CommandReg, PCD_Idle); + + // 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() +{ + /* Reset MFRC522 */ + m_RESET = 0; + wait_ms(10); + m_RESET = 1; + + // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74us. Let us be generous: 50ms. + wait_ms(50); + + // 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 25us. + 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_WriteRegister(RFCfgReg, (0x07<<4)); // Set Rx Gain to max + + PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) +} // 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,74us. Let us be generous: 50ms. + wait_ms(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 disabled. + */ +void MFRC522::PCD_AntennaOn() +{ + uint8_t value = PCD_ReadRegister(TxControlReg); + if ((value & 0x03) != 0x03) + { + PCD_WriteRegister(TxControlReg, value | 0x03); + } +} // End PCD_AntennaOn() + +///////////////////////////////////////////////////////////////////////////////////// +// Functions for communicating with PICCs +///////////////////////////////////////////////////////////////////////////////////// + +/** + * Executes the Transceive command. + * CRC validation can only be done if backData and backLen are specified. + */ +uint8_t MFRC522::PCD_TransceiveData(uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData, + uint8_t *backLen, + uint8_t *validBits, + uint8_t rxAlign, + bool checkCRC) +{ + uint8_t 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 commend, waits for completion and transfers data back from the FIFO. + * CRC validation can only be done if backData and backLen are specified. + */ +uint8_t MFRC522::PCD_CommunicateWithPICC(uint8_t command, + uint8_t waitIRq, + uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData, + uint8_t *backLen, + uint8_t *validBits, + uint8_t rxAlign, + bool checkCRC) +{ + uint8_t n, _validBits = 0; + uint32_t i; + + // Prepare values for BitFramingReg + uint8_t txLastBits = validBits ? *validBits : 0; + uint8_t 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_SetRegisterBits(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_SetRegisterBits(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.86us. + 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 condions 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. + uint8_t 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. + uint8_t controlBuffer[2]; + n = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]); + if (n != STATUS_OK) + { + return n; + } + + 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. + */ +uint8_t MFRC522::PICC_RequestA(uint8_t *bufferATQA, uint8_t *bufferSize) +{ + 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. + */ +uint8_t MFRC522::PICC_WakeupA(uint8_t *bufferATQA, uint8_t *bufferSize) +{ + 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. + */ +uint8_t MFRC522::PICC_REQA_or_WUPA(uint8_t command, uint8_t *bufferATQA, uint8_t *bufferSize) +{ + uint8_t validBits; + uint8_t status; + + if (bufferATQA == NULL || *bufferSize < 2) + { // The ATQA response is 2 bytes long. + return STATUS_NO_ROOM; + } + + // ValuesAfterColl=1 => Bits received after collision are cleared. + PCD_ClrRegisterBits(CollReg, 0x80); + + // For REQA and WUPA we need the short frame format + // - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0] + validBits = 7; + + 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. + */ +uint8_t MFRC522::PICC_Select(Uid *uid, uint8_t validBits) +{ + bool uidComplete; + bool selectDone; + bool useCascadeTag; + uint8_t cascadeLevel = 1; + uint8_t result; + uint8_t count; + uint8_t index; + uint8_t uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level. + uint8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. + uint8_t buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A + uint8_t bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. + uint8_t rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. + uint8_t txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. + uint8_t *responseBuffer; + uint8_t 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 is 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 + // ValuesAfterColl=1 => Bits received after collision are cleared. + PCD_ClrRegisterBits(CollReg, 0x80); + + // 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? + if(validBits > (8 * uidIndex)) + { + currentLevelKnownBits = validBits - (8 * uidIndex); + } + else + { + currentLevelKnownBits = 0; + } + + // Copy the known bits from uid->uidByte[] to buffer[] + index = 2; // destination index in buffer[] + if (useCascadeTag) + { + buffer[index++] = PICC_CMD_CT; + } + + uint8_t bytesToCopy = currentLevelKnownBits / 8 + (currentLevelKnownBits % 8 ? 1 : 0); // The number of bytes needed to represent the known bits for this level. + if (bytesToCopy) + { + // Max 4 bytes in each Cascade Level. Only 3 left if we use the Cascade Tag + uint8_t maxBytes = useCascadeTag ? 3 : 4; + 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("SELECT: currentLevelKnownBits="); Serial.println(currentLevelKnownBits, DEC); + buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole bytes + + // Calulate 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("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 seperate 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. + result = PCD_ReadRegister(CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] + if (result & 0x20) + { // CollPosNotValid + return STATUS_COLLISION; // Without a valid collision position we cannot continue + } + + uint8_t collisionPos = result & 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. + */ +uint8_t MFRC522::PICC_HaltA() +{ + uint8_t result; + uint8_t 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) + { + // 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 an success. + result = PCD_TransceiveData(buffer, sizeof(buffer), NULL, 0); + if (result == STATUS_TIMEOUT) + { + result = STATUS_OK; + } + else if (result == STATUS_OK) + { // That is ironically NOT ok in this case ;-) + result = STATUS_ERROR; + } + } + + return result; +} // End PICC_HaltA() + + +///////////////////////////////////////////////////////////////////////////////////// +// Functions for communicating with MIFARE PICCs +///////////////////////////////////////////////////////////////////////////////////// + +/* + * Executes the MFRC522 MFAuthent command. + */ +uint8_t MFRC522::PCD_Authenticate(uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid) +{ + uint8_t i, waitIRq = 0x10; // IdleIRq + + // Build command buffer + uint8_t sendData[12]; + sendData[0] = command; + sendData[1] = blockAddr; + + for (i = 0; i < MF_KEY_SIZE; i++) + { // 6 key bytes + sendData[2+i] = key->keyByte[i]; + } + + for (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_ClrRegisterBits(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. + */ +uint8_t MFRC522::MIFARE_Read(uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize) +{ + uint8_t result = STATUS_NO_ROOM; + + // Sanity check + if ((buffer == NULL) || (*bufferSize < 18)) + { + return result; + } + + // 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. + */ +uint8_t MFRC522::MIFARE_Write(uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize) +{ + uint8_t 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. + uint8_t cmdBuffer[2]; + cmdBuffer[0] = PICC_CMD_MF_WRITE; + cmdBuffer[1] = blockAddr; + // Adds CRC_A and checks that the response is MF_ACK. + result = PCD_MIFARE_Transceive(cmdBuffer, 2); + if (result != STATUS_OK) + { + return result; + } + + // Step 2: Transfer the data + // Adds CRC_A and checks that the response is MF_ACK. + result = PCD_MIFARE_Transceive(buffer, bufferSize); + if (result != STATUS_OK) + { + return result; + } + + return STATUS_OK; +} // End MIFARE_Write() + +/* + * Writes a 4 byte page to the active MIFARE Ultralight PICC. + */ +uint8_t MFRC522::MIFARE_UltralightWrite(uint8_t page, uint8_t *buffer, uint8_t bufferSize) +{ + uint8_t result; + + // Sanity check + if (buffer == NULL || bufferSize < 4) + { + return STATUS_INVALID; + } + + // Build commmand buffer + uint8_t 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. + */ +uint8_t MFRC522::MIFARE_Decrement(uint8_t blockAddr, uint32_t delta) +{ + 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. + */ +uint8_t MFRC522::MIFARE_Increment(uint8_t blockAddr, uint32_t delta) +{ + 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. + */ +uint8_t MFRC522::MIFARE_Restore(uint8_t blockAddr) +{ + // 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. + */ +uint8_t MFRC522::MIFARE_TwoStepHelper(uint8_t command, uint8_t blockAddr, uint32_t data) +{ + uint8_t result; + uint8_t 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; + + // Adds CRC_A and checks that the response is MF_ACK. + result = PCD_MIFARE_Transceive(cmdBuffer, 2); + if (result != STATUS_OK) + { + return result; + } + + // Step 2: Transfer the data + // Adds CRC_A and accept timeout as success. + result = PCD_MIFARE_Transceive((uint8_t *) &data, 4, true); + 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. + */ +uint8_t MFRC522::MIFARE_Transfer(uint8_t blockAddr) +{ + uint8_t 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; + + // Adds CRC_A and checks that the response is MF_ACK. + return PCD_MIFARE_Transceive(cmdBuffer, 2); +} // End MIFARE_Transfer() + + +///////////////////////////////////////////////////////////////////////////////////// +// 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. + */ +uint8_t MFRC522::PCD_MIFARE_Transceive(uint8_t *sendData, uint8_t sendLen, bool acceptTimeout) +{ + uint8_t result; + uint8_t 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[] + uint8_t waitIRq = 0x30; // RxIRq and IdleIRq + uint8_t cmdBufferSize = sizeof(cmdBuffer); + uint8_t 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() + + +/* + * Translates the SAK (Select Acknowledge) to a PICC type. + */ +uint8_t MFRC522::PICC_GetType(uint8_t sak) +{ + uint8_t retType = PICC_TYPE_UNKNOWN; + + if (sak & 0x04) + { // UID not complete + retType = PICC_TYPE_NOT_COMPLETE; + } + else + { + switch (sak) + { + case 0x09: retType = PICC_TYPE_MIFARE_MINI; break; + case 0x08: retType = PICC_TYPE_MIFARE_1K; break; + case 0x18: retType = PICC_TYPE_MIFARE_4K; break; + case 0x00: retType = PICC_TYPE_MIFARE_UL; break; + case 0x10: + case 0x11: retType = PICC_TYPE_MIFARE_PLUS; break; + case 0x01: retType = PICC_TYPE_TNP3XXX; break; + default: + if (sak & 0x20) + { + retType = PICC_TYPE_ISO_14443_4; + } + else if (sak & 0x40) + { + retType = PICC_TYPE_ISO_18092; + } + break; + } + } + + return (retType); +} // End PICC_GetType() + +/* + * Returns a string pointer to the PICC type name. + */ +char* MFRC522::PICC_GetTypeName(uint8_t piccType) +{ + if(piccType == PICC_TYPE_NOT_COMPLETE) + { + piccType = MFRC522_MaxPICCs - 1; + } + + return((char *) _TypeNamePICC[piccType]); +} // End PICC_GetTypeName() + +/* + * Returns a string pointer to a status code name. + */ +char* MFRC522::GetStatusCodeName(uint8_t code) +{ + return((char *) _ErrorMessage[code]); +} // End GetStatusCodeName() + +/* + * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1). + */ +void MFRC522::MIFARE_SetAccessBits(uint8_t *accessBitBuffer, + uint8_t g0, + uint8_t g1, + uint8_t g2, + uint8_t g3) +{ + uint8_t c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2); + uint8_t c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1); + uint8_t 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() + +///////////////////////////////////////////////////////////////////////////////////// +// 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. + */ +bool MFRC522::PICC_IsNewCardPresent(void) +{ + uint8_t bufferATQA[2]; + uint8_t bufferSize = sizeof(bufferATQA); + uint8_t result = PICC_RequestA(bufferATQA, &bufferSize); + return ((result == STATUS_OK) || (result == STATUS_COLLISION)); +} // End PICC_IsNewCardPresent() + +/* + * Simple wrapper around PICC_Select. + */ +bool MFRC522::PICC_ReadCardSerial(void) +{ + uint8_t result = PICC_Select(&uid); + return (result == STATUS_OK); +} // End PICC_ReadCardSerial() diff --git a/modules/MFRC522/MFRC522.h b/modules/MFRC522/MFRC522.h new file mode 100644 index 0000000..a793720 --- /dev/null +++ b/modules/MFRC522/MFRC522.h @@ -0,0 +1,785 @@ +/** + * 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 Soren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) + * Ported to mbed by Martin Olejar, Dec, 2013 + * + * 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.nxp.com/documents/data_sheet/MF1S503x.pdf + * 4K: http://www.nxp.com/documents/data_sheet/MF1S703x.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.nxp.com/documents/data_sheet/MF1S503x.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 chech 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 = 64 bytes. + * Pages 0 + 1 is used for the 7-byte UID. + * Page 2 contains the last chech 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 "mbed.h" + +/** +* MFRC522 example +* +* @code +* #include "mbed.h" +* #include "MFRC522.h" +* +* //KL25Z Pins for MFRC522 SPI interface +* #define SPI_MOSI PTC6 +* #define SPI_MISO PTC7 +* #define SPI_SCLK PTC5 +* #define SPI_CS PTC4 +* // KL25Z Pin for MFRC522 reset +* #define MF_RESET PTC3 +* // KL25Z Pins for Debug UART port +* #define UART_RX PTA1 +* #define UART_TX PTA2 +* +* DigitalOut LedRed (LED_RED); +* DigitalOut LedGreen (LED_GREEN); +* +* Serial DebugUART(UART_TX, UART_RX); +* MFRC522 RfChip (SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS, MF_RESET); +* +* int main(void) { +* // Set debug UART speed +* DebugUART.baud(115200); +* +* // Init. RC522 Chip +* RfChip.PCD_Init(); +* +* while (true) { +* LedRed = 1; +* LedGreen = 1; +* +* // Look for new cards +* if ( ! RfChip.PICC_IsNewCardPresent()) +* { +* wait_ms(500); +* continue; +* } +* +* LedRed = 0; +* +* // Select one of the cards +* if ( ! RfChip.PICC_ReadCardSerial()) +* { +* wait_ms(500); +* continue; +* } +* +* LedRed = 1; +* LedGreen = 0; +* +* // Print Card UID +* printf("Card UID: "); +* for (uint8_t i = 0; i < RfChip.uid.size; i++) +* { +* printf(" %X02", RfChip.uid.uidByte[i]); +* } +* printf("\n\r"); +* +* // Print Card type +* uint8_t piccType = RfChip.PICC_GetType(RfChip.uid.sak); +* printf("PICC Type: %s \n\r", RfChip.PICC_GetTypeName(piccType)); +* wait_ms(1000); +* } +* } +* @endcode +*/ + +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, + TCntValueRegH = 0x2E << 1, // shows the 16-bit timer value + TCntValueRegL = 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 + }; + + // 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 1 + PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 1 + 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.nxp.com/documents/data_sheet/MF1S503x.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. + enum PICC_Type { + PICC_TYPE_UNKNOWN = 0, + PICC_TYPE_ISO_14443_4 = 1, // PICC compliant with ISO/IEC 14443-4 + PICC_TYPE_ISO_18092 = 2, // PICC compliant with ISO/IEC 18092 (NFC) + PICC_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes + PICC_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB + PICC_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB + PICC_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C + PICC_TYPE_MIFARE_PLUS = 7, // MIFARE Plus + PICC_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure + PICC_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete. + }; + + // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. + enum StatusCode { + STATUS_OK = 1, // Success + STATUS_ERROR = 2, // Error in communication + STATUS_COLLISION = 3, // Collision detected + STATUS_TIMEOUT = 4, // Timeout in communication. + STATUS_NO_ROOM = 5, // A buffer is not big enough. + STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-) + STATUS_INVALID = 7, // Invalid argument. + STATUS_CRC_WRONG = 8, // The CRC_A does not match + STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK. + }; + + // A struct used for passing the UID of a PICC. + typedef struct { + uint8_t size; // Number of bytes in the UID. 4, 7 or 10. + uint8_t uidByte[10]; + uint8_t 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 { + uint8_t keyByte[MF_KEY_SIZE]; + } MIFARE_Key; + + // Member variables + Uid uid; // Used by PICC_ReadCardSerial(). + + // Size of the MFRC522 FIFO + static const uint8_t FIFO_SIZE = 64; // The FIFO is 64 bytes. + + /** + * MFRC522 constructor + * + * @param mosi SPI MOSI pin + * @param miso SPI MISO pin + * @param sclk SPI SCLK pin + * @param cs SPI CS pin + * @param reset Reset pin + */ + MFRC522(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset); + + /** + * MFRC522 destructor + */ + ~MFRC522(); + + + // ************************************************************************************ + //! @name Functions for manipulating the MFRC522 + // ************************************************************************************ + //@{ + + /** + * Initializes the MFRC522 chip. + */ + void PCD_Init (void); + + /** + * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. + */ + void PCD_Reset (void); + + /** + * Turns the antenna on by enabling pins TX1 and TX2. + * After a reset these pins disabled. + */ + void PCD_AntennaOn (void); + + /** + * Writes a byte to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to write to. One of the PCD_Register enums. + * @param value The value to write. + */ + void PCD_WriteRegister (uint8_t reg, uint8_t value); + + /** + * Writes a number of bytes to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to write to. One of the PCD_Register enums. + * @param count The number of bytes to write to the register + * @param values The values to write. Byte array. + */ + void PCD_WriteRegister (uint8_t reg, uint8_t count, uint8_t *values); + + /** + * Reads a byte from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to read from. One of the PCD_Register enums. + * @returns Register value + */ + uint8_t PCD_ReadRegister (uint8_t reg); + + /** + * Reads a number of bytes from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to read from. One of the PCD_Register enums. + * @param count The number of bytes to read. + * @param values Byte array to store the values in. + * @param rxAlign Only bit positions rxAlign..7 in values[0] are updated. + */ + void PCD_ReadRegister (uint8_t reg, uint8_t count, uint8_t *values, uint8_t rxAlign = 0); + + /** + * Sets the bits given in mask in register reg. + * + * @param reg The register to update. One of the PCD_Register enums. + * @param mask The bits to set. + */ + void PCD_SetRegisterBits(uint8_t reg, uint8_t mask); + + /** + * Clears the bits given in mask from register reg. + * + * @param reg The register to update. One of the PCD_Register enums. + * @param mask The bits to clear. + */ + void PCD_ClrRegisterBits(uint8_t reg, uint8_t mask); + + /** + * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. + * + * @param data Pointer to the data to transfer to the FIFO for CRC calculation. + * @param length The number of bytes to transfer. + * @param result Pointer to result buffer. Result is written to result[0..1], low byte first. + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_CalculateCRC (uint8_t *data, uint8_t length, uint8_t *result); + + /** + * Executes the Transceive command. + * CRC validation can only be done if backData and backLen are specified. + * + * @param sendData Pointer to the data to transfer to the FIFO. + * @param sendLen Number of bytes to transfer to the FIFO. + * @param backData NULL or pointer to buffer if data should be read back after executing the command. + * @param backLen Max number of bytes to write to *backData. Out: The number of bytes returned. + * @param validBits The number of valid bits in the last byte. 0 for 8 valid bits. Default NULL. + * @param rxAlign Defines the bit position in backData[0] for the first bit received. Default 0. + * @param checkCRC True => The last two bytes of the response is assumed to be a CRC_A that must be validated. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_TransceiveData (uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData, + uint8_t *backLen, + uint8_t *validBits = NULL, + uint8_t rxAlign = 0, + bool checkCRC = false); + + + /** + * Transfers data to the MFRC522 FIFO, executes a commend, waits for completion and transfers data back from the FIFO. + * CRC validation can only be done if backData and backLen are specified. + * + * @param command The command to execute. One of the PCD_Command enums. + * @param waitIRq The bits in the ComIrqReg register that signals successful completion of the command. + * @param sendData Pointer to the data to transfer to the FIFO. + * @param sendLen Number of bytes to transfer to the FIFO. + * @param backData NULL or pointer to buffer if data should be read back after executing the command. + * @param backLen In: Max number of bytes to write to *backData. Out: The number of bytes returned. + * @param validBits In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. + * @param rxAlign In: Defines the bit position in backData[0] for the first bit received. Default 0. + * @param checkCRC In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_CommunicateWithPICC(uint8_t command, + uint8_t waitIRq, + uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData = NULL, + uint8_t *backLen = NULL, + uint8_t *validBits = NULL, + uint8_t rxAlign = 0, + bool checkCRC = false); + + /** + * 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. + * + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_RequestA (uint8_t *bufferATQA, uint8_t *bufferSize); + + /** + * 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. + * + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_WakeupA (uint8_t *bufferATQA, uint8_t *bufferSize); + + /** + * 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. + * + * @param command The command to send - PICC_CMD_REQA or PICC_CMD_WUPA + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_REQA_or_WUPA (uint8_t command, uint8_t *bufferATQA, uint8_t *bufferSize); + + /** + * 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? + * + * + * @param uid Pointer to Uid struct. Normally output, but can also be used to supply a known UID. + * @param validBits The number of known UID bits supplied in *uid. Normally 0. If set you must also supply uid->size. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_Select (Uid *uid, uint8_t validBits = 0); + + /** + * Instructs a PICC in state ACTIVE(*) to go to state HALT. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_HaltA (void); + + // ************************************************************************************ + //@} + + + // ************************************************************************************ + //! @name 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. + * + * @param command PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B + * @param blockAddr The block number. See numbering in the comments in the .h file. + * @param key Pointer to the Crypteo1 key to use (6 bytes) + * @param uid Pointer to Uid struct. The first 4 bytes of the UID is used. + * + * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. + */ + uint8_t PCD_Authenticate (uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid); + + /** + * 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 PCD_StopCrypto1 (void); + + /** + * 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. + * + * @param blockAddr MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. + * @param buffer The buffer to store the data in + * @param bufferSize Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Read (uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize); + + /** + * 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 opretaion 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. + * + * @param blockAddr MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. + * @param buffer The 16 bytes to write to the PICC + * @param bufferSize Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Write (uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize); + + /** + * Writes a 4 byte page to the active MIFARE Ultralight PICC. + * + * @param page The page (2-15) to write to. + * @param buffer The 4 bytes to write to the PICC + * @param bufferSize Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_UltralightWrite(uint8_t page, uint8_t *buffer, uint8_t bufferSize); + + /** + * 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. + * + * @param blockAddr The block (0-0xff) number. + * @param delta This number is subtracted from the value of block blockAddr. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Decrement (uint8_t blockAddr, uint32_t delta); + + /** + * 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. + * + * @param blockAddr The block (0-0xff) number. + * @param delta This number is added to the value of block blockAddr. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Increment (uint8_t blockAddr, uint32_t delta); + + /** + * 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. + * + * @param blockAddr The block (0-0xff) number. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Restore (uint8_t blockAddr); + + /** + * 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]. + * + * @param blockAddr The block (0-0xff) number. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Transfer (uint8_t blockAddr); + + // ************************************************************************************ + //@} + + + // ************************************************************************************ + //! @name 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. + * + * @param sendData Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. + * @param sendLen Number of bytes in sendData. + * @param acceptTimeout True => A timeout is also success + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_MIFARE_Transceive(uint8_t *sendData, uint8_t sendLen, bool acceptTimeout = false); + + /** + * Translates the SAK (Select Acknowledge) to a PICC type. + * + * @param sak The SAK byte returned from PICC_Select(). + * + * @return PICC_Type + */ + uint8_t PICC_GetType (uint8_t sak); + + /** + * Returns a string pointer to the PICC type name. + * + * @param type One of the PICC_Type enums. + * + * @return A string pointer to the PICC type name. + */ + char* PICC_GetTypeName (uint8_t type); + + /** + * Returns a string pointer to a status code name. + * + * @param code One of the StatusCode enums. + * + * @return A string pointer to a status code name. + */ + char* GetStatusCodeName (uint8_t code); + + /** + * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1). + * + * @param accessBitBuffer Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. + * @param g0 Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) + * @param g1 Access bits [C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) + * @param g2 Access bits [C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) + * @param g3 Access bits [C1 C2 C3] for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) + */ + void MIFARE_SetAccessBits (uint8_t *accessBitBuffer, + uint8_t g0, + uint8_t g1, + uint8_t g2, + uint8_t g3); + + // ************************************************************************************ + //@} + + + // ************************************************************************************ + //! @name 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 PICC_IsNewCardPresent(void); + + /** + * 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 PICC_ReadCardSerial (void); + + // ************************************************************************************ + //@} + + +private: + SPI m_SPI; + DigitalOut m_CS; + DigitalOut m_RESET; + + /** + * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. + * + * @param command The command to use + * @param blockAddr The block (0-0xff) number. + * @param data The data to transfer in step 2 + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_TwoStepHelper(uint8_t command, uint8_t blockAddr, uint32_t data); +}; + +#endif diff --git a/modules/MQTT/MQTT.cpp b/modules/MQTT/MQTT.cpp new file mode 100644 index 0000000..3bb606d --- /dev/null +++ b/modules/MQTT/MQTT.cpp @@ -0,0 +1,210 @@ +//=====[Libraries]============================================================= + +#include "MQTT.h" + +//=====[Declaration of private defines]======================================== + +//=====[Declaration of private data types]===================================== + +//=====[Declaration and initialization of public global objects]=============== + +//=====[Declaration of external public global variables]======================= + +//=====[Declaration and initialization of public global variables]============= + +//=====[Declaration and initialization of private global variables]============ + +//=====[Declarations (prototypes) of private functions]======================== + +//=====[Implementations of public functions]=================================== + +//=====[Implementations of private functions]================================== + +//=====[Implementations of public methods]===================================== + +MQTT::MQTT(PinName Tx, PinName Rx, int baudrate, PinName pin_status, PinName pin_led_connected, PinName pin_led_disconnected, PinName pin_led_message): + esp32(Tx, Rx, baudrate), status_in(pin_status, PullDown), led_connected(pin_led_connected), led_message(pin_led_message, OFF), + led_disconnected(pin_led_disconnected), int_MQTT_status(pin_status, PullDown), int_MQTT_mensaje(PIN_MQTT_MENSAJE, PullDown), message_led_delay(MQTT_MESSAGE_RECEIVED_LED_DELAY_TIME_MS, callback(this, &MQTT::delay_callback)) +{ + if(status_in == HIGH){ + MQTT::update_status(CONECTADO); + } + else{ + MQTT::update_status(DESCONECTADO); + } + + this->int_MQTT_status.rise(callback(this, &MQTT::int_MQTT_status_callback_on)); + this->int_MQTT_status.fall(callback(this, &MQTT::int_MQTT_status_callback_off)); + this->int_MQTT_mensaje.fall(callback(this, &MQTT::int_MQTT_mensaje_callback)); +} + +void MQTT::subscribe(const char * topic) +{ + if (!isSubscribed(topic)) { + pendingSubscriptions.push_back(topic); + } +} + +void MQTT::unsubscribe(const char * topic) +{ + pendingUnsubscriptions.push_back(topic); +} + +void MQTT::publish(const char * topic, const char * message) +{ + if(MQTT_status == CONECTADO){ + PendingMessage_t pendingMessage = {topic, message}; + pendingMessages.push_back(pendingMessage); + } +} + +bool MQTT::receive(char* topic, char* message) { + if (!this->esp32.readable()) { + return false; + } + + char buffer[256]; + int index = 0; + char ch = '\0'; + + while (ch != '\n' && index < sizeof(buffer) - 1) { + if (this->esp32.readable()) { + this->esp32.read(&ch, 1); + if (ch != '\n') { + buffer[index++] = ch; + } + } + } + buffer[index] = '\0'; + + char* separator = strchr(buffer, ':'); + if (separator != NULL) { + *separator = '\0'; + strcpy(topic, buffer); + strcpy(message, separator + 1); + } else { + topic[0] = '\0'; + message[0] = '\0'; + } + return true; +} + +MQTT_status_t MQTT::status() +{ + return this->MQTT_status; +} + +bool MQTT::isSubscribed(const char* topic) { + std::string strTopic(topic); + return std::find(subscribedTopics.begin(), subscribedTopics.end(), strTopic) != subscribedTopics.end(); +} + +std::vector MQTT::getSubscribedTopics() { + return subscribedTopics; +} + +void MQTT::processPendings() { + if(this->reset_subscriptions){ + // Move all subscribed topics to pending subscriptions + for (const std::string& topic : subscribedTopics) { + pendingSubscriptions.push_back(topic); + } + subscribedTopics.clear(); + this->reset_subscriptions = false; + } + + // Enviar mensajes de suscripción pendientes + for (const std::string& topic : pendingSubscriptions) { + MQTT::write(subscribe_str, topic.c_str()); + } + // Enviar mensajes de desuscripción pendientes + for (const std::string& topic : pendingUnsubscriptions) { + MQTT::write(unsubscribe_str, topic.c_str()); + } + + /* + // Enviar mensajes pendientes + for (const PendingMessage_t& msg : pendingMessages) { + if(MQTT_status == CONECTADO){ + MQTT::write(msg.topic.c_str(), msg.message.c_str()); + } + } + pendingMessages.clear(); + */ + + // Enviar el mensaje pendiente más antiguo + if (!pendingMessages.empty()) { + const PendingMessage_t& msg = pendingMessages.front(); + if(MQTT_status == CONECTADO){ + MQTT::write(msg.topic.c_str(), msg.message.c_str()); + pendingMessages.erase(pendingMessages.begin()); // Eliminar el mensaje más antiguo + } + } +} + +void MQTT::confirmSubscription(const char* topic) { + std::string confirmedTopic(topic); + auto it = std::find(pendingSubscriptions.begin(), pendingSubscriptions.end(), confirmedTopic); + if (it != pendingSubscriptions.end()) { + pendingSubscriptions.erase(it); + subscribedTopics.push_back(confirmedTopic); + } +} + +void MQTT::confirmUnsubscription(const char* topic) { + std::string confirmedTopic(topic); + auto it = std::find(pendingUnsubscriptions.begin(), pendingUnsubscriptions.end(), confirmedTopic); + if (it != pendingUnsubscriptions.end()) { + pendingUnsubscriptions.erase(it); + subscribedTopics.erase(std::remove(subscribedTopics.begin(), subscribedTopics.end(), confirmedTopic), subscribedTopics.end()); + } +} + +//=====[Implementations of private methods]==================================== + +void MQTT::update_status(MQTT_status_t new_status) +{ + this->MQTT_status = new_status; + switch (MQTT_status){ + case CONECTADO: + this->led_connected = ON; + this->led_disconnected = OFF; + break; + case DESCONECTADO: + this->led_connected = OFF; + this->led_disconnected = ON; + break; + default: + break; + } +} + +void MQTT::int_MQTT_status_callback_on() +{ + MQTT::update_status(CONECTADO); +} + +void MQTT::int_MQTT_status_callback_off() +{ + MQTT::update_status(DESCONECTADO); + this-> reset_subscriptions = true; +} + +void MQTT::int_MQTT_mensaje_callback() +{ + this->led_message = ON; + this->message_led_delay.Start(); +} + +void MQTT::delay_callback() +{ + this->led_message = OFF; +} + +void MQTT::write(const char * topic, const char * message) +{ + this->esp32.write(topic, strlen(topic)); + this->esp32.write(":", 1); + this->esp32.write(message, strlen(message)); + this->esp32.write("\n", 1); +} diff --git a/modules/MQTT/MQTT.h b/modules/MQTT/MQTT.h new file mode 100644 index 0000000..a4e4649 --- /dev/null +++ b/modules/MQTT/MQTT.h @@ -0,0 +1,116 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _MQTT_H_ +#define _MQTT_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" +#include "arm_book_lib.h" + +#include "global_defines.h" +#include "led.h" +#include "non_blocking_delay.h" +#include +#include + +//=====[Declaration of public defines]========================================= + +#ifndef MQTT_MESSAGE_RECEIVED_LED_DELAY_TIME_MS +#define MQTT_MESSAGE_RECEIVED_LED_DELAY_TIME_MS 1000 +#endif + +//=====[Declaration of public data types]====================================== + +typedef enum{ + CONECTADO, + DESCONECTADO +} MQTT_status_t; + +typedef struct { + std::string topic; + std::string message; +} PendingMessage_t; + +//=====[Declaration of public classes]========================================= + +class MQTT +{ + public: + // Crea el objeto + MQTT(PinName Tx, PinName Rx, int baudrate, PinName pin_status, PinName pin_led_connected, PinName pin_led_disconnected, PinName pin_led_message); + + // Se suscribe a un tópico + void subscribe(const char * topic); + + // Se desuscribe a un tópico + void unsubscribe(const char * topic); + + // Envía un mensaje a un tópico + void publish(const char * topic, const char * message); + + // + bool receive(char* topic, char* message); + + // Devuelve el estado de la conexión MQTT + MQTT_status_t status(); + + bool isSubscribed(const char* topic); + + std::vector getSubscribedTopics(); + + void processPendings(); + + void confirmSubscription(const char* topic); + void confirmUnsubscription(const char* topic); + + private: + // Conexión con el módulo esp32 que maneja MQTT + BufferedSerial esp32; + + // Pin que indica el estado de la conexión MQTT + DigitalIn status_in; + + // Led indicativo de que la conexión MQTT está activa + Led led_connected; + + // Led indicativo de que la conexión MQTT está inactiva + Led led_disconnected; + + // Led indicativo de que se recibió un mensaje + Led led_message; + + MQTT_status_t MQTT_status; + + const char * subscribe_str = "subscribe"; + const char * unsubscribe_str = "unsubscribe"; + + InterruptIn int_MQTT_status; + InterruptIn int_MQTT_mensaje; + + nonBlockingDelay message_led_delay; + + std::vector subscribedTopics; + std::vector pendingSubscriptions; + std::vector pendingUnsubscriptions; + std::vector pendingMessages; + + bool reset_subscriptions = false; + + // Actualiza el status de la conexión + void update_status(MQTT_status_t new_status); + + void int_MQTT_status_callback_on(); + void int_MQTT_status_callback_off(); + void int_MQTT_mensaje_callback(); + + void delay_callback(); + + void write(const char * topic, const char * message); +}; + +//=====[Declarations (prototypes) of public functions]========================= + +//=====[#include guards - end]================================================= + +#endif // _MQTT_H_ diff --git a/modules/code/code.cpp b/modules/code/code.cpp deleted file mode 100644 index 818255e..0000000 --- a/modules/code/code.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "code.h" - -#include "user_interface.h" -#include "pc_serial_com.h" -#include "date_and_time.h" -#include "temperature_sensor.h" -#include "gas_sensor.h" -#include "matrix_keypad.h" - -//=====[Declaration of private defines]======================================== - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -//=====[Declaration of external public global variables]======================= - -extern char codeSequenceFromUserInterface[CODE_NUMBER_OF_KEYS]; -extern char codeSequenceFromPcSerialCom[CODE_NUMBER_OF_KEYS]; - -//=====[Declaration and initialization of private global variables]============ - -static int numberOfIncorrectCodes = 0; -static char codeSequence[CODE_NUMBER_OF_KEYS] = { '1', '8', '0', '5' }; - -//=====[Declarations (prototypes) of private functions]======================== - -static bool codeMatch( char* codeToCompare ); -static void codeDeactivate(); - -//=====[Implementations of public functions]=================================== - -void codeWrite( char* newCodeSequence ) -{ - int i; - for (i = 0; i < CODE_NUMBER_OF_KEYS; i++) { - codeSequence[i] = newCodeSequence[i]; - } -} - -bool codeMatchFrom( codeOrigin_t codeOrigin ) -{ - bool codeIsCorrect = false; - switch (codeOrigin) { - case CODE_KEYPAD: - if( userInterfaceCodeCompleteRead() ) { - codeIsCorrect = codeMatch(codeSequenceFromUserInterface); - userInterfaceCodeCompleteWrite(false); - if ( codeIsCorrect ) { - codeDeactivate(); - } else { - incorrectCodeStateWrite(ON); - numberOfIncorrectCodes++; - } - } - - - break; - case CODE_PC_SERIAL: - if( pcSerialComCodeCompleteRead() ) { - codeIsCorrect = codeMatch(codeSequenceFromPcSerialCom); - pcSerialComCodeCompleteWrite(false); - if ( codeIsCorrect ) { - codeDeactivate(); - pcSerialComStringWrite( "\r\nThe code is correct\r\n\r\n" ); - } else { - incorrectCodeStateWrite(ON); - numberOfIncorrectCodes++; - pcSerialComStringWrite( "\r\nThe code is incorrect\r\n\r\n" ); - } - } - - break; - default: - break; - } - - if ( numberOfIncorrectCodes >= 5 ) { - systemBlockedStateWrite(ON); - } - - return codeIsCorrect; -} - -//=====[Implementations of private functions]================================== - -static bool codeMatch( char* codeToCompare ) -{ - int i; - for (i = 0; i < CODE_NUMBER_OF_KEYS; i++) { - if ( codeSequence[i] != codeToCompare[i] ) { - return false; - } - } - return true; -} - -static void codeDeactivate() -{ - systemBlockedStateWrite(OFF); - incorrectCodeStateWrite(OFF); - numberOfIncorrectCodes = 0; -} \ No newline at end of file diff --git a/modules/code/code.h b/modules/code/code.h deleted file mode 100644 index bd1606f..0000000 --- a/modules/code/code.h +++ /dev/null @@ -1,24 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _CODE_H_ -#define _CODE_H_ - -//=====[Declaration of public defines]========================================= - -#define CODE_NUMBER_OF_KEYS 4 - -//=====[Declaration of public data types]====================================== - -typedef enum{ - CODE_KEYPAD, - CODE_PC_SERIAL, -} codeOrigin_t; - -//=====[Declarations (prototypes) of public functions]========================= - -void codeWrite( char* newCodeSequence ); -bool codeMatchFrom( codeOrigin_t codeOrigin ); - -//=====[#include guards - end]================================================= - -#endif // _CODE_H_ \ No newline at end of file diff --git a/modules/date_and_time/date_and_time.cpp b/modules/date_and_time/date_and_time.cpp deleted file mode 100644 index 9f9b197..0000000 --- a/modules/date_and_time/date_and_time.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" - -#include "date_and_time.h" - -//=====[Declaration of private defines]======================================== - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -//=====[Declarations (prototypes) of private functions]======================== - -//=====[Implementations of public functions]=================================== - -char* dateAndTimeRead() -{ - time_t epochSeconds; - epochSeconds = time(NULL); - return ctime(&epochSeconds); -} - -void dateAndTimeWrite( int year, int month, int day, - int hour, int minute, int second ) -{ - struct tm rtcTime; - - rtcTime.tm_year = year - 1900; - rtcTime.tm_mon = month - 1; - rtcTime.tm_mday = day; - rtcTime.tm_hour = hour; - rtcTime.tm_min = minute; - rtcTime.tm_sec = second; - - rtcTime.tm_isdst = -1; - - set_time( mktime( &rtcTime ) ); -} - -//=====[Implementations of private functions]================================== - diff --git a/modules/date_and_time/date_and_time.h b/modules/date_and_time/date_and_time.h deleted file mode 100644 index 17b2ca7..0000000 --- a/modules/date_and_time/date_and_time.h +++ /dev/null @@ -1,19 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _DATE_AND_TIME_H_ -#define _DATE_AND_TIME_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -char* dateAndTimeRead(); - -void dateAndTimeWrite( int year, int month, int day, - int hour, int minute, int second ); - -//=====[#include guards - end]================================================= - -#endif // _DATE_AND_TIME_H_ \ No newline at end of file diff --git a/modules/display/display.cpp b/modules/display/display.cpp deleted file mode 100644 index 7d9a78b..0000000 --- a/modules/display/display.cpp +++ /dev/null @@ -1,226 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" -#include "display.h" - -//=====[Declaration of private defines]======================================== - -#define DISPLAY_IR_CLEAR_DISPLAY 0b00000001 -#define DISPLAY_IR_ENTRY_MODE_SET 0b00000100 -#define DISPLAY_IR_DISPLAY_CONTROL 0b00001000 -#define DISPLAY_IR_FUNCTION_SET 0b00100000 -#define DISPLAY_IR_SET_DDRAM_ADDR 0b10000000 - -#define DISPLAY_IR_ENTRY_MODE_SET_INCREMENT 0b00000010 -#define DISPLAY_IR_ENTRY_MODE_SET_DECREMENT 0b00000000 -#define DISPLAY_IR_ENTRY_MODE_SET_SHIFT 0b00000001 -#define DISPLAY_IR_ENTRY_MODE_SET_NO_SHIFT 0b00000000 - -#define DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_ON 0b00000100 -#define DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_OFF 0b00000000 -#define DISPLAY_IR_DISPLAY_CONTROL_CURSOR_ON 0b00000010 -#define DISPLAY_IR_DISPLAY_CONTROL_CURSOR_OFF 0b00000000 -#define DISPLAY_IR_DISPLAY_CONTROL_BLINK_ON 0b00000001 -#define DISPLAY_IR_DISPLAY_CONTROL_BLINK_OFF 0b00000000 - -#define DISPLAY_IR_FUNCTION_SET_8BITS 0b00010000 -#define DISPLAY_IR_FUNCTION_SET_4BITS 0b00000000 -#define DISPLAY_IR_FUNCTION_SET_2LINES 0b00001000 -#define DISPLAY_IR_FUNCTION_SET_1LINE 0b00000000 -#define DISPLAY_IR_FUNCTION_SET_5x10DOTS 0b00000100 -#define DISPLAY_IR_FUNCTION_SET_5x8DOTS 0b00000000 - -#define DISPLAY_20x4_LINE1_FIRST_CHARACTER_ADDRESS 0 -#define DISPLAY_20x4_LINE2_FIRST_CHARACTER_ADDRESS 64 -#define DISPLAY_20x4_LINE3_FIRST_CHARACTER_ADDRESS 20 -#define DISPLAY_20x4_LINE4_FIRST_CHARACTER_ADDRESS 84 - -#define DISPLAY_RS_INSTRUCTION 0 -#define DISPLAY_RS_DATA 1 - -#define DISPLAY_RW_WRITE 0 -#define DISPLAY_RW_READ 1 - -#define DISPLAY_PIN_RS 4 -#define DISPLAY_PIN_RW 5 -#define DISPLAY_PIN_EN 6 -#define DISPLAY_PIN_D0 7 -#define DISPLAY_PIN_D1 8 -#define DISPLAY_PIN_D2 9 -#define DISPLAY_PIN_D3 10 -#define DISPLAY_PIN_D4 11 -#define DISPLAY_PIN_D5 12 -#define DISPLAY_PIN_D6 13 -#define DISPLAY_PIN_D7 14 - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -DigitalOut displayD0( D0 ); -DigitalOut displayD1( D1 ); -DigitalOut displayD2( D2 ); -DigitalOut displayD3( D3 ); -DigitalOut displayD4( D4 ); -DigitalOut displayD5( D5 ); -DigitalOut displayD6( D6 ); -DigitalOut displayD7( D7 ); -DigitalOut displayRs( D8 ); -DigitalOut displayEn( D9 ); - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -//=====[Declarations (prototypes) of private functions]======================== - -static void displayPinWrite( uint8_t pinName, int value ); -static void displayDataBusWrite( uint8_t dataByte ); -static void displayCodeWrite( bool type, uint8_t dataBus ); - -//=====[Implementations of public functions]=================================== - -void displayInit() -{ - delay( 50 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_FUNCTION_SET | - DISPLAY_IR_FUNCTION_SET_8BITS ); - delay( 5 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_FUNCTION_SET | - DISPLAY_IR_FUNCTION_SET_8BITS ); - delay( 1 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_FUNCTION_SET | - DISPLAY_IR_FUNCTION_SET_8BITS ); - delay( 1 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_FUNCTION_SET | - DISPLAY_IR_FUNCTION_SET_8BITS | - DISPLAY_IR_FUNCTION_SET_2LINES | - DISPLAY_IR_FUNCTION_SET_5x8DOTS ); - delay( 1 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_DISPLAY_CONTROL | - DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_OFF | - DISPLAY_IR_DISPLAY_CONTROL_CURSOR_OFF | - DISPLAY_IR_DISPLAY_CONTROL_BLINK_OFF ); - delay( 1 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_CLEAR_DISPLAY ); - delay( 1 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_ENTRY_MODE_SET | - DISPLAY_IR_ENTRY_MODE_SET_INCREMENT | - DISPLAY_IR_ENTRY_MODE_SET_NO_SHIFT ); - delay( 1 ); - - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_DISPLAY_CONTROL | - DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_ON | - DISPLAY_IR_DISPLAY_CONTROL_CURSOR_OFF | - DISPLAY_IR_DISPLAY_CONTROL_BLINK_OFF ); - delay( 1 ); -} - -void displayCharPositionWrite( uint8_t charPositionX, uint8_t charPositionY ) -{ - switch( charPositionY ) { - case 0: - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_SET_DDRAM_ADDR | - ( DISPLAY_20x4_LINE1_FIRST_CHARACTER_ADDRESS + - charPositionX ) ); - delay( 1 ); - break; - - case 1: - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_SET_DDRAM_ADDR | - ( DISPLAY_20x4_LINE2_FIRST_CHARACTER_ADDRESS + - charPositionX ) ); - delay( 1 ); - break; - - case 2: - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_SET_DDRAM_ADDR | - ( DISPLAY_20x4_LINE3_FIRST_CHARACTER_ADDRESS + - charPositionX ) ); - delay( 1 ); - break; - - case 3: - displayCodeWrite( DISPLAY_RS_INSTRUCTION, - DISPLAY_IR_SET_DDRAM_ADDR | - ( DISPLAY_20x4_LINE4_FIRST_CHARACTER_ADDRESS + - charPositionX ) ); - delay( 1 ); - break; - } -} - -void displayStringWrite( const char * str ) -{ - while (*str) { - displayCodeWrite(DISPLAY_RS_DATA, *str++); - } -} - -//=====[Implementations of private functions]================================== - -static void displayCodeWrite( bool type, uint8_t dataBus ) -{ - if ( type == DISPLAY_RS_INSTRUCTION ) - displayPinWrite( DISPLAY_PIN_RS, DISPLAY_RS_INSTRUCTION); - else - displayPinWrite( DISPLAY_PIN_RS, DISPLAY_RS_DATA); - displayPinWrite( DISPLAY_PIN_RW, DISPLAY_RW_WRITE ); - displayDataBusWrite( dataBus ); -} - -static void displayPinWrite( uint8_t pinName, int value ) -{ - switch( pinName ) { - case DISPLAY_PIN_D0: displayD0 = value; break; - case DISPLAY_PIN_D1: displayD1 = value; break; - case DISPLAY_PIN_D2: displayD2 = value; break; - case DISPLAY_PIN_D3: displayD3 = value; break; - case DISPLAY_PIN_D4: displayD4 = value; break; - case DISPLAY_PIN_D5: displayD5 = value; break; - case DISPLAY_PIN_D6: displayD6 = value; break; - case DISPLAY_PIN_D7: displayD7 = value; break; - case DISPLAY_PIN_RS: displayRs = value; break; - case DISPLAY_PIN_EN: displayEn = value; break; - case DISPLAY_PIN_RW: break; - default: break; - } -} - -static void displayDataBusWrite( uint8_t dataBus ) -{ - displayPinWrite( DISPLAY_PIN_EN, OFF ); - displayPinWrite( DISPLAY_PIN_D7, dataBus & 0b10000000 ); - displayPinWrite( DISPLAY_PIN_D6, dataBus & 0b01000000 ); - displayPinWrite( DISPLAY_PIN_D5, dataBus & 0b00100000 ); - displayPinWrite( DISPLAY_PIN_D4, dataBus & 0b00010000 ); - displayPinWrite( DISPLAY_PIN_D3, dataBus & 0b00001000 ); - displayPinWrite( DISPLAY_PIN_D2, dataBus & 0b00000100 ); - displayPinWrite( DISPLAY_PIN_D1, dataBus & 0b00000010 ); - displayPinWrite( DISPLAY_PIN_D0, dataBus & 0b00000001 ); - displayPinWrite( DISPLAY_PIN_EN, ON ); - delay( 1 ); - displayPinWrite( DISPLAY_PIN_EN, OFF ); - delay( 1 ); -} \ No newline at end of file diff --git a/modules/display/display.h b/modules/display/display.h deleted file mode 100644 index 98c5eb3..0000000 --- a/modules/display/display.h +++ /dev/null @@ -1,20 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _DISPLAY_H_ -#define _DISPLAY_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void displayInit( void ); - -void displayCharPositionWrite( uint8_t charPositionX, uint8_t charPositionY ); - -void displayStringWrite( const char * str ); - -//=====[#include guards - end]================================================= - -#endif // _DISPLAY_H_ \ No newline at end of file diff --git a/modules/event_log/event_log.cpp b/modules/event_log/event_log.cpp deleted file mode 100644 index a363035..0000000 --- a/modules/event_log/event_log.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "event_log.h" - -#include "siren.h" -#include "fire_alarm.h" -#include "user_interface.h" -#include "date_and_time.h" -#include "pc_serial_com.h" - -//=====[Declaration of private defines]======================================== - -//=====[Declaration of private data types]===================================== - -typedef struct systemEvent { - time_t seconds; - char typeOfEvent[EVENT_LOG_NAME_MAX_LENGTH]; -} systemEvent_t; - -//=====[Declaration and initialization of public global objects]=============== - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -static bool sirenLastState = OFF; -static bool gasLastState = OFF; -static bool tempLastState = OFF; -static bool ICLastState = OFF; -static bool SBLastState = OFF; -static int eventsIndex = 0; -static systemEvent_t arrayOfStoredEvents[EVENT_LOG_MAX_STORAGE]; - -//=====[Declarations (prototypes) of private functions]======================== - -static void eventLogElementStateUpdate( bool lastState, - bool currentState, - const char* elementName ); - -//=====[Implementations of public functions]=================================== - -void eventLogUpdate() -{ - bool currentState = sirenStateRead(); - eventLogElementStateUpdate( sirenLastState, currentState, "ALARM" ); - sirenLastState = currentState; - - currentState = gasDetectorStateRead(); - eventLogElementStateUpdate( gasLastState, currentState, "GAS_DET" ); - gasLastState = currentState; - - currentState = overTemperatureDetectorStateRead(); - eventLogElementStateUpdate( tempLastState, currentState, "OVER_TEMP" ); - tempLastState = currentState; - - currentState = incorrectCodeStateRead(); - eventLogElementStateUpdate( ICLastState, currentState, "LED_IC" ); - ICLastState = currentState; - - currentState = systemBlockedStateRead(); - eventLogElementStateUpdate( SBLastState ,currentState, "LED_SB" ); - SBLastState = currentState; -} - -int eventLogNumberOfStoredEvents() -{ - return eventsIndex; -} - -void eventLogRead( int index, char* str ) -{ - str[0] = '\0'; - strcat( str, "Event = " ); - strcat( str, arrayOfStoredEvents[index].typeOfEvent ); - strcat( str, "\r\nDate and Time = " ); - strcat( str, ctime(&arrayOfStoredEvents[index].seconds) ); - strcat( str, "\r\n" ); -} - -void eventLogWrite( bool currentState, const char* elementName ) -{ - char eventAndStateStr[EVENT_LOG_NAME_MAX_LENGTH] = ""; - - strcat( eventAndStateStr, elementName ); - if ( currentState ) { - strcat( eventAndStateStr, "_ON" ); - } else { - strcat( eventAndStateStr, "_OFF" ); - } - - arrayOfStoredEvents[eventsIndex].seconds = time(NULL); - strcpy( arrayOfStoredEvents[eventsIndex].typeOfEvent, eventAndStateStr ); - if ( eventsIndex < EVENT_LOG_MAX_STORAGE -1 ) { - eventsIndex++; - } else { - eventsIndex = 0; - } - - pcSerialComStringWrite(eventAndStateStr); - pcSerialComStringWrite("\r\n"); -} - -//=====[Implementations of private functions]================================== - -static void eventLogElementStateUpdate( bool lastState, - bool currentState, - const char* elementName ) -{ - if ( lastState != currentState ) { - eventLogWrite( currentState, elementName ); - } -} diff --git a/modules/event_log/event_log.h b/modules/event_log/event_log.h deleted file mode 100644 index 4b2a84d..0000000 --- a/modules/event_log/event_log.h +++ /dev/null @@ -1,31 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _EVENT_LOG_H_ -#define _EVENT_LOG_H_ - -//=====[Declaration of public defines]========================================= - -#define EVENT_LOG_MAX_STORAGE 20 -#define EVENT_HEAD_STR_LENGTH 8 -#define EVENT_LOG_NAME_MAX_LENGTH 13 -#define DATE_AND_TIME_STR_LENGTH 18 -#define CTIME_STR_LENGTH 25 -#define NEW_LINE_STR_LENGTH 3 -#define EVENT_STR_LENGTH (EVENT_HEAD_STR_LENGTH + \ - EVENT_LOG_NAME_MAX_LENGTH + \ - DATE_AND_TIME_STR_LENGTH + \ - CTIME_STR_LENGTH + \ - NEW_LINE_STR_LENGTH) - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void eventLogUpdate(); -int eventLogNumberOfStoredEvents(); -void eventLogRead( int index, char* str ); -void eventLogWrite( bool currentState, const char* elementName ); - -//=====[#include guards - end]================================================= - -#endif // _EVENT_LOG_H_ diff --git a/modules/fire_alarm/fire_alarm.cpp b/modules/fire_alarm/fire_alarm.cpp deleted file mode 100644 index b604ff4..0000000 --- a/modules/fire_alarm/fire_alarm.cpp +++ /dev/null @@ -1,149 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "fire_alarm.h" - -#include "siren.h" -#include "strobe_light.h" -#include "user_interface.h" -#include "code.h" -#include "date_and_time.h" -#include "temperature_sensor.h" -#include "gas_sensor.h" -#include "matrix_keypad.h" - -//=====[Declaration of private defines]======================================== - -#define TEMPERATURE_C_LIMIT_ALARM 50.0 -#define STROBE_TIME_GAS 1000 -#define STROBE_TIME_OVER_TEMP 500 -#define STROBE_TIME_GAS_AND_OVER_TEMP 100 - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -DigitalIn alarmTestButton(BUTTON1); - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -static bool gasDetected = OFF; -static bool overTemperatureDetected = OFF; -static bool gasDetectorState = OFF; -static bool overTemperatureDetectorState = OFF; - -//=====[Declarations (prototypes) of private functions]======================== - -static void fireAlarmActivationUpdate(); -static void fireAlarmDeactivationUpdate(); -static void fireAlarmDeactivate(); -static int fireAlarmStrobeTime(); - -//=====[Implementations of public functions]=================================== - -void fireAlarmInit() -{ - temperatureSensorInit(); - gasSensorInit(); - sirenInit(); - strobeLightInit(); - - alarmTestButton.mode(PullDown); -} - -void fireAlarmUpdate() -{ - fireAlarmActivationUpdate(); - fireAlarmDeactivationUpdate(); - sirenUpdate( fireAlarmStrobeTime() ); - strobeLightUpdate( fireAlarmStrobeTime() ); -} - -bool gasDetectorStateRead() -{ - return gasDetectorState; -} - -bool overTemperatureDetectorStateRead() -{ - return overTemperatureDetectorState; -} - -bool gasDetectedRead() -{ - return gasDetected; -} - -bool overTemperatureDetectedRead() -{ - return overTemperatureDetected; -} - -//=====[Implementations of private functions]================================== - -static void fireAlarmActivationUpdate() -{ - temperatureSensorUpdate(); - gasSensorUpdate(); - - overTemperatureDetectorState = temperatureSensorReadCelsius() > - TEMPERATURE_C_LIMIT_ALARM; - - if ( overTemperatureDetectorState ) { - overTemperatureDetected = ON; - sirenStateWrite(ON); - strobeLightStateWrite(ON); - } - - gasDetectorState = !gasSensorRead(); - - if ( gasDetectorState ) { - gasDetected = ON; - sirenStateWrite(ON); - strobeLightStateWrite(ON); - } - - if( alarmTestButton ) { - overTemperatureDetected = ON; - gasDetected = ON; - sirenStateWrite(ON); - strobeLightStateWrite(ON); - } -} - -static void fireAlarmDeactivationUpdate() -{ - if ( sirenStateRead() ) { - if ( codeMatchFrom(CODE_KEYPAD) || - codeMatchFrom(CODE_PC_SERIAL) ) { - fireAlarmDeactivate(); - } - } -} - -static void fireAlarmDeactivate() -{ - sirenStateWrite(OFF); - strobeLightStateWrite(OFF); - overTemperatureDetected = OFF; - gasDetected = OFF; -} - -static int fireAlarmStrobeTime() -{ - if( gasDetectedRead() && overTemperatureDetectedRead() ) { - return STROBE_TIME_GAS_AND_OVER_TEMP; - } else if ( gasDetectedRead() ) { - return STROBE_TIME_GAS; - } else if ( overTemperatureDetectedRead() ) { - return STROBE_TIME_OVER_TEMP; - } else { - return 0; - } -} diff --git a/modules/fire_alarm/fire_alarm.h b/modules/fire_alarm/fire_alarm.h deleted file mode 100644 index ab85d31..0000000 --- a/modules/fire_alarm/fire_alarm.h +++ /dev/null @@ -1,21 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _FIRE_ALARM_H_ -#define _FIRE_ALARM_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void fireAlarmInit(); -void fireAlarmUpdate(); -bool gasDetectorStateRead(); -bool overTemperatureDetectorStateRead(); -bool gasDetectedRead(); -bool overTemperatureDetectedRead(); - -//=====[#include guards - end]================================================= - -#endif // _FIRE_ALARM_H_ \ No newline at end of file diff --git a/modules/global_defines.h b/modules/global_defines.h new file mode 100644 index 0000000..c410988 --- /dev/null +++ b/modules/global_defines.h @@ -0,0 +1,89 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _GLOBAL_DEFINES_H_ +#define _GLOBAL_DEFINES_H_ + +//=====[Declaration of public defines]========================================= + +//---Lista de Placas--- +#define NUCLEO_F429ZI 0 +//--- + +// Placa usada +#define PLACA NUCLEO_F429ZI + +//---Defines para cada placa--- + +//---Defines para NUCLEO_F429ZI--- +#if PLACA == NUCLEO_F429ZI + +#define PC_BAUDRATE 115200 + +#define PIN_TRANQUERA D0 +#define PIN_LED_WIFI_SIN_CONEXION D1 +#define PIN_LED_WIFI_CONECTADO D2 +#define PIN_LED_LECTURA D3 +#define PIN_LED_MODO_NORMAL D4 +#define PIN_LED_MODO_SOLO_LECTURA D5 +#define PIN_LED_MENSAJE_MQTT D6 + +#define PIN_SWITCH_BALANZA D7 +#define PIN_SWITCH_SOLO_LECTURA D8 +#define PIN_BOTON_ABRIR D9 +#define PIN_BOTON_CERRAR D10 + +#define PIN_BALANZA A0 + +#define MODE_PIN_SWITCH_BALANZA PullDown +#define MODE_PIN_SWITCH_SOLO_LECTURA PullDown +#define MODE_PIN_BOTON_ABRIR PullDown +#define MODE_PIN_BOTON_CERRAR PullDown + +#define PIN_RFID_MOSI PF_9 +#define PIN_RFID_MISO PF_8 +#define PIN_RFID_SCLK PF_7 +#define PIN_RFID_RESET PG_1 +#define PIN_RFID_CS PE_3 + +#define PIN_MQTT_TX PC_12 +#define PIN_MQTT_RX PD_2 +#define PIN_MQTT_STATUS PG_3 +#define PIN_MQTT_MENSAJE PG_2 +#define MQTT_BAUDRATE 115200 + +#endif //PLACA +//--- + +//---Defines de Módulos--- +//MQTT.h: +#define MQTT_MESSAGE_RECEIVED_LED_DELAY_TIME_MS 1000 + +//rfid.h: +#define RFID_READ_DELAY_TIME_MS 3000 +//--- + +//---Defines del sistema--- +//Delays: +#define RFID_READ_TRY_DELAY_TIME_MS 250 +//MQTT Topics: + //Para Suscribirme +#define TOPIC_TRANQUERA "ProyectoTranquera/Tranquera" +#define TOPIC_SYSTEM_MODE "ProyectoTranquera/Sistema" + //Para Enviar +#define TOPIC_TRANQUERA_ESTADO "ProyectoTranquera/Tranquera/Estado" +#define TOPIC_RFID_LECTURA "ProyectoTranquera/RFID/Lectura" +#define TOPIC_SYSTEM_MODE_ESTADO "ProyectoTranquera/Sistema/Estado" +//MQTT Messages: +#define MESSAGE_TRANQUERA_ABRIR "1" +#define MESSAGE_TRANQUERA_ABIERTO "1" +#define MESSAGE_TRANQUERA_CERRAR "0" +#define MESSAGE_TRANQUERA_CERRADO "0" +#define MESSAGE_TRANQUERA_PEDIR_ESTADO "PedirEstado" +#define MESSAGE_SYSTEM_MODE "PedirEstado" +#define MESSAGE_SYSTEM_MODE_IDLE "Idle" +#define MESSAGE_SYSTEM_MODE_SOLO_LECTURA "SoloLectura" +//--- + +//=====[#include guards - end]================================================= + +#endif // _GLOBAL_DEFINES_H_ \ No newline at end of file diff --git a/modules/gas_sensor/gas_sensor.cpp b/modules/led/led.cpp similarity index 70% rename from modules/gas_sensor/gas_sensor.cpp rename to modules/led/led.cpp index 3ac4c9e..1c5267a 100644 --- a/modules/gas_sensor/gas_sensor.cpp +++ b/modules/led/led.cpp @@ -1,8 +1,6 @@ //=====[Libraries]============================================================= -#include "mbed.h" - -#include "gas_sensor.h" +#include "led.h" //=====[Declaration of private defines]======================================== @@ -10,8 +8,6 @@ //=====[Declaration and initialization of public global objects]=============== -DigitalIn mq2(PE_12); - //=====[Declaration of external public global variables]======================= //=====[Declaration and initialization of public global variables]============= @@ -22,17 +18,27 @@ DigitalIn mq2(PE_12); //=====[Implementations of public functions]=================================== -void gasSensorInit() +//=====[Implementations of private functions]================================== + +//=====[Implementations of public methods]===================================== + +Led::Led(PinName pin): DO(pin, OFF) { } -void gasSensorUpdate() +Led::Led(PinName pin, int value): DO(pin, value) { } -bool gasSensorRead() +void Led::write(int value) { - return mq2; + DO = value; } -//=====[Implementations of private functions]================================== + +int Led::read() +{ + return DO; +} + +//=====[Implementations of private methods]==================================== \ No newline at end of file diff --git a/modules/led/led.h b/modules/led/led.h new file mode 100644 index 0000000..6863318 --- /dev/null +++ b/modules/led/led.h @@ -0,0 +1,55 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _LED_H_ +#define _LED_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" +#include "arm_book_lib.h" + +//=====[Declaration of public defines]========================================= + +//=====[Declaration of public data types]====================================== + +//=====[Declaration of public classes]========================================= + +class Led +{ + public: + // Crea el led y lo inicializa apagado + Led(PinName pin); + + // Crea el led y le indica el valor de inicio (ON / OFF) + Led(PinName pin, int value); + + // Setea el led en ON / OFF + void write(int value); + + // Lee el valor del led + int read(); + + // Sobrecarga del operador = para escribir + Led &operator= (int value) + { + write(value); + return *this; + } + + // Sobrecarga de int() para leer + operator int() + { + return read(); + } + + private: + // Salida digital + DigitalOut DO; + +}; + +//=====[Declarations (prototypes) of public functions]========================= + +//=====[#include guards - end]================================================= + +#endif // _LED_H_ \ No newline at end of file diff --git a/modules/matrix_keypad/matrix_keypad.cpp b/modules/matrix_keypad/matrix_keypad.cpp deleted file mode 100644 index 4807f2b..0000000 --- a/modules/matrix_keypad/matrix_keypad.cpp +++ /dev/null @@ -1,141 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "matrix_keypad.h" - -#include "date_and_time.h" - -//=====[Declaration of private defines]======================================== - -#define MATRIX_KEYPAD_NUMBER_OF_ROWS 4 -#define MATRIX_KEYPAD_NUMBER_OF_COLS 4 -#define DEBOUNCE_KEY_TIME_MS 40 - -//=====[Declaration of private data types]===================================== - -typedef enum { - MATRIX_KEYPAD_SCANNING, - MATRIX_KEYPAD_DEBOUNCE, - MATRIX_KEYPAD_KEY_HOLD_PRESSED -} matrixKeypadState_t; - -//=====[Declaration and initialization of public global objects]=============== - -DigitalOut keypadRowPins[MATRIX_KEYPAD_NUMBER_OF_ROWS] = {PB_3, PB_5, PC_7, PA_15}; -DigitalIn keypadColPins[MATRIX_KEYPAD_NUMBER_OF_COLS] = {PB_12, PB_13, PB_15, PC_6}; - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -static matrixKeypadState_t matrixKeypadState; -static int timeIncrement_ms = 0; - -//=====[Declarations (prototypes) of private functions]======================== - -static char matrixKeypadScan(); -static void matrixKeypadReset(); - -//=====[Implementations of public functions]=================================== - -void matrixKeypadInit( int updateTime_ms ) -{ - timeIncrement_ms = updateTime_ms; - matrixKeypadState = MATRIX_KEYPAD_SCANNING; - int pinIndex = 0; - for( pinIndex=0; pinIndex= - DEBOUNCE_KEY_TIME_MS ) { - keyDetected = matrixKeypadScan(); - if( keyDetected == matrixKeypadLastKeyPressed ) { - matrixKeypadState = MATRIX_KEYPAD_KEY_HOLD_PRESSED; - } else { - matrixKeypadState = MATRIX_KEYPAD_SCANNING; - } - } - accumulatedDebounceMatrixKeypadTime = - accumulatedDebounceMatrixKeypadTime + timeIncrement_ms; - break; - - case MATRIX_KEYPAD_KEY_HOLD_PRESSED: - keyDetected = matrixKeypadScan(); - if( keyDetected != matrixKeypadLastKeyPressed ) { - if( keyDetected == '\0' ) { - keyReleased = matrixKeypadLastKeyPressed; - } - matrixKeypadState = MATRIX_KEYPAD_SCANNING; - } - break; - - default: - matrixKeypadReset(); - break; - } - return keyReleased; -} - -//=====[Implementations of private functions]================================== - -static char matrixKeypadScan() -{ - int row = 0; - int col = 0; - int i = 0; - - char matrixKeypadIndexToCharArray[] = { - '1', '2', '3', 'A', - '4', '5', '6', 'B', - '7', '8', '9', 'C', - '*', '0', '#', 'D', - }; - - for( row=0; rowsystem_mode; +} + +//=====[Implementations of private methods]==================================== + +void ModeSelector::update_state(system_mode_t new_mode) +{ + this->system_mode = new_mode; + switch (this->system_mode){ + case IDLE: + this->led_idle = ON; + this->led_solo_lectura = OFF; + break; + case SOLO_LECTURA: + this->led_idle = OFF; + this->led_solo_lectura = ON; + break; + default: + break; + } + + this->mode_changed = true; +} + +void ModeSelector::int_system_mode_idle_callback() +{ + ModeSelector::update_state(IDLE); +} + +void ModeSelector::int_system_mode_solo_lectura_callback() +{ + ModeSelector::update_state(SOLO_LECTURA); +} \ No newline at end of file diff --git a/modules/mode_selector/mode_selector.h b/modules/mode_selector/mode_selector.h new file mode 100644 index 0000000..07282ec --- /dev/null +++ b/modules/mode_selector/mode_selector.h @@ -0,0 +1,61 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _MODE_SELECTOR_H_ +#define _MODE_SELECTOR_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" +#include "arm_book_lib.h" + +#include "led.h" + +//=====[Declaration of public defines]========================================= + +//=====[Declaration of public data types]====================================== + +typedef enum{ + IDLE, + SOLO_LECTURA +} system_mode_t; + +//=====[Declaration of public classes]========================================= + +class ModeSelector +{ + public: + // + ModeSelector(PinName pin_switch_mode_selector, PinMode mode_switch_mode_selector, PinName led_mode_idle, PinName led_mode_solo_lectura); + + system_mode_t read_state(); + + operator system_mode_t() + { + return read_state(); + } + + bool mode_changed = false; + + private: + // + Led led_idle; + Led led_solo_lectura; + + DigitalIn system_mode_selector_in; + + system_mode_t system_mode; + + InterruptIn int_system_mode_selector; + + void update_state(system_mode_t new_mode); + + void int_system_mode_idle_callback(); + void int_system_mode_solo_lectura_callback(); + +}; + +//=====[Declarations (prototypes) of public functions]========================= + +//=====[#include guards - end]================================================= + +#endif // _MODE_SELECTOR_H_ \ No newline at end of file diff --git a/modules/non_blocking_delay/_non_blocking_delay.cpp b/modules/non_blocking_delay/_non_blocking_delay.cpp new file mode 100644 index 0000000..e6ed0fa --- /dev/null +++ b/modules/non_blocking_delay/_non_blocking_delay.cpp @@ -0,0 +1,99 @@ +/*//=====[Libraries]============================================================= + +#include "_non_blocking_delay.h" + +//=====[Declaration of private defines]======================================== + +//=====[Declaration of private data types]===================================== + +//=====[Declaration and initialization of public global objects]=============== + +//=====[Declaration of external public global variables]======================= + +//=====[Declaration and initialization of public global variables]============= + +//=====[Declaration and initialization of private global variables]============ + +static Ticker ticker; +static tick_t tickCounter; + +//=====[Declarations (prototypes) of private functions]======================== + + void tickerCallback(); + +//=====[Implementations of public functions]=================================== + + +void tickInit() +{ + ticker.attach( tickerCallback, 1ms); +} + +//=====[Implementations of private functions]================================== + +void tickerCallback( void ) +{ + tickCounter++; +} + +//=====[Implementations of public methods]===================================== + +nonBlockingDelay::nonBlockingDelay(tick_t durationValue) +{ + duration = durationValue; + isRunning = false; +} + +void nonBlockingDelay::Start() +{ + this->startTime = tickCounter; + this->isRunning = true; +} + +void nonBlockingDelay::Start(tick_t new_duration) +{ + this->startTime = tickCounter; + this->isRunning = true; + this->duration = new_duration; +} +*/ +/* +bool nonBlockingDelay::Read( ) +{ + bool timeArrived = false; + tick_t elapsedTime; + + if( !this->isRunning ) { + this->startTime = tickCounter; + this->isRunning = true; + } else { + elapsedTime = tickCounter - this->startTime; + if ( elapsedTime >= this->duration ) { + timeArrived = true; + this->isRunning = false; + } + } + + return timeArrived; +} +*/ +/* +bool nonBlockingDelay::Read( ) +{ + bool timeArrived = false; + tick_t elapsedTime = tickCounter - this->startTime; + + if ( elapsedTime >= this->duration ) { + timeArrived = true; + this->isRunning = false; + } + + return timeArrived; +} + +void nonBlockingDelay::Write( tick_t durationValue ) +{ + this->duration = durationValue; +} + +//=====[Implementations of private methods]====================================*/ \ No newline at end of file diff --git a/modules/non_blocking_delay/_non_blocking_delay.h b/modules/non_blocking_delay/_non_blocking_delay.h new file mode 100644 index 0000000..6e1f3f3 --- /dev/null +++ b/modules/non_blocking_delay/_non_blocking_delay.h @@ -0,0 +1,38 @@ +/*//=====[#include guards - begin]=============================================== + +#ifndef __NON_BLOCKING_DELAY_H_ +#define __NON_BLOCKING_DELAY_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" + +//=====[Declaration of public defines]========================================= + +//=====[Declaration of public data types]====================================== + +typedef uint64_t tick_t; + +//=====[Declaration of public classes]========================================= + +class nonBlockingDelay { + public: + nonBlockingDelay(tick_t durationValue); + void Start(); + void Start(tick_t new_duration); + bool Read(); + void Write(tick_t durationValue); + private: + tick_t startTime; + tick_t duration; + bool isRunning; + +}; + +//=====[Declarations (prototypes) of public functions]========================= + +void tickInit(); + +//=====[#include guards - end]================================================= + +#endif // __NON_BLOCKING_DELAY_H_*/ \ No newline at end of file diff --git a/modules/non_blocking_delay/non_blocking_delay.cpp b/modules/non_blocking_delay/non_blocking_delay.cpp new file mode 100644 index 0000000..4efdbcc --- /dev/null +++ b/modules/non_blocking_delay/non_blocking_delay.cpp @@ -0,0 +1,105 @@ +//=====[Libraries]============================================================= + +#include "non_blocking_delay.h" + +//=====[Declaration of private defines]======================================== + +//=====[Declaration of private data types]===================================== + +//=====[Declaration and initialization of public global objects]=============== + +//=====[Declaration of external public global variables]======================= + +//=====[Declaration and initialization of public global variables]============= + +//=====[Declaration and initialization of private global variables]============ + +//=====[Declarations (prototypes) of private functions]======================== + +//=====[Implementations of public functions]=================================== + +//=====[Implementations of private functions]================================== + +//=====[Implementations of public methods]===================================== + +nonBlockingDelay::nonBlockingDelay(tick_t durationValue) +{ + nonBlockingDelay::SetDuration(durationValue); + nonBlockingDelay::SetCallback(nullptr); + this->isRunning = false; +} + +nonBlockingDelay::nonBlockingDelay(tick_t durationValue, Callback cb) +{ + nonBlockingDelay::SetDuration(durationValue); + nonBlockingDelay::SetCallback(cb); + this->isRunning = false; +} + +void nonBlockingDelay::Start() +{ + this->isRunning = true; + if(this->my_callback){ + this->ticker.attach(callback(this, &nonBlockingDelay::tickerCallback), std::chrono::milliseconds(this->duration)); + } + this->ready_ticker.attach(callback(this, &nonBlockingDelay::readyTickerCallback), std::chrono::milliseconds(this->duration)); +} + +void nonBlockingDelay::Start(tick_t new_duration) +{ + this->isRunning = true; + nonBlockingDelay::SetDuration(new_duration); + if(this->my_callback){ + this->ticker.attach(callback(this, &nonBlockingDelay::tickerCallback), std::chrono::milliseconds(this->duration)); + } + this->ready_ticker.attach(callback(this, &nonBlockingDelay::readyTickerCallback), std::chrono::milliseconds(this->duration)); +} + +void nonBlockingDelay::Start(tick_t new_duration, Callback cb) +{ + this->isRunning = true; + nonBlockingDelay::SetDuration(new_duration); + nonBlockingDelay::SetCallback(cb); + this->ticker.attach(callback(this, &nonBlockingDelay::tickerCallback), std::chrono::milliseconds(this->duration)); + this->ready_ticker.attach(callback(this, &nonBlockingDelay::readyTickerCallback), std::chrono::milliseconds(this->duration)); +} + +void nonBlockingDelay::Start(Callback cb) +{ + this->isRunning = true; + nonBlockingDelay::SetCallback(cb); + this->ticker.attach(callback(this, &nonBlockingDelay::tickerCallback), std::chrono::milliseconds(this->duration)); + this->ready_ticker.attach(callback(this, &nonBlockingDelay::readyTickerCallback), std::chrono::milliseconds(this->duration)); +} + +bool nonBlockingDelay::isReady() +{ + return !this->isRunning; +} + +void nonBlockingDelay::SetDuration(tick_t durationValue) +{ + this->duration = durationValue; +} + +void nonBlockingDelay::SetCallback(Callback cb) +{ + this->my_callback = cb; + if(!this->my_callback){ + this->ticker.detach(); + } +} + +//=====[Implementations of private methods]==================================== + +void nonBlockingDelay::tickerCallback() +{ + if (this->my_callback) { + this->my_callback(); + } +} + +void nonBlockingDelay::readyTickerCallback() +{ + this->isRunning = false; +} \ No newline at end of file diff --git a/modules/non_blocking_delay/non_blocking_delay.h b/modules/non_blocking_delay/non_blocking_delay.h new file mode 100644 index 0000000..470847d --- /dev/null +++ b/modules/non_blocking_delay/non_blocking_delay.h @@ -0,0 +1,46 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _NON_BLOCKING_DELAY_H_ +#define _NON_BLOCKING_DELAY_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" + +//=====[Declaration of public defines]========================================= + +//=====[Declaration of public data types]====================================== + +typedef uint64_t tick_t; + +//=====[Declaration of public classes]========================================= + +class nonBlockingDelay { + public: + nonBlockingDelay(tick_t durationValue); + nonBlockingDelay(tick_t durationValue, Callback cb); + void Start(); + void Start(tick_t new_duration); + void Start(tick_t new_duration, Callback cb); + void Start(Callback cb); + bool isReady(); + void SetDuration(tick_t durationValue); + void SetCallback(Callback cb); + private: + tick_t startTime; + tick_t duration; + bool isRunning; + Callback my_callback; + Ticker ticker; + Ticker ready_ticker; + + void tickerCallback(); + void readyTickerCallback(); + +}; + +//=====[Declarations (prototypes) of public functions]========================= + +//=====[#include guards - end]================================================= + +#endif // _NON_BLOCKING_DELAY_H_ diff --git a/modules/pc_serial_com/pc_serial_com.cpp b/modules/pc_serial_com/pc_serial_com.cpp deleted file mode 100644 index 37482de..0000000 --- a/modules/pc_serial_com/pc_serial_com.cpp +++ /dev/null @@ -1,310 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "pc_serial_com.h" - -#include "siren.h" -#include "fire_alarm.h" -#include "code.h" -#include "date_and_time.h" -#include "temperature_sensor.h" -#include "gas_sensor.h" -#include "event_log.h" - -//=====[Declaration of private defines]======================================== - -//=====[Declaration of private data types]===================================== - -typedef enum{ - PC_SERIAL_COMMANDS, - PC_SERIAL_GET_CODE, - PC_SERIAL_SAVE_NEW_CODE, -} pcSerialComMode_t; - -//=====[Declaration and initialization of public global objects]=============== - -UnbufferedSerial uartUsb(USBTX, USBRX, 115200); - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -char codeSequenceFromPcSerialCom[CODE_NUMBER_OF_KEYS]; - -//=====[Declaration and initialization of private global variables]============ - -static pcSerialComMode_t pcSerialComMode = PC_SERIAL_COMMANDS; -static bool codeComplete = false; -static int numberOfCodeChars = 0; - -//=====[Declarations (prototypes) of private functions]======================== - -static void pcSerialComStringRead( char* str, int strLength ); - -static void pcSerialComGetCodeUpdate( char receivedChar ); -static void pcSerialComSaveNewCodeUpdate( char receivedChar ); - -static void pcSerialComCommandUpdate( char receivedChar ); - -static void availableCommands(); -static void commandShowCurrentAlarmState(); -static void commandShowCurrentGasDetectorState(); -static void commandShowCurrentOverTemperatureDetectorState(); -static void commandEnterCodeSequence(); -static void commandEnterNewCode(); -static void commandShowCurrentTemperatureInCelsius(); -static void commandShowCurrentTemperatureInFahrenheit(); -static void commandSetDateAndTime(); -static void commandShowDateAndTime(); -static void commandShowStoredEvents(); - -//=====[Implementations of public functions]=================================== - -void pcSerialComInit() -{ - availableCommands(); -} - -char pcSerialComCharRead() -{ - char receivedChar = '\0'; - if( uartUsb.readable() ) { - uartUsb.read( &receivedChar, 1 ); - } - return receivedChar; -} - -void pcSerialComStringWrite( const char* str ) -{ - uartUsb.write( str, strlen(str) ); -} - -void pcSerialComUpdate() -{ - char receivedChar = pcSerialComCharRead(); - if( receivedChar != '\0' ) { - switch ( pcSerialComMode ) { - case PC_SERIAL_COMMANDS: - pcSerialComCommandUpdate( receivedChar ); - break; - - case PC_SERIAL_GET_CODE: - pcSerialComGetCodeUpdate( receivedChar ); - break; - - case PC_SERIAL_SAVE_NEW_CODE: - pcSerialComSaveNewCodeUpdate( receivedChar ); - break; - default: - pcSerialComMode = PC_SERIAL_COMMANDS; - break; - } - } -} - -bool pcSerialComCodeCompleteRead() -{ - return codeComplete; -} - -void pcSerialComCodeCompleteWrite( bool state ) -{ - codeComplete = state; -} - -//=====[Implementations of private functions]================================== - -static void pcSerialComStringRead( char* str, int strLength ) -{ - int strIndex; - for ( strIndex = 0; strIndex < strLength; strIndex++) { - uartUsb.read( &str[strIndex] , 1 ); - uartUsb.write( &str[strIndex] ,1 ); - } - str[strLength]='\0'; -} - -static void pcSerialComGetCodeUpdate( char receivedChar ) -{ - codeSequenceFromPcSerialCom[numberOfCodeChars] = receivedChar; - pcSerialComStringWrite( "*" ); - numberOfCodeChars++; - if ( numberOfCodeChars >= CODE_NUMBER_OF_KEYS ) { - pcSerialComMode = PC_SERIAL_COMMANDS; - codeComplete = true; - numberOfCodeChars = 0; - } -} - -static void pcSerialComSaveNewCodeUpdate( char receivedChar ) -{ - static char newCodeSequence[CODE_NUMBER_OF_KEYS]; - - newCodeSequence[numberOfCodeChars] = receivedChar; - pcSerialComStringWrite( "*" ); - numberOfCodeChars++; - if ( numberOfCodeChars >= CODE_NUMBER_OF_KEYS ) { - pcSerialComMode = PC_SERIAL_COMMANDS; - numberOfCodeChars = 0; - codeWrite( newCodeSequence ); - pcSerialComStringWrite( "\r\nNew code configured\r\n\r\n" ); - } -} - -static void pcSerialComCommandUpdate( char receivedChar ) -{ - switch (receivedChar) { - case '1': commandShowCurrentAlarmState(); break; - case '2': commandShowCurrentGasDetectorState(); break; - case '3': commandShowCurrentOverTemperatureDetectorState(); break; - case '4': commandEnterCodeSequence(); break; - case '5': commandEnterNewCode(); break; - case 'c': case 'C': commandShowCurrentTemperatureInCelsius(); break; - case 'f': case 'F': commandShowCurrentTemperatureInFahrenheit(); break; - case 's': case 'S': commandSetDateAndTime(); break; - case 't': case 'T': commandShowDateAndTime(); break; - case 'e': case 'E': commandShowStoredEvents(); break; - default: availableCommands(); break; - } -} - -static void availableCommands() -{ - pcSerialComStringWrite( "Available commands:\r\n" ); - pcSerialComStringWrite( "Press '1' to get the alarm state\r\n" ); - pcSerialComStringWrite( "Press '2' to get the gas detector state\r\n" ); - pcSerialComStringWrite( "Press '3' to get the over temperature detector state\r\n" ); - pcSerialComStringWrite( "Press '4' to enter the code to deactivate the alarm\r\n" ); - pcSerialComStringWrite( "Press '5' to enter a new code to deactivate the alarm\r\n" ); - pcSerialComStringWrite( "Press 'f' or 'F' to get lm35 reading in Fahrenheit\r\n" ); - pcSerialComStringWrite( "Press 'c' or 'C' to get lm35 reading in Celsius\r\n" ); - pcSerialComStringWrite( "Press 's' or 'S' to set the date and time\r\n" ); - pcSerialComStringWrite( "Press 't' or 'T' to get the date and time\r\n" ); - pcSerialComStringWrite( "Press 'e' or 'E' to get the stored events\r\n" ); - pcSerialComStringWrite( "\r\n" ); -} - -static void commandShowCurrentAlarmState() -{ - if ( sirenStateRead() ) { - pcSerialComStringWrite( "The alarm is activated\r\n"); - } else { - pcSerialComStringWrite( "The alarm is not activated\r\n"); - } -} - -static void commandShowCurrentGasDetectorState() -{ - if ( gasDetectorStateRead() ) { - pcSerialComStringWrite( "Gas is being detected\r\n"); - } else { - pcSerialComStringWrite( "Gas is not being detected\r\n"); - } -} - -static void commandShowCurrentOverTemperatureDetectorState() -{ - if ( overTemperatureDetectorStateRead() ) { - pcSerialComStringWrite( "Temperature is above the maximum level\r\n"); - } else { - pcSerialComStringWrite( "Temperature is below the maximum level\r\n"); - } -} - -static void commandEnterCodeSequence() -{ - if( sirenStateRead() ) { - pcSerialComStringWrite( "Please enter the four digits numeric code " ); - pcSerialComStringWrite( "to deactivate the alarm: " ); - pcSerialComMode = PC_SERIAL_GET_CODE; - codeComplete = false; - numberOfCodeChars = 0; - } else { - pcSerialComStringWrite( "Alarm is not activated.\r\n" ); - } -} - -static void commandEnterNewCode() -{ - pcSerialComStringWrite( "Please enter the new four digits numeric code " ); - pcSerialComStringWrite( "to deactivate the alarm: " ); - numberOfCodeChars = 0; - pcSerialComMode = PC_SERIAL_SAVE_NEW_CODE; - -} - -static void commandShowCurrentTemperatureInCelsius() -{ - char str[100] = ""; - sprintf ( str, "Temperature: %.2f \xB0 C\r\n", - temperatureSensorReadCelsius() ); - pcSerialComStringWrite( str ); -} - -static void commandShowCurrentTemperatureInFahrenheit() -{ - char str[100] = ""; - sprintf ( str, "Temperature: %.2f \xB0 C\r\n", - temperatureSensorReadFahrenheit() ); - pcSerialComStringWrite( str ); -} - -static void commandSetDateAndTime() -{ - char year[5] = ""; - char month[3] = ""; - char day[3] = ""; - char hour[3] = ""; - char minute[3] = ""; - char second[3] = ""; - - pcSerialComStringWrite("\r\nType four digits for the current year (YYYY): "); - pcSerialComStringRead( year, 4); - pcSerialComStringWrite("\r\n"); - - pcSerialComStringWrite("Type two digits for the current month (01-12): "); - pcSerialComStringRead( month, 2); - pcSerialComStringWrite("\r\n"); - - pcSerialComStringWrite("Type two digits for the current day (01-31): "); - pcSerialComStringRead( day, 2); - pcSerialComStringWrite("\r\n"); - - pcSerialComStringWrite("Type two digits for the current hour (00-23): "); - pcSerialComStringRead( hour, 2); - pcSerialComStringWrite("\r\n"); - - pcSerialComStringWrite("Type two digits for the current minutes (00-59): "); - pcSerialComStringRead( minute, 2); - pcSerialComStringWrite("\r\n"); - - pcSerialComStringWrite("Type two digits for the current seconds (00-59): "); - pcSerialComStringRead( second, 2); - pcSerialComStringWrite("\r\n"); - - pcSerialComStringWrite("Date and time has been set\r\n"); - - dateAndTimeWrite( atoi(year), atoi(month), atoi(day), - atoi(hour), atoi(minute), atoi(second) ); -} - -static void commandShowDateAndTime() -{ - char str[100] = ""; - sprintf ( str, "Date and Time = %s", dateAndTimeRead() ); - pcSerialComStringWrite( str ); - pcSerialComStringWrite("\r\n"); -} - -static void commandShowStoredEvents() -{ - char str[EVENT_STR_LENGTH] = ""; - int i; - for (i = 0; i < eventLogNumberOfStoredEvents(); i++) { - eventLogRead( i, str ); - pcSerialComStringWrite( str ); - pcSerialComStringWrite( "\r\n" ); - } -} \ No newline at end of file diff --git a/modules/pc_serial_com/pc_serial_com.h b/modules/pc_serial_com/pc_serial_com.h deleted file mode 100644 index dcad96c..0000000 --- a/modules/pc_serial_com/pc_serial_com.h +++ /dev/null @@ -1,21 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _PC_SERIAL_COM_H_ -#define _PC_SERIAL_COM_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void pcSerialComInit(); -char pcSerialComCharRead(); -void pcSerialComStringWrite( const char* str ); -void pcSerialComUpdate(); -bool pcSerialComCodeCompleteRead(); -void pcSerialComCodeCompleteWrite( bool state ); - -//=====[#include guards - end]================================================= - -#endif // _PC_SERIAL_COM_H_ \ No newline at end of file diff --git a/modules/rfid/rfid.cpp b/modules/rfid/rfid.cpp new file mode 100644 index 0000000..c5e156e --- /dev/null +++ b/modules/rfid/rfid.cpp @@ -0,0 +1,82 @@ +//=====[Libraries]============================================================= + +#include "rfid.h" + +//=====[Declaration of private defines]======================================== + +//=====[Declaration of private data types]===================================== + +//=====[Declaration and initialization of public global objects]=============== + +//=====[Declaration of external public global variables]======================= + +//=====[Declaration and initialization of public global variables]============= + +//=====[Declaration and initialization of private global variables]============ + +//=====[Declarations (prototypes) of private functions]======================== + +//=====[Implementations of public functions]=================================== + +//=====[Implementations of private functions]================================== + +//=====[Implementations of public methods]===================================== + +RFID::RFID(PinName pin_mosi, PinName pin_miso, PinName pin_sclk, PinName pin_cs, PinName pin_reset, PinName pin_led): + reader(pin_mosi, pin_miso, pin_sclk, pin_cs, pin_reset), led_lectura(pin_led, OFF), read_delay(RFID_READ_DELAY_TIME_MS, callback(this, &RFID::read_delay_callback)) +{ + this->reader.PCD_Init(); + RFID::set_status(ESPERANDO); + this->led_lectura = OFF; +} + +char * RFID::read() +{ + if(this->RFID_status == ESPERANDO){ + // Limpiar el buffer del ID + memset(id, 0, sizeof(id)); + + // Buscar nuevas tarjetas + if (reader.PICC_IsNewCardPresent()) { + // Seleccionar una de las tarjetas + if (reader.PICC_ReadCardSerial()) { + RFID::set_status(LEYENDO); + // Convertir el UID a una cadena de caracteres hexadecimales + for (uint8_t i = 0; i < this->reader.uid.size; i++) { + sprintf(&this->id[i * 2], "%02X", this->reader.uid.uidByte[i]); + } + this->id[reader.uid.size * 2] = '\0'; // Agregar el carácter nulo al final + return this->id; + } + } + } + return nullptr; // Devolver nullptr si no se leyó ninguna tarjeta +} + +RFID_status_t RFID::get_status() +{ + return this->RFID_status; +} + +//=====[Implementations of private methods]==================================== + +void RFID::set_status(RFID_status_t new_status) +{ + this->RFID_status = new_status; + switch (RFID_status){ + case LEYENDO: + this->led_lectura = ON; + this->read_delay.Start(); + break; + case ESPERANDO: + this->led_lectura = OFF; + break; + default: + break; + } +} + +void RFID::read_delay_callback() +{ + RFID::set_status(ESPERANDO); +} \ No newline at end of file diff --git a/modules/rfid/rfid.h b/modules/rfid/rfid.h new file mode 100644 index 0000000..ac30606 --- /dev/null +++ b/modules/rfid/rfid.h @@ -0,0 +1,69 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _RFID_H_ +#define _RFID_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" +#include "arm_book_lib.h" + +#include "MFRC522.h" +#include "led.h" +#include "non_blocking_delay.h" + +//=====[Declaration of public defines]========================================= + +#ifndef RFID_READ_DELAY_TIME_MS +#define RFID_READ_DELAY_TIME_MS 3000 +#endif + +//=====[Declaration of public data types]====================================== + +typedef enum{ + LEYENDO, + ESPERANDO +} RFID_status_t; + +//=====[Declaration of public classes]========================================= + +class RFID +{ + public: + // Crea el objeto y lo inicializa + RFID(PinName pin_mosi, PinName pin_miso, PinName pin_sclk, PinName pin_cs, PinName pin_reset, PinName pin_led); + + // Busca si hay una tarjeta y la lee + char * read(); + + // + RFID_status_t get_status(); + + private: + // Módulo lector de rfid + MFRC522 reader; + + // ID leído + char id[20]; + + // Led de lectura + Led led_lectura; + + nonBlockingDelay read_delay; + + // + RFID_status_t RFID_status; + + // + void set_status(RFID_status_t new_status); + + // + void read_delay_callback(); + +}; + +//=====[Declarations (prototypes) of public functions]========================= + +//=====[#include guards - end]================================================= + +#endif // _RFID_H_ \ No newline at end of file diff --git a/modules/scale/scale.cpp b/modules/scale/scale.cpp new file mode 100644 index 0000000..211d8d5 --- /dev/null +++ b/modules/scale/scale.cpp @@ -0,0 +1,87 @@ +//=====[Libraries]============================================================= + +#include "scale.h" + +//=====[Declaration of private defines]======================================== + +//=====[Declaration of private data types]===================================== + +//=====[Declaration and initialization of public global objects]=============== + +//=====[Declaration of external public global variables]======================= + +//=====[Declaration and initialization of public global variables]============= + +//=====[Declaration and initialization of private global variables]============ + +state_t state; + +//=====[Declarations (prototypes) of private functions]======================== + +//=====[Implementations of public functions]=================================== + +//=====[Implementations of private functions]================================== + +//=====[Implementations of public methods]===================================== + +Scale::Scale(PinName pin_scale, PinName pin_enable_switch, PinMode mode_enable_switch): + AI(pin_scale), enable_switch(pin_enable_switch, mode_enable_switch), int_enable_switch(pin_enable_switch, mode_enable_switch) +{ + if(enable_switch == HIGH){ + Scale::update_state(ENCENDIDO); + } + else{ + Scale::update_state(APAGADO); + } + + int_enable_switch.rise(callback(this, &Scale::int_enable_switch_callback_on)); + int_enable_switch.fall(callback(this, &Scale::int_enable_switch_callback_off)); +} + +bool Scale::read(char * buffer) +{ + // Verificar si la balanza está apagada + if (state == APAGADO) { + strcpy(buffer, "-"); + return false; // La balanza está apagada, devuelve false + } + + // La sobrecarga de float() en Scale llamará a AI.read() automáticamente + // Leer el valor analógico + float value = AI.read() * 500.0f; + + // Formatear el valor con dos dígitos decimales en buffer + snprintf(buffer, 16, "%.2f", value); + + return true; // La balanza está encendida, devuelve true +} + +state_t Scale::read_state() +{ + return state; +} + +//=====[Implementations of private methods]==================================== + +void Scale::update_state(state_t new_state) +{ + state = new_state; + switch (state){ + case ENCENDIDO: + break; + case APAGADO: + break; + default: + break; + } +} + +void Scale::int_enable_switch_callback_on() +{ + Scale::update_state(ENCENDIDO); +} + +void Scale::int_enable_switch_callback_off() +{ + Scale::update_state(APAGADO); +} \ No newline at end of file diff --git a/modules/scale/scale.h b/modules/scale/scale.h new file mode 100644 index 0000000..c6cff9c --- /dev/null +++ b/modules/scale/scale.h @@ -0,0 +1,56 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _SCALE_H_ +#define _SCALE_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" +#include "arm_book_lib.h" + +//=====[Declaration of public defines]========================================= + +//=====[Declaration of public data types]====================================== + +typedef enum{ + ENCENDIDO, + APAGADO +} state_t; + +//=====[Declaration of public classes]========================================= + +class Scale +{ + public: + // Crea la balanza + Scale(PinName pin_scale, PinName pin_enable_switch, PinMode mode_enable_switch); + + // Lee el valor de la balanza, entre 0 y 500 kg. -1 si la balanza está apagada + bool read(char * value); + + // Lee el valor del estado de la balanza + state_t read_state(); + + private: + // Entrada analógica + AnalogIn AI; + + // + DigitalIn enable_switch; + + // + InterruptIn int_enable_switch; + + // + void update_state(state_t new_state); + + void int_enable_switch_callback_on(); + void int_enable_switch_callback_off(); + +}; + +//=====[Declarations (prototypes) of public functions]========================= + +//=====[#include guards - end]================================================= + +#endif // _SCALE_H_ \ No newline at end of file diff --git a/modules/siren/siren.cpp b/modules/siren/siren.cpp deleted file mode 100644 index 38380f0..0000000 --- a/modules/siren/siren.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "siren.h" - -#include "smart_home_system.h" - -//=====[Declaration of private defines]======================================== - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -DigitalOut sirenPin(PE_10); - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -static bool sirenState = OFF; - -//=====[Declarations (prototypes) of private functions]======================== - -//=====[Implementations of public functions]=================================== - -void sirenInit() -{ - sirenPin = ON; -} - -bool sirenStateRead() -{ - return sirenState; -} - -void sirenStateWrite( bool state ) -{ - sirenState = state; -} - -void sirenUpdate( int strobeTime ) -{ - static int accumulatedTimeAlarm = 0; - accumulatedTimeAlarm = accumulatedTimeAlarm + SYSTEM_TIME_INCREMENT_MS; - - if( sirenState ) { - if( accumulatedTimeAlarm >= strobeTime ) { - accumulatedTimeAlarm = 0; - sirenPin= !sirenPin; - } - } else { - sirenPin = ON; - } -} - -//=====[Implementations of private functions]================================== - diff --git a/modules/siren/siren.h b/modules/siren/siren.h deleted file mode 100644 index 8743f17..0000000 --- a/modules/siren/siren.h +++ /dev/null @@ -1,19 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _SIREN_H_ -#define _SIREN_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void sirenInit(); -bool sirenStateRead(); -void sirenStateWrite( bool state ); -void sirenUpdate( int strobeTime ); - -//=====[#include guards - end]================================================= - -#endif // _SIREN_H_ diff --git a/modules/smart_home_system/smart_home_system.cpp b/modules/smart_home_system/smart_home_system.cpp deleted file mode 100644 index 9a09c5e..0000000 --- a/modules/smart_home_system/smart_home_system.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//=====[Libraries]============================================================= - -#include "arm_book_lib.h" - -#include "smart_home_system.h" - -#include "siren.h" -#include "user_interface.h" -#include "fire_alarm.h" -#include "pc_serial_com.h" -#include "event_log.h" - -//=====[Declaration of private defines]======================================== - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -//=====[Declarations (prototypes) of private functions]======================== - -//=====[Implementations of public functions]=================================== - -void smartHomeSystemInit() -{ - userInterfaceInit(); - fireAlarmInit(); - pcSerialComInit(); -} - -void smartHomeSystemUpdate() -{ - userInterfaceUpdate(); - fireAlarmUpdate(); - pcSerialComUpdate(); - eventLogUpdate(); - delay(SYSTEM_TIME_INCREMENT_MS); -} - -//=====[Implementations of private functions]================================== diff --git a/modules/smart_home_system/smart_home_system.h b/modules/smart_home_system/smart_home_system.h deleted file mode 100644 index c79e44a..0000000 --- a/modules/smart_home_system/smart_home_system.h +++ /dev/null @@ -1,19 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _SMART_HOME_SYSTEM_H_ -#define _SMART_HOME_SYSTEM_H_ - -//=====[Declaration of public defines]========================================= - -#define SYSTEM_TIME_INCREMENT_MS 10 - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void smartHomeSystemInit(); -void smartHomeSystemUpdate(); - -//=====[#include guards - end]================================================= - -#endif // _SMART_HOME_SYSTEM_H_ \ No newline at end of file diff --git a/modules/strobe_light/strobe_light.cpp b/modules/strobe_light/strobe_light.cpp deleted file mode 100644 index 327407a..0000000 --- a/modules/strobe_light/strobe_light.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "strobe_light.h" -#include "smart_home_system.h" - -//=====[Declaration of private defines]======================================== - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -DigitalOut strobeLight(LED1); - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -static bool strobeLightState = OFF; - -//=====[Declarations (prototypes) of private functions]======================== - -//=====[Implementations of public functions]=================================== - -void strobeLightInit() -{ - strobeLight = OFF; -} - -bool strobeLightStateRead() -{ - return strobeLightState; -} - -void strobeLightStateWrite( bool state ) -{ - strobeLightState = state; -} - -void strobeLightUpdate( int strobeTime ) -{ - static int accumulatedTimeAlarm = 0; - accumulatedTimeAlarm = accumulatedTimeAlarm + SYSTEM_TIME_INCREMENT_MS; - - if( strobeLightState ) { - if( accumulatedTimeAlarm >= strobeTime ) { - accumulatedTimeAlarm = 0; - strobeLight= !strobeLight; - } - } else { - strobeLight = OFF; - } -} - -//=====[Implementations of private functions]================================== - diff --git a/modules/strobe_light/strobe_light.h b/modules/strobe_light/strobe_light.h deleted file mode 100644 index 41b246e..0000000 --- a/modules/strobe_light/strobe_light.h +++ /dev/null @@ -1,19 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _STROBE_LIGHT_H_ -#define _STROBE_LIGHT_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void strobeLightInit(); -bool strobeLightStateRead(); -void strobeLightStateWrite( bool state ); -void strobeLightUpdate( int strobeTime ); - -//=====[#include guards - end]================================================= - -#endif // _STROBE_LIGHT_H_ \ No newline at end of file diff --git a/modules/system/system.cpp b/modules/system/system.cpp new file mode 100644 index 0000000..676e9d1 --- /dev/null +++ b/modules/system/system.cpp @@ -0,0 +1,155 @@ +//=====[Libraries]============================================================= + +#include "arm_book_lib.h" +#include "mbed.h" + +#include "global_defines.h" + +#include "system.h" +#include "non_blocking_delay.h" +#include "tranquera.h" +#include "scale.h" +#include "MQTT.h" +#include "rfid.h" +#include "mode_selector.h" + +//=====[Declaration of private defines]======================================== + +//=====[Declaration of private data types]===================================== + +//=====[Declarations (prototypes) of private functions]======================== + +void parse_message_received(const char * topic, const char * message); +void send_tranquera_position(); +void send_system_mode(); + +//=====[Declaration and initialization of public global objects]=============== + +// ---Módulos--- +static Tranquera tranquera(PIN_TRANQUERA, PIN_BOTON_ABRIR, MODE_PIN_BOTON_ABRIR, PIN_BOTON_CERRAR, MODE_PIN_BOTON_CERRAR); +static Scale scale(PIN_BALANZA, PIN_SWITCH_BALANZA, MODE_PIN_SWITCH_BALANZA); +static RFID rfid_reader(PIN_RFID_MOSI, PIN_RFID_MISO, PIN_RFID_SCLK, PIN_RFID_CS, PIN_RFID_RESET, PIN_LED_LECTURA); +static MQTT mqtt(PIN_MQTT_TX, PIN_MQTT_RX, MQTT_BAUDRATE, PIN_MQTT_STATUS, PIN_LED_WIFI_CONECTADO, PIN_LED_WIFI_SIN_CONEXION, PIN_LED_MENSAJE_MQTT); +static ModeSelector system_mode(PIN_SWITCH_SOLO_LECTURA, MODE_PIN_SWITCH_SOLO_LECTURA, PIN_LED_MODO_NORMAL, PIN_LED_MODO_SOLO_LECTURA); +// --- + +// ---Delays--- +static nonBlockingDelay RFID_read_delay(RFID_READ_TRY_DELAY_TIME_MS); +// --- + +//=====[Declaration of external public global variables]======================= + +//=====[Declaration and initialization of public global variables]============= + +//=====[Declaration and initialization of private global variables]============ + +char * lectura_rfid = nullptr; +char lectura_scale [256] = ""; +char msg [256] = ""; +char topic_received[256] = ""; +char message_received[256] = ""; + +//=====[Implementations of public functions]=================================== + +void system_init() +{ + RFID_read_delay.Start(); + + mqtt.subscribe(TOPIC_TRANQUERA); + mqtt.subscribe(TOPIC_SYSTEM_MODE); +} + +void system_update() +{ + if(RFID_read_delay.isReady()){ + RFID_read_delay.Start(); + + lectura_rfid = rfid_reader.read(); + if(lectura_rfid != nullptr){ + scale.read(lectura_scale); + strcpy(msg, lectura_rfid); + strcat(msg, ":"); + strcat(msg, lectura_scale); + mqtt.publish(TOPIC_RFID_LECTURA, msg); + } + + if(tranquera.position_changed){ + send_tranquera_position(); + tranquera.position_changed = false; + } + + if(system_mode.mode_changed){ + send_system_mode(); + system_mode.mode_changed = false; + } + + } + + mqtt.processPendings(); + + if(mqtt.receive(topic_received, message_received)){ + parse_message_received(topic_received, message_received); + } +} + +//=====[Implementations of private functions]================================== + +void parse_message_received(const char * topic, const char * message) +{ + if (strcmp(topic, "subscribed") == 0) { + mqtt.confirmSubscription(message); + } + else if (strcmp(topic, "unsubscribed") == 0) { + mqtt.confirmUnsubscription(message); + } + + else if (strcmp(topic, TOPIC_TRANQUERA) == 0) { + if(strcmp(message, MESSAGE_TRANQUERA_ABRIR) == 0 && system_mode == IDLE){ + tranquera = ABIERTO; + } + else if(strcmp(message, MESSAGE_TRANQUERA_CERRAR) == 0 && system_mode == IDLE){ + tranquera = CERRADO; + } + else if(strcmp(message, MESSAGE_TRANQUERA_PEDIR_ESTADO) == 0){ + send_tranquera_position(); + } + } + + else if (strcmp(topic, TOPIC_SYSTEM_MODE) == 0) { + if(strcmp(message, MESSAGE_SYSTEM_MODE) == 0){ + send_system_mode(); + } + } +} + +void send_tranquera_position() +{ + position_t position = tranquera; + switch (position){ + case ABIERTO: + mqtt.publish(TOPIC_TRANQUERA_ESTADO, MESSAGE_TRANQUERA_ABIERTO); + break; + case CERRADO: + mqtt.publish(TOPIC_TRANQUERA_ESTADO, MESSAGE_TRANQUERA_CERRADO); + break; + default: + break; + } + +} + +void send_system_mode() +{ + system_mode_t mode = system_mode; + switch (mode){ + case IDLE: + mqtt.publish(TOPIC_SYSTEM_MODE_ESTADO, MESSAGE_SYSTEM_MODE_IDLE); + break; + case SOLO_LECTURA: + mqtt.publish(TOPIC_SYSTEM_MODE_ESTADO, MESSAGE_SYSTEM_MODE_SOLO_LECTURA); + break; + default: + break; + } + +} \ No newline at end of file diff --git a/modules/gas_sensor/gas_sensor.h b/modules/system/system.h similarity index 74% rename from modules/gas_sensor/gas_sensor.h rename to modules/system/system.h index b2d1bcd..c3f1363 100644 --- a/modules/gas_sensor/gas_sensor.h +++ b/modules/system/system.h @@ -1,7 +1,7 @@ //=====[#include guards - begin]=============================================== -#ifndef _GAS_SENSOR_H_ -#define _GAS_SENSOR_H_ +#ifndef _SYSTEM_H_ +#define _SYSTEM_H_ //=====[Declaration of public defines]========================================= @@ -9,10 +9,9 @@ //=====[Declarations (prototypes) of public functions]========================= -void gasSensorInit(); -void gasSensorUpdate(); -bool gasSensorRead(); +void system_init(); +void system_update(); //=====[#include guards - end]================================================= -#endif // _GAS_SENSOR_H_ +#endif // _SYSTEM_H_ \ No newline at end of file diff --git a/modules/temperature_sensor/temperature_sensor.cpp b/modules/temperature_sensor/temperature_sensor.cpp deleted file mode 100644 index df0798f..0000000 --- a/modules/temperature_sensor/temperature_sensor.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" - -#include "temperature_sensor.h" - -#include "smart_home_system.h" - -//=====[Declaration of private defines]======================================== - -#define LM35_NUMBER_OF_AVG_SAMPLES 10 - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -AnalogIn lm35(A1); - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -//=====[Declaration and initialization of private global variables]============ - -float lm35TemperatureC = 0.0; -float lm35ReadingsArray[LM35_NUMBER_OF_AVG_SAMPLES]; - -//=====[Declarations (prototypes) of private functions]======================== - -static float analogReadingScaledWithTheLM35Formula( float analogReading ); - -//=====[Implementations of public functions]=================================== - -void temperatureSensorInit() -{ - int i; - - for( i=0; i= LM35_NUMBER_OF_AVG_SAMPLES) { - lm35SampleIndex = 0; - } - - lm35ReadingsSum = 0.0; - for (i = 0; i < LM35_NUMBER_OF_AVG_SAMPLES; i++) { - lm35ReadingsSum = lm35ReadingsSum + lm35ReadingsArray[i]; - } - lm35ReadingsAverage = lm35ReadingsSum / LM35_NUMBER_OF_AVG_SAMPLES; - lm35TemperatureC = analogReadingScaledWithTheLM35Formula ( lm35ReadingsAverage ); -} - - -float temperatureSensorReadCelsius() -{ - return lm35TemperatureC; -} - -float temperatureSensorReadFahrenheit() -{ - return celsiusToFahrenheit( lm35TemperatureC ); -} - -float celsiusToFahrenheit( float tempInCelsiusDegrees ) -{ - return ( tempInCelsiusDegrees * 9.0 / 5.0 + 32.0 ); -} - -//=====[Implementations of private functions]================================== - -static float analogReadingScaledWithTheLM35Formula( float analogReading ) -{ - return ( analogReading * 3.3 / 0.01 ); -} diff --git a/modules/temperature_sensor/temperature_sensor.h b/modules/temperature_sensor/temperature_sensor.h deleted file mode 100644 index b45c314..0000000 --- a/modules/temperature_sensor/temperature_sensor.h +++ /dev/null @@ -1,20 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _TEMPERATURE_SENSOR_H_ -#define _TEMPERATURE_SENSOR_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void temperatureSensorInit(); -void temperatureSensorUpdate(); -float temperatureSensorReadCelsius(); -float temperatureSensorReadFahrenheit(); -float celsiusToFahrenheit( float tempInCelsiusDegrees ); - -//=====[#include guards - end]================================================= - -#endif // _TEMPERATURE_SENSOR_H_ \ No newline at end of file diff --git a/modules/tranquera/tranquera.cpp b/modules/tranquera/tranquera.cpp new file mode 100644 index 0000000..24543e0 --- /dev/null +++ b/modules/tranquera/tranquera.cpp @@ -0,0 +1,84 @@ +//=====[Libraries]============================================================= + +#include "tranquera.h" + +//=====[Declaration of private defines]======================================== + +//=====[Declaration of private data types]===================================== + +//=====[Declaration and initialization of public global objects]=============== + +//=====[Declaration of external public global variables]======================= + +//=====[Declaration and initialization of public global variables]============= + +//=====[Declaration and initialization of private global variables]============ + +position_t position; + +//=====[Declarations (prototypes) of private functions]======================== + +//=====[Implementations of public functions]=================================== + +//=====[Implementations of private functions]================================== + +//=====[Implementations of public methods]===================================== + +Tranquera::Tranquera(PinName pin_tranquera, PinName pin_boton_abrir, PinMode mode_boton_abrir, PinName pin_boton_cerrar, PinMode mode_boton_cerrar): + output(pin_tranquera), int_boton_abrir(pin_boton_abrir, mode_boton_abrir), int_boton_cerrar(pin_boton_cerrar, mode_boton_cerrar) +{ + // Se inicializa en CERRADO + Tranquera::update_position(CERRADO); + + int_boton_abrir.rise(callback(this, &Tranquera::int_boton_abrir_callback)); + int_boton_cerrar.rise(callback(this, &Tranquera::int_boton_cerrar_callback)); +} + +Tranquera::Tranquera(PinName pin_tranquera, int value, PinName pin_boton_abrir, PinMode mode_boton_abrir, PinName pin_boton_cerrar, PinMode mode_boton_cerrar): + output(pin_tranquera, value), int_boton_abrir(pin_boton_abrir, mode_boton_abrir), int_boton_cerrar(pin_boton_cerrar, mode_boton_cerrar) +{ + if(value == OFF){ + Tranquera::update_position(CERRADO); + } + else{ + Tranquera::update_position(ABIERTO); + } + + int_boton_abrir.rise(callback(this, &Tranquera::int_boton_abrir_callback)); + int_boton_cerrar.rise(callback(this, &Tranquera::int_boton_cerrar_callback)); +} + +void Tranquera::update_position(position_t new_position) +{ + position = new_position; + switch (position){ + case ABIERTO: + output = ON; + break; + case CERRADO: + output = OFF; + break; + default: + break; + } + + this->position_changed = true; +} + + +position_t Tranquera::read() +{ + return position; +} + +//=====[Implementations of private methods]==================================== + +void Tranquera::int_boton_abrir_callback() +{ + Tranquera::update_position(ABIERTO); +} + +void Tranquera::int_boton_cerrar_callback() +{ + Tranquera::update_position(CERRADO); +} \ No newline at end of file diff --git a/modules/tranquera/tranquera.h b/modules/tranquera/tranquera.h new file mode 100644 index 0000000..209c0aa --- /dev/null +++ b/modules/tranquera/tranquera.h @@ -0,0 +1,72 @@ +//=====[#include guards - begin]=============================================== + +#ifndef _TRANQUERA_H_ +#define _TRANQUERA_H_ + +//==================[Libraries]=============================================== + +#include "mbed.h" +#include "arm_book_lib.h" + +#include "led.h" + +//=====[Declaration of public defines]========================================= + +//=====[Declaration of public data types]====================================== + +typedef enum{ + CERRADO, + ABIERTO +} position_t; + +//=====[Declaration of public classes]========================================= + +class Tranquera +{ + public: + // Crea la tranquera y la inicializa cerrada + Tranquera(PinName pin_tranquera, PinName pin_boton_abrir, PinMode mode_boton_abrir, PinName pin_boton_cerrar, PinMode mode_boton_cerrar); + + // Crea la tranquera y le indica el valor de inicio (ON=abierto / OFF=cerrado) + Tranquera(PinName pin_tranquera, int value, PinName pin_boton_abrir, PinMode mode_boton_abrir, PinName pin_boton_cerrar, PinMode mode_boton_cerrar); + + // + void update_position(position_t new_position); + + // Lee el valor de la tranquera + position_t read(); + + // + bool position_changed; + + // Sobrecarga del operador = para escribir + Tranquera &operator= (position_t new_position) + { + update_position(new_position); + return *this; + } + + // Sobrecarga de position_t() para leer + operator position_t() + { + return read(); + } + + private: + // leds de salida + Led output; + + // + InterruptIn int_boton_abrir; + InterruptIn int_boton_cerrar; + + void int_boton_abrir_callback(); + void int_boton_cerrar_callback(); + +}; + +//=====[Declarations (prototypes) of public functions]========================= + +//=====[#include guards - end]================================================= + +#endif // _TRANQUERA_H_ \ No newline at end of file diff --git a/modules/user_interface/user_interface.cpp b/modules/user_interface/user_interface.cpp deleted file mode 100644 index fb999c9..0000000 --- a/modules/user_interface/user_interface.cpp +++ /dev/null @@ -1,192 +0,0 @@ -//=====[Libraries]============================================================= - -#include "mbed.h" -#include "arm_book_lib.h" - -#include "user_interface.h" - -#include "code.h" -#include "siren.h" -#include "smart_home_system.h" -#include "fire_alarm.h" -#include "date_and_time.h" -#include "temperature_sensor.h" -#include "gas_sensor.h" -#include "matrix_keypad.h" -#include "display.h" - -//=====[Declaration of private defines]======================================== - -#define DISPLAY_REFRESH_TIME_MS 1000 - -//=====[Declaration of private data types]===================================== - -//=====[Declaration and initialization of public global objects]=============== - -DigitalOut incorrectCodeLed(LED3); -DigitalOut systemBlockedLed(LED2); - -//=====[Declaration of external public global variables]======================= - -//=====[Declaration and initialization of public global variables]============= - -char codeSequenceFromUserInterface[CODE_NUMBER_OF_KEYS]; - -//=====[Declaration and initialization of private global variables]============ - -static bool incorrectCodeState = OFF; -static bool systemBlockedState = OFF; - -static bool codeComplete = false; -static int numberOfCodeChars = 0; - -//=====[Declarations (prototypes) of private functions]======================== - -static void userInterfaceMatrixKeypadUpdate(); -static void incorrectCodeIndicatorUpdate(); -static void systemBlockedIndicatorUpdate(); - -static void userInterfaceDisplayInit(); -static void userInterfaceDisplayUpdate(); - -//=====[Implementations of public functions]=================================== - -void userInterfaceInit() -{ - incorrectCodeLed = OFF; - systemBlockedLed = OFF; - matrixKeypadInit( SYSTEM_TIME_INCREMENT_MS ); - userInterfaceDisplayInit(); -} - -void userInterfaceUpdate() -{ - userInterfaceMatrixKeypadUpdate(); - incorrectCodeIndicatorUpdate(); - systemBlockedIndicatorUpdate(); - userInterfaceDisplayUpdate(); -} - -bool incorrectCodeStateRead() -{ - return incorrectCodeState; -} - -void incorrectCodeStateWrite( bool state ) -{ - incorrectCodeState = state; -} - -bool systemBlockedStateRead() -{ - return systemBlockedState; -} - -void systemBlockedStateWrite( bool state ) -{ - systemBlockedState = state; -} - -bool userInterfaceCodeCompleteRead() -{ - return codeComplete; -} - -void userInterfaceCodeCompleteWrite( bool state ) -{ - codeComplete = state; -} - -//=====[Implementations of private functions]================================== - -static void userInterfaceMatrixKeypadUpdate() -{ - static int numberOfHashKeyReleased = 0; - char keyReleased = matrixKeypadUpdate(); - - if( keyReleased != '\0' ) { - - if( sirenStateRead() && !systemBlockedStateRead() ) { - if( !incorrectCodeStateRead() ) { - codeSequenceFromUserInterface[numberOfCodeChars] = keyReleased; - numberOfCodeChars++; - if ( numberOfCodeChars >= CODE_NUMBER_OF_KEYS ) { - codeComplete = true; - numberOfCodeChars = 0; - } - } else { - if( keyReleased == '#' ) { - numberOfHashKeyReleased++; - if( numberOfHashKeyReleased >= 2 ) { - numberOfHashKeyReleased = 0; - numberOfCodeChars = 0; - codeComplete = false; - incorrectCodeState = OFF; - } - } - } - } - } -} - -static void userInterfaceDisplayInit() -{ - displayInit(); - - displayCharPositionWrite ( 0,0 ); - displayStringWrite( "Temperature:" ); - - displayCharPositionWrite ( 0,1 ); - displayStringWrite( "Gas:" ); - - displayCharPositionWrite ( 0,2 ); - displayStringWrite( "Alarm:" ); -} - -static void userInterfaceDisplayUpdate() -{ - static int accumulatedDisplayTime = 0; - char temperatureString[3] = ""; - - if( accumulatedDisplayTime >= - DISPLAY_REFRESH_TIME_MS ) { - - accumulatedDisplayTime = 0; - - sprintf(temperatureString, "%.0f", temperatureSensorReadCelsius()); - displayCharPositionWrite ( 12,0 ); - displayStringWrite( temperatureString ); - displayCharPositionWrite ( 14,0 ); - displayStringWrite( "'C" ); - - displayCharPositionWrite ( 4,1 ); - - if ( gasDetectorStateRead() ) { - displayStringWrite( "Detected " ); - } else { - displayStringWrite( "Not Detected" ); - } - - displayCharPositionWrite ( 6,2 ); - - if ( sirenStateRead() ) { - displayStringWrite( "ON " ); - } else { - displayStringWrite( "OFF" ); - } - - } else { - accumulatedDisplayTime = - accumulatedDisplayTime + SYSTEM_TIME_INCREMENT_MS; - } -} - -static void incorrectCodeIndicatorUpdate() -{ - incorrectCodeLed = incorrectCodeStateRead(); -} - -static void systemBlockedIndicatorUpdate() -{ - systemBlockedLed = systemBlockedState; -} \ No newline at end of file diff --git a/modules/user_interface/user_interface.h b/modules/user_interface/user_interface.h deleted file mode 100644 index e1e596c..0000000 --- a/modules/user_interface/user_interface.h +++ /dev/null @@ -1,25 +0,0 @@ -//=====[#include guards - begin]=============================================== - -#ifndef _USER_INTERFACE_H_ -#define _USER_INTERFACE_H_ - -//=====[Declaration of public defines]========================================= - -//=====[Declaration of public data types]====================================== - -//=====[Declarations (prototypes) of public functions]========================= - -void userInterfaceInit(); -void userInterfaceUpdate(); -bool userInterfaceCodeCompleteRead(); -void userInterfaceCodeCompleteWrite( bool state ); - -bool incorrectCodeStateRead(); -void incorrectCodeStateWrite( bool state ); - -bool systemBlockedStateRead(); -void systemBlockedStateWrite( bool state ); - -//=====[#include guards - end]================================================= - -#endif // _USER_INTERFACE_H_ \ No newline at end of file