Related
I have a char *data that is a Datagram to represent the packet I want to send in but I need to insert on that an uint8_t array.
// Datagram to represent the packet
char datagram[4096], source_ip[32], *data, *pseudogram;
// zero out the packet buffer
memset(datagram, 0, 4096);
// IP header
struct iphdr *iph = (struct iphdr *)datagram;
// UDP header
struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct ip));
// Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
uint8_t packet_bytes[] = { 0xff, 0xff, 0x81, 0x01, 0x01 };
memcpy(data, packet_bytes, 5);
Doing this allows me to insert what I need and it works but the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array, how can I make it to work with this array instead ?
char packet_bytes[] = {
0xff, 0xff, 0x81, 0x00, 0x00, 0x00, 0x00, 0x30,
0x13, 0x43, 0x00, 0x01, 0x01, 0x01, 0x02, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x06, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x63,
0x02, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x09, 0x04, 0x00,
0x0a, 0x00, 0x03, 0x01, 0x00, 0x11, 0x77, 0x25
};
the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array
There is no such thing as "termination of an array" in C. There is null termination of character arrays used as strings, but that isn't applicable here. So the memcpy part will work just fine.
You have some other problems however:
char datagram[4096], char packet_bytes[] etc
char is unsuitable, dangerous and non-portable for the purpose of holding raw binary data. Use uint8_t instead. See Is char signed or unsigned by default?
struct iphdr *iph = (struct iphdr *)datagram;
This will lead to undefined behavior because of alignment and strict aliasing. What is the strict aliasing rule? You cannot wildly type pun from a character array to another type by pointer casts (though the other way around from "any type" to character type is possible). Furthermore, your struct may contain padding, in which case it is extra non-portable and you don't want to be sending padding bytes around.
(struct udphdr *)(datagram + sizeof(struct ip)); Same problem as above.
The only reliable way to do this is either to disable struct padding and then memcpy in/out of the struct. Or alternatively write serialization/deserialization routines accessing one struct member at a time, moving it to/from the raw data.
I currently have this HID report descriptor:
static
unsigned char hid_report_descriptor[] __attribute__ ((aligned(64))) = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0xA1, 0x00, // Collection (Physical)
0x85, 0x01, // Report ID (1)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x10, // Usage Maximum (0x10)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x10, // Report Count (16)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x33, // Usage (Rx)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection
};
It corresponds to this struct.
struct GamepadReport {
uint8_t report_id;
uint16_t buttons;
int8_t left_x;
int8_t left_y;
int8_t right_x;
int8_t right_y;
} __attribute__((packed));
I'm trying to add support for a single extra button that should serve as the "home" button (think of the X on an Xbox controller). This, in theory, should be done by changing the lines containing 0x29, 0x10 and 0x95, 0x10 to 0x29, 0x11 and 0x95, 0x11 respectively. However, doing so breaks the connection with the custom controller.
I cannot for the life of me figure out why this is and it makes absolutely zero sense to me. Can someone with more experience or knowledge about HID descriptors give me a hand?
In case anyone stumbles upon this or has a similar issue. You can't create a report count field on hid descriptors with numbers not divisible by 8 unless you add padding bits.
The solution was straightforward after reviewing the comments on my question and looking at similar issues online.
My gamepad report struct could only hold 16 bits. Even if I had a correctly defined hid descriptor, this would've prevented it from working. I changed my struct to the following.
struct GamepadReport {
uint8_t report_id;
uint32_t buttons;
int8_t left_x;
int8_t left_y;
int8_t right_x;
int8_t right_y;
} __attribute__((packed));
Modify your hid descriptor to contain the padding bits to the next number divisible by 8 that fits within your struct types. In this case, I need to fill 32 bits and I have 17 buttons. 32 - 17 means I need to add 15 padding bits.
0x75, 0xF, // Report Size (15) - PADDING BITS
0x95, 0x01, // Report Count (1)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
I have recently restarted to play around with micro controllers and finally got kinda stuck. So what I am building is a custom game pad. I can simulate data correctly for buttons but nothing works when I bring in the hat switch. I assume I am sending wrong data packet but cannot figure out the correct structure. In the test code I am just trying to send some "button press" and also trying to press down a key from hat switch, but it looks like that pc cannot recognise my data packet. I did go through the hid documentation (especially page 64, 65) and still have no idea why this is not working.
My HID descriptor:
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x0e, // USAGE_MAXIMUM (Button 14)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x0e, // REPORT_COUNT (14)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x02, // REPORT_SIZE (2)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x39, // USAGE (Hat switch)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x03, // LOGICAL_MAXIMUM (3)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x04, // REPORT_SIZE (4)
0x81, 0x42, // INPUT (Data,Var,Abs,Null)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x04, // REPORT_SIZE (4)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
Basic test code:
struct gamepad_report_t
{
uint16_t buttons;
uint8_t hs0 : 1;
uint8_t hs1 : 1;
uint8_t hs2 : 1;
uint8_t hs3 : 1;
};
struct gamepad_report_t gamepad_report;
gamepad_report.buttons = 0x0001;
gamepad_report.hs0 = 1;
gamepad_report.hs1 = 0;
gamepad_report.hs2 = 0;
gamepad_report.hs3 = 0;
int main()
{
while (1)
{
gamepad_report.buttons = 0x0010;
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, &gamepad_report, sizeof(struct gamepad_report_t));
HAL_Delay(500);
}
}
Data packet structure I have imaganed
What I see in the device properties when the uC is connected
The problem I struggled here was the struct variable I wanted to send to the PC. If I am sending an array, everything works as expected... so the conclusion is that sizeof(struct) is not returning correct value, I should read through data structure alignment ... typically simple issue what can drive people crazy.
First thing I see wrong is that you are trying to use the hat switch like buttons. The hat switch has a value for each direction.
For example Up-Left has its own value, it is not a combination of Up and Left being pressed.
You will have to read your buttons, and then encode them as a value.
It can be a little finicky to set up for the first time.
Here are the values for each button, which should clear up any confusion. (Won't work with every report descriptor!)
#define HATSWITCH_UP 0x00
#define HATSWITCH_UPRIGHT 0x01
#define HATSWITCH_RIGHT 0x02
#define HATSWITCH_DOWNRIGHT 0x03
#define HATSWITCH_DOWN 0x04
#define HATSWITCH_DOWNLEFT 0x05
#define HATSWITCH_LEFT 0x06
#define HATSWITCH_UPLEFT 0x07
#define HATSWITCH_NONE 0x0F
And here is part of a descriptor that will work with those values.
Just define a uint8_t for the hat switch in the report descriptor and you should be good to go.
0x05, 0x01, //Usage Page : Generic Desktop
0x09, 0x39, //Usage : Hat Switch,
0x15, 0x00, //Logical Min : 0
0x25, 0x07, //Logical Max : 7
0x46, 0x3B, 0x01, //Physical Maximum : 315 degrees (Optional)
0x75, 0x08, //Report Size : 8
0x95, 0x01, //Report Count : 1
0x65, 0x14, //Unit : English Rotation/Angular Position 1 degree (Optional)
0x81, 0x42, //Input : Data, Var, Abs, Null State
I know this is an old topic, and you most likely figured it out, but it will help people in the future.
I have a structure as follows
typedef struct s_CanMsg
{
uint32_t id;
uint16_t timestamp;
uint8_t data[8];
uint8_t dlc;
bool_t isExtended;
bool_t isRemote;
} s_CanMsg_t;
and I have a structure variable as follows
s_CanMsg_t CANEraseResponse;
Now I am trying to pass an array to the data member of the structure variable as follows:
CANEraseResponse.data[8] = {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00};
This is showing syntax error and how can I pass the data to the structure variable with array member? Thanks in advance.
You can initialize the whole structure when you define the variable:
s_CanMsg_t CANEraseResponse = {
some_value_for_id,
some_value_for_timestamp,
{0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00},
some_value_for_dlc,
some_value_for_isExtended,
some_value_for_isRemote
};
You can also use a designator to explicitly initialize only the array member;
s_CanMsg_t CANEraseResponse = {
.data = {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00}
};
Then all other members will be initialized to zero.
And of course you can define a temporary array and copy into the structure array:
static uint8_t data[8] = {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00},
s_CanMsg_t CANEraseResponse;
memcpy(CANEraseResponse.data, data, sizeof data);
Lastly, if none of the ways above are acceptable, then the only remaining solution is to explicitly assign to each element of the array:
CANEraseResponse.data[0] = 0x00;
CANEraseResponse.data[1] = 0xFF;
CANEraseResponse.data[2] = 0x00;
CANEraseResponse.data[3] = 0x04;
CANEraseResponse.data[4] = 0x02;
CANEraseResponse.data[5] = 0x00;
CANEraseResponse.data[6] = 0x00;
CANEraseResponse.data[7] = 0x00;
The notation you are using can only be used to initialize an array. Once you declare your struct variable, you have moved past initialization. You can, however, do it with something called a "designated initializer" like so:
s_CanMsg_t CANEraseResponse = {.data= {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00}};
CANEraseResponse.data[8] refers to the 9th element of the data member (as the array is zero based. Try removing the [8].
Edit/Clarification: removing the [8] will not solve your issue, but you should be aware that CANEraseResponse.data[8] points to a position outside of the data array.
You can't assign arrays directly in C. As well as the initialization techniques shown in other answers, you could use a compound literal and memmove() (or memcpy()):
memmove(CANEraseResponse.data, (uint8_t[]){ 0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00 }, sizeof(CANEraseResponse.data));
I have a small c program which connect and authenticate with my security DVR which in turn starts sending me data over the socket. I can connect on port 5000 or port 80 sending different authentification methods to start receiving the video/images. My problem is; I am new to c first of all, and I am very lost on how to process the data received over the socket. This is the data I am sending to authenticate.
char authenticate[] = {
0x31, 0x31, 0x31, 0x31, 0x88, 0x00, 0x00, 0x00,
0x01, 0x01, 0x00, 0x00, 0x88, 0x7d, 0xa6, 0x47,
0x0c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x61, 0x64, 0x6d, 0x69, 0x6e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x43, 0x6f, 0x6c, 0x74, 0x6f, 0x6e, 0x73, 0x2d,
0x4d, 0x61, 0x63, 0x42, 0x6f, 0x6f, 0x6b, 0x2d,
0x50, 0x72, 0x6f, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x00, 0x00, 0x00, 0x35, 0x34, 0x32, 0x36,
0x39, 0x36, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
};
x = sendto(sockfd, authenticate, sizeof(authenticate), 0,
(struct sockaddr*)&servaddr, sizeof(servaddr));
I am then recieving the data with
while(1)
{
n = recvfrom(sockfd, data, 2048, 0, NULL, NULL);
When I connect via http port 80 This is the image data that I receive:
Content-length: 2153
Content-type: image/jpeg
ˇÿˇ‡JFIFHHˇ€Cˇ€Cˇ¿#ˇƒ
ˇƒ8 2A!$X"#3QRTqëîóò“’÷ˇƒˇƒ#
!1A"2QRqrë#SacÅ°¢≥—“ÒBCstÇí¥”ˇ⁄ ?e›n◊}mÀ⁄ÔÅ≥j¿ò[0ÂáֱNU…9'*‚®#ô &yéïùr‰Ù®{ï“däŒÆl$Kkë R,√fƒSl—EX
z \û£≠âflüÈ‚≠ê*àÉ*—1E;q}Ìp6#>øÆÂòŸR≠^Ì˝çò ı;R∆b¡»ü>aÊ∫a˙5KKüz∑¶Î´D“≤κl∂ÎÓ„∆Àn∫¥•sh8vß4≠äöûñy‰H¢çyºí0TQrÏ#π dÅèåfi*XY*F¨Óƒl™¢‰˝S^sgh]î…flzXNü‡†2∑ñæ5t€Tp`qìåos◊iGùjˆ˙+FÈ™‚‘_§≈[”Jˇ *•<*´∆≥ÁpVGfl
ï¶ñ—€{ñgíJmd*ôï„å[YT-J†∞π∂¯ë…{¶dyÓaÓhå©!øg⁄∆™≤È:
≥Ô`Mú)∞ÚÌǯhˇÿ„Tø∑,9˛õ°˛ıØö~ø«ûÔ˝˙aa{ÜÔû÷Èé‡ÂΩk÷ºµ\sÉÒ¬XÓ∞`¯⁄X“">eäÅœ»G¡ìöÜ"˘mütòÅtuÓbÌh;vB1dflL ∂)
´È
Hm∂Í
Ω¡î*Ä≤e‘nÄï‘HΩ…77ÙIè6%â%ãµ"T¿n¢Í3%‹zj#™:”ÂmR˛=L ZsZ[_ïz±»r…™2®ú.«]∑$q¢1)ùftÙ˘îà[q£°Îü&%Ï÷#á∂¿ôEy!ËÇJ0‚‚j»¥|∆fi–ü5"èRj›D˘„õUäú≥û>•«bdôãq]Ö$2ˆ„Gc#,ó±Ò<√-p}ZÍSÛ £ëóŒsäóNçı≠◊òÊö•mÈÇ_W„Y2∆∫9œxπŸ¸*±’dË⁄1(¸05{üfW∆Éû
‘ÿSÑ‘„û.JTÓ9˙Ìø˝∆º=∆ ¬ï∆h≥!`uˆ’Uçõèd„Ï…ı®*GÕıŸ6iíÆiñ¶’ØmBë‰WáÈö˛â‚ı∞>Ó˛◊_Â’ˇπ?º”˘øh~8TÔÕ/ùˆO¬Ewü^◊]…6
ÕïÊ«p2ˆ◊ä”õU÷ËÖˆ◊䲲ãk–«_2ûk4Éÿ‰aÖƒîP∑ùg⁄†·¢µ’ÂS÷}XNï¯5GWæßGk”óS8fòˇ;˝âp;≈“ƒ5ˇ˜„Éû·&Áa¨ö2tÿ±íÉìcÇeÓ"¬Â„(8¯:øØíM £rmfiá~≠æ(:oT/U≤/täó U√ñT0ëªÕ ê’¢víRT#˙‚ìO7ÖÆÒ‘D<dm#;F®—yÑmPǃ5É+FZÀ"8≥-˙7"ç–ãm{Å∑Öunü»à·®icëcoDìf¬·ñ)!å A¡ñÂNrx√aeP\ZM®£ ‘Y\<kJÿ‚’Ó#„Œª+â3
¨π©%Uü±Àñ¨œò§S2àŸßUJjwûYãZ#Ç∆˚¶&hr⁄xj¬ì È™sàK-… 28Fm‡Ôr√û 8Qè
ª∑ØP ptt£‚N—Œ∆Iπ ıo«Y{Èe.U[´‰•ı∫ÎæöÙU’‘…)¶Gy
†“ä]ãä6U≤Å∞b 7X„ ™˙#ÓMÖ∑>_ó
=fiÔ>·π∂ˇ÷ãÎΩfl«Y!µÎô≥—ß;¨J™èΩ|tLoîRˇM›.#nŸÍ±≈±Ê∏Ï~qkãsv≈Xõ‰í∞Lπ/cR,j*6.Sí„ÿ˘fÑ»7f|_™≥RçÿíE°°bã {{Ïõç#·Ãæ:7çú√´u o
⁄N¨Ω\€ù◊K,Z4àÕ8N\˙πÍë’D∫vbfl∏¢>äz.¸¨⁄Ä‘°dx≈ªàˆÕ45‡ßõub-ü%TVTN8⁄∞¨≤µÁñÜD[;o—˘ƒNˇóóØ[ò;´¡O*∫¿ƒ©∏2ߘG#20˘H∆µªú’2€∂O°Â⁄Ùb®äÌ/hÿQÁXÓŸJzB¬Öw]Ù2ÿ—⁄§∆«gÜö·´˚Ëãt‚+˛Iì¯∂⁄nÎ{ºVʬ)aà∆´°ÀÚËÃkr÷â„ç^1©ôæ
óv'ô8∆ãπkB˙цπ¯zÉsÀpv;Ã]ÓI€[Ìj/˙A≤øÒ}O˚ËS|Dûƒˇ¶3=ÓÍæ6?Ú…å!¥›¨Ûˆ¸f…€·I~à≥ g>∆®‰√Û0≥30®Æ) èMÖçGÃ∑dÑÖ∞¥Œéf≥ÔyµE¢Yå.õ·ç+r˙ú ≤ZÄP ‰y¨Km⁄±~ävfl¡'I+b»Ñî[ö<¬ æñ8raEãk
I am unsure if this data is some weird encoding or if it need to be processed somehow to make it valid. I have searched around with no luck or examples of how to properly do this. If i connect via the data port (port 5000 which sends via instead of an image) the data looks pretty much the same although i know it may be processed or unprocessed H.246 video data.
The raw data is an image. It starts after the blank line which terminate the headers.
Code:
n = recvfrom(sockfd, data, 2048, 0, NULL, NULL); // might as well replace with read().
// use a much larger buffer, ideally large enough to fit largest possible whole image
headers_end_str = "\r\n\r\n";
headers_end_position = strstr(data, headers_end_str);
headers_end_position += strlen(headers_end_str );
if (headers_end_position > n) { ... } // handle errors
FILE* fh = fopen("image.jpg", "wb");
int result = fwrite( &( data[ headers_end_position ), n - headers_end_position, 1, fh);
// check result for errors
// continue reading from socket and writing to file, subsequent reads do not have headers
This should get you started, you need to fine tune reading additional data, and also error handling and end of file.
However, even before you have done all that, you should be able to run "file -s image.jpg" (on linux, or cygwin) and it will tell you it's a JPEG image.
I used WireShark to monitor the communication between the DVR and it's web browser plugin client and the authentication message header is similar to your post (0x31 0x31 0x31 0x31...). How did you construct this array? I searched a lot for this protocol documentation but I didn't find.
In my case I do the requests at port 7171 (it's a DVR settings). I also used a while(true) to keep listening this port and the server sends me a h264 stream.
The problem is that the stream is not like rtps protocol describes, see this great post. In our case we have to parse a kind of proprietary header first (that starts with 0x31 0x31 0x31 0x31) to stract the frame, sps and pps.