int acr122_usb_init(nfc_device *pnd) { int res = 0; int i; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; /* // See ACR122 manual: "Bi-Color LED and Buzzer Control" section uint8_t acr122u_get_led_state_frame[] = { 0x6b, // CCID 0x09, // lenght of frame 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding // frame: 0xff, // Class 0x00, // INS 0x40, // P1: Get LED state command 0x00, // P2: LED state control 0x04, // Lc 0x00, 0x00, 0x00, 0x00, // Blinking duration control }; log_put (LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Get LED state"); if ((res = acr122_usb_bulk_write (DRIVER_DATA (pnd), (uint8_t *) acr122u_get_led_state_frame, sizeof (acr122u_get_led_state_frame), 1000)) < 0) return res; if ((res = acr122_usb_bulk_read (DRIVER_DATA (pnd), abtRxBuf, sizeof (abtRxBuf), 1000)) < 0) return res; */ if ((res = pn53x_set_property_int(pnd, NP_TIMEOUT_COMMAND, 1000)) < 0) return res; // Power On ICC uint8_t ccid_frame[] = { PC_to_RDR_IccPowerOn, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 }; if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), ccid_frame, sizeof(struct ccid_header), 1000)) < 0) return res; if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000)) < 0) return res; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 PICC Operating Parameters"); if ((res = acr122_usb_send_apdu(pnd, 0x00, 0x51, 0x00, NULL, 0, 0, abtRxBuf, sizeof(abtRxBuf))) < 0) return res; res = 0; for (i = 0; i < 3; i++) { if (res < 0) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 init failed, trying again..."); if ((res = pn53x_init(pnd)) >= 0) break; } if (res < 0) return res; return NFC_SUCCESS; }
nfc_device * acr122_open (const nfc_connstring connstring) { struct acr122_descriptor ndd; int connstring_decode_level = acr122_connstring_decode (connstring, &ndd); if (connstring_decode_level < 2) { return NULL; } // FIXME: acr122_open() does not take care about bus index char *pcFirmware; nfc_device *pnd = nfc_device_new (connstring); pnd->driver_data = malloc (sizeof (struct acr122_data)); // Alloc and init chip's data pn53x_data_new (pnd, &acr122_io); SCARDCONTEXT *pscc; log_put (LOG_CATEGORY, NFC_PRIORITY_TRACE, "Attempt to open %s", ndd.pcsc_device_name); // Test if context succeeded if (!(pscc = acr122_get_scardcontext ())) goto error; // Test if we were able to connect to the "emulator" card if (SCardConnect (*pscc, ndd.pcsc_device_name, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &(DRIVER_DATA (pnd)->hCard), (void *) &(DRIVER_DATA (pnd)->ioCard.dwProtocol)) != SCARD_S_SUCCESS) { // Connect to ACR122 firmware version >2.0 if (SCardConnect (*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA (pnd)->hCard), (void *) &(DRIVER_DATA (pnd)->ioCard.dwProtocol)) != SCARD_S_SUCCESS) { // We can not connect to this device. log_put (LOG_CATEGORY, NFC_PRIORITY_TRACE, "%s", "PCSC connect failed"); goto error; } } // Configure I/O settings for card communication DRIVER_DATA (pnd)->ioCard.cbPciLength = sizeof (SCARD_IO_REQUEST); // Retrieve the current firmware version pcFirmware = acr122_firmware (pnd); if (strstr (pcFirmware, FIRMWARE_TEXT) != NULL) { // Done, we found the reader we are looking for snprintf (pnd->name, sizeof (pnd->name), "%s / %s", ndd.pcsc_device_name, pcFirmware); // 50: empirical tuning on Touchatag // 46: empirical tuning on ACR122U CHIP_DATA (pnd)->timer_correction = 50; pnd->driver = &acr122_driver; pn53x_init (pnd); return pnd; } error: nfc_device_free (pnd); return NULL; }
int pn53x_usb_init (nfc_device *pnd) { int res = 0; // Sometimes PN53x USB doesn't reply ACK one the first frame, so we need to send a dummy one... //pn53x_check_communication (pnd); // Sony RC-S360 doesn't support this command for now so let's use a get_firmware_version instead: const uint8_t abtCmd[] = { GetFirmwareVersion }; pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, 0, 0); // ...and we don't care about error pnd->last_error = 0; if (SONY_RCS360 == DRIVER_DATA (pnd)->model) { log_put (LOG_CATEGORY, NFC_PRIORITY_TRACE, "%s", "SONY RC-S360 initialization."); const uint8_t abtCmd2[] = { 0x18, 0x01 }; pn53x_transceive (pnd, abtCmd2, sizeof (abtCmd2), NULL, 0, 0); pn53x_usb_ack (pnd); } if ((res = pn53x_init (pnd)) < 0) return res; if (ASK_LOGO == DRIVER_DATA (pnd)->model) { log_put (LOG_CATEGORY, NFC_PRIORITY_TRACE, "%s", "ASK LoGO initialization."); /* Internal registers */ /* Disable 100mA current limit, Power on Secure IC (SVDD) */ pn53x_write_register (pnd, PN53X_REG_Control_switch_rng, 0xFF, SYMBOL_CURLIMOFF | SYMBOL_SIC_SWITCH_EN | SYMBOL_RANDOM_DATAREADY); /* Select the signal to be output on SIGOUT: Modulation signal (envelope) from the internal coder */ pn53x_write_register (pnd, PN53X_REG_CIU_TxSel, 0xFF, 0x14); /* SFR Registers */ /* Setup push-pulls for pins from P30 to P35 */ pn53x_write_register (pnd, PN53X_SFR_P3CFGB, 0xFF, 0x37); /* On ASK LoGO hardware: LEDs port bits definition: * LED 1: bit 2 (P32) * LED 2: bit 1 (P31) * LED 3: bit 0 or 3 (depending of hardware revision) (P30 or P33) * LED 4: bit 5 (P35) Notes: * Set logical 0 to switch LED on; logical 1 to switch LED off. * Bit 4 should be maintained at 1 to keep RF field on. Progressive field activation: The ASK LoGO hardware can progressively power-up the antenna. To use this feature we have to switch on the field by switching on the field on PN533 (RFConfiguration) then set P34 to '1', and cut-off the field by switching off the field on PN533 then set P34 to '0'. */ /* Set P30, P31, P33, P35 to logic 1 and P32, P34 to 0 logic */ /* ie. Switch LED1 on and turn off progressive field */ pn53x_write_register (pnd, PN53X_SFR_P3, 0xFF, _BV (P30) | _BV (P31) | _BV (P33) | _BV (P35)); } return NFC_SUCCESS; }
static nfc_device * pn532_uart_open(const nfc_context *context, const nfc_connstring connstring) { struct pn532_uart_descriptor ndd; int connstring_decode_level = pn532_connstring_decode(connstring, &ndd); if (connstring_decode_level < 2) { return NULL; } if (connstring_decode_level < 3) { ndd.speed = PN532_UART_DEFAULT_SPEED; } serial_port sp; nfc_device *pnd = NULL; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d bauds.", ndd.port, ndd.speed); sp = uart_open(ndd.port); if (sp == INVALID_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", ndd.port); if (sp == CLAIMED_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", ndd.port); if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL; // We need to flush input to be sure first reply does not comes from older byte transceive uart_flush_input(sp); uart_set_speed(sp, ndd.speed); // We have a connection pnd = nfc_device_new(context, connstring); snprintf(pnd->name, sizeof(pnd->name), "%s:%s", PN532_UART_DRIVER_NAME, ndd.port); pnd->driver_data = malloc(sizeof(struct pn532_uart_data)); DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data pn53x_data_new(pnd, &pn532_uart_io); // SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532 CHIP_DATA(pnd)->type = PN532; // This device starts in LowVBat mode CHIP_DATA(pnd)->power_mode = LOWVBAT; // empirical tuning CHIP_DATA(pnd)->timer_correction = 48; pnd->driver = &pn532_uart_driver; #ifndef WIN32 // pipe-based abort mecanism if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { return NULL; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif // Check communication using "Diagnose" command, with "Communication test" (0x00) if (pn53x_check_communication(pnd) < 0) { nfc_perror(pnd, "pn53x_check_communication"); pn532_uart_close(pnd); return NULL; } pn53x_init(pnd); return pnd; }
/** * @brief Connect to a NFC device * @param pndd device description if specific device is wanted, \c NULL otherwise * @return Returns pointer to a \a nfc_device_t struct if successfull; otherwise returns \c NULL value. * * If \e pndd is \c NULL, the first available NFC device is claimed. * It will automatically search the system using all available drivers to determine a device is NFC-enabled. * * If \e pndd is passed then this function will try to claim the right device using information provided by the \a nfc_device_desc_t struct. * * When it has successfully claimed a NFC device, memory is allocated to save the device information. It will return a pointer to a \a nfc_device_t struct. * This pointer should be supplied by every next functions of libnfc that should perform an action with this device. * * @note During this function, the device will be configured with default options: * - Crc is handled by the device (NDO_HANDLE_CRC = true) * - Parity is handled the device (NDO_HANDLE_PARITY = true) * - Cryto1 cipher is disabled (NDO_ACTIVATE_CRYPTO1 = false) * - Easy framing is enabled (NDO_EASY_FRAMING = true) * - Auto-switching in ISO14443-4 mode is enabled (NDO_AUTO_ISO14443_4 = true) * - Invalid frames are not accepted (NDO_ACCEPT_INVALID_FRAMES = false) * - Multiple frames are not accepted (NDO_ACCEPT_MULTIPLE_FRAMES = false) */ nfc_device_t * nfc_connect (nfc_device_desc_t * pndd) { nfc_device_t *pnd = NULL; uint32_t uiDriver; // Search through the device list for an available device for (uiDriver = 0; uiDriver < sizeof (drivers_callbacks_list) / sizeof (drivers_callbacks_list[0]); uiDriver++) { if (pndd == NULL) { // No device description specified: try to automatically claim a device if (drivers_callbacks_list[uiDriver].pick_device != NULL) { DBG ("Autodetecting available devices using %s driver.", drivers_callbacks_list[uiDriver].acDriver); pndd = drivers_callbacks_list[uiDriver].pick_device (); if (pndd != NULL) { DBG ("Auto-connecting to %s using %s driver", pndd->acDevice, drivers_callbacks_list[uiDriver].acDriver); pnd = drivers_callbacks_list[uiDriver].connect (pndd); if (pnd == NULL) { DBG ("No device available using %s driver", drivers_callbacks_list[uiDriver].acDriver); pndd = NULL; } free (pndd); } } } else { // Specific device is requested: using device description pndd if (0 != strcmp (drivers_callbacks_list[uiDriver].acDriver, pndd->pcDriver)) { continue; } else { pnd = drivers_callbacks_list[uiDriver].connect (pndd); } } // Test if the connection was successful if (pnd != NULL) { DBG ("[%s] has been claimed.", pnd->acName); // Great we have claimed a device pnd->pdc = &(drivers_callbacks_list[uiDriver]); // TODO: Put this pn53x related in driver_init() if (!pn53x_init (pnd)) return NULL; if (pnd->pdc->init) { pnd->pdc->init (pnd); } // Set default configuration options // Make sure we reset the CRC and parity to chip handling. if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) return NULL; if (!nfc_configure (pnd, NDO_HANDLE_PARITY, true)) return NULL; // Deactivate the CRYPTO1 cipher, it may could cause problems when still active if (!nfc_configure (pnd, NDO_ACTIVATE_CRYPTO1, false)) return NULL; // Activate "easy framing" feature by default if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) return NULL; // Activate auto ISO14443-4 switching by default if (!nfc_configure (pnd, NDO_AUTO_ISO14443_4, true)) return NULL; // Disallow invalid frame if (!nfc_configure (pnd, NDO_ACCEPT_INVALID_FRAMES, false)) return NULL; // Disallow multiple frames if (!nfc_configure (pnd, NDO_ACCEPT_MULTIPLE_FRAMES, false)) return NULL; return pnd; } else { DBG ("No device found using driver: %s", drivers_callbacks_list[uiDriver].acDriver); } } // Too bad, no reader is ready to be claimed return NULL; }
static nfc_device * acr122_pcsc_open(const nfc_context *context, const nfc_connstring connstring) { struct acr122_pcsc_descriptor ndd; int connstring_decode_level = connstring_decode(connstring, ACR122_PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); if (connstring_decode_level < 1) { return NULL; } nfc_connstring fullconnstring; if (connstring_decode_level == 1) { // Device was not specified, take the first one we can find size_t szDeviceFound = acr122_pcsc_scan(context, &fullconnstring, 1); if (szDeviceFound < 1) return NULL; connstring_decode_level = connstring_decode(fullconnstring, ACR122_PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); if (connstring_decode_level < 2) { return NULL; } } else { memcpy(fullconnstring, connstring, sizeof(nfc_connstring)); } if (strlen(ndd.pcsc_device_name) < 5) { // We can assume it's a reader ID as pcsc_name always ends with "NN NN" // Device was not specified, only ID, retrieve it size_t index; if (sscanf(ndd.pcsc_device_name, "%4" SCNuPTR, &index) != 1) { free(ndd.pcsc_device_name); return NULL; } nfc_connstring *ncs = malloc(sizeof(nfc_connstring) * (index + 1)); if (!ncs) { perror("malloc"); free(ndd.pcsc_device_name); return NULL; } size_t szDeviceFound = acr122_pcsc_scan(context, ncs, index + 1); if (szDeviceFound < index + 1) { free(ncs); free(ndd.pcsc_device_name); return NULL; } strncpy(fullconnstring, ncs[index], sizeof(nfc_connstring)); fullconnstring[sizeof(nfc_connstring) - 1] = '\0'; free(ncs); connstring_decode_level = connstring_decode(fullconnstring, ACR122_PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); if (connstring_decode_level < 2) { free(ndd.pcsc_device_name); return NULL; } } char *pcFirmware; nfc_device *pnd = nfc_device_new(context, fullconnstring); if (!pnd) { perror("malloc"); goto error; } pnd->driver_data = malloc(sizeof(struct acr122_pcsc_data)); if (!pnd->driver_data) { perror("malloc"); goto error; } // Alloc and init chip's data if (pn53x_data_new(pnd, &acr122_pcsc_io) == NULL) { perror("malloc"); goto error; } SCARDCONTEXT *pscc; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open %s", ndd.pcsc_device_name); // Test if context succeeded if (!(pscc = acr122_pcsc_get_scardcontext())) goto error; // Test if we were able to connect to the "emulator" card if (SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)) != SCARD_S_SUCCESS) { // Connect to ACR122 firmware version >2.0 if (SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)) != SCARD_S_SUCCESS) { // We can not connect to this device. log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed"); goto error; } } // Configure I/O settings for card communication DRIVER_DATA(pnd)->ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST); // Retrieve the current firmware version pcFirmware = acr122_pcsc_firmware(pnd); if (strstr(pcFirmware, FIRMWARE_TEXT) != NULL) { // Done, we found the reader we are looking for snprintf(pnd->name, sizeof(pnd->name), "%s / %s", ndd.pcsc_device_name, pcFirmware); // 50: empirical tuning on Touchatag // 46: empirical tuning on ACR122U CHIP_DATA(pnd)->timer_correction = 50; pnd->driver = &acr122_pcsc_driver; pn53x_init(pnd); free(ndd.pcsc_device_name); return pnd; } error: free(ndd.pcsc_device_name); nfc_device_free(pnd); return NULL; }
static nfc_device * arygon_open(const nfc_context *context, const nfc_connstring connstring) { struct arygon_descriptor ndd; char *speed_s; int connstring_decode_level = connstring_decode(connstring, ARYGON_DRIVER_NAME, NULL, &ndd.port, &speed_s); if (connstring_decode_level == 3) { ndd.speed = 0; if (sscanf(speed_s, "%10"PRIu32, &ndd.speed) != 1) { // speed_s is not a number free(ndd.port); free(speed_s); return NULL; } free(speed_s); } if (connstring_decode_level < 2) { return NULL; } if (connstring_decode_level < 3) { ndd.speed = ARYGON_DEFAULT_SPEED; } serial_port sp; nfc_device *pnd = NULL; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d baud.", ndd.port, ndd.speed); sp = uart_open(ndd.port); if (sp == INVALID_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", ndd.port); if (sp == CLAIMED_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", ndd.port); if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) { free(ndd.port); return NULL; } // We need to flush input to be sure first reply does not comes from older byte transceive uart_flush_input(sp, true); uart_set_speed(sp, ndd.speed); // We have a connection pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); free(ndd.port); uart_close(sp); return NULL; } snprintf(pnd->name, sizeof(pnd->name), "%s:%s", ARYGON_DRIVER_NAME, ndd.port); free(ndd.port); pnd->driver_data = malloc(sizeof(struct arygon_data)); if (!pnd->driver_data) { perror("malloc"); uart_close(sp); nfc_device_free(pnd); return NULL; } DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data if (pn53x_data_new(pnd, &arygon_tama_io) == NULL) { perror("malloc"); uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); return NULL; } // The PN53x chip opened to ARYGON MCU doesn't seems to be in LowVBat mode CHIP_DATA(pnd)->power_mode = NORMAL; // empirical tuning CHIP_DATA(pnd)->timer_correction = 46; pnd->driver = &arygon_driver; #ifndef WIN32 // pipe-based abort mecanism if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); return NULL; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif // Check communication using "Reset TAMA" command if (arygon_reset_tama(pnd) < 0) { arygon_close_step2(pnd); return NULL; } char arygon_firmware_version[10]; arygon_firmware(pnd, arygon_firmware_version); char *pcName; pcName = strdup(pnd->name); snprintf(pnd->name, sizeof(pnd->name), "%s %s", pcName, arygon_firmware_version); free(pcName); pn53x_init(pnd); return pnd; }