Problems communicating with MS/TP using the bacnet-stack-1.0.0 apps example - c

I use the server example in apps to simulate BACNET MS/TP SERVER, by modifying the environment variable to set the baud rate 38400, MAC address 0x78.
The operation effect is as follows:
/var/user/app/device_supervisor # ./bacserv 20000
BACnet Server Demo
BACnet Stack Version 1.0.0
BACnet Device ID: 20000
Max APDU: 480
pyh defined MSTP
MS/TP Interface: /dev/ttyO3
RS485: Initializing /dev/ttyO3 at Baud Rate 38400=success!
MS/TP MAC: 78
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 1
I use the readprop example in apps to simulate the BACNET MS/TP CLIENT, by modifying the environment variable to set the baud rate of 38400, MAC address 0x79,
The operation effect is as follows:
root#pyhao-VirtualBox:~/pyhao/tmp/bacnet-stack-1.0.0-yuan/apps/readprop# ./bacrp_mstp_x86 20000 0 0 85 --mac 78
pyh defined MSTP
MS/TP Interface: /dev/ttyS1
RS485: Initializing /dev/ttyS1 at Baud Rate 38400=success!
MS/TP MAC: 79
MS/TP Max_Master: 7F
MS/TP Max_Info_Frames: 10
pyh send read req
pyh Send_Read_Property_Request_Address
pyh dlmstp_send_pdu
pyh Ringbuf_Data_Put
pyh bytes_sent = 13
pyh pdu len = 0
pyh pdu len = 0
pyh pdu len = 0
pyh pdu len = 0
pyh pdu len = 0
pyh pdu len = 0
pyh pdu len = 0
bacnet-stack-1.0.0-yuan/apps/readprop/main.c
/* returns 0 bytes on timeout */
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
printf("pyh pdu len = %d\n", pdu_len);
As shown above, when I ran the client program I did not read the value of the property, and the server did not print anything, I was sure that my connection was okay because I used rs485.c for the 485 test and sent and received data normally.
The same way I used bacnet/ip to communicate normally, but it didn't work in mstp mode, I searched for some materials, but it didn't help me with the problem I was having

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

DPDK: Enable jumbo frames on X710 NIC card

I am working with dpdk-stable-18.05.1 on Linux with an Intel X710 NIC.
The above NIC is capable of sending a packet size up to 9000 Bytes. My application is not able to send a packet size of more than 1500. Here is my code:
const struct rte_eth_conf default_port_conf = { .rxmode = { .max_rx_pkt_len = 9000, .offloads = DEV_RX_OFFLOAD_JUMBO_FRAME, .jumbo_frame = 1,}
.txmode = { .offloads = DEV_TX_OFFLOAD_MULTI_SEGS, } }
I am trying to send the IPV4 packet size of 8192Bytes but on the RX side, we are getting 2048Bytes.
(sample pcap is attached).
I also tried with rte_eth_dev_set_mtu(pid, 9000); But no luck.
Anything if I am missing please let me know.
Intel NIC x710 has no issues in supporting multi-segmented Jumbo frames. This can be easily verified using DPDK 18.11.7 LTS (always use LTS for better support and fixes) and DPDK example skeleton.
To enable multi-segmented JUMBO frames please change the port_conf to
static const struct rte_eth_conf port_conf_default = {
.rxmode = {
.max_rx_pkt_len = 9000,
.split_hdr_size = 0,
.offloads = (DEV_RX_OFFLOAD_JUMBO_FRAME),
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
.offloads = (DEV_TX_OFFLOAD_IPV4_CKSUM |
DEV_TX_OFFLOAD_MULTI_SEGS),
},
};
The only conflicting configuration is using jumbo_frame = 1 along with DEV_RX_OFFLOAD_JUMBO_FRAME. As per DPDK releases (18.11 LTS) it is recommended to use DEV_RX_OFFLOAD_JUMBO_FRAME as jumbo_frame is deprecated.
Hence the assumption of x710 NIC not supporting Multi-segmented Jumbo frames is incorrect.
CMD:
# ./build/basicfwd -w 0000:08:00.0 -w 0000:08:00.1 -w 0000:08:00.2 -w 0000:08:00.3
EAL: Detected 88 lcore(s)
EAL: Detected 2 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'VA'
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL: PCI device 0000:08:00.0 on NUMA socket 0
EAL: probe driver: 8086:1572 net_i40e
EAL: using IOMMU type 1 (Type 1)
EAL: PCI device 0000:08:00.1 on NUMA socket 0
EAL: probe driver: 8086:1572 net_i40e
EAL: PCI device 0000:08:00.2 on NUMA socket 0
EAL: probe driver: 8086:1572 net_i40e
EAL: PCI device 0000:08:00.3 on NUMA socket 0
EAL: probe driver: 8086:1572 net_i40e
Port 0 MAC: 3c fd fe 9f 3a 00
Port 1 MAC: 3c fd fe 9f 3a 01
Port 2 MAC: 3c fd fe 9f 3a 02
Port 3 MAC: 3c fd fe 9f 3a 03
WARNING: Too many lcores enabled. Only 1 used.
Core 0 forwarding packets. [Ctrl+C to quit]

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.

raw socket send two packets on a virtual Network

I've a problem with my sendto function in my code, when I try to send a raw ethernet packet.
I use a Ubuntu 12.04.01 LTS, with two tap devices connected over two vde_switches and a dpipe
Example:
my send programm create the packet like below, the programm is binded by the socket from tap0 and send the packet to tap1. On tap1 one receiver wait for all packets on socket.
My raw ethernet packet looks so:
destination Addr ____source Addr _________ type/length ___data
00:00:01:00:00:00___00:00:01:00:00:01____ length in Byte__some data
Example packet to send:
00:00:01:00:00:00 00:00:01:00:00:01 (length in byte) (Message)test
but my programm generate two packets, when I look in wireshark:
first packet is an IPX packet and [Malformed Packet] and looks like in hex (data = test)
00 04 00 01 00 06 00 00 01 00 00 01 00 00 00 01 74 65 73 74 00
Linux cooked capture
Packet type: sent by us (4)
Link-layer address type: 1
Link-layer address length: 6
Source: 00:00:01:00:00:01
Protocol: Raw 802.3 (0x0001)
[Malformed Packet: IPX]
second packet unknown protocol
00 00 00 01 00 06 00 00 01 00 00 01 00 00 31 00 74 65 73 74 00
Linux cooked capture
Packet type: Unicast to us (0)
Link-layer address type: 1
Link-layer address length: 6
Source: 00:00:01:00:00:01
Protocol: Unknown (0x3100)
Data
Data: 7465737400
[Length: 5]
outcut from my source code
sock_desc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
/*struct for sending*/
sock_addr.sll_family = AF_PACKET;
sock_addr.sll_protocol = htons(ETH_P_802_3);
sock_addr.sll_ifindex = if_nametoindex(argv[1]);
sock_addr.sll_hatype = ARPHRD_ETHER; //Ethernet 10Mbps
sock_addr.sll_pkttype = PACKET_HOST; // Paket zu irgendjemand
sock_addr.sll_halen = ETH_ALEN; //6 Oktets in einer ethernet addr
/*MAC Length 8 Oktets*/
sock_addr.sll_addr[0] = frame.src_mac[0];
sock_addr.sll_addr[1] = frame.src_mac[1];
sock_addr.sll_addr[2] = frame.src_mac[2];
sock_addr.sll_addr[3] = frame.src_mac[3];
sock_addr.sll_addr[4] = frame.src_mac[4];
sock_addr.sll_addr[5] = frame.src_mac[5];
/*not in use*/
sock_addr.sll_addr[6] = 0x00;
sock_addr.sll_addr[7] = 0x00;
memset(buffer, '0', sizeof(char)*ETH_FRAME_LEN);
/*set the frame header*/
/*build RAW Ethernet packet*/
buffer[0] = frame.dest_mac[0];
buffer[1] = frame.dest_mac[1];
buffer[2] = frame.dest_mac[2];
buffer[3] = frame.dest_mac[3];
buffer[4] = frame.dest_mac[4];
buffer[5] = frame.dest_mac[5];
buffer[6] = frame.src_mac[0];
buffer[7] = frame.src_mac[1];
buffer[8] = frame.src_mac[2];
buffer[9] = frame.src_mac[3];
buffer[10] = frame.src_mac[4];
buffer[11] = frame.src_mac[5];
while(frame.data[0] != '*'){
printf("Input: ");
scanf("%s", frame.data);
tempLength = 0;
while(frame.data[tempLength] != '\0'){
tempLength++;
}
input = 0;
for(sendLen = 14;sendLen <= (14+tempLength);sendLen++){
buffer[sendLen] = frame.data[input];
input++;
}
sprintf(convLen,"%x", (14 + input));
buffer[12] = convLen[0];
buffer[13] = convLen[1];
length_in_byte = sendto(sock_desc, buffer, 14+input,0,(struct sockaddr*) &sock_addr,sizeof(struct sockaddr_ll));
if(length_in_byte <= 0){
printf("Error beim Senden");
}else{
printf("\n");
printf("src: %02x:%02x:%02x:%02x:%02x:%02x\t->\tdest: %02x:%02x:%02x:%02x:%02x:%02x\n",frame.src_mac[0],frame.src_mac[1],frame.src_mac[2],frame.src_mac[3],frame.src_mac[4],frame.src_mac[5],frame.dest_mac[0],frame.dest_mac[1],frame.dest_mac[2],frame.dest_mac[3],frame.dest_mac[4],frame.dest_mac[5]);
printf("Data: %s\n", frame.data);
}
}
please i need some help to find my mistake.
Thank you forward.
Please give us the lines dealing with the socket creation operation.
I assume you have created your socket like that :
int socket = socket(AF_PACKET,SOCK_RAW,IPPROTO_IP)
You are right when you build the ethernet header (by the way you should use instead struct ethhdr, it's cleaner).
After that you send your data, without putting L4 header and L3 header.... It's normal that your code doesn't work.
I assume you now the OSI Model.
If it's not the case read the paper before reading the next text.
So when you want to create a RAW packet, you have many things to do before.
For example if you want to use TCP/IP protocol you will have to do the next operation
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#DEFINE SIZEMAX 1000
int main() {
char buffer[65535] // MDU
// CREATE YOUR SOCKET
int socket = socket(AF_PACKET,SOCK_RAW,IPPROTO_RAW) ;
// You can also specify some opt to your socket but I let you done your own stuffs
struct ethhdr * ethdr ;
struct iphdr * iph ;
struct tcphdr * tcph;
// Fill all the fields of these last structures (i can't do it for you too long).
// Fill the buffer
memcpy(buffer,ethdr,sizeof(struct ethhdr)) ;
// Deplace it to the good addr
buffer = buffer + sizeof(struct ethhdr) ;
memcpy(buffer,iph,sizeof(struct iphdr)) ;
buffer = buffer + sizeof(struct iphdr)) ;
memcpy(buffer,tcph,sizeof(struct tcphdr)) ;
printf("your entry : \n") ;
char * entry = malloc(SIZEMAX) ;
sncanf("%s",entry,100) ;
buffer = buffer+ 100 ;
memcpy(buffer,entry,100) ;
int size_send = sendto(socket,.......) ;
if(size_send =< 0)
perror("error sending data") ;
return 0 ;
}
This is pseudo-code but it tell you how to send raw packet.
This paper will do the work for you :
RAW Socket TCP/IP
Hope it will help you
Anthony
I think your code is missing the ethernet "packet type ID field". See struct ethhdr in if_ether.h. Now you put convLen where the proto should be. It probably matches the proto number of IPX. Try setting it to something (eg ETH_P_IP) or test what happens when you set it to zero.
I understand you want to make your own protocol and are using the field after the ethernet addresses for the length. However I do suggest you keep at least the ethernet level header standards compliant and build your own on top of that (in the ethernet frame payload). Otherwise youll get problems with tools(like wireshark) and device drivers that try to parse the ethernet headers.
As to why you send two packets, I think the reason lies in the way you scanf input from the user. The while loop is peculiar. I suggest trying to send some data with a fixed input, eg char msg[] = "Test";
Sorry if the answer is vague. It is difficult to help you, since your code is not complete and I can not test it.
OK I see why my receiver receiv two packets. The first packet ist the send by us packet and the second is the Unicast to us. The problem I don't need the first packet to receive. I have test my code and have one capture with the two packets as example.
First frame in hex code from Wireshark:
0004 0001 0006 0000010000020000 0060 the message
Second frame:
0000 0001 0006 0000010000020000 1234 the message
This is Linux cooked capture an means:
2 Bytes packet typ // 0 = To us; 1 = Broadcast; 2 = Multicast; 3 = from somebody to somebody; 4 = sent by us
2 Bytes LINUX ARPHDR_ value
2 Bytes Link layer addr. lenght
8 Bytes source address
2 Bytes Ethernet protocol //e.g. 1 Novell 802.3 without 802.2 header; 4 frames with 802.2 header
My questions:
First is it possible to filter or ignore the first packet?
Second why contains the first packet the protocol typ from the send structur and the second packet the protocol typ from buffer?
Example:
For the first packet
sock_addr.sll_family = AF_PACKET;
sock_addr.sll_protocol = htons(0x0060);
sock_addr.sll_ifindex = 3;
sock_addr.sll_hatype = ARPHRD_ETHER;
sock_addr.sll_pkttype = PACKET_HOST;
sock_addr.sll_halen = ETH_ALEN;
/*MAC Length 8 Oktets*/
sock_addr.sll_addr[0] = 0x00;
sock_addr.sll_addr[1] = 0x00;
sock_addr.sll_addr[2] = 0x01
sock_addr.sll_addr[3] = 0x00;
sock_addr.sll_addr[4] = 0x00;
sock_addr.sll_addr[5] = 0x02;
/*not in use*/
sock_addr.sll_addr[6] = 0x00;
sock_addr.sll_addr[7] = 0x00;
for second packet the buffer like 802.3 frame
buffer[0-5] = 0x00 0x00 0x01 0x00 0x00 0x03 // Destination address
buffer[6-11] = 0x00 0x00 0x01 0x00 0x00 0x02 // Source address
buffer[12-13] = 0x12 0x34 // Protocol dummy typ
My receiver can capture the first packet without a connection between two vde_switches and when I connect the switches with dpipe and vde_plug can I capture the second packet too.

Resources