I'd just write a loop that goes around generating packets and sending them at the appropriate interval, e.g: given:
static constexpr int NUM_CHANNELS = 32;
static constexpr int NUM_SAMPLES_PER_PACKET = 15;
struct packet {
uint64_t timestamp_ms;
uint32_t packet_counter;
int16_t data[NUM_CHANNELS * NUM_SAMPLES_PER_PACKET];
};
I've obviously made up the packet format as you didn't specify anything. you'd need to hack this around to match what's actually required. I'm also using 16 bit values here to make the data easier to work with, filling in 24bit samples would probably be easiest with an array of uint8_t
s and some bitwise operations to pack values in.
next I define the function to implement the loop:
void
generate_samples(int sockfd)
{
struct timespec scheduler;
clock_gettime(CLOCK_MONOTONIC, &scheduler);
struct packet pkt {};
auto time = 0;
while (time < 200000) {
// fill data into packet
for (auto sample = 0; sample < NUM_SAMPLES_PER_PACKET; ++sample) {
double t = time++ * (2 * M_PI / 100);
for (auto channel = 0; channel < NUM_CHANNELS; ++channel) {
pkt.data[sample * NUM_CHANNELS + channel] = sin(t + 0.1 * channel) * (1<<15);
}
}
// wait until an appropriate amount of time has passed before
// sending out the next packet
scheduler.tv_nsec += 75000;
if(scheduler.tv_nsec >= 1000000000) {
scheduler.tv_nsec -= 1000000000;
scheduler.tv_sec++;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &scheduler, NULL);
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
// update book-keeping fields
pkt.timestamp_ms = int64_t{now.tv_sec} * 1000000 + int64_t{now.tv_nsec} / 1000;
pkt.packet_counter += 1;
// actually send the packet
send(sockfd, &pkt, sizeof(pkt), 0);
}
}
the sockfd
parameter is just a file handle from socket()
that's been connect()
ed to the relevant address so the send
knows where to go. you'd probably want some error checking (e.g. around the clock_*
and send
calls) but this does something sensible for me.