#include #include #include #include #include #include #include #include #include #include #include const uint8_t fw_version = 1; uint32_t reset_reason __attribute__((section(".bootinfo"))); static bool do_reset; void reset_bootloader() { reset_reason = 0xb007; SCB.AIRCR = (0x5fa << 16) | (1 << 2); // SYSRESETREQ } enum tag_type_t { ISO15693, ISO18092, }; auto report_desc = pack( usage_page(0xffca), usage(0x01), collection(Collection::Application, // ISO 15693 report_id(1), usage_page(0xffca), usage(0x41), logical_minimum(0), logical_maximum(255), report_size(8), report_count(8), input(0x02), // ISO 18092 report_id(2), usage_page(0xffca), usage(0x42), logical_minimum(0), logical_maximum(255), report_size(8), report_count(8), input(0x02) ) ); auto dev_desc = device_desc(0x200, 0, 0, 0, 64, 0x1d50, 0x60f8, 0, 0, 0, 0, 1); auto conf_desc = configuration_desc(2, 1, 0, 0xc0, 0, interface_desc(1, 0, 1, 0x03, 0x00, 0x00, 0, hid_desc(0x111, 0, 1, 0x22, sizeof(report_desc)), endpoint_desc(0x81, 0x03, 64, 0) ), interface_desc(2, 0, 1, 0xff, 0x00, 0x00, 0, endpoint_desc(0x82, 0x03, 64, 0) ) ); desc_t dev_desc_p = {sizeof(dev_desc), (void*)&dev_desc}; desc_t conf_desc_p = {sizeof(conf_desc), (void*)&conf_desc}; desc_t report_desc_p = {sizeof(report_desc), (void*)&report_desc}; USB_l0 usb(USB, dev_desc_p, conf_desc_p); Pin nfc_sck = GPIOB[3]; Pin nfc_miso = GPIOB[4]; Pin nfc_mosi = GPIOB[5]; Pin nfc_ss = GPIOB[6]; Pin nfc_irq_out = GPIOB[7]; Pin nfc_irq_in = GPIOC[13]; Pin button = GPIOA[3]; Pin led = GPIOA[4]; PinArray kp_rows = GPIOB.array(12, 15); PinArray kp_cols = GPIOA.array(8, 10); class CR95HF { private: SPI_t& spi; Pin& ss; public: CR95HF(SPI_t& spi_bus, Pin& p) : spi(spi_bus), ss(p) {} void send_cmd(uint8_t cmd, uint32_t len, uint8_t* buf) { ss.off(); spi.transfer_byte(0); spi.transfer_byte(cmd); spi.transfer_byte(len); while(len--) { spi.transfer_byte(*buf++); } ss.on(); } uint32_t get_response(uint32_t maxlen, uint8_t* buf) { uint32_t len = 0; while(nfc_irq_out.get()); ss.off(); spi.transfer_byte(2); *buf++ = spi.transfer_byte(); len++; uint32_t datalen = spi.transfer_byte(); *buf++ = datalen; len++; while(len < datalen + 2) { *buf++ = spi.transfer_byte(); len++; } ss.on(); return len; } }; CR95HF cr95hf(SPI1, nfc_ss); class HID_NFC : public USB_HID { public: HID_NFC(USB_generic& usbd, desc_t rdesc) : USB_HID(usbd, rdesc, 1, 1, 64) {} }; HID_NFC hid_nfc(usb, report_desc_p); /* class USB_NFC : public USB_class_driver { private: USB_generic& usb; public: USB_NFC(USB_generic& usbd) : usb(usbd) { usb.register_driver(this); } protected: virtual void handle_set_configuration(uint8_t configuration) { if(configuration) { usb.hw_conf_ep(0x81, EPType::Bulk, 64); } } }; USB_NFC usb_nfc(usb); */ class USB_keypad : public USB_class_driver { private: USB_generic& usb; public: USB_keypad(USB_generic& usbd) : usb(usbd) { usb.register_driver(this); } protected: virtual void handle_set_configuration(uint8_t configuration) { if(configuration) { usb.hw_conf_ep(0x82, EPType::Interrupt, 64); } } }; USB_keypad usb_keypad(usb); class USB_fwver : public USB_class_driver { private: USB_generic& usb; bool reset_boot(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { if(wValue != 0xb007) { return false; } do_reset = true; usb.write(0, nullptr, 0); return true; } bool get_version(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { if(wLength < 1) { return false; } uint32_t buf = fw_version; usb.write(0, &buf, 1); return true; } public: USB_fwver(USB_generic& usbd) : usb(usbd) { usb.register_driver(this); } protected: virtual SetupStatus handle_setup(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength) { if(bmRequestType == 0xc0 && bRequest == 0xf0) { return get_version(wValue, wIndex, wLength) ? SetupStatus::Ok : SetupStatus::Stall; } if(bmRequestType == 0x40 && bRequest == 0xff) { return reset_boot(wValue, wIndex, wLength) ? SetupStatus::Ok : SetupStatus::Stall; } return SetupStatus::Unhandled; } }; USB_fwver usb_fwver(usb); int main() { rcc_init(); // Initialize system timer. STK.LOAD = 32000000 / 8 / 1000; // 1000 Hz. STK.VAL = 0; STK.CTRL = 0x03; // Enable CRS. RCC.enable(RCC.CRS); CRS.enable(); RCC.enable(RCC.GPIOA); RCC.enable(RCC.GPIOB); RCC.enable(RCC.GPIOC); led.set_mode(Pin::Output); RCC.enable(RCC.USB); usb.init(); Time::sleep(10); USB.reg.BCDR |= 1 << 15; RCC.enable(RCC.SPI1); nfc_irq_out.set_mode(Pin::Input); nfc_irq_in.on(); nfc_irq_in.set_mode(Pin::Output); nfc_ss.on(); nfc_ss.set_mode(Pin::Output); nfc_sck.set_speed(Pin::High); nfc_sck.set_mode(Pin::AF); nfc_miso.set_mode(Pin::AF); nfc_mosi.set_mode(Pin::AF); SPI1.reg.CR1 = (1 << 9) | (1 << 8) | (1 << 6) | (4 << 3) | (1 << 2) | (0 << 1) | (0 << 0); // SSM, SSI, SPE, 36/32MHz, MSTR, CPOL=0, CPHA=0 SPI1.reg.CR2 = (1 << 12) | (7 << 8); // FRXTH, DS = 8bit Time::sleep(1); nfc_irq_in.off(); Time::sleep(1); nfc_irq_in.on(); Time::sleep(1); uint8_t buf[64]; bool cmd_sent = false; uint32_t nfc_delay_until = 0; uint8_t bulk_buf[9]; tag_type_t active_type = ISO15693; Time::sleep(1000); kp_cols.set_mode(Pin::Input); kp_cols.set_pull(Pin::PullUp); kp_rows.set_type(Pin::OpenDrain); kp_rows.set_mode(Pin::Output); uint32_t kp_last = 0; while(1) { if(Time::time() < nfc_delay_until) { // Just do nothing. } else if(!cmd_sent) { led.off(); if(active_type == ISO15693) { cr95hf.send_cmd(0x02, 2, (uint8_t*)"\x01\x05"); // Select ISO 15693 cr95hf.get_response(64, buf); cr95hf.send_cmd(0x04, 3, (uint8_t*)"\x26\x01\x00"); // INVENTORY } else if(active_type == ISO18092) { cr95hf.send_cmd(0x02, 2, (uint8_t*)"\x04\x51"); // Select ISO 18092 cr95hf.get_response(64, buf); cr95hf.send_cmd(0x04, 5, (uint8_t*)"\x00\xff\xff\x00\x00"); // REQC } cmd_sent = true; } else if(!nfc_irq_out.get()) { cr95hf.get_response(64, buf); cmd_sent = false; if(buf[0] == 128 && buf[14] == 0) { led.on(); uint8_t* id_buf = bulk_buf; if(active_type == ISO15693) { *id_buf++ = 1; uint8_t* id_raw = &buf[11]; for(uint32_t i = 0; i < 8; i++) { *id_buf++ = *id_raw--; } } else if(active_type == ISO18092) { *id_buf++ = 2; uint8_t* id_raw = &buf[3]; for(uint32_t i = 0; i < 8; i++) { *id_buf++ = *id_raw++; } } if(usb.ep_ready(1)) { usb.write(1, (uint32_t*)bulk_buf, sizeof(bulk_buf)); } nfc_delay_until = Time::time() + 5000; // Valid for five seconds. } else { nfc_delay_until = Time::time() + 100; // Retry in 100ms. if(active_type == ISO15693) { active_type = ISO18092; } else { active_type = ISO15693; } } } uint32_t kp_state = 0; for(int i = 0; i < 4; i++) { kp_rows.set(~(1 << i)); asm volatile("dmb"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); kp_state |= ((~kp_cols.get()) & 0x7) << (i * 3); } if(kp_state != kp_last && usb.ep_ready(2)) { usb.write(2, &kp_state, 2); kp_last = kp_state; } if(do_reset) { Time::sleep(10); reset_bootloader(); } usb.process(); } }