mac osx prism header pcap - macos

i'm trying to capture packets in monitor mode on my mac for research issues. From these packets i need some special information, e.g. the rssi. Unfortunately, the linktype says DLT_IEEE802_11_RADIO, but i actually expect DLT_PRISM_HEADER, because monitor mode should be turned on. This is a problem, because the radiotap header does not provide any RSSI value or other stuff i need.
Here is my code (i leave out the callback method and so forth):
int main(int argc, char *argv[])
{
pcap_t *handle; /* Session handle */
char *dev; /* The device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
struct pcap_pkthdr header; /* The header that pcap gives us */
const u_char *packet; /* The actual packet */
struct ether_header *ether; /* net/ethernet.h */
/* Define the device */
dev = pcap_lookupdev(errbuf);
if(dev == NULL) {
printf("Couldn't find default device: %s\n", errbuf);
exit(EXIT_FAILURE);
}
printf("Device: %s\n", dev);
//handle = pcap_open_live(dev, 1562, 1, 500, errbuf);
handle = pcap_create(dev, errbuf);
if(handle == NULL) {
printf("pcap_create failed: %s\n", errbuf);
exit(EXIT_FAILURE);
}
/* set monitor mode on */
if(pcap_set_rfmon(handle, 1) != 0) {
printf("monitor mode not available\n");
exit(EXIT_FAILURE);
}
pcap_set_snaplen(handle, 2048); // Set the snapshot length to 2048
pcap_set_promisc(handle, 1); // Turn promiscuous mode on
pcap_set_timeout(handle, 512); // Set the timeout to 512 milliseconds
int status = pcap_activate(handle);
if(status != 0) {
printf("activation failed: %d\n", status);
}
printf("link-type: %s\n", pcap_datalink_val_to_name(pcap_datalink(handle)));
int loop = pcap_loop(handle, 1, process_packet, NULL);
if(loop != 0) {
printf("loop terminated before exhaustion: %d\n", loop);
}
/* And close the session */
pcap_close(handle);
return(0);
}
So does anybody know, why i am receiving radiotap and not prism and how i should do instead?
Again i am coding under OSX.

From these packets i need some special information, e.g. the rssi.
Then, unless the driver will let you request PPI headers rather than radiotap headers - use pcap_list_datalinks() in monitor mode after calling pcap_activate() and, if that includes DLT_PPI, set the link-layer header type to DLT_PPI with pcap_set_datalink() - you're out of luck. If you can request PPI headers, then you might be able to get RSSI values from that header; see the PPI specification.
Unfortunately, the linktype says DLT_IEEE802_11_RADIO, but i actually expect DLT_PRISM_HEADER, because monitor mode should be turned on.
There is no reason whatsoever to, on an arbitrary operating system with an arbitrary Wi-Fi device and driver, to expect that you'll get Prism headers in monitor mode. If you get radio information at all, you get whatever header the driver writer supplies. These days, drivers tend to use radiotap - Linux mac80211 drivers, most *BSD drivers, and OS X drivers do.

Related

How to differentiate between devices in the windows HID API?

I need to detect when a gamepad is plugged in for my game (I'm not using a higher-level input API for reasons), how can I do this? I've already enumerated all HID devices and opened files on them (except keyboard, mouse ofc) and can get all the info on the device, but what info do I want? What value(s) will tell me right away that this is an xbox controller, for example, and where are these values?
My code for enumerating over the devices (very messy atm :p):
DWORD required_size = 0, determined_size;
SP_DEVICE_INTERFACE_DATA device_interface_data;
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data;
HANDLE current_device;
PHIDP_PREPARSED_DATA preparsed_data;
WCHAR product_string[128];
for (int i = 0; ; ++i) /* Enumerate HID devices */
{
rv = SetupDiEnumDeviceInterfaces(device_enumeration, NULL, &interface_guid, i, &device_interface_data); /* Does the actual enumeration,
each time we increase index i
to get the next device */
error = GetLastError();
if (error == ERROR_NO_MORE_ITEMS) /* If there are no more devices, break */
break;
else if (!rv && error != ERROR_NO_MORE_ITEMS) /* Otherwise, we have a legit error */
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
SetupDiGetDeviceInterfaceDetail(device_enumeration, &device_interface_data, NULL, 0, &required_size, NULL); /* Probing call only to get buffer size,
so error code (122) ignored */
/* Allocate new device detail struct using buffer size we obtained */
determined_size = required_size;
device_interface_detail_data = cr_safe_malloc(required_size);
device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
/* Get detailed info about device */
rv = SetupDiGetDeviceInterfaceDetail(device_enumeration, &device_interface_data, device_interface_detail_data, determined_size, &required_size, NULL);
if (!rv)
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
cr_printf("FOUNDD DEVICE: %s\n\n", device_interface_detail_data->DevicePath);
current_device = cr_open_device(device_interface_detail_data->DevicePath);
if (!current_device && GetLastError() == ERROR_ACCESS_DENIED)
goto Done;
cr_printf("OPENED DEVICE: %s\n\n", device_interface_detail_data->DevicePath);
preparsed_data = HidD_GetPreparsedData(current_device, &preparsed_data);
if (!preparsed_data)
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
HidD_GetProductString(current_device, product_string, sizeof(product_string));
cr_printf("PRODUCT STRING: %S\n\n", product_string);
HidD_FreePreparsedData(&preparsed_data);
DeleteFile(device_interface_detail_data->DevicePath);
Done:
cr_safe_free(&device_interface_detail_data);
}
SetupDiDestroyDeviceInfoList(device_enumeration);
As you can see I've found the product string, which tells me what the device actually is, but maybe comparing product strings is not the best way to do PnP?
Check if the device ID contains "IG_". If it does, then it's an XInput device.
More info on that. But which device corresponds to which XInput dwUserIndex is more difficult question...
Also you can try to check for XUSB interface:
// {EC87F1E3-C13B-4100-B5F7-8B84D54260CB}
DEFINE_GUID(XUSB_INTERFACE_CLASS_GUID, 0xEC87F1E3, 0xC13B, 0x4100, 0xB5, 0xF7, 0x8B, 0x84, 0xD5, 0x42, 0x60, 0xCB);

ESP32 SDCARD speed issue

I am trying to use SD Card on Wrover kit but it seems that speed is the big issue on the board itself.
At first I wanted to download file from the net and save it to SDCARD but it took too long so to test it I've written a loop to save some chars into file and create ~1MB large file on a SDCARD and it takes forever.
What could be the cause that ~1MB file could be such a long task to do.
I have combined two examples into one to do the task.
Also I have commented everything and left just part with writing to file to demonstrate issue.
/* ESP HTTP Client Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#define LOG_LOCAL_LEVEL ESP_LOG_ERROR
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "app_wifi.h"
#include "esp_http_client.h"
/* SD CARD */
#include "esp_vfs_fat.h"
#include "driver/sdmmc_host.h"
#include "driver/sdspi_host.h"
#include "sdmmc_cmd.h"
/* SD CARD */
#define USE_SPI_MODE
#ifdef USE_SPI_MODE
// Pin mapping when using SPI mode.
// With this mapping, SD card can be used both in SPI and 1-line SD mode.
// Note that a pull-up on CS line is required in SD mode.
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 15
#define PIN_NUM_CLK 14
#define PIN_NUM_CS 13
#endif //USE_SPI_MODE
//#define MAX_HTTP_RECV_BUFFER 512
#define MAX_HTTP_RECV_BUFFER 1024
static const char *TAG = "HTTP_CLIENT";
// ------------------ GLOBAL VARS -----------------------------
FILE *fp=NULL;
// ------------------ GLOBAL VARS -----------------------------
/* Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem
The PEM file was extracted from the output of this command:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA root cert is the last cert given in the chain of certs.
To embed it in the app binary, the PEM file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start");
extern const char howsmyssl_com_root_cert_pem_end[] asm("_binary_howsmyssl_com_root_cert_pem_end");
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGE (TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGE (TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGE (TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGE (TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGE (TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
// Write out data
// printf("%.*s", evt->data_len, (char*)evt->data);
if(fp == NULL){
fp = fopen("/sdcard/muzika.mp3","wb");
}
if(fp != NULL){
fwrite(evt->data,1,evt->data_len,fp);
ESP_LOGE (TAG, "---------- HTTP_EVENT_ON_DATA - WRITING TO SD CARD ----------");
}
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGE (TAG, "HTTP_EVENT_ON_FINISH");
fclose(fp);
fp = NULL;
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGE (TAG, "HTTP_EVENT_DISCONNECTED");
break;
}
return ESP_OK;
}
static void http_download_chunk()
{
esp_http_client_config_t config = {
//.url = "http://httpbin.org/stream-bytes/8912",
.url = "http://www.theoctopusproject.com/mp3/whatthey.mp3",
.event_handler = _http_event_handler,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP chunk encoding Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
}
static void http_test_task(void *pvParameters)
{
app_wifi_wait_connected();
ESP_LOGI(TAG, "Connected to AP, begin http example");
http_download_chunk();
ESP_LOGI(TAG, "Finish http example");
vTaskDelete(NULL);
}
void app_main()
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// -- app_wifi_initialise();
/* SDCARD SETUP */
#ifndef USE_SPI_MODE
ESP_LOGI(TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// To use 1-line SD mode, uncomment the following line:
// slot_config.width = 1;
// GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
// Internal pull-ups are not sufficient. However, enabling internal pull-ups
// does make a difference some boards, so we do that here.
gpio_set_pull_mode(15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes
gpio_set_pull_mode(2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes
gpio_set_pull_mode(4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only
gpio_set_pull_mode(12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only
gpio_set_pull_mode(13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes
#else
ESP_LOGI(TAG, "Using SPI peripheral");
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
slot_config.gpio_miso = PIN_NUM_MISO;
slot_config.gpio_mosi = PIN_NUM_MOSI;
slot_config.gpio_sck = PIN_NUM_CLK;
slot_config.gpio_cs = PIN_NUM_CS;
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
#endif //USE_SPI_MODE
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
// formatted in case when mounting fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
// Please check its source code and implement error recovery when developing
// production applications.
sdmmc_card_t* card;
ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set format_if_mount_failed = true.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
return;
}
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
// Use POSIX and C standard library functions to work with files.
// First create a file.
ESP_LOGE(TAG, "Opening file");
FILE* f = fopen("/sdcard/hello.txt", "w");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
// ------------------------ WRITE INTO FILE -------------------
int j=0;
for(int i = 0 ; i < 1048576 ; i++,j++){
//fprintf(f, "Hello %s!\n", card->cid.name);
fprintf(f, "X");
if(j > 1024){
vTaskDelay(3);
j = 0;
}
}
fclose(f);
ESP_LOGE(TAG, "File written");
// ------------------------ WRITE INTO FILE -------------------
//-- xTaskCreate(&http_test_task, "http_test_task", 8192, NULL, 5, NULL);
//xTaskCreate(&http_test_task, "http_test_task", 16384, NULL, 5, NULL);
}
Your example is writing one byte at a time. That won't get you an accurate idea of how the overall speed of writing to the SD card - your code will spend a disproportionate amount of time processing the individual writes.
If you want to get a more accurate idea of how fast you can write to the card, try writing 1024 bytes (or even more) at a time. Benchmarks that measure maximum throughput and performance-sensitive applications will always write as much data as they can at a time in order to minimize the overhead of the write.
Also, don't use fprintf() if possible. It has extra overhead because it parses the format string. Try fwrite() - it will have less overhead and will give you a better idea of what you can expect in the best case.
Try something like this instead:
char *buf = malloc(1024);
if(buf) {
for(int i = 0; i < 1024; i++) {
fwrite(buf, 1, 1024, f);
vTaskDelay(3); // you'll speed this up if you can omit this
}
ESP_LOGE(TAG, "File written");
free(buf);
} else
ESP_LOGE(TAG, "malloc() failed");
fclose(f);

Need to write driver for USB peripheral device?

I'm working on designing a USB peripheral which will occasionally connect to a Windows PC, and transfer a few KB of data in each direction. There will be a custom PC application that controls the data transfers, using a proprietary protocol (i.e. for the USB payloads).
I see at the following link that Microsoft describes how to write a driver for a USB device. But do I need one?
Developing Windows client drivers for USB devices
The PC application is the only application that we intend to know how to communicate with the device, so there's no need for a driver from an application sharing standpoint.
Can I just bake the custom protocol directly into the application, have the application speak "raw USB" to the device, and do without a separate driver?
"raw USB", no, you can't do that from an application.
But because you control the device also, you can make it appear as one of the device classes for which Windows provides a device driver that's generic enough to do just about anything you want.
Those device classes are HID (Human Interface Device) and "WinUSB". Of these, HID is cross-platform but more limited in capability, WinUSB allows high performance data transfers as well as interrupt endpoints.
Instructions for setting up your device's string descriptors so that Windows automatically binds it to the WinUSB driver are on MSDN
A WinUSB device is a Universal Serial Bus (USB) device whose firmware defines certain Microsoft operating system (OS) feature descriptors that report the compatible ID as "WINUSB".
The purpose of a WinUSB device is to enable Windows to load Winusb.sys as the device's function driver without a custom INF file. For a WinUSB device, you are not required to distribute INF files for your device, making the driver installation process simple for end users.
There is another way with no need to write driver to write what You want to device using WriteFile function:WinUSB, how to do this:
Include WinUsb.h
Add WinUsb.lib to the list of linked libraries.
in Usb100.h some macros.
Use the device interface GUID to obtain the device path. The correct GUID is the one that you specified in the INF that was used to install WinUsb.sys.
Get a handle to the device information set by passing the device interface GUID that you defined in the INF to SetupDiGetClassDevs. The function returns an HDEVINFO handle.
Call SetupDiEnumDeviceInterfaces to enumerate the system’s device interfaces and obtain information on your device interface.
Call SetupDiGetDeviceInterfaceDetail to get detailed data for the device interface.
Call the GetDevicePath function to obtain the device path.
Pass the device path to CreateFile to obtain a file handle for the device. Use ReadFile and Write File to communicate with device!
Pass the file handle to WinUsb_Initialize to initialize WinUSB and obtain a WinUSB handle. You use the device’s WinUSB handle to identify the device when you call WinUSB API functions, not the device’s file handle.
For more advanced solutions - use functions:
WinUsb_QueryDeviceInformation to obtain the device’s speed.
WinUsb_QueryInterfaceSettings to obtain the corresponding interface descriptors. The WinUSB handle corresponds to the first interface.
WinUsb_QueryPipe gets information about each endpoint.
WinUsb_WritePipe writes the buffer to the device - default behavior: zero-length writes are forwarded down the stack. If the transfer length is greater than a maximum transfer length, WinUSB divides the request into smaller requests of maximum transfer length and submits them serially.
more functions and info: http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/winusb_howto.docx
For debugging purposes You probably need:
winusbtrace_tool https://blogs.msdn.microsoft.com/usbcoreblog/2010/02/05/how-to-generate-and-view-a-winusb-debug-trace-log/;
Wireshark https://www.wireshark.org with USBPcap plugin.
Other Example:
http://searchingforbit.blogspot.com/2012/04/winusb-communication-with-stm32-part-1.html.
Sample template comes with Visual Studio.
You need also have knowledge of writing .inf files.
Another easy way to communicate with USB - libusb-win32 https://sourceforge.net/projects/libusb-win32/
My simple console app sends chunks to device (raw data write immediately to device bypassing the stack):
#include "stdafx.h"
#include <SetupAPI.h>
#include <Hidsdi.h>
#include <devguid.h>
#include <winusb.h>
#include <usb.h>
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "winusb.lib")
#include <iUString.h>
iString<char> DevicePath;
bool WinusbHandle_Open=false;
bool DeviceHandle_Open = false;
WINUSB_INTERFACE_HANDLE WinusbHandle;
HANDLE DeviceHandle;
UCHAR usb_out_buffer[64];
DEFINE_GUID(GUID_DEVCLASS_WINUSB, 0x88bae032L, 0x5a81, 0x49f0, 0xbc, 0x3d, 0xa4, 0xff, 0x13, 0x82, 0x16, 0xd6);
DEFINE_GUID(GUID_DEVCLASS_STL, 0xf177724dL, 0x74d3, 0x430e, 0x86, 0xb5, 0xf0, 0x36, 0x89, 0x10, 0xeb, 0x23);
GUID winusb_guid;
GUID stl_guid;
bool connectusb();
void disconnectusb();
int main()
{
DWORD n;
DWORD numEvents;
HANDLE rHnd;
WinusbHandle_Open = false;
DeviceHandle_Open = false;
winusb_guid = GUID_DEVCLASS_WINUSB;
stl_guid = GUID_DEVCLASS_STL;
usb_out_buffer[0] = 0;
usb_out_buffer[1] = 1;
usb_out_buffer[2] = 2;
usb_out_buffer[3] = 3;
ULONG bytesWritten;
ULONG timeout;
timeout = 100;
rHnd = GetStdHandle(STD_INPUT_HANDLE);
WinUsb_SetPipePolicy(WinusbHandle, 0x01, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, AUTO_CLEAR_STALL, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, RAW_IO, sizeof(ULONG), &timeout);//Bypasses queuing and error handling to boost performance for multiple read requests.
while (true)
{
if ((!WinusbHandle_Open) || (!WinusbHandle_Open)) { if (!connectusb())Sleep(2000); }
if ((!WinusbHandle_Open) || (!WinusbHandle_Open))continue;
bytesWritten = 0;
if (!WinUsb_WritePipe(WinusbHandle, 0x01, &usb_out_buffer[0], 2, &bytesWritten, NULL))
{
n = GetLastError();
disconnectusb();
}
Sleep(2000);
}
disconnectusb();
return 0;
}
bool connectusb()
{
BOOL bResult = FALSE;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA interfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
DWORD n;
SP_DEVINFO_DATA devinfo;
BYTE devdetailbuffer[4096];
bool found;
deviceInfo = SetupDiGetClassDevs(&stl_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfo == INVALID_HANDLE_VALUE) { return false; }
found = false;
for (n = 0;; n++)
{
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &stl_guid, n, &interfaceData))
{
n = GetLastError();
break;
}
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)devdetailbuffer;
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
devinfo.cbSize = sizeof(devinfo);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, sizeof(devdetailbuffer), NULL, &devinfo)) { printf("SetupDiGetDeviceInterfaceDetail: %u\n", GetLastError()); break; }
if (IsEqualGUID(devinfo.ClassGuid, winusb_guid))
{
if ((-1 != iStrPos(detailData->DevicePath, "VID_0483")) || (-1 != iStrPos(detailData->DevicePath, "vid_0483")))
{
if ((-1 != iStrPos(detailData->DevicePath, "PID_576B")) || (-1 != iStrPos(detailData->DevicePath, "pid_576b")))
{
DevicePath = detailData->DevicePath;
found = true;
break;
}
}
}
}
SetupDiDestroyDeviceInfoList(deviceInfo);
if (!found)return false;
DeviceHandle = CreateFile(DevicePath.Buffer() ,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == DeviceHandle) {
n = GetLastError();
}
if (INVALID_HANDLE_VALUE == DeviceHandle) return false;
DeviceHandle_Open = true;
if (!WinUsb_Initialize(DeviceHandle, &WinusbHandle))
{
n = GetLastError();
CloseHandle(DeviceHandle); DeviceHandle_Open = false;
return false;
}
WinusbHandle_Open = true;
return true;
}
void disconnectusb()
{
if (WinusbHandle_Open) { WinUsb_Free(WinusbHandle); WinusbHandle_Open = false; }
if (DeviceHandle_Open) { CloseHandle(DeviceHandle); DeviceHandle_Open = false; }
}
Making your firmware to be enumerated as a WINUSB (winusb generic driver) device makes life easier.
I believe it'd be clear if you have a demo and code so I made one for you :)
My KEIL project using the STM32F4 Discovery board working with WINUSB as an USB CDC device. You can see more information and have the source code from my GitHub.

How to read/write to an USB storage device with a linux driver?

During the attempt to write my own simple usb driver for an usb-flash-drive, I got stuck reading the data that I wrote to the device.
So, my first question is:
How is the transfer and the storage on a device going on? (in detail)
I know I have to perform the following steps:
Create an urb (USB request block)
Allocate a DMA buffer
Transfer the data from the user-space into the DMA buffer
Send the data through a pipe to the device
I couldn't find any documentation on how a device handles this data.
Is this even possible to write such a driver, or would it be necessary to disassemble the usb device, to send special commands?
The code I have written looks something like the following and is from the ldd3 and "http://lxr.free-electrons.com/source/drivers/usb/usb-skeleton.c". It only shows a shortened version of the important functions.
After loading the driver into the kernel, I can write to the device without any error, but if I read, an EPIPE error occurs. Ldd3 mentions that the usb_clear_halt() could solve this problem, but it doesn't.
// This function is called when the device is plugged in
static int my_driver_probe(struct usb_interface* interface, const struct usb_device_id* id)
{
struct usb_skel* dev = NULL;
struct usb_device* udev = interface_to_usbdev(interface);
struct usb_host_interface* iface_desc;
struct usb_endpoint_descriptor* endpoint;
int retval = -ENODEV;
int i = 0;
size_t buffer_size;
dev = kzalloc(sizeof(struct usb_skel), GFP_KERNEL);
// Check vendor and product id
// …
dev->udev = udev;
dev->interface = interface;
// Set up the endpoint information
iface_desc = interface->cur_altsetting;
for(i=0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if(!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
buffer_size = endpoint->wMaxPacketSize;
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if(!dev->bulk_in_buffer) {
printk("Could not allocate bulk_in_buffer\n");
goto error;
}
dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
}
if(!dev->bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint))
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
// Check that the endpoints are set
// …
// Save our data pointer in this interface device
usb_set_intfdata(interface, dev);
// Register the device
retval = usb_register_dev(interface, &class_descr);
return retval;
}
// Is called when another program writes into /dev/my_usb_driver
static ssize_t my_driver_write( struct file* file, const char __user* user_buffer, size_t count, loff_t* offs)
{
struct usb_skel* dev = file->private_data;
struct urb* urb = NULL;
char* buf = NULL;
int retval = 0;
size_t writesize = min(count, (size_t)MAX_TRANSFER);
// Create a urb, and a buffer for it, and copy the data to the urb
urb = usb_alloc_urb(0, GFP_KERNEL);
// Creates a DMA buffer
buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);
// The data that is passed to the driver should be copied into the DMA buffer
copy_from_user(buf, user_buffer, writesize;
// Initialize the urb proberly
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, writesize, (void*)my_write_bulk_callback, dev);
// Send the data out the bulk port
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(urb, GFP_KERNEL);
return writesize;
}
// Is called when another program reads from /dev/my_usb_driver
static ssize_t my_driver_read( struct file *file, char* buffer, size_t count, loff_t* offs)
{
struct usb_skel* dev = file->private_data;
int retval = 0;
// Check that we have data to read
// …
usb_fill_bulk_urb(dev->bulk_in_urb, dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count), read_bulk_callback, dev);
retval = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
// If the read was succesful, copy the data to user space
copy_to_user(buffer, dev->bulk_in_buffer, count);
return retval;
}
USB is just a transport layer. Storage devices generally implement SCSI protocol. Create a SCSI command for reading or writing from the data that user space has sent. Then create URB for the SCSI command and send it to the USB device.
SCSI is a huge protocol, for learning USB device driver development it is better to start with simple devices like USB to serial devices.

Libnfc How to read NFC card content?

I'm trying to simply read an ISO 14443-2B ST SRx card content using ACR122 card reader.
I've set up my environment with Libnfc and the proper reader driver.
Right now I've managed to write a code that simply read the card UID and prints that out.
There's no documentation at all, and I totally don't know where to start for reading card content. Any clue or code snippet?
This is what I've done:
// To compile this simple example:
// $ gcc -o quick_start_example1 quick_start_example1.c -lnfc
// ./quick_start_example1
#include <stdlib.h>
#include <nfc/nfc.h>
void print_nfc_target(const nfc_target *pnt, bool verbose)
{
char *s;
str_nfc_target(&s, pnt, verbose);
printf("%s", s);
nfc_free(s);
}
int main(int argc, const char *argv[])
{
nfc_device *pnd;
nfc_target nt;
// Allocate only a pointer to nfc_context
nfc_context *context;
// Initialize libnfc and set the nfc_context
nfc_init(&context);
if (context == NULL) {
printf("Unable to init libnfc (malloc)\n");
exit(EXIT_FAILURE);
}
// Display libnfc version
const char *acLibnfcVersion = nfc_version();
(void)argc;
printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
// Open, using the first available NFC device
pnd = nfc_open(context, NULL);
if (pnd == NULL) {
printf("ERROR: %s\n", "Unable to open NFC device.");
exit(EXIT_FAILURE);
}
// Set opened NFC device to initiator mode
if (nfc_initiator_init(pnd) < 0) {
nfc_perror(pnd, "nfc_initiator_init");
exit(EXIT_FAILURE);
}
printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
nfc_target ant[1];
nfc_modulation nm;
nm.nmt = NMT_ISO14443B;
nm.nbr = NBR_106;
nfc_initiator_list_passive_targets(pnd,nm,ant,1);
printf("%s\n",nfc_strerror(pnd)); // print Success
nfc_target ant2[1];
nfc_modulation nm2;
nm2.nmt = NMT_ISO14443B2SR;
nm2.nbr = NBR_106;
int res = 0;
int n = 0;
res = nfc_initiator_list_passive_targets(pnd, nm2, ant2, 1);
printf("%s\n",nfc_strerror(pnd)); // print Success
// printf("Cart identifier: %s\n", nt.nti.nsi.abtUID);
for (n = 0; n < res; n++) {
print_nfc_target(&ant2[n], true);
printf("\n");
}
// Close NFC device
nfc_close(pnd);
// Release the context
nfc_exit(context);
exit(EXIT_SUCCESS);
}
PS: I'm listing 2 times the targets because of a known bug ( http://www.libnfc.org/community/topic/1044/problem-with-init-of-iso14443b/ )
I wrote a small helper program to read ST SRx tags using LibNFC:
https://github.com/Depau/nfc-st-srx/
It still needs some changes to write them but it does read them successfully.
For a start (this is how I began), get EMV book 3 and read on the commands for card transactions, including the command APDUs and how they are written, response APDUs and how they are processed, response codes, status byte codes e.t.c. Then get books 1 - 5 to accompany the above book. Also get the book Implementing Electronic Card Payment Systems by Cristian Radu which will guide you through every step needed to learn how to develop EMV card applications. Hope that helps.

Resources