bRAWcap 1.1.0
b-plus Technologies - Ethernet Performance Transmitter Receiver
Loading...
Searching...
No Matches
12_buffer_sorting_f.c

This example shows how to create a bRAWcap packet buffer, fill it with packets, sort the packets inside the buffer by their timestamp or payload and verify the sorting.

1/**
2 * @file 12_buffer_sorting_f.c
3 *
4 * @brief bRAWcap Example - Demonstrates how to sort a bRWAcap packet buffer by timestamp or payload.
5 *
6 * It shows how to:
7 * - How to create a bRAWcap packet buffer
8 * - How to fill the buffer with packets
9 * - How to sort the buffer by timestamp or payload field
10 *
11 * This example makes use of C only.
12 *
13 * @version 1.0
14 *
15 * @date 2025-10-21
16 *
17 * HISTORY:
18 * - 2025-10-21: Initial version
19 *
20 * @copyright
21 * <b> © 2021 - b-plus technologies GmbH. All rights reserved!</b>
22 *
23 * All rights exclusively reserved for b-plus GmbH, unless expressly otherwise agreed.
24 *
25 * Redistribution in source or any other form, with or without modification, is not permitted.
26 *
27 * You may use this code under the according license terms of b-plus.
28 * Please contact b-plus at services@b-plus.com to get the appropriate terms and conditions.
29 */
30// Include bRAWcap
31#include "libbrawcap.h"
32
33
34// C STD
35#include <stdlib.h> // for rand, strtol
36#include <stdbool.h>
37#include <stdint.h> // for uint32_t, uint8_t
38#include <stdio.h> // for printf
39#include <time.h> // for printing time info
40#include <stdbool.h> // for bool type
41
42// Helper for microsecond timing
43#define TIME_DIFF_MS(start, end) ((double)(end - start) * 1000.0 / CLOCKS_PER_SEC)
44
45 // Seqid for payload sorting
46struct seqid {
47 uint32_t offset;
48 uint8_t length; // supported 1, 2, 4 bytes
49};
50
51// Compare timestamps: returns <0 if a<b, 0 if a==b, >0 if a>b
52static int compare_timestamps(brawcap_timestamp_t* a, brawcap_timestamp_t* b) {
53 UINT64 a_secs = 0;
54 UINT32 a_nsecs = 0;
55 UINT64 b_secs = 0;
56 UINT32 b_nsecs = 0;
57 brawcap_timestamp_value_ns_get(a, &a_secs, &a_nsecs);
58 brawcap_timestamp_value_ns_get(b, &b_secs, &b_nsecs);
59 UINT64 a_ns = ((UINT64)a_secs * 1000000000ULL) + a_nsecs;
60 UINT64 b_ns = ((UINT64)b_secs * 1000000000ULL) + b_nsecs;
61 if (a_ns < b_ns) return -1;
62 if (a_ns > b_ns) return 1;
63 return 0;
64}
65
66// Compare payload seqid: returns <0 if a<b, 0 if a==b, >0 if a>b
67static int compare_seqid(const unsigned char* a, const unsigned char* b, UINT8 length) {
68 UINT32 va = 0, vb = 0;
69 for (UINT8 i = 0; i < length; ++i) {
70 va |= ((UINT32)a[i]) << (8 * i);
71 vb |= ((UINT32)b[i]) << (8 * i);
72 }
73 if (va < vb) return -1;
74 if (va > vb) return 1;
75 return 0;
76}
77
78// Verify sort order: type 0=timestamp, 1=payload; order 0=rising, 1=falling
79bool verify_sort(brawcap_buffer_t* pBuffer, int type, int order, UINT32 seqid_offset, UINT8 seqid_length) {
81 if (brawcap_buffer_count(pBuffer, &count) != BRAWCAP_STATUS_SUCCESS) {
82 printf("[VERIFY] Could not get buffer count!\n");
83 return false;
84 }
85 for (brawcap_buffer_packet_count_t i = 1; i < count; ++i) {
86 brawcap_packet_t *pPrev = NULL, *pCurr = NULL;
87 if (brawcap_buffer_at_index(pBuffer, i-1, &pPrev) != BRAWCAP_STATUS_SUCCESS ||
88 brawcap_buffer_at_index(pBuffer, i, &pCurr) != BRAWCAP_STATUS_SUCCESS) {
89 printf("[VERIFY] Could not get packet at index %llu or %llu!\n", (unsigned long long)(i-1), (unsigned long long)i);
90 return false;
91 }
92 int cmp = 0;
93 if (type == 0) { // timestamp
94 brawcap_timestamp_t *tPrev = NULL, *tCurr = NULL;
95 brawcap_packet_timestamp_get(pPrev, &tPrev);
96 brawcap_packet_timestamp_get(pCurr, &tCurr);
97 cmp = compare_timestamps(tPrev, tCurr);
98 } else { // payload seqid
99 const unsigned char *payloadPrev = NULL, *payloadCurr = NULL;
100 brawcap_packet_size_t lenPrev = 0, lenCurr = 0;
101 brawcap_packet_payload_get_v2(pPrev, &payloadPrev, &lenPrev);
102 brawcap_packet_payload_get_v2(pCurr, &payloadCurr, &lenCurr);
103 if (payloadPrev == NULL || payloadCurr == NULL ||
104 seqid_offset + seqid_length > lenPrev || seqid_offset + seqid_length > lenCurr) {
105 printf("[VERIFY] Invalid payload or seqid range!\n");
106 return false;
107 }
108 cmp = compare_seqid(payloadPrev + seqid_offset, payloadCurr + seqid_offset, seqid_length);
109 }
110 if ((order == 0 && cmp > 0) || (order == 1 && cmp < 0)) {
111 printf("[VERIFY] Sort error at index %llu!\n", (unsigned long long)i);
112 return false;
113 }
114 }
115 return true;
116}
117
118int main(int argc, char** argv)
119{
120 // user params
121 const uint32_t packet_count = 10000;
122 const uint16_t payload_length = 1000;
123 const struct seqid seqid = { 520, 8 };
124 const bool verify = true;
125
126 // Set console title
127 SetConsoleTitleA("bRAWcap Example - Packet Buffer Sorting");
128
129 // Time tracking
130 clock_t t_start, t_end;
131 double elapsed_us;
132
133 // Seed random number generator
134 srand((unsigned int)time(NULL));
135
136 // The packet buffer to be sorted
137 brawcap_buffer_t* pBuffer = 0;
138 // A packet to add to the buffer
139 brawcap_packet_t* pPacket = 0;
140 // Payload
141 unsigned char* pPayload = (unsigned char*)malloc(payload_length);
142
143 if(seqid.length != 1 && seqid.length != 2 && seqid.length != 4 && seqid.length != 8) {
144 printf("[ERROR] Unsupported seqid length: %u. Supported lengths are 1, 2, 4 or 8 bytes.\n", seqid.length);
145 return -1;
146 }
147
148 printf("[INFO] Configuration: \n");
149 printf("\t - Packets: %u\n", packet_count);
150 printf("\t - Payload Length: %u\n", payload_length);
151 printf("\t - SeqId Offset: %u\n", seqid.offset);
152 printf("\t - SeqId Length: %u\n", seqid.length);
153
154 // Fill the payload with random data and set seqid
155 for (size_t i = 0; i < payload_length; ++i)
156 {
157 pPayload[i] = (unsigned char)(rand() % 256);
158 }
159
160
161 // Create a bRAWcap packet buffer
162 if(brawcap_buffer_create(&pBuffer, payload_length, packet_count) != BRAWCAP_STATUS_SUCCESS)
163 {
164 printf("[ERROR] Failed to create bRAWcap packet buffer. Status: %d\n", brawcap_last_status());
165 return -1;
166 }
167 printf("[INFO] Created bRAWcap packet buffer.\n");
168
169 // Create a packet to add to the buffer
170 if(brawcap_packet_create(&pPacket, payload_length) != BRAWCAP_STATUS_SUCCESS)
171 {
172 printf("[ERROR] Failed to create bRAWcap packet. Status: %d\n", brawcap_last_status());
173 brawcap_buffer_free(pBuffer);
174 return -1;
175 }
176
177 // Fill the buffer with packets
178 for(brawcap_buffer_packet_count_t i = 0, seqid_counter = 0; i < packet_count; ++i)
179 {
180 // Simulate packet data (for demonstration purposes)
181 // In a real scenario, you would fill the packet with actual captured data
182 brawcap_timestamp_t* pTimestamp;
183 brawcap_packet_timestamp_get(pPacket, &pTimestamp);
184 struct timespec ts;
185 timespec_get(&ts, TIME_UTC);
186 brawcap_timestamp_value_ns_set(pTimestamp, ts.tv_sec, ts.tv_nsec);
187 // Set seqid in payload
188 if (seqid.offset + seqid.length < payload_length)
189 {
190 uint64_t max_val =
191 (seqid.length == 1) ? 0xFF :
192 (seqid.length == 2) ? 0xFFFF :
193 (seqid.length == 4) ? 0xFFFFFFFF :
194 (seqid.length == 8) ? 0xFFFFFFFFFFFFFFFF : 0;
195 seqid_counter = (seqid_counter + 1) & max_val;
196 for (size_t i = 0; i < seqid.length; ++i) {
197 pPayload[seqid.offset + i] = (unsigned char)((seqid_counter >> (8 * i)) & 0xFF);
198 }
199 }
200 // Apply payload to packet
201 brawcap_packet_payload_set_v2(pPacket, pPayload, payload_length); // Empty payload for demonstration
202 // Add packet to buffer
203 if(brawcap_buffer_add_back(pBuffer, pPacket) != BRAWCAP_STATUS_SUCCESS)
204 {
205 printf("[ERROR] Failed to add packet to buffer. Status: %d\n", brawcap_last_status());
206 }
207 }
208
209
210
211 // Sort the buffer by timestamp (rising)
212 t_start = clock();
213 if(brawcap_buffer_sort(pBuffer,
216 0,
217 0,
220 ){
221 printf("[ERROR] Failed to sort buffer by timestamp. Status: %d\n", brawcap_last_status());
222 return -1;
223 }
224 t_end = clock();
225 elapsed_us = TIME_DIFF_MS(t_start, t_end);
226 printf("[INFO] Sorted buffer by timestamp rising order. Time: %.0f ms\n", elapsed_us);
227 if (verify) {
228 printf("[VERIFY] Timestamp rising: %s\n", verify_sort(pBuffer, 0, 0, seqid.offset, seqid.length) ? "OK" : "FAILED");
229 }
230
231 // Sort the buffer by timestamp (falling)
232 t_start = clock();
233 if(brawcap_buffer_sort(pBuffer,
236 0,
237 0,
240 ){
241 printf("[ERROR] Failed to sort buffer by timestamp. Status: %d\n", brawcap_last_status());
242 return -1;
243 }
244 t_end = clock();
245 elapsed_us = TIME_DIFF_MS(t_start, t_end);
246 printf("[INFO] Sorted buffer by timestamp falling order. Time: %.0f ms\n", elapsed_us);
247 if (verify) {
248 printf("[VERIFY] Timestamp falling: %s\n", verify_sort(pBuffer, 0, 1, seqid.offset, seqid.length) ? "OK" : "FAILED");
249 }
250
251 // Sort the buffer by payload seqid (rising)
252 t_start = clock();
253 if(brawcap_buffer_sort(pBuffer,
256 seqid.offset,
257 seqid.length,
260 ){
261 printf("[ERROR] Failed to sort buffer by payload seqid. Status: %d\n", brawcap_last_status());
262 return -1;
263 }
264 t_end = clock();
265 elapsed_us = TIME_DIFF_MS(t_start, t_end);
266 printf("[INFO] Sorted buffer by payload seqid (rising order). Time: %.0f ms\n", elapsed_us);
267 if (verify) {
268 printf("[VERIFY] Payload seqid rising: %s\n", verify_sort(pBuffer, 1, 0, seqid.offset, seqid.length) ? "OK" : "FAILED");
269 }
270
271 // Sort the buffer by payload seqid (falling)
272 t_start = clock();
273 if(brawcap_buffer_sort(pBuffer,
276 seqid.offset,
277 seqid.length,
280 ){
281 printf("[ERROR] Failed to sort buffer by payload seqid. Status: %d\n", brawcap_last_status());
282 return -1;
283 }
284 t_end = clock();
285 elapsed_us = TIME_DIFF_MS(t_start, t_end);
286 printf("[INFO] Sorted buffer by payload seqid (falling order). Time: %.0f ms\n", elapsed_us);
287 if (verify) {
288 printf("[VERIFY] Payload seqid falling: %s\n", verify_sort(pBuffer, 1, 1, seqid.offset, seqid.length) ? "OK" : "FAILED");
289 }
290
291 brawcap_buffer_free(pBuffer);
292 return 0;
293}
bRAWcap main header.
brawcap_status_t brawcap_last_status()
Reads the last status appeared in bRAWcap, for the calling thread.
@ BRAWCAP_STATUS_SUCCESS
Definition: brawcap_types_shared.h:142
struct _brawcap_timestamp brawcap_timestamp_t
bRAWcap timestamp object.
Definition: brawcap_types_shared.h:608
brawcap_status_t brawcap_timestamp_value_ns_get(brawcap_timestamp_t *const pTimestamp, UINT64 *const pSeconds, UINT32 *const pNanoseconds)
Reads out the timestamp value in seconds and nanoseconds.
brawcap_status_t brawcap_timestamp_value_ns_set(brawcap_timestamp_t *const pTimestamp, const UINT64 seconds, const UINT32 nanoseconds)
Sets the timestamp value in seconds and nanoseconds.
UINT16 brawcap_packet_size_t
Type for handling the number of payload bytes per packet.
Definition: brawcap_types_shared.h:666
brawcap_status_t brawcap_packet_create(brawcap_packet_t **const pPacket, const brawcap_packet_size_t maxSize)
Creates a new packet.
brawcap_status_t brawcap_packet_payload_set_v2(brawcap_packet_t *const pPacket, const unsigned char *const pPayload, const brawcap_packet_size_t length)
Sets the packet payload of the specified packet.
struct _brawcap_packet brawcap_packet_t
bRAWcap packet object.
Definition: brawcap_types_shared.h:675
brawcap_status_t brawcap_packet_payload_get_v2(brawcap_packet_t *const pPacket, const unsigned char **const pPayload, brawcap_packet_size_t *const pLength)
Reads out the payload of the specified packet.
brawcap_status_t brawcap_packet_timestamp_get(brawcap_packet_t *const pPacket, brawcap_timestamp_t **const pTimestamp)
Reads out the timestamp object for the specified packet.
struct _brawcap_buffer brawcap_buffer_t
bRAWcap packet buffer object.
Definition: brawcap_types_shared.h:746
brawcap_status_t brawcap_buffer_sort(brawcap_buffer_t *const pBuffer, const brawcap_buffer_sort_order_t order, const brawcap_buffer_sort_types_t type, const brawcap_packet_size_t offset, const brawcap_packet_size_t length, const brawcap_buffer_sort_endian_t endian)
Sorts packets in a buffer by timestamp or by a payload field.
brawcap_status_t brawcap_buffer_add_back(brawcap_buffer_t *const pBuffer, const brawcap_packet_t *const pPacket)
Adds the specified packet at the end of the specified packet buffer.
brawcap_status_t brawcap_buffer_free(brawcap_buffer_t *pBuffer)
Frees the specified packet buffer. When this function is called the specified packet buffer becomes i...
UINT32 brawcap_buffer_packet_count_t
Type for handling the number of packets which can be stored in a packet buffer.
Definition: brawcap_types_shared.h:738
brawcap_status_t brawcap_buffer_at_index(brawcap_buffer_t *const pBuffer, const brawcap_buffer_packet_count_t index, brawcap_packet_t **const pPacket)
Reads out a buffered packet at the index of the specified packet buffer.
brawcap_status_t brawcap_buffer_count(brawcap_buffer_t *const pBuffer, brawcap_buffer_packet_count_t *const pPacketCount)
Reads out the number of currently buffered packets in the specified packet buffer.
brawcap_status_t brawcap_buffer_create(brawcap_buffer_t **const pBuffer, const brawcap_packet_size_t maxPacketPayloadSize, const brawcap_buffer_packet_count_t numPackets)
Creates a new packet buffer.
@ BRAWCAP_BUFFER_SORT_ORDER_RISING
Rising sort order.
Definition: brawcap_types_um.h:224
@ BRAWCAP_BUFFER_SORT_ORDER_FALLING
Falling sort order.
Definition: brawcap_types_um.h:225
@ BRAWCAP_BUFFER_SORT_TYPE_PAYLOAD
Definition: brawcap_types_um.h:237
@ BRAWCAP_BUFFER_SORT_TYPE_TIMESTAMP
Definition: brawcap_types_um.h:236
@ BRAWCAP_BUFFER_SORT_ENDIAN_LITTLE
Definition: brawcap_types_um.h:246