How to do response/request URB interrupt in libusb? - c

I'm trying to replicate a Windows program on Linux. The program talks to the USB device.
Now I'm stuck on the part where the device sends URB_interrupt IN first, and the host answers. The capture looks like this (and this is the result I want to have):
Frame 29: 72 bytes on wire (576 bits), 72 bytes captured (576 bits) on interface usbmon0, id 0
USB URB
[Source: 1.16.2]
[Destination: host]
URB id: 0xffff8d92d4ece840
URB type: URB_COMPLETE ('C')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 16
URB bus id: 1
Device setup request: not relevant ('-')
Data: present (0)
URB sec: 1664781571
URB usec: 862138
URB status: Success (0)
URB length [bytes]: 8
Data length [bytes]: 8
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
Leftover Capture Data: 0508ff0000000000
Frame 30: 64 bytes on wire (512 bits), 64 bytes captured (512 bits) on interface usbmon0, id 0
USB URB
[Source: host]
[Destination: 1.16.2]
URB id: 0xffff8d9321011cc0
URB type: URB_SUBMIT ('S')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 16
URB bus id: 1
Device setup request: not relevant ('-')
Data: not present ('<')
URB sec: 1664781571
URB usec: 865989
URB status: Operation now in progress (-EINPROGRESS) (-115)
URB length [bytes]: 8
Data length [bytes]: 0
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
It looks like the device sends the answer first (URB type is 'URB_COMPLETE'), and after that, the host answers ('URB_SUBMIT'). Previously I have only encountered the opposite situation (i. e. swap order of the captured packets) and I know how to do it, but I have no idea how to do the upper-mentioned one.
I do the URB interrupt by the following function:
#define INTR_EP_IN 0x82
#define INTR_LENGTH 8
typedef unsigned char byte_t;
/* Proper opening, kernel detaching, and interface claiming... */
static int send_interrupt(libusb_device_handle *handle)
{
byte_t *packet;
int transferred = 0;
short sent;
packet = calloc(INTR_LENGTH, 1);
sent = libusb_interrupt_transfer(handle, INTR_EP_IN, packet, INTR_LENGTH,
&transferred, 10);
free(packet);
/* Note: always TIMEOUT_ERROR, but the packet gets captured anyway */
/*
if(sent != 0)
fprintf(stderr, INTRRPT_ERR_MSG, libusb_strerror(sent));
*/
return sent;
}
I've tried to change libusb_interrupt_transfer parameters, but nothing gave me the desired result.
Every time I get something like the following:
Frame 30: 64 bytes on wire (512 bits), 64 bytes captured (512 bits) on interface usbmon0, id 0
USB URB
[Source: host]
[Destination: 1.6.2]
URB id: 0xffff922c3bd69540
URB type: URB_SUBMIT ('S')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 6
URB bus id: 1
Device setup request: not relevant ('-')
Data: not present ('<')
URB sec: 1668092600
URB usec: 503008
URB status: Operation now in progress (-EINPROGRESS) (-115)
URB length [bytes]: 8
Data length [bytes]: 0
[Response in: 31]
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
Frame 31: 64 bytes on wire (512 bits), 64 bytes captured (512 bits) on interface usbmon0, id 0
USB URB
[Source: 1.6.2]
[Destination: host]
URB id: 0xffff922c3bd69540
URB type: URB_COMPLETE ('C')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 6
URB bus id: 1
Device setup request: not relevant ('-')
Data: present (0)
URB sec: 1668092600
URB usec: 506108
URB status: No such file or directory (-ENOENT) (-2)
URB length [bytes]: 0
Data length [bytes]: 0
[Request in: 30]
[Time from request: 0.003100000 seconds]
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
Which totally isn't what I intend to have.
I'm assuming I don't know something as I am not an expert in the USB protocol. There's also a chance that libusb just doesn't allow to do such transfer. In this case, I should do this via corresponding syscalls, but this is the last resort for me.

Related

ESP IDF: Task never leaves vTaskDelay()

I am building a system that creates a WLAN AP over which the end user can Connect/disconnect the ESP to another AP ( For example a router) by posting a JSON String to a URL. In APSTA mode. When this is done a bool "_STA_START" is set to true. And the login parameters are saved in _STA_WIFI_SSID and _STA_WIFI_PASS.
I encounter a problem when writing the Task that manages the esp as Station. When the vTaskDelay() is called the code in the vTask_Manage_STA_Connection() just stops running. If I delete the statement. The code runs very fast until it casues a stack overflow and resets the esp.
start_Manage_STA_Connection() is called in main.c after I initialise the esp as Access Point.
Right now I see on the monitor that the loop in the vTask_Manage_STA_Connection runs a single time.
Below you can find my Tasks.c and Task.h
Task.h
#ifndef INCLUDE
#define INCLUDE
#include "config.h"
#endif
#ifndef INCLUDE_WLAN_STA
#define INCLUDE_WLAN_STA
#include "WLAN_STA.h"
#endif
// Dimensions the buffer that the task being created will use as its stack.
// NOTE: This is the number of words the stack will hold, not the number of
// bytes. For example, if each stack item is 32-bits, and this is set to 100,
// then 400 bytes (100 * 32-bits) will be allocated.
#define STACK_SIZE 2048
/// #brief Starts a Task to Manage the STA Connection
/// #param pvParameters
void vTask_Manage_STA_Connection( void * pvParameters );
/// #brief Calls vTask_Manage_STA_Connection in main.c
/// #param
void start_Manage_STA_Connection( void );
Tasks.c
#include "Tasks.h"
static const char *TAG_Manage_STA = "Manage STA Connection";
// Task to be created.
void vTask_Manage_STA_Connection(void *pvParameters)
{
for (;;)
{
// Task code goes here.
if (_STA_START == true)
{
ESP_LOGI(TAG_Manage_STA, "Connecting to Station...");
wifi_init_sta(
_STA_WIFI_SSID,
_STA_WIFI_PASS);
_STA_START = false;
}
ESP_LOGI(TAG_Manage_STA, "Managing STA Connection...");
vTaskDelay(100/portTICK_PERIOD_MS);
}
}
// Function that creates a task.
void start_Manage_STA_Connection(void)
{
static uint8_t ucParameterToPass;
TaskHandle_t xHandle = NULL;
// Create the task pinned to core 0, storing the handle. Note that the passed parameter ucParameterToPass
// must exist for the lifetime of the task, so in this case is declared static. If it was just an
// an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
// the new task attempts to access it.
xTaskCreatePinnedToCore(vTask_Manage_STA_Connection,
"Manage_STA_Connection",
STACK_SIZE,
&ucParameterToPass,
(configMAX_PRIORITIES-1),
&xHandle, 0);
configASSERT(xHandle);
// Use the handle to delete the task.
if (xHandle != NULL)
{
vTaskDelete(xHandle);
}
}
The Monitor Output:
I (0) cpu_start: App cpu up.
I (388) cpu_start: Pro cpu start user code
I (388) cpu_start: cpu freq: 160000000
I (388) cpu_start: Application information:
I (392) cpu_start: Project name: wifi_softAP
I (398) cpu_start: App version: 1
I (402) cpu_start: Compile time: Dec 5 2022 11:50:36
I (408) cpu_start: ELF file SHA256: 3597702b82953470...
I (414) cpu_start: ESP-IDF: v4.4.2
I (419) heap_init: Initializing. RAM available for dynamic allocation:
I (426) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (432) heap_init: At 3FFB7508 len 00028AF8 (162 KiB): DRAM
I (438) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (445) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (451) heap_init: At 400944E0 len 0000BB20 (46 KiB): IRAM
I (459) spi_flash: detected chip: gd
I (462) spi_flash: flash io: dio
I (467) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (559) MAIN: ESP_WIFI_MODE_AP/STA
I (569) WLAN AP: Wifi Loop Started
I (579) wifi:wifi driver task: 3ffc0378, prio:23, stack:6656, core=0
I (579) system_api: Base MAC address is not set
I (579) system_api: read default base MAC address from EFUSE
I (609) wifi:wifi firmware version: eeaa27d
I (609) wifi:wifi certification version: v7.0
I (609) wifi:config NVS flash: enabled
I (609) wifi:config nano formating: disabled
I (609) wifi:Init data frame dynamic rx buffer num: 32
I (619) wifi:Init management frame dynamic rx buffer num: 32
I (619) wifi:Init management short buffer num: 32
I (629) wifi:Init dynamic tx buffer num: 32
I (629) wifi:Init static rx buffer size: 1600
I (629) wifi:Init static rx buffer num: 10
I (639) wifi:Init dynamic rx buffer num: 32
I (639) wifi_init: rx ba win: 6
I (649) wifi_init: tcpip mbox: 32
I (649) wifi_init: udp mbox: 6
I (649) wifi_init: tcp mbox: 6
I (659) wifi_init: tcp tx win: 5744
I (659) wifi_init: tcp rx win: 5744
I (669) wifi_init: tcp mss: 1440
I (669) wifi_init: WiFi IRAM OP enabled
I (669) wifi_init: WiFi RX IRAM OP enabled
I (689) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (789) wifi:mode : sta (30:ae:a4:80:4e:88) + softAP (30:ae:a4:80:4e:89)
I (789) wifi:enable tsf
I (789) wifi:Total power save buffer number: 16
I (789) wifi:Init max length of beacon: 752/752
I (789) wifi:Init max length of beacon: 752/752
I (799) WLAN AP: Error: Unknown AP Exception
I (799) WLAN AP: wifi_init_softap finished. SSID:myssid password:mypassword channel:4
I (799) WLAN AP: Access point started!
I (819) Manage STA Connection: Managing STA Connection...
I (91529) wifi:new:<1,1>, old:<1,1>, ap:<1,1>, sta:<0,0>, prof:1
I (91529) wifi:station: 1c:bf:ce:ca:79:de join, AID=1, bgn, 40U
I (91549) WLAN AP: station 1c:bf:ce:ca:79:de join, AID=1
I (91559) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.5.2
I (91559) AP Webserver: Starting webserver
I (91559) AP Webserver: Starting server on port: '80'
I (91569) AP Webserver: Registering URI handlers
W (95189) wifi:<ba-add>idx:2 (ifx:1, 1c:bf:ce:ca:79:de), tid:0, ssn:190, winSize:64

Sending don't fragment UDP packets at the server and receiving fragmented packets at the client

I've created a program in C that sends data with UDP packets.
Socket is made don't fragment using
int optval = IP_PMTUDISC_DO;
if(setsockopt(sd,IPPROTO_IP,IP_MTU_DISCOVER,&optval,sizeof(int))!=0)
{
perror("setsocketopt()");
return 0;
}
Checking with TSHARK at the server (debian 8 KVM virtualizied), for all packets don't fragment has been set:
But at the client, large packets receiving fragmented!!
Then I figured something more wired. The IPv4 ID field has been set to 0!
I thought it might be because of the don't fragment effect (because no packet is going to be fragmented).
Then I started Openvpn program and sniffed its packets at the server but the packets had IPv4 ID != 0 while don't fragment was set.
Do you guys have any idea that why is this happening to me?!
Edit: Here is another sample of a large packet at server copy and pasted from tshark result.
Frame 1049: 1514 bytes on wire (12112 bits), 1514 bytes captured (12112 bits) on interface 0
Ethernet II, Src: server_mac, Dst: gateway_mac
Internet Protocol Version 4, Src: server_ip, Dst: client_ip
Version: 4
Header Length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
Total Length: 1500
Identification: 0x0000 (0)
Flags: 0x02 (Don't Fragment)
0... .... = Reserved bit: Not set
.1.. .... = Don't fragment: Set
..0. .... = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: UDP (17)
Header checksum: 0xa52d [validation disabled]
[Good: False]
[Bad: False]
Source: server_ip
Destination: client_ip
[Source GeoIP: Unknown]
[Destination GeoIP: Unknown]
User Datagram Protocol, Src Port: 7554 (7554), Dst Port: 45376 (45376)
Data (1472 bytes)
Like you see, don't fragment has been set, while all packets larger than PMTU are receiving fragmented to client side.
This is a packet trace example of openvpn on the same server. like you see it at least has IPv4 ID calculated!
Frame 3749: 1455 bytes on wire (11640 bits), 1455 bytes captured (11640 bits) on interface 0
Ethernet II, Src: SERVER_MAC, Dst: GATEWAY_MAC
Internet Protocol Version 4, Src: SERVER_IP, Dst: CLIENT_IP
Version: 4
Header Length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
Total Length: 1441
Identification: 0xcc96 (52374)
Flags: 0x02 (Don't Fragment)
0... .... = Reserved bit: Not set
.1.. .... = Don't fragment: Set
..0. .... = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: UDP (17)
Header checksum: 0xe252 [validation disabled]
[Good: False]
[Bad: False]
Source: SERVER_IP
Destination: CLIENT_IP
[Source GeoIP: Unknown]
[Destination GeoIP: Unknown]
User Datagram Protocol, Src Port: 19234 (19234), Dst Port: 46921 (46921)
Data (1413 bytes)

Bluetooth: hci1 hardware error 0x41

I'm trying to connect to a Parrot Drone (BLE device) through Bluez in C, but the connection always fails with:
Connection timed out
hcidump says:
< HCI Command: LE Create Connection (0x08|0x000d) plen 25
bdaddr 78:BD:BC:0F:17:D8 type 0
interval 4 window 4 initiator_filter 0
own_bdaddr_type 0 min_interval 15 max_interval 15
latency 0 supervision_to 3200 min_ce 1 max_ce 1
> HCI Event: Command Status (0x0f) plen 4
LE Create Connection (0x08|0x000d) status 0x00 ncmd 1
The relevant portion of code:
uint16_t handle;
startBTHost();
if(hci_le_create_conn(
bte_params.dd,
htobs(0x0004),
htobs(0x0004),
0x00,
LE_PUBLIC_ADDRESS,
device->addr,
LE_PUBLIC_ADDRESS,
htobs(0x000F),
htobs(0x000F),
htobs(0x0000),
htobs(0x0C80),
htobs(0x0001),
htobs(0x0001),
&handle,
25000
) < 0) {
writelog(LOG_ERROR, "Can not connect: %s", strerror(errno));
}
uint8_t reason;
bte_params.err = hci_disconnect(bte_params.dd, handle, reason, 25000);
stopBTHost();
It is almost a 1:1 copy from the hcitool (lecc option) source code: http://code.metager.de/source/xref/linux/bluetooth/bluez/tools/hcitool.c#cmd_lecc
I think the crucial information comes from dmesg. Everytime a connection timeout happens, the following error is reported:
[52106.588813] Bluetooth: hci1 hardware error 0x41
[52252.305876] Bluetooth: hci1 hardware error 0x41
[52292.853491] Bluetooth: hci1 hardware error 0x41
[52477.116149] Bluetooth: hci1 hardware error 0x41
Anyone knows where hardware error 0x41 comes from? I get the same results when using hcitool lecc directly:
cehrig-tpgnome parrot-drone-c # hcitool -i hci1 lecc 78:BD:BC:0F:17:D8
Could not create connection: Connection timed out
I'm running Gentoo kernel 4.4.6 with built-in BLE features.
thx in advance

LPC1788 microcontroller intermittently not sending USB messages

I'm developing code for the NXP LPC1788 microcontroller, and part of my work is making the product based on it USB-compatible. Most of the legwork is done and in general communication over USB works almost as well as over CAN.
However, one of the issues I've been encountering is that, when producing a constant output of USB messages from the microcontroller that are sent pretty close together, some of these messages are occasionally dropped.
I'm using a custom driver I wrote based on WinUSB to receive the messages on the PC side, and I originally suspected that the problem was on the receiving end of things. However, using USBLyzer I'm now confident that the problem is on the sending side - the USBLyzer logs perfectly match logs produced from what I get out of WinUsb_ReadPipe().
The LPC1788 uses USB 2.0 Full Speed protocol and I've confirmed that information is being sent and received at around 12 MHz using a probe, which is what it should be.
The device is configured to make use of two endpoints: logical endpoint 2 IN and logical endpoint 2 OUT. Both of these are configured for bulk transfer with a maximum packet size of 64 bytes.
I would think that messages are being sent around 500-600 microseconds apart at the least (I've introduced an artificial 500 us delay in the thread and message transmission should take a lot less time than that). This is about what I got last week; I can't check now as my debugging tools are acting up.
This is the USB initialisation code for the microcontroller:
void USBInit()
{
// Configure USB pins.
PINSEL_ConfigPin(0, 29, 1); // USB_D+1
PINSEL_ConfigPin(0, 30, 1); // USB_D-1
PINSEL_ConfigPin(1, 18, 1); // USB_UP_LED1
PINSEL_ConfigPin(2, 9, 1); // USB_CONNECT1
PINSEL_ConfigPin(1, 30, 2); // USB_VBUS
// Turn on power and clock
CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCUSB, ENABLE);
PINSEL_SetPinMode(1, 30, PINSEL_BASICMODE_PLAINOUT);
// Set DEV_CLK_EN and AHB_CLK_EN.
LPC_USB->USBClkCtrl |= 0x12;
// Wait until change is reflected in clock status register.
while((LPC_USB->USBClkSt & 0x12) != 0x12);
// Enable NVIC USB interrupts.
NVIC_EnableIRQ(USB_IRQn);
// Reset the USB.
USBReset();
// Set device address to 0x0 and enable device & connection.
USBSetAddress(0);
}
This is the code used by the microcontroller to send messages via USB:
uint32_t USB_Send(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
// Convert into a form that can be sent successfully using USB.
uint8_t data[USB_MAX_PACKET_SIZE];
for(int i=0; i < count; i++)
{
data[i*2] = hex[(pData[i] >> 4)];
data[(i*2)+1] = hex[(pData[i] & 0xF)];
}
return USBWriteEndpoint(endpoint, data, count*2);
}
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i;
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)pData);
pData += 4;
}
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
return count;
}
void USBValidateEndpoint(uint32_t endpoint)
{
writeSIEEndpointCommand(endpoint, CMD_VALID_BUF);
}
void writeSIECommandData(uint32_t cmd, uint32_t data)
{
LPC_USB->DevIntClr = CCEMTY_INT;
LPC_USB->CmdCode = cmd;
while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
LPC_USB->DevIntClr = CCEMTY_INT;
LPC_USB->CmdCode = data;
while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
}
EDIT
To give an idea of what's happening, this is a log file produced from my USB driver's receive function (the one from USBLyzer is practically identical):
0000030D000D
0000010D002D0004001B0024
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
I should be receiving messages in the following cycle:
0000000D...
0000010D...
0000020D...
0000030D...
You can see from this log that some of the messages in the cycle are getting skipped.
EDIT 2
Included below are excerpts from the raw and filtered capture logs produced by USBLyzer. The raw logs mostly consist of cancelled requests because my driver is poll-driven and uses a timeout.
Raw logs:
USBlyzer Report
Capture List
Type Seq Time Elapsed Duration Request Request Details Raw Data I/O C:I:E Device Object Device Name Driver Name IRP Status
START 0001 11:09:15.413
URB 0002 11:09:18.484 3.071197 s Bulk or Interrupt Transfer 10 bytes data 30 30 30 30 30 30 31 46... out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h
00000000 30 30 30 30 30 30 31 46 30 31 0000001F01
URB 0003 11:09:18.484 3.071212 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0004-0002 11:09:18.484 3.071371 s 174 us Bulk or Interrupt Transfer 10 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h Success (Success)
URB 0005-0003 11:09:18.485 3.071586 s 374 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0006 11:09:18.485 3.071608 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0007-0006 11:09:18.486 3.072582 s 974 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0008 11:09:18.486 3.072603 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0009-0008 11:09:18.487 3.073598 s 996 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0010 11:09:18.487 3.073630 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0011-0010 11:09:18.488 3.074601 s 970 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
[...]
URB 2504-2501 11:09:19.734 4.320666 s 161 us Bulk or Interrupt Transfer 14 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA800CF662D0h Success (Success)
URB 2505-2503 11:09:19.734 4.320785 s 192 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
Filtered logs:
USBlyzer Report
Capture List
Type Seq Time Elapsed Duration Request Request Details Raw Data I/O C:I:E Device Object Device Name Driver Name IRP Status
URB 0004-0002 11:09:18.484 3.071371 s 174 us Bulk or Interrupt Transfer 10 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h Success (Success)
URB 2504-2501 11:09:19.734 4.320666 s 161 us Bulk or Interrupt Transfer 14 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA800CF662D0h Success (Success)
URB 2505-2503 11:09:19.734 4.320785 s 192 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
URB 2507-2506 11:09:19.734 4.321309 s 459 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 31 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34 0000010D002D0004
00000010 30 30 31 46 30 30 32 44 001F002D
URB 2511-2510 11:09:19.735 4.321931 s 311 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 32 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38 0000020D00280028
00000010 30 30 31 42 30 30 33 31 001B0031
URB 2513-2512 11:09:19.735 4.322306 s 332 us Bulk or Interrupt Transfer 12 bytes data 30 30 30 30 30 33 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 33 30 44 30 30 30 44 0000030D000D
URB 2725-2724 11:09:19.840 4.426662 s 89 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
URB 2727-2726 11:09:19.840 4.427183 s 471 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 31 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34 0000010D002D0004
00000010 30 30 31 46 30 30 32 44 001F002D
URB 2731-2730 11:09:19.841 4.427803 s 209 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 32 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38 0000020D00280028
00000010 30 30 31 42 30 30 33 31 001B0031
Do you have a hardware USB analyzer available? I'm not sure how USBLyzer works but I presume it is still using the Windows USB subsystem at the lowest levels. My experience with Windows USB subsystem has been that it is extremely bug-riddled - one particular example was when transferring data that is an exact multiple of the max frame size, it doesn't work. I'm not saying this is your exact problem - we had different symptoms from what you are reporting - but in your shoes I would look at a) changing the max amount of data your transmitting end will send in one frame so it's not an exact multiple of the frame size, and b) getting a hardware USB analyzer to see what is actually on the wire.
The problem might be the USB_IRQHandler interrupting your write function. That would leave the USB unexpected in a different state, thus the write fails.
You can temporary disable the IRQ as a workaround:
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i;
NVIC_DisableIRQ(USB_IRQn); // USB IRQ handlaer must not run ...
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)pData);
pData += 4;
}
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
NVIC_EnableIRQ(USB_IRQn); // ... until we are here. Enable USB IRQ again
return count;
}
I think I've managed to make some significant improvements in the way that the microcontroller sends USB messages.
On page 400 of the LPC178x/7x user manual, I saw a description for how to properly handle sending data from the device to the host using a bulk IN endpoint. It was pretty lucky that I eventually stumbled across it since it was within the DMA section of the chapter (and I'm not using DMA so until now I've ignored it).
Based on what I read there, I added the following method:
// Params: endpoint - the logical endpoint number.
// Returns: TRUE if at least one write buffer is free,
// FALSE otherwise.
// Description: Checks that the IN endpoint has a free write buffer.
uint8_t USBCheckInEndpointFree(uint32_t endpoint)
{
uint16_t data;
uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);
writeSIECommand(CMD_SEL_EP(physicalEndpoint));
data = readSIECommandData(DAT_SEL_EP(physicalEndpoint));
return (data & 0x1) == 0;
}
I changed USBWriteEndpoint to the following:
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i = 0;
NVIC_DisableIRQ(USB_IRQn);
if((endpoint & 0xF) != 0)
{
while(getSendMessageFlag(endpoint & 0xF) != 0);
setSendMessageFlag(endpoint & 0xF);
}
while(!USBCheckInEndpointFree(endpoint))
{
uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);
writeSIECommand(CMD_SEL_EP(physicalEndpoint));
ITM_EVENT32_WITH_PC(3, readSIECommandData(DAT_SEL_EP(physicalEndpoint)));
}
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)(pData+i*4));
//pData += 4;
}
ITM_EVENT32_WITH_PC(4, (pData[4] << 24) | (pData[5] << 16) | (pData[6] << 8) | pData[7]);
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
NVIC_EnableIRQ(USB_IRQn);
return count;
}
The ITM_EVENT32_WITH_PC macro is used for debugging.
While sending USB messages at a high rate, I noticed this pattern in the event timeline:
In that image, the lines within the third channel show where the thread is caught within the while loop because none of the write buffers of the endpoint I'm using are free. The lines in the fourth channel are where a message is written to one of the endpoint's write buffers.
The LPC1788 uses double-buffering for bulk and isochronous endpoints, so what you're seeing in that image is the following:
The microcontroller tries to send a USB message to the host. Both write buffers are free, so it picks one and uses that.
The micro tries to send a second message. It uses the remaining free write buffer.
The micro tries to send a third message. Both buffers are in use so it has to wait. That produces the series of lines in the third channel while the micro polls the endpoint status.
Eventually one of the buffers (probably the first one used) becomes free, and the message is written to that.
The micro tries to send a fourth message. Both buffers are in use and the micro apparently has to wait a fair while before one of them becomes free.
Eventually one of the buffers becomes free and it writes the message to that.
Before adding in that additional check, I got behaviour like this:
Clearly without the check, the endpoint's buffers are getting overwritten!
To check how well this change resolved the problem, I created a Python script with a simple algorithm that I chose to evaluate performance by comparing how well the output from the USB logs (generated by one of my USB drivers on the PC end) conforms to a perfect cycle (which is what I'd ideally want).
I did three runs of my program with the additional check and three runs of my program without it, each time leaving it running long enough for 1000 USB messages to be received and recorded in a log file by the DLL.
The three logs with the additional check were USBLogGood1.txt ... USBLogGood3.txt. The three without the check were USBLogBad1.txt ... USBLogBad3.txt.
The Python code is given below:
# Checks how well the USB is performing by checking how
# closely the stream of USB messages returned by the DLL
# matches a perfect cyclical pattern.
from statistics import *
cycle = [1,2,3,4]
sampleSize = 1000
class Globals:
totalCount = 0
errorCount = 0
usbLogFile = "usbLog.txt"
usbGoodLogFiles = ["usbLogGood1.txt",
"usbLogGood2.txt",
"usbLogGood3.txt"]
usbBadLogFiles = ["usbLogBad1.txt",
"usbLogBad2.txt",
"usbLogBad3.txt"]
# Switch between sets of log files.
usbLogFiles = usbBadLogFiles
# Read log file.
def readLog(logFile):
with open(logFile) as fIn:
return fIn.readlines()
# Converts raw log data into a list of cycle values.
def processLog(log):
data = []
for line in log:
data.append(processLogLine(line))
return data
# Converts raw log line into a cycle value.
def processLogLine(logLine):
l = logLine.replace("Message ", "")
return int(l[5],16)+1
# Counts distance in one direction, so the distance
# will be high if i2 is behind i1.
def getListDistance(val1, val2):
cycleLen = len(cycle)
i1 = cycle.index(val1)
i2 = cycle.index(val2)
if i1 <= i2:
return i2 - i1
else:
return (cycleLen - i1) + i2
def getNextValueInCycle(val):
cycleLen = len(cycle)
i = cycle.index(val)
if i < cycleLen-1:
return cycle[i+1]
else:
return cycle[0]
def checkCycleValue(expected, value):
Globals.totalCount += 1
if value != expected:
Globals.errorCount += getListDistance(expected, value)
expected = getNextValueInCycle(value)
return expected
def getPerformance():
return 1-float(Globals.errorCount)/float(Globals.totalCount)
def printPerformance():
print("Sampled %d values. USB performance: %0.1f%%"
% (Globals.totalCount, getPerformance()*100))
# Read log file and evaluate performance.
def evaluatePerformance(logFile):
Globals.totalCount = 0
Globals.errorCount = 0
log = readLog(logFile)
data = processLog(log)
if not data:
print("No data available")
return
if len(data) < sampleSize:
print("Not enough data available to meet requirements")
return
else:
data = data[:sampleSize]
expected = data[0]
for value in data:
expected = checkCycleValue(expected, value)
return getPerformance()
def printAggregatePerformanceData(logFiles, performances):
performances = [100*p for p in performances]
for f, p in zip(logFiles, performances):
print("%s: %0.2f%%" % (f, p))
print("\nAverage performance: %0.2f%%" % mean(performances))
print("Standard deviation: %0.2f" % stdev(performances))
def main():
performances = []
for logFile in usbLogFiles:
performances.append(evaluatePerformance(logFile))
printAggregatePerformanceData(usbLogFiles, performances)
if __name__ == "__main__":
main()
With the good set of logs, I got the following output:
usbLogGood1.txt: 93.70%
usbLogGood2.txt: 92.50%
usbLogGood3.txt: 92.60%
Average performance: 92.93%
Standard deviation: 0.67
For the bad set, I got this:
usbLogBad1.txt: 16.60%
usbLogBad2.txt: 13.80%
usbLogBad3.txt: 14.10%
Average performance: 14.83%
Standard deviation: 1.54
By adding in the additional check to make sure a write buffer is free, I managed to increase the 'performance' of the USB by around 78.1% (100% means a perfect cycle of USB messages: 1,2,3,4,1,2,3,4,1,2,3,4...).
In addition to this, I found that the message throughput about doubled when I put the check in, despite the delays associated with waiting in while loops.
92.93% still isn't perfect, but the manual talks about checking for ACKS from the host as well as just free write endpoints. I tried to do that earlier (without apparent success), but this was before I tried this check. Hopefully, if I implement both together I can get the USB performance to rival that of CAN.
Edit: The wait for ACK thing didn't work, but if I force a 1ms delay in between sending messages, I can get a performance of ~99.99...%.
This is not an ideal solution since 1ms is quite a long time to be delaying for, so I'm leaving the question unresolved for now.
EDIT
I quite firmly believe at this point that the issue is mainly with the PC-side driver I wrote. It doesn't read fast enough.

Why does my pc send more than 1514 byte packet in one go

I wrote a program to send 1460 byte data using TCP client and server continuously. My system interface MTU is 1500.
Here is my program of client
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
setsockopt(sockfd,SOL_TCP,TCP_NODELAY,&one,sizeof(one));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(9998);
serv_addr.sin_addr.s_addr = inet_addr("10.10.12.1");
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
while(1)
{
write(sockfd, send_buff, 1448) ;
}
In wireshark initial 15 to 30 packets are showing that 1514 byte of packet is going but afterwards showing as below
wireshark output of some packet
No. Time Source Destination Protocol Length Info
16 0.000000 10.10.12.2 10.10.12.1 TCP 5858 53649 > distinct32 [ACK] Seq=3086892290 Ack=250285353 Win=14608 Len=5792 TSval=23114307 TSecr=23833274
Frame 16: 5858 bytes on wire (46864 bits), 5858 bytes captured (46864 bits)
Ethernet II, Src: 6c:3b:e5:14:9a:a2 (6c:3b:e5:14:9a:a2), Dst: Ibm_b5:86:85 (00:1a:64:b5:86:85)
Internet Protocol Version 4, Src: 10.10.12.2 (10.10.12.2), Dst: 10.10.12.1 (10.10.12.1)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
Total Length: 5844
Identification: 0x8480 (33920)
Flags: 0x00
Fragment offset: 0
Time to live: 64
Protocol: TCP (6)
Header checksum: 0xb38d [correct]
Source: 10.10.12.2 (10.10.12.2)
Destination: 10.10.12.1 (10.10.12.1)
Transmission Control Protocol, Src Port: 53649 (53649), Dst Port: distinct32 (9998), Seq: 3086892290, Ack: 250285353, Len: 5792
Source port: 53649 (53649)
Destination port: distinct32 (9998)
[Stream index: 0]
Sequence number: 3086892290
[Next sequence number: 3086898082]
Acknowledgement number: 250285353
Header length: 32 bytes
Flags: 0x010 (ACK)
Window size value: 913
[Calculated window size: 14608]
[Window size scaling factor: 16]
Checksum: 0x42dd [validation disabled]
Options: (12 bytes)
No-Operation (NOP)
No-Operation (NOP)
Timestamps: TSval 23114307, TSecr 23833274
Data (5792 bytes)
On wireshark it is showing that more than 5792, 7000, 65535 byte of packet are going.
But i am sending 1514 byte of packet in one go. on other side i am receiving 1514 byte of packets only due to network mtu.
So my question is
why this much of huge packets are going ?
I tried without NODELAY option also but it is not working.
Is there any solution to send particular packet size (such as 1514 byte) can be send, no jumbo frames ?
I update my tcp_rmem and tcp_wmem also for tcp sending buffer and receiving buffer also. But did not found any solution.
TCP, by design, bundles up multiple write() calls into larger packets. Also, TCP coalesces packets by default according to Nagle's Algorithm.
If you want more control over the actual size of network packets, use UDP.
These are "jumbo frames", and they're faster than traditional frame sizes because they don't load up a CPU as much.
Consider yourself fortunate that you're getting them without futzing around with your IP stack's settings.
I searched a lot and found that, we need to change some parameter on interface.
On my interface eth0 default option are
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: off
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off
now using ethtool we need to off some sending side segementation offload.
For that
sudo ethtool -K eth0 tso off gso off
using this
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: off
udp-fragmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off
After this your interface will send packets whatever you want to send.

Resources