Created
February 21, 2022 02:37
-
-
Save btidor/2144fcf4d5a14eb7a7ef17e67137b758 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <mbed.h> | |
#include "USBFprint.h" | |
int main() { | |
Serial1.begin(115200); | |
Serial1.println("\r\n --8<------------------------\r\n"); | |
Serial1.print("Connecting I"); | |
USBFprint fp(false); | |
Serial1.print("C"); | |
fp.connect(); | |
Serial1.println("*"); | |
while (true) { | |
thread_sleep_for(1000); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2018-2019, Arm Limited and affiliates. | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#include <stdint.h> | |
#include <string.h> | |
#include "Arduino.h" | |
#include "USBFprint.h" | |
#include "EndpointResolver.h" | |
#include "usb_phy_api.h" | |
#define DEFAULT_CONFIGURATION (1) | |
USBFprint::USBFprint(bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) | |
: USBDevice(get_usb_phy(), vendor_id, product_id, product_release) | |
{ | |
_init(); | |
if (connect_blocking) { | |
connect(); | |
} else { | |
init(); | |
} | |
} | |
USBFprint::USBFprint(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) | |
: USBDevice(phy, vendor_id, product_id, product_release) | |
{ | |
_init(); | |
} | |
USBFprint::~USBFprint() | |
{ | |
deinit(); | |
} | |
void USBFprint::_init() | |
{ | |
EndpointResolver resolver(endpoint_table()); | |
resolver.endpoint_ctrl(BULK_MAX_PACKET_SIZE); | |
_bulk_in = resolver.endpoint_in(USB_EP_TYPE_BULK, BULK_MAX_PACKET_SIZE); | |
_bulk_out = resolver.endpoint_out(USB_EP_TYPE_BULK, BULK_MAX_PACKET_SIZE); | |
_int_in = resolver.endpoint_in(USB_EP_TYPE_INT, INT_MAX_PACKET_SIZE); | |
MBED_ASSERT(resolver.valid()); | |
} | |
void USBFprint::callback_state_change(DeviceState new_state) | |
{ | |
Serial1.print("callback_state_change new_state="); | |
assert_locked(); | |
/* Called in ISR context */ | |
switch (new_state) { | |
case Attached: | |
Serial1.print("Attached"); | |
break; | |
case Powered: | |
Serial1.print("Powered"); | |
break; | |
case Default: | |
Serial1.print("Default"); | |
break; | |
case Address: | |
Serial1.print("Address"); | |
break; | |
case Configured: | |
Serial1.print("Configured"); | |
break; | |
default: | |
Serial1.print("Unknown"); | |
break; | |
} | |
Serial1.println("*"); | |
} | |
void USBFprint::callback_request(const setup_packet_t *setup) | |
{ | |
Serial1.print("callback_request bRequest=0x"); | |
Serial1.println(setup->bRequest, HEX); | |
assert_locked(); | |
/* Called in ISR context */ | |
complete_request(PassThrough, NULL, 0); | |
// The Windows driver always asks to un-stall the endpoints, but we must | |
// re-begin the read after this is handled. | |
if (setup->bRequest == 0x01) { | |
read_start(_bulk_out, _rx_buffer, sizeof(_rx_buffer)); | |
} | |
} | |
void USBFprint::callback_request_xfer_done(const setup_packet_t *setup, bool aborted) | |
{ | |
Serial1.print("callback_xfer_done"); | |
assert_locked(); | |
/* Called in ISR context */ | |
complete_request_xfer_done(false); | |
} | |
void USBFprint::callback_set_configuration(uint8_t configuration) | |
{ | |
Serial1.print("callback_set_configuration cfg=0x"); | |
Serial1.println(configuration, HEX); | |
assert_locked(); | |
/* Called in ISR context */ | |
bool ret = false; | |
if (configuration == DEFAULT_CONFIGURATION) { | |
// Configure endpoints > 0 | |
endpoint_add(_int_in, INT_MAX_PACKET_SIZE, USB_EP_TYPE_INT); | |
endpoint_add(_bulk_in, BULK_MAX_PACKET_SIZE, USB_EP_TYPE_BULK, &USBFprint::_send_isr); | |
endpoint_add(_bulk_out, BULK_MAX_PACKET_SIZE, USB_EP_TYPE_BULK, &USBFprint::_receive_isr); | |
read_start(_bulk_out, _rx_buffer, sizeof(_rx_buffer)); | |
ret = true; | |
} | |
complete_set_configuration(ret); | |
} | |
void USBFprint::callback_set_interface(uint16_t interface, uint8_t alternate) | |
{ | |
Serial1.print("callback_set_interface cfg=0x"); | |
Serial1.println(interface, HEX); | |
assert_locked(); | |
complete_set_interface(true); | |
} | |
/* | |
* Called by when CDC data is sent | |
* Warning: Called in ISR | |
*/ | |
void USBFprint::_send_isr() | |
{ | |
assert_locked(); | |
write_finish(_bulk_in); | |
} | |
uint8_t version_data[] = { | |
// Padding | |
0x00, 0x00, | |
// Build Time (little endian) | |
0x47, 0x51, 0x2a, 0x5f, | |
// Build Num. (little endian) | |
0x27, 0xf2, 0x31, 0x00, | |
// Version Major, Minor | |
0x0a, 0x01, | |
// Target, Product | |
0x01, 0x41, | |
// Silicon Rev., Formal Release, Platform, Patch | |
0x01, 0xc1, 0x00, 0x00, | |
// Serial Num. (021354, swapped nibbles) | |
0x21, 0x65, 0x43, 0x87, 0xcb, 0xa9, | |
// Security Level (little endian) | |
0x0f, 0xa9, | |
// Interface, Device Type | |
0x00, 0x00, | |
// ??? | |
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, | |
}; | |
bmkt_resp_t resp = { | |
// These fields shouldn't be touched | |
.padding = 0, | |
.header_id = BMKT_MESSAGE_HEADER_ID, | |
}; | |
uint8_t uid[64]; | |
uint8_t uid_len; | |
int remaining; | |
uint8_t resp8e09[] = { | |
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, | |
0x09, 0x00, 0x86, 0x0d, 0x00, 0x00, 0xf4, 0x01, | |
0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, | |
}; | |
uint8_t resp8e1a[] = { | |
0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x44, 0x00, | |
0x1a, 0x00, 0xab, 0xc2, 0x02, 0x00, 0xbe, 0xc0, | |
0x02, 0x00, 0x5b, 0x1b, 0x00, 0x00, 0x0a, 0x00, | |
0x00, 0x00, 0x44, 0x00, 0x56, 0x00, 0x68, 0x00, | |
0x03, 0x00, 0x6b, 0x01, 0x20, 0x03, 0x00, 0x00, | |
0x00, 0x00, 0x10, 0x27, 0x41, 0x00, 0xa0, 0x0f, | |
0xd7, 0x00, 0x00, 0x00, 0x19, 0x00, 0x19, 0x00, | |
0x19, 0x00, 0x19, 0x00, 0x19, 0x00, 0x19, 0x00, | |
0x19, 0x00, 0x19, 0x00, 0x19, 0x00, 0x19, 0x00, | |
0x19, 0x00, 0x19, 0x00, 0x19, 0x00, | |
}; | |
uint8_t resp8e2f[] = { | |
0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, | |
0x2f, 0x00, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, | |
0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, | |
0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x32, 0x00, | |
0x00, 0x00, | |
}; | |
uint8_t respaf01[] = { | |
0x00, 0x00, 0xea, 0x5c, 0x59, 0x15, 0x01, 0xff, | |
0xff, 0xff, | |
}; | |
uint8_t resp19[] = { | |
0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0xf4, 0xd0, 0xea, 0x5a, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, | |
}; | |
/* | |
* Called by when CDC data is received | |
* Warning: Called in ISR | |
*/ | |
void USBFprint::_receive_isr() | |
{ | |
assert_locked(); | |
uint32_t size = read_finish(_bulk_out); | |
Serial1.print("recv"); | |
_print_buffer_hex(_rx_buffer, size); | |
Serial1.println(); | |
_handle(size); | |
// Get ready to read next message | |
read_start(_bulk_out, _rx_buffer, sizeof(_rx_buffer)); | |
} | |
void USBFprint::_handle(uint32_t size) | |
{ | |
bmkt_msg_t *msg; | |
cmd_id_user_t *id_user; | |
MBED_ASSERT(size > 0); | |
switch (_rx_buffer[0]) { | |
case SENSOR_CMD_GET_VERSION: | |
MBED_ASSERT(size == 1); | |
_send_buffer(version_data, sizeof(version_data)); | |
Serial1.println("> GET_VERSION -> VERSION(...)"); | |
break; | |
case SENSOR_CMD_ACE_COMMAND: | |
msg = (bmkt_msg_t*)(&_rx_buffer[1]); | |
MBED_ASSERT(msg->header_id == BMKT_MESSAGE_HEADER_ID); | |
switch (msg->msg_id) { | |
case BMKT_CMD_FPS_INIT: | |
MBED_ASSERT(size == 1 + sizeof(msg)); | |
resp = { | |
.padding = 0, | |
.header_id = BMKT_MESSAGE_HEADER_ID, | |
.seq_num = msg->seq_num, | |
.msg_id = BMKT_RSP_FPS_INIT_OK, | |
.payload_len = 1, | |
}; | |
resp.payload[0] = 0; | |
_send_buffer((uint8_t*)&resp, RESP_BASE_LEN + 1); | |
Serial1.println("> FPS_INIT() -> FPS_INIT_OK(0)"); | |
break; | |
case BMKT_CMD_GET_TEMPLATE_RECORDS: | |
// Report 0 enrolled fingers if queried | |
MBED_ASSERT(size == 1 + sizeof(msg)); | |
resp = { | |
.padding = 0, | |
.header_id = BMKT_MESSAGE_HEADER_ID, | |
.seq_num = msg->seq_num, | |
.msg_id = BMKT_RSP_QUERY_RESPONSE_COMPLETE, | |
.payload_len = 0, | |
}; | |
_send_buffer((uint8_t*)&resp, RESP_BASE_LEN); | |
Serial1.println("> GET_TEMPLATE_RECORDS() -> QUERY_RESPONSE_COMPLETE()"); | |
break; | |
case BMKT_CMD_ID_USER_IN_ORDER: | |
// Save first UID only | |
id_user = (cmd_id_user_t*)(msg->payload); | |
MBED_ASSERT(id_user->payload_ct == 1); | |
resp = { | |
.padding = 0, | |
.header_id = BMKT_MESSAGE_HEADER_ID, | |
.seq_num = msg->seq_num, | |
.msg_id = 0, | |
.payload_len = 0, | |
}; | |
memcpy(uid, id_user->uid, id_user->uid_len); | |
uid_len = id_user->uid_len; | |
remaining = id_user->total_ct - id_user->payload_ct; | |
if (remaining > 0) { | |
resp.msg_id = BMKT_RSP_SEND_NEXT_USER_ID; | |
} else { | |
resp.msg_id = BMKT_RSP_ID_READY; | |
} | |
_send_buffer((uint8_t*)&resp, RESP_BASE_LEN); | |
Serial1.print("> ID_USER_IN_ORDER("); | |
Serial1.print(id_user->total_ct, DEC); | |
Serial1.print(", "); | |
Serial1.print(id_user->payload_ct, DEC); | |
Serial1.print(", "); | |
Serial1.print(id_user->uid_len, DEC); | |
Serial1.print(", \""); | |
_print_buffer_char(id_user->uid, id_user->uid_len); | |
if (remaining > 0) { | |
Serial1.println("\") -> SEND_NEXT_USER_ID()"); | |
} else { | |
Serial1.println("\") -> ID_READY()"); | |
} | |
break; | |
case BMKT_CMD_ID_NEXT_USER: | |
// XXX: we *should* respond with ID_READY | |
// but short-circuiting to ID_OK works... | |
remaining -= msg->payload[0]; | |
MBED_ASSERT(remaining == 0); | |
resp = { | |
.padding = 0, | |
.header_id = BMKT_MESSAGE_HEADER_ID, | |
.seq_num = msg->seq_num, | |
.msg_id = BMKT_RSP_ID_OK, | |
.payload_len = 3 + uid_len, | |
}; | |
resp.payload[0] = 0x2b; | |
resp.payload[1] = 0x38; | |
resp.payload[2] = 0x01; | |
memcpy(&resp.payload[3], uid, uid_len); | |
_send_buffer((uint8_t*)&resp, RESP_BASE_LEN + 3 + uid_len); | |
Serial1.print("> ID_NEXT_USER("); | |
Serial1.print(msg->payload[0], DEC); | |
Serial1.println(", ...) -> ID_OK(56.43, 1, ...)"); | |
break; | |
case BMKT_CMD_POWER_DOWN_NOTIFY: | |
MBED_ASSERT(size == 1 + sizeof(msg)); | |
resp = { | |
.padding = 0, | |
.header_id = BMKT_MESSAGE_HEADER_ID, | |
.seq_num = msg->seq_num, | |
.msg_id = BMKT_RSP_POWER_DOWN_READY, | |
.payload_len = 0, | |
}; | |
_send_buffer((uint8_t*)&resp, RESP_BASE_LEN); | |
Serial1.println("> POWER_DOWN_NOTIFY() -> POWER_DOWN_READY()"); | |
break; | |
default: | |
Serial1.print("! UNKNOWN:ACE:0x"); | |
Serial1.println(msg->msg_id, HEX); | |
break; | |
} | |
break; | |
case 0x8E: | |
MBED_ASSERT(size > 1); | |
switch (_rx_buffer[1]) { | |
case 0x09: | |
_send_buffer(resp8e09, sizeof(resp8e09)); | |
Serial1.println("> 8E:09() -> ..."); | |
break; | |
case 0x1A: | |
_send_buffer(resp8e1a, sizeof(resp8e1a)); | |
Serial1.println("> 8E:1A() -> ..."); | |
break; | |
case 0x2F: | |
_send_buffer(resp8e2f, sizeof(resp8e2f)); | |
Serial1.println("> 8E:2F() -> ..."); | |
break; | |
default: | |
Serial1.print("! UNKNOWN:0x8E:0x"); | |
Serial1.println(msg->msg_id, HEX); | |
break; | |
} | |
break; | |
case 0xAF: | |
_send_buffer(respaf01, sizeof(respaf01)); | |
Serial1.println("> AF:01() -> ..."); | |
break; | |
case 0x19: | |
_send_buffer(resp19, sizeof(resp19)); | |
Serial1.println("> 19() -> ..."); | |
break; | |
default: | |
Serial1.print("! UNKNOWN:SENSOR:0x"); | |
Serial1.println(_rx_buffer[0], HEX); | |
break; | |
} | |
} | |
void USBFprint::_send_buffer(uint8_t *buffer, uint32_t size) | |
{ | |
Serial1.print("send"); | |
_print_buffer_hex(buffer, size); | |
Serial1.println(); | |
write_start(_bulk_in, buffer, size); | |
} | |
void USBFprint::_print_buffer_hex(uint8_t *buffer, uint32_t size) | |
{ | |
Serial1.print("("); | |
Serial1.print(size, DEC); | |
Serial1.print("): 0x"); | |
for (int i = 0; i < size; i++) { | |
if (buffer[i] < 0x10) { | |
Serial1.print("0"); | |
} | |
Serial1.print(buffer[i], HEX); | |
Serial1.print(" "); | |
} | |
} | |
void USBFprint::_print_buffer_char(uint8_t *buffer, uint32_t size) | |
{ | |
for (int i = 0; i < size; i++) { | |
Serial1.print((char)buffer[i]); | |
} | |
} | |
const uint8_t *USBFprint::string_iserial_desc() | |
{ | |
static const uint8_t stringIserialDescriptor[] = { | |
0x1a, | |
STRING_DESCRIPTOR, | |
'1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0, '9', 0, 'a', 0, 'b', 0, 'c', 0, | |
}; | |
return stringIserialDescriptor; | |
} | |
const uint8_t *USBFprint::device_desc() | |
{ | |
uint8_t ep0_size = endpoint_max_packet_size(0x00); | |
uint8_t device_descriptor_temp[] = { | |
18, // bLength | |
1, // bDescriptorType | |
0x00, 0x02, // bcdUSB | |
255, // bDeviceClass | |
16, // bDeviceSubClass | |
255, // bDeviceProtocol | |
ep0_size, // bMaxPacketSize0 // XXX: should be 8, not 64 | |
(uint8_t)(LSB(vendor_id)), (uint8_t)(MSB(vendor_id)), // idVendor | |
(uint8_t)(LSB(product_id)), (uint8_t)(MSB(product_id)),// idProduct | |
0x00, 0x00, // bcdDevice | |
0, // iManufacturer | |
0, // iProduct | |
STRING_OFFSET_ISERIAL,// iSerialNumber | |
1 // bNumConfigurations | |
}; | |
MBED_ASSERT(sizeof(device_descriptor_temp) == sizeof(device_descriptor)); | |
memcpy(device_descriptor, device_descriptor_temp, sizeof(device_descriptor)); | |
return device_descriptor; | |
} | |
#define CONFIG1_DESC_SIZE (9+9+7+7+7) | |
const uint8_t *USBFprint::configuration_desc(uint8_t index) | |
{ | |
uint8_t config_descriptor_temp[] = { | |
// configuration descriptor | |
9, // bLength | |
2, // bDescriptorType | |
LSB(CONFIG1_DESC_SIZE), // wTotalLength | |
MSB(CONFIG1_DESC_SIZE), | |
1, // bNumInterfaces | |
1, // bConfigurationValue | |
0, // iConfiguration | |
0xa0, // bmAttributes | |
50, // bMaxPower | |
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |
9, // bLength | |
4, // bDescriptorType | |
0, // bInterfaceNumber | |
0, // bAlternateSetting | |
3, // bNumEndpoints | |
255, // bInterfaceClass | |
0, // bInterfaceSubClass | |
0, // bInterfaceProtocol | |
0, // iInterface | |
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |
ENDPOINT_DESCRIPTOR_LENGTH, // bLength | |
ENDPOINT_DESCRIPTOR, // bDescriptorType | |
_bulk_out, // bEndpointAddress | |
E_BULK, // bmAttributes (0x02=bulk) | |
LSB(BULK_MAX_PACKET_SIZE), // wMaxPacketSize (LSB) | |
MSB(BULK_MAX_PACKET_SIZE), // wMaxPacketSize (MSB) | |
0, // bInterval | |
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |
ENDPOINT_DESCRIPTOR_LENGTH, // bLength | |
ENDPOINT_DESCRIPTOR, // bDescriptorType | |
_bulk_in, // bEndpointAddress | |
E_BULK, // bmAttributes (0x02=bulk) | |
LSB(BULK_MAX_PACKET_SIZE), // wMaxPacketSize (LSB) | |
MSB(BULK_MAX_PACKET_SIZE), // wMaxPacketSize (MSB) | |
0, // bInterval | |
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |
ENDPOINT_DESCRIPTOR_LENGTH, // bLength | |
ENDPOINT_DESCRIPTOR, // bDescriptorType | |
_int_in, // bEndpointAddress // XXX: should be 0x83, not 0x82 | |
E_INTERRUPT, // bmAttributes (0x03=intr) | |
LSB(INT_MAX_PACKET_SIZE), // wMaxPacketSize (LSB) | |
MSB(INT_MAX_PACKET_SIZE), // wMaxPacketSize (MSB) | |
4 // bInterval | |
}; | |
if (index == 0) { | |
MBED_ASSERT(sizeof(config_descriptor_temp) == sizeof(_config_descriptor)); | |
memcpy(_config_descriptor, config_descriptor_temp, sizeof(_config_descriptor)); | |
return _config_descriptor; | |
} else { | |
return NULL; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2018-2019, Arm Limited and affiliates. | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#ifndef USBFPRINT_H | |
#define USBFPRINT_H | |
/* These headers are included for child class. */ | |
#include "USBDescriptor.h" | |
#include "USBDevice_Types.h" | |
#include "USBDevice.h" | |
#include "OperationList.h" | |
/** | |
* \defgroup drivers_USBFprint USBFprint class | |
* \ingroup drivers-public-api-usb | |
* @{ | |
*/ | |
// XXX: Synaptics lies, says 64 but actually transfers packets of 206+ | |
// unfortunately mbedOS checks | |
#define BULK_MAX_PACKET_SIZE 256 | |
#define INT_MAX_PACKET_SIZE 8 | |
#define SENSOR_CMD_GET_VERSION 0x01 | |
#define SENSOR_CMD_ACE_COMMAND 0xA7 | |
#define SENSOR_CMD_ASYNCMSG_READ 0xA8 | |
#define BMKT_MESSAGE_HEADER_ID 0xFE | |
#define BMKT_CMD_FPS_INIT 0x11 | |
#define BMKT_RSP_FPS_INIT_OK 0x13 | |
#define BMKT_RSP_FPS_INIT_FAIL 0x12 | |
#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71 | |
#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76 | |
#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1 | |
#define BMKT_RSP_POWER_DOWN_READY 0xA2 | |
#define BMKT_RSP_POWER_DOWN_FAIL 0xA3 | |
#define BMKT_CMD_ID_USER_IN_ORDER 0xE1 | |
#define BMKT_CMD_ID_NEXT_USER 0xE3 | |
#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2 | |
#define BMKT_RSP_ID_READY 0x62 | |
#define BMKT_RSP_ID_OK 0x64 | |
typedef struct { | |
uint8_t header_id; | |
uint8_t seq_num; | |
uint8_t msg_id; | |
uint8_t payload_len; | |
uint8_t payload[64]; | |
} bmkt_msg_t; | |
typedef struct { | |
uint16_t padding; | |
uint8_t header_id; | |
uint8_t seq_num; | |
uint8_t msg_id; | |
uint8_t payload_len; | |
uint8_t payload[64]; | |
} bmkt_resp_t; | |
#define RESP_BASE_LEN 6 | |
typedef struct { | |
uint8_t total_ct; | |
uint8_t payload_ct; | |
// XXX: we don't support payloads containing multiple UIDs | |
uint8_t uid_len; | |
uint8_t uid[64]; | |
} cmd_id_user_t; | |
class USBFprint: public USBDevice { | |
public: | |
/** | |
* Basic constructor | |
* | |
* Construct this object optionally connecting and blocking until it is ready. | |
* | |
* @note Do not use this constructor in derived classes. | |
* | |
* @param connect_blocking true to perform a blocking connect, false to start in a disconnected state | |
* @param vendor_id Your vendor_id | |
* @param product_id Your product_id | |
* @param product_release Your product_release | |
*/ | |
USBFprint(bool connect_blocking = true, uint16_t vendor_id = 0x06cb, uint16_t product_id = 0x00bd, uint16_t product_release = 0x0001); | |
/** | |
* Fully featured constructor | |
* | |
* Construct this object with the supplied USBPhy and parameters. The user | |
* this object is responsible for calling connect() or init(). | |
* | |
* @note Derived classes must use this constructor and call init() or | |
* connect() themselves. Derived classes should also call deinit() in | |
* their destructor. This ensures that no interrupts can occur when the | |
* object is partially constructed or destroyed. | |
* | |
* @param phy USB phy to use | |
* @param vendor_id Your vendor_id | |
* @param product_id Your product_id | |
* @param product_release Your product_release | |
*/ | |
USBFprint(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release); | |
/** | |
* Destroy this object | |
* | |
* Any classes which inherit from this class must call deinit | |
* before this destructor runs. | |
*/ | |
virtual ~USBFprint(); | |
protected: | |
virtual const uint8_t *string_iserial_desc(); | |
virtual const uint8_t *device_desc(); | |
virtual const uint8_t *configuration_desc(uint8_t index); | |
protected: | |
virtual void callback_reset() {}; | |
virtual void callback_state_change(DeviceState new_state); | |
virtual void callback_request(const setup_packet_t *setup); | |
virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted); | |
virtual void callback_set_configuration(uint8_t configuration); | |
virtual void callback_set_interface(uint16_t interface, uint8_t alternate); | |
void _init(); | |
void _send_isr_start(); | |
void _send_isr(); | |
void _receive_isr_start(); | |
void _receive_isr(); | |
void _handle(uint32_t size); | |
void _send_buffer(uint8_t *buffer, uint32_t size); | |
void _print_buffer_hex(uint8_t *buffer, uint32_t size); | |
void _print_buffer_char(uint8_t *buffer, uint32_t size); | |
usb_ep_t _bulk_in; | |
usb_ep_t _bulk_out; | |
usb_ep_t _int_in; | |
uint8_t _config_descriptor[39]; | |
uint8_t _tx_buffer[BULK_MAX_PACKET_SIZE]; | |
uint8_t _rx_buffer[BULK_MAX_PACKET_SIZE]; | |
}; | |
/** @}*/ | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment