Skip to content

Commit

Permalink
Create JSON sender and receiver applications
Browse files Browse the repository at this point in the history
  • Loading branch information
tszumski committed Jan 13, 2025
1 parent 255fc6b commit c3d2c98
Show file tree
Hide file tree
Showing 3 changed files with 581 additions and 1 deletion.
11 changes: 10 additions & 1 deletion sdk/samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,13 @@ add_executable(pong_app pong_app.c pingpong_common.c)
target_include_directories(pong_app PRIVATE ../include)
target_link_libraries(pong_app PRIVATE mcm_dp)

install(TARGETS sender_app recver_app ping_app pong_app RUNTIME COMPONENT Runtime)
add_executable(sender_app_json sender_app_json.c)
target_include_directories(sender_app_json PRIVATE ../include)
target_link_libraries(sender_app_json PRIVATE mcm_dp)

add_executable(recver_app_json recver_app_json.c)
target_include_directories(recver_app_json PRIVATE ../include)
target_link_libraries(recver_app_json PRIVATE mcm_dp)


install(TARGETS sender_app recver_app ping_app pong_app sender_app_json recver_app_json RUNTIME COMPONENT Runtime)
265 changes: 265 additions & 0 deletions sdk/samples/recver_app_json.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <bsd/string.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mesh_dp.h"

#define RECV_LOCAL_FILE "recv.yuv"
#define RECV_JSON_FILE "recv.json"

static volatile bool keepRunning = true;

void intHandler(int dummy) { keepRunning = 0; }

size_t get_file_size(FILE *f) {
if (f == NULL) {
return 0;
}
long prev = ftell(f);
if (prev < 0) {
return 0;
}
if (fseek(f, (long)0, (long)SEEK_END) != 0) {
(void)fseek(f, prev, (long)SEEK_SET);
return 0;
} else {
long size = ftell(f);
(void)fseek(f, prev, (long)SEEK_SET);
if (size < 0) {
return 0;
}
return (size_t)size;
}
}

/* print a description of all supported options */
void usage(FILE *fp, const char *path) {
/* take only the last portion of the path */
const char *basename = strrchr(path, '/');
basename = basename ? basename + 1 : path;

fprintf(fp, "Usage: %s [OPTION]\n", basename);
fprintf(fp, "-H, --help\t\t\t"
"Print this help and exit\n");
fprintf(fp,
"-j, --json=file_name\t"
"JSON file with receiver configuration(example: %s)\n",
RECV_JSON_FILE);
fprintf(fp,
"-o, --outputfile=file_name\t"
"Save stream to local file (example: %s)\n",
RECV_LOCAL_FILE);
fprintf(fp, "\n");
}

int main(int argc, char **argv) {
char output_filename[128] = "";
FILE *outputfile = NULL;

char json_filename[128] = "";
FILE *jsonfile = NULL;
char *json_config = NULL;

MeshClient *client = NULL;
MeshConnection *conn = NULL;
MeshBuffer *buf = NULL;
int err;

int help_flag = 0;
int opt;
struct option longopts[] = {{"help", no_argument, &help_flag, 'H'},
{"outputfile", required_argument, NULL, 'o'},
{"json", required_argument, NULL, 'j'},
{0}};

/* infinite loop, to be broken when we are done parsing options */
while (1) {
opt = getopt_long(argc, argv, "H:o:j:", longopts, 0);
if (opt == -1) {
break;
}

switch (opt) {
case 'H':
help_flag = 1;
break;
case 'o':
strlcpy(output_filename, optarg, sizeof(output_filename));
break;
case 'j':
strlcpy(json_filename, optarg, sizeof(json_filename));
break;
case '?':
usage(stderr, argv[0]);
return 1;
default:
break;
}
}

if (help_flag) {
usage(stdout, argv[0]);
return 0;
}

jsonfile = fopen(json_filename, "rb");
if (!jsonfile) {
fprintf(stderr, "Invalid json file \n");
err = -1;
goto fail;
}

const size_t json_filesize = get_file_size(jsonfile);
if (json_filesize == 0) {
fprintf(stderr, "Json file empty \n");
err = -1;
goto fail;
}

json_config = calloc(1, json_filesize + 1);
if (!json_config) {
fprintf(stderr, "Failed to allocate memory for json config \n");
err = -1;
goto fail;
}

if (fread(json_config, 1, json_filesize, jsonfile) != json_filesize) {
fprintf(stderr, "Failed to read json file \n");
err = -1;
goto fail;
}

if (strlen(output_filename) > 0) {
outputfile = fopen(output_filename, "wb");
if (!outputfile) {
fprintf(stderr, "Cannot create output file \n");
err = -1;
goto fail;
}
}

err = mesh_create_client_json(&client, json_config);
if (err) {
printf("Failed to create a mesh client: %s (%d)\n", mesh_err2str(err), err);
goto fail;
}

err = mesh_create_rx_connection(client, &conn, json_config);
if (err) {
printf("Failed to create a mesh connection: %s (%d)\n", mesh_err2str(err), err);
goto fail;
}

signal(SIGINT, intHandler);

uint32_t frame_count = 0;
uint32_t frm_size = conn->buf_size;

const uint32_t stat_interval = 10;
double fps = 0.0;
double throughput_MB = 0;
double stat_period_s = 0;
void *ptr = NULL;
int timeout = MESH_TIMEOUT_INFINITE;
bool first_frame = true;
float latency = 0;
struct timespec ts_recv = {}, ts_send = {};
struct timespec ts_begin = {}, ts_end = {};

while (keepRunning) {
/* receive frame */
if (first_frame) {
/* infinite for the 1st frame. */
timeout = MESH_TIMEOUT_INFINITE;
} else {
/* 1 second */
timeout = 1000;
}

err = mesh_get_buffer_timeout(conn, &buf, timeout);
if (err == -MESH_ERR_CONN_CLOSED) {
printf("Connection closed\n");
break;
}
if (err) {
printf("Failed to get buffer: %s (%d)\n", mesh_err2str(err), err);
break;
}

printf("INFO: buf->len = %ld frame size = %u\n", buf->data_len, frm_size);

clock_gettime(CLOCK_REALTIME, &ts_recv);
if (first_frame) {
ts_begin = ts_recv;
first_frame = false;
}

if (outputfile) {
fwrite(buf->data, buf->data_len, 1, outputfile);
} else {
// Following code are mainly for test purpose, it requires the sender side to
// pre-set the first several bytes
ptr = buf->data;
if (*(uint32_t *)ptr != frame_count) {
printf("Wrong data content: expected %u, got %u\n", frame_count, *(uint32_t *)ptr);
/* catch up the sender frame count */
frame_count = *(uint32_t *)ptr;
}
ptr += sizeof(frame_count);
ts_send = *(struct timespec *)ptr;

latency = 1000.0 * (ts_recv.tv_sec - ts_send.tv_sec);
latency += (ts_recv.tv_nsec - ts_send.tv_nsec) / 1000000.0;
}

if (frame_count % stat_interval == 0) {
/* calculate FPS */
clock_gettime(CLOCK_REALTIME, &ts_end);

stat_period_s = (ts_end.tv_sec - ts_begin.tv_sec);
stat_period_s += (ts_end.tv_nsec - ts_begin.tv_nsec) / 1e9;
fps = stat_interval / stat_period_s;
throughput_MB = fps * frm_size / 1000000;

clock_gettime(CLOCK_REALTIME, &ts_begin);
}
printf("RX frames: [%u], latency: %0.1f ms, FPS: %0.3f\n", frame_count, latency, fps);
printf("Throughput: %.2lf MB/s, %.2lf Gb/s \n", throughput_MB, throughput_MB * 8 / 1000);

frame_count++;

err = mesh_put_buffer(&buf);
if (err) {
printf("Failed to put buffer: %s (%d)\n", mesh_err2str(err), err);
break;
}

printf("\n");
}

fail:
if (conn) {
mesh_delete_connection(&conn);
}
if (client) {
mesh_delete_client(&client);
}
if (json_config) {
free(json_config);
}
if (jsonfile) {
fclose(jsonfile);
}
if (outputfile) {
fclose(outputfile);
}
return err;
}
Loading

0 comments on commit c3d2c98

Please sign in to comment.