Hi
I'm using USB HID library to implement an small HID device. I already have read this library and USB 1.1 specification, but I still have a small problem. I still cannot understand relation between 3 sizes in descriptor: 1- EP0 packet size(that you can specify in usbcfg.h) 2- Endpoint's wMaxPacketSize 3- maximum size of reports
In my case, I need to transfer 128 bytes of data to and from device. Then I have defined my reports like this: ReportSize(8) ReportCount(128) But I still cannot get how wMaxPacketSize and EP0 packet size are related to these values. From some samples, I saw that people set wMaxPacketSize to 64. But how I should transfer my reports if wMaxPacketsize is 64? or are they related at all?
Regards
Hi Thanks for reply.
I'm using USB HID sample that is distributed with RealView as my base code.
I will try to find out how I should split my report for sending in wMaxPacketSize buffers. But a questions: 1- Using bigger wMaxPacketSize(up to 64) will increase performance,isn't it? 2- When my device is going to send and receive data is it possible to use EP0 for sending control and data to host and another endpoint for receiving data from host(2 endpoints) or I should use EP0 as control and 2 other endpoint for sending or receiving data(3 endpoints used). if both possible,which one is better?
> I'm using USB HID sample that is distributed with RealView as my base code.
Then, this thread will help you. http://www.keil.com/forum/docs/thread15613.asp
The first packet is sent / received by polling (or "timer-ed" polling) Latter packet(s) are exchanged in the endpoint interrupt > 1- Using bigger wMaxPacketSize(up to 64) will increase performance,isn't it?
Yes. For interrupt transfer, the transaction of each "packet" occurs at the rate of bInterval value on the endpoint descriptor (*1). When you divide the report into more packets under smaller wMaxPacketSize, it takes longer duration to finish the transfer of the entire report. > 2- When my device is going to send and receive data is it possible to use EP0 for sending control and data to host and another endpoint for receiving data from host(2 endpoints) or I should use EP0 as control and 2 other endpoint for sending or receiving data(3 endpoints used).
It's the time to learn USB terms and concepts, before we enter to the explanation ;-) See these web pages for "Transfer - Transaction - Packet"
USB Made Simple - Data Flow (Packets - Transaction - Transfer) www.usbmadesimple.co.uk/ums_3.htm
Transfer - Transaction - Packet www.cygnal.org/.../001627.html
Transfers over single endpoint don't overlap each other. But transfers over different endpoints, including EP0, are independent and their period may be overlapped each other, at the unit of transactions.
While the report transfer of multiple transactions over EP1 is going, your device may receives a request (control transfer) over EP0. This principle is same for EP0. Control transfer consists of two or three stages, SETUP, optional DATA, and STATUS. SETUP and STATUS stage is carried by single transaction, respectively. DATA stage may extend to multiple transactions, depending on the length of the data to be carried.
These transfers may be mixed up on the bi-directional USB cable, at the unit of transactions. Therefore, your firmware have to expect that transfers over different endpoints take place simultaneously.
Even if transfer takes longer, your firmware doesn't always need to spend all time for it. The USB engine takes care of the communication in background. Just when transaction finishes, the engine notifies it to your firmware. And then, your firmware processes the received "packet" (*2) over OUT endpoint, or it puts another "packet" to the IN endpoint. > if both possible,which one is better?
Transfer over interrupt IN or OUT endpoint is better, for frequent transfer exchange. The request over EP0 is too heavy process to do it regularly, though it's coding is easy ;-). (*1) actually, major OS (Windows, MacOSX and Linux) reduces the interval into power of 2, which is nearest to the bInterval value (up to 32 ms). ie. 1, 2, 4, 8, 16 or 32 ms
(*2) This "packet" is not exact USB term :-) It means the payload of a transaction. But we often use it like this.
Tsuneo
That post was really useful,thanks a lot... :)
Even though my HID device is working on a request/response nature that starts from host, I think it is possible to use only 2 endpoints(EP0 for control and another one for data transfer), but I think that I can reach better performance using 3 endpoints(EP0 and 2 more,1 for sending and another one for receiving data) too.
I have made changes to HID library for this reason, but I have an strange problem and I think it comes from my descriptors, but I cannot find that problem.
I'm observing USB ports using USBlyzer. When I attach my programmed USB device to PC, it immediately says "Unrecognized USB device" and I cannot see any logs in USBlyzer. But when I start debugging my device by ULINK debugger and set a breakpoint in USB_EndPoint0, I see it breaks several times for getting various descriptors. This will not help recognizing device, but this time I can see USB requests in USBlyzer and some steps of USB configuration proceeds. From my point of view, delay that happens by breaking on my breakpoint in USB_EndPoint0, is the reason that some steps of configuration proceeds. I thought that this problem happens because my USB_ReadEP and USB_WriteEP is not interrupt protected. then I used SWI 0 and 1(because I don't use RTX, then using them should not be any problem) to protect these 2 functions. But it did not solve problem. Any idea why this happens? This is list of my descriptors:
/* HID Report Descriptor */ const BYTE HID_ReportDescriptor[] = { HID_UsagePageVendor(0x00), HID_Usage(0x01), HID_Collection(HID_Application), HID_UsagePage(0x01), HID_LogicalMin(0), HID_LogicalMax(0xFF), HID_ReportCount(64), HID_ReportSize(8), HID_Input(HID_Data | HID_ARRAY | HID_Absolute), HID_UsagePage(0x02), HID_LogicalMin(0), HID_LogicalMax(0xFF), HID_ReportCount(64), HID_ReportSize(8), HID_Output(HID_Data | HID_ARRAY | HID_Absolute), HID_EndCollection, }; /* USB Configuration Descriptor */ /* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */ const BYTE USB_ConfigDescriptor[] = { /* Configuration 1 */ USB_CONFIGUARTION_DESC_SIZE, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ WBVAL( /* wTotalLength */ USB_CONFIGUARTION_DESC_SIZE + USB_INTERFACE_DESC_SIZE + HID_DESC_SIZE + USB_ENDPOINT_DESC_SIZE * 2 ), 0x01, /* bNumInterfaces */ 0x01, /* bConfigurationValue */ 0x00, /* iConfiguration */ USB_CONFIG_BUS_POWERED /*|*/ /* bmAttributes */ /*USB_CONFIG_REMOTE_WAKEUP*/, USB_CONFIG_POWER_MA(100), /* bMaxPower */ /* Interface 0, Alternate Setting 0, HID Class */ USB_INTERFACE_DESC_SIZE, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x00, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ 0x02, /* bNumEndpoints */ USB_DEVICE_CLASS_HUMAN_INTERFACE, /* bInterfaceClass */ HID_SUBCLASS_NONE, /* bInterfaceSubClass */ HID_PROTOCOL_NONE, /* bInterfaceProtocol */ 0x5C, /* iInterface */ /* HID Class Descriptor */ /* HID_DESC_OFFSET = 0x0012 */ HID_DESC_SIZE, /* bLength */ HID_HID_DESCRIPTOR_TYPE, /* bDescriptorType */ WBVAL(0x0100), /* 1.00 */ /* bcdHID */ 0x00, /* bCountryCode */ 0x01, /* bNumDescriptors */ HID_REPORT_DESCRIPTOR_TYPE, /* bDescriptorType */ WBVAL(HID_REPORT_DESC_SIZE), /* wDescriptorLength */ /* Endpoint, HID Interrupt In */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_IN(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ WBVAL(0x0040), /* wMaxPacketSize */ 0x20, /* 32ms */ /* bInterval */ /* Endpoint, HID Interrupt Out */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_OUT(2), /* bEndpointAddress */ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ WBVAL(0x0004), /* wMaxPacketSize */ 0x20, /* 32ms */ /* bInterval */ /* Terminator */ 0 /* bLength */ };
As you see my Report count is currently 64, so it should be transferable in 1 USB transaction,because I have configured wMaxPacketSize to 64, But I need to increase it to 128 later. In addition there are 2 more questions too: 1- what is bAlternateSetting for? 2- when I were checking USB library code, I saw this function:
void USB_DataInStage (void) { DWORD cnt; if (EP0Data.Count > USB_MAX_PACKET0) { cnt = USB_MAX_PACKET0; } else { cnt = EP0Data.Count; } cnt = USB_WriteEP(0x80, EP0Data.pData, cnt); EP0Data.pData += cnt; EP0Data.Count -= cnt; }
But this function was somehow strange, because if EP0Data.Count is more than USB_MAX_PACKET0, then how the reminder of buffer will be transfered? I thought it should be something like this:
void USB_DataInStage (void) { DWORD cnt; while (EP0Data.Count) { if (EP0Data.Count > USB_MAX_PACKET0) { cnt = USB_MAX_PACKET0; } else { cnt = EP0Data.Count; } cnt = USB_WriteEP(0x80, EP0Data.pData, cnt); EP0Data.pData += cnt; EP0Data.Count -= cnt; } }
isn't it?
> Even though my HID device is working on a request/response nature that starts from host,…
Send request from PC application to the interrupt OUT endpoint. Parse the request, and send back response to the interrupt IN endpoint. > When I attach my programmed USB device to PC, it immediately says "Unrecognized USB device" and I cannot see any logs in USBlyzer.
Maybe, on your board, D+ pull-up resistor is fixed one, not controlled by the MCU. Which board are you using? Is it a development board or custom one? Can you show us its schematics? Report descriptor is revised as follows. Configuration descriptor set is fine.
/* HID Report Descriptor */ const BYTE HID_ReportDescriptor[] = { HID_UsagePageVendor(0x00), HID_Usage(0x01), HID_Collection(HID_Application), // ---------- common global items ---------- HID_LogicalMin(0), HID_LogicalMaxS(0xFF), HID_ReportSize(8), // ---------- input report ---------- HID_ReportCount(64), HID_Usage(0x01), HID_Input(HID_Data | HID_Variable | HID_Absolute), // ---------- output report ---------- HID_ReportCount(4), HID_Usage(0x01), HID_Output(HID_Data | HID_Variable | HID_Absolute), HID_EndCollection, };
Which MCU are you using? Keil's example code is almost same for any type of MCU, but there are minor differences.
I'm using a custom board,but I should say when I program that board with provided HID example with no change, everything works fine. But when I program it with my own code, that problem shows up.
In addition, my MCU is AT91SAM7S256.
I will test my board with this revised report descriptor and tell you what happens.
Regards.
> I'm using a custom board,but I should say when I program that board with provided HID example with no change, everything works fine.
Do you mean debug function also works fine with the example? Anyway, the descriptor has problem, but it isn't the cause of USBlyzer / debugger trouble.
Fixed / controlled D+ (or D-) pull-up. Here is a bad example.
Keil MCB2140 schematic http://www.keil.com/mcb2140/mcb2140-schematics.pdf
At the bottom right corner of the first page, you'll see USB connector. On the D+ line from the connector, R35 (1k5) pull-up resistor is connected. This resistor is fixed one, not controlled by the MCU port.
This pull-up configuration is bad for the development of USB application. You have to plug-off/plug-in USB connector to re-start USB enumeration, every time the debugger puts reset. Also, this board is supplied just by USB connector. Plug-off/plug-in connector powers down the board, the debugger is disturbed.
The workaround of this board is, insert a self-powered hub (supplied by wall-mount adapter) between this board and PC USB port.The self-powered hub supplies power to the board regardless of PC connection. But you still have to plug-off/plug-in the hub - PC USB port connection for re-enumeration.
Here is a good example.
Keil MCB2300 schematic http://www.keil.com/mcb2300/mcb2300-schematics.pdf
On this schematic, USB connector is found at the right hand of the second page. R3 (1k5) pull-up resistor is connected to the D+ line (connected to pin 3 of the connector). This pull-up is controlled by Q1 PNP transistor, which connects to P2.9 MCU port through J5.
This configuration is fine for USB development. When debugger puts reset, the port goes to initial state, and the D+ pull-up is disabled automatically. After reset, the firmware enables the pull-up, and re-enumeration starts smoothly without connector plug-in/off.
Which type of D+ pull-up on your borad?
Thanks for schematics. I should say that my board is using bad mode of pull-up resistor for D+, but I have used a simple way to solve enumeration problem. I power up my board with an additional 5v(for JTAG), and start debugging board. In this mode,USB is not enumerated yet. Then I attach USB cable from my board to PC and enumeration starts with no problem. But this is not my problem for sure. When I program my board with base HID example from USB library, there is no problem with anything. my board works both normally(attaching device to PC), or when I debug my board with ULINK. then there should not be any problem with my board. But when I program board with my own USB codes(customized from those libraries), if I attach device to PC it says "USB device not recognized", but when I start debugging my board(then there are some delays between configuration steps when I break on breakpoints), my configuration of USB device proceeds several steps(not to a exact steps, once only till getting report descriptor, once till fully recognizing device). Then I think there is a synchronization problem in my code that leads to this behavior.
In addition I tested my code using new report descriptor, but nothing changed. EP0 is a 2 way control endpoint, is it possible that configuration packets via this endpoint are transferred incorrectly?
> When I program my board with base HID example from USB library, there is no problem with anything.
Then, go step by step. 1) Firstly, copy the example project to your working folder. Build it and run it once, to ensure the copy works fine. Of course, it'll run without any problem, but do it just for double check.
2) And then, replace just the descriptors (Device, Config set and Report descriptors) on the copy. The other source code are left untouched. It should still be enumerated, unless the descriptors have any problem.
For different configuration, assign different VID/PID (Vendor/Product ID) on the Device descriptor. While development, you can use any VID/PID, unless it doesn't conflict with other USB devices on your PC. I usually apply VID = 0xFFxx (xx is arbitrary number), and arbitrary PID for development. Before release of the product, get official VID/PID. USBDeview lists up USB deviceson your PC, with their VID/PID.
USBDeview www.nirsoft.net/.../usb_devices_view.html
3) When you finish the descriptors, modify endpoint handler a little (report size, etc). Then check the result. Jan Axelson's "generic_hid_vb" or "generic_hid_cs" will work as a test bench on the PC side. http://www.lvr.com/hidpage.htm Up to this phase, I think you don't see so much trouble on debugging.
4) When you satisfy with the USB communication, modify the example processes and add your own tasks to the source code. If some trouble would occur on debugging, it's here. - When you declare large array or numerous global variables, it delays start-up initialization. - You may access to USB endpoints, before USB connection is established.
In this way, you can narrow down the source of trouble, easily.
Sorry for late replay, I was on my weekend. :)
After working more on my device, I noticed what the problem was. It seems that my code itself had no problems but there are some problem with USBlyzer on my PC. Because after uninstalling it, my HID device is recognized with no problem. But I currently have another problem that I'm working on it. I can send data to my HID usb device, but I cannot read anything from it. I don't think it that the problem comes from my PC side test code, but I need to investigate more. But there is some more small questions if you have time for them too.. :) 1- Is it ok to send 2 packets of data both equal to wMaxPacketSize with no delay? I mean can I simply split my buffer which is bigger than wMaxPacketSize to smaller buffers and send then like this(it is pseudo-code):
Send_Buffer_To_Host(buf, len) while (len > 0) { tmplen = len > wMaxPacketSize? wMaxPacketSize : len USB_SendEP(0x81, tmplen of buf, tmplen) len -= tmplen buf += tmplen }
I mean several calls for sending data will not cause any problem? 2-There are quite a lot unimplemented event callbacks in HID library. Is there any special one which is recommended to implement? 3-Should I make sure to protect my write and read function with SWI for interrupt protecting? Is there any other functions that is needed to protect too or not?
> It seems that my code itself had no problems but there are some problem with USBlyzer on my PC. Because after uninstalling it, my HID device is recognized with no problem.
Did you install two or more software sniffers on the PC? Depending on the sniffers, it causes conflict among sniffers each other. > 1- Is it ok to send 2 packets of data both equal to wMaxPacketSize with no delay?
As the interrupt endpoint doesn't have double buffer, the firmware has to wait until the first packet finishes to transfer to host, before it passes next packet to the endpoint.
For request/response pair over HID OUT/IN endpoint, typical code pattern is as follows.
The size of request / response affects the descriptors as follows. request (4 bytes) - output report - OUT endpoint response (128 bytes) - input report IN endpoint On the report descriptor, the size of the input and output reports exactly match to the requirement. On the OUT endpoint descriptor, set to equal or more size than the requirement - any value from 4 to 64 bytes will do. For IN endpoint, set it to 64 (maximum for full-speed). The input report is split into two 64 bytes packets.
usbdesc.c /* HID Report Descriptor */ const BYTE HID_ReportDescriptor[] = { HID_UsagePageVendor(0x00), HID_Usage(0x01), HID_Collection(HID_Application), // ---------- common global items ---------- HID_LogicalMin(0), HID_LogicalMaxS(0xFF), HID_ReportSize(8), // ---------- input report ---------- HID_ReportCount(128), // <------ set to 128 bytes HID_Usage(0x01), HID_Input(HID_Data | HID_Variable | HID_Absolute), // ---------- output report ---------- HID_ReportCount(4), // <------ set to 4 bytes HID_Usage(0x01), HID_Output(HID_Data | HID_Variable | HID_Absolute), HID_EndCollection, }; const BYTE USB_ConfigDescriptor[] = { ... ... /* Endpoint, HID Interrupt In */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_IN(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ WBVAL(0x0040), /* wMaxPacketSize */ <------- set to 64 bytes 0x20, /* 32ms */ /* bInterval */ /* Endpoint, HID Interrupt Out */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_OUT(2), /* bEndpointAddress */ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ WBVAL(0x0004), /* wMaxPacketSize */ <------- set to 4 - 64 bytes 0x20, /* 32ms */ /* bInterval */ ...
Simple implementation is here. - When output report comes from host, is it caught in EP2 interrupt - EP2 ISR (Interrupt Service Routine) parses the request. As the result, an input report is generated on a buffer. The first packet of IN transfer is sent to the IN EP1 in this interrupt. - When the transaction of the first packet finishes, EP1 ISR is called. In this ISR, the latter half of the input report is passed to the endpoint.
usbcfg.h #define USB_EP_EVENT 0x0007 // enable EP0, 1, 2 interrupts usbuser.c BYTE request_buf[4]; BYTE response_buf[128]; BOOL send_next = FALSE; void USB_EndPoint1 (DWORD event) { // IN EP if ( send_next ) { send_next = FALSE; USB_WriteEP( 0x81, &response_buf[64], 64 ); // send the second packet } } void USB_EndPoint2 (DWORD event) { // OUT EP DWORD byte_count; byte_count = USB_ReadEP( 0x02, request_buf ); // read output report // // parse the request here // and fill response_buf // USB_WriteEP( 0x81, response_buf, 64 ); // send the first packet send_next = TRUE; } void USB_EndPoint3 (DWORD event) { // EP3 is not used // Comment these lines // GetInReport(); // USB_WriteEP(0x83, &InReport, sizeof(InReport)); }
In above code, USB_EndPoint2() is called twice, when both of the first and second transaction finishes. send_next flag distinguishes these calls. This kind of flags and variables, which relate to USB communication, are initialized in USB_Configure_Event() - Set_Configuration request handler.
usbuser.c #if USB_CONFIGURE_EVENT void USB_Configure_Event (void) { if (USB_Configuration) { /* Check if USB is configured */ // For request / response exchange, the first input report is not required. // Comment these lines // GetInReport(); // USB_WriteEP(0x83, &InReport, sizeof(InReport)); // // Instead other initialization is placed here // send_next = FALSE; } } #endif
In above post, the first packet is passed to IN EP using USB_WriteEP() in the OUT EP ISR. This scheme is fine when it doesn't take so much time to generate the input report. But if it takes so long, waiting in the ISR is not a good idea. In such case, USB_WriteEP() moves to elsewhere, at the place where the report generation finishes.
Suppose that the request orders 64 x 2 bytes samples from ADC, starting at the arrival of the request. - The parser on the OUT EP ISR starts ADC. The ISR just finishes. - In the ADC ISR, the report buffer is filled one sample by one. - In the ADC ISR, USB_WriteEP() is called for the first packet, when the 64th sample is filled to the buffer. - The second packet is sent in the IN EP ISR, like above.
In this way, you can move USB_WriteEP() to anywhere, on the place it fits best.
Similarly, USB_ReadEP() is placed on anywhere. Suppose that your firmware doesn't want to be disturbed by the next request, until current process finishes. - In the OUT EP ISR, just raise a flog, without calling USB_ReadEP(). - The flag is checked in timer-ed polling or main-loop polling, when current process finishes. In this polling routine, USB_ReadEP() is called to starts next process.
While the OUT endpoint is occupied by the last packet, the USB engine returns NAK (not ready) to the host. Host waits until the endpoint becomes empty (NAK flow control). No packet is lost. When you move USB_ReadEP() and/or USB_WriteEP() out of the endpoint ISR, you have to care of atomic access of these functions, so as not to re-enter to these routines each other. USB_ReadEP() and USB_WriteEP() are used in the several part of USB ISR in the USB stack.
To use these functions in an ISR of ADC, timer, etc., the interrupt priority of these ISRs should be same as those of USB interrupt. To use them on main-loop task, SWI is applied for these functions. For SWI, see the discussion on this topic, from the post on 26-Sep-2009 03:46 GMT http://www.keil.com/forum/docs/thread15613.asp
Thanks for quick and great replies. :)
In above code, USB_EndPoint2() is called twice Why it is called twice? Shouldn't it get called only once when I receive data on EP2?
Is there any flag that shows a buffer in an IN endpoint has been sent to host(and host is received it)?
And regarding processing time, device has a really wide range of processing time, from a few milliseconds to even 1.5 mins, But I don't think it really makes problems for my application side, if this delay won't make any problem in MCU itself(for example these process delays will happen in ISR because of library code).
>> In above code, USB_EndPoint2() is called twice > Why it is called twice? > Shouldn't it get called only once when I receive data on EP2?
Auu, my bad ... It's EP1 (IN endpoint), instead of EP2 (OUT endpoint) The OUT EP ISR is called once, when the OUT endpoint receives the request from host. The IN EP ISR is called twice, when the IN endpoint sends each packet to the host. > Is there any flag that shows a buffer in an IN endpoint has been sent to host(and host is received it)?
These Bits on USB engine registers are available for polling, when interrupt is not enabled on the endpoint.
UDP_ISR (Interrupt Status Register) - EPxINT bit (IN and OUT endpoint) or UDP_CSRx (Endpoint Control and Status Register) - TXCOMP (IN endpoint), RX_DATA_BK0 (OUT endpoint)
Hi Tsuneo
Thanks for your great replies. :) I worked on my code for a lot and now I have no problem on sending and receiving small buffers(less than wMaxPacketSize). But I should say that I were not able to send any report that is bigger than wMaxPacketSize. Assume that I have set my INPUT and OUTPUT report size to 8 and report count to 128(so buffer is 128 bytes) and my wMaxPacketSize is 64. When I try to send data from host to device,I need to send them in 128 byte buffers(and trying to send less than this much generates errors), but I only receive first 64 bytes in my device. Similarly, when I need to read 128 bytes from device(less than that much is not allowed), I can only send first 64 bytes from device to endpoint, then because host side has not received enough data, it goes into deadlock for receiving reminder of data that never happens. Any idea how I can repair this problem? In addition, the is a flag for INPUT and OUTPUT reports called 'Byte Stream'. is it good to set this flag if all my report data is byte aligned?
I should say That was able to send 128 Byte buffer (bigger than wMaxPacketSize) from host to device on my OUTPUT report, so no problem for this part anymore... :) But my problem for INPUT report persists, and I cannot send data to host... :(
> When I try to send data from host to device,I need to send them in 128 byte buffers
Are you working on Windows? Then, the buffer size to pass to ReadFile()/Writefile() is 129 bytes (1 + 128). Report ID (1 byte) precedes before the 128 bytes body.
When the report descriptor on the device doesn't have any report ID, - Windows app: default report ID (0) precedes. - HID device: no report ID is attached.