#include #include #include #include #include #include #include #include "dp_common.h" #include "log.h" enum DP_DoomState { DP_DS_Ready, DP_DS_Running, DP_DS_Quit, DP_DS_COUNT, }; static const char *const DP_DoomState_Strings[DP_DS_COUNT] = { "DoomState_Ready", "DoomState_Running", "DoomState_Quit", }; #define doomstate_str(s) DP_DoomState_Strings[s] struct DoomContext; #define DEF_DOOM_STATE_FUNC(fn) int fn(DoomContext *ctx) typedef DEF_DOOM_STATE_FUNC(DoomStateFunc); typedef struct DoomContext { nng_socket pub; nng_socket sub; doomid_t id; DP_DoomState state; DoomStateFunc *f; } DoomContext; DEF_DOOM_STATE_FUNC(do_doom_ready) { assert(ctx->state == DP_DS_Ready); int res = 0; // Publish { DP_MT_DoomReady, doomid }. { nng_msg *msg = NULL; if ((res = nng_msg_alloc(&msg, sizeof(dmt_t) + sizeof(doomid_t)))) dp_nng_fatal("doom/alloc", res); if ((res = nng_msg_append_u16(msg, DP_MT_DoomReady))) dp_nng_fatal("doom/msg", res); if ((res = nng_msg_append_u32(msg, ctx->id))) dp_nng_fatal("doom/msg", res); if ((res = nng_sendmsg(ctx->pub, msg, 0))) dp_nng_fatal("doom/sendmsg", res); } // Incoming Message | Next State // ------------------------------- // DP_MT_RunDoom -> DP_DS_Running // DP_MT_QuitDoom -> DP_DS_Quit // */none -> DP_DS_Ready { nng_msg *msg = NULL; if ((res = nng_msg_alloc(&msg, sizeof(int) + sizeof(doomid_t)))) dp_nng_fatal("doom/alloc", res); if ((res = nng_recvmsg(ctx->sub, &msg, 0))) { if (res != NNG_ETIMEDOUT) dp_nng_fatal("doom/recvmsg", res); return 0; } dmt_t mt = DP_MT_Invalid; if ((res = nng_msg_trim_u16(msg, &mt))) dp_nng_fatal("doom/msg_trim", res); nng_msg_free(msg); if (mt == DP_MT_RunDoom) ctx->state = DP_DS_Running; else if (mt == DP_MT_QuitDoom) ctx->state = DP_DS_Quit; } return res; } DEF_DOOM_STATE_FUNC(do_doom_running) { assert(ctx->state == DP_DS_Running); // Non-blocking receive of incoming messages. // Check if we should quit. // Handle incoming input. // Let doom render a new frame // Publish the frame return 0; } int doom_loop(nng_socket pubSock, nng_socket subSock, doomid_t doomId) { log_debug("doom#%zu started", doomId); DoomContext ctx { pubSock, subSock, doomId, DP_DS_Ready, do_doom_ready, }; int res = 0; while (ctx.state != DP_DS_Quit && res == 0) { DP_DoomState prevState = ctx.state; res = ctx.f(&ctx); if (prevState != ctx.state) { log_info("transition %s -> %s", doomstate_str(prevState), doomstate_str(ctx.state)); } } return res; } int main(int argc, char *argv[]) { log_info("doomsim starting"); std::optional doomId; for (int i=1; i parameter!"); return 1; } dp_nng_init_limits(1, 1, 1); auto pubSock = make_doom_pub(DoomUrl); auto subSock = make_doom_sub(CtrlUrl); int ret = doom_loop(pubSock, subSock, *doomId); nng_close(pubSock); nng_close(subSock); return ret; }