Начиная с virtual environment смешалось всё. JSON и всё такое
прочее -- это детали реализации конкретной системы, а не
высокоуровневое описание. Да есть управляющее ПО перенесённое на
ПЦ, есть слой драйверов, который на ПЦ реализован иначе (но имеет
общий, с точки зрения управляющего ПО, интерфейс с драйверами на
таргете). И драйвера могут непосредственно реализовать виртуальное
окружение, либо выступать интерфейсной частью к нему. Я, например,
делал так, что драйвера содержали прослойку для связи C с Tcl, а "окружение" можно было допрограммировать на тикле. А некоторые вещи, ту же память, нет смысла протаскивать через Tcl, она сразу отображалась на файл в компьютере, прямо драйвером. И не нужны никакие роутеры, шины, соединения... собственно как и сервер -- всё работает в одном процессе, на одном компьютере. Тем более непонятно, какие там соединения возможны -- I2C не подключишь к UART'у, у них разные интерфейсы и логика работы...
Симуляция сетей и радиоканала отдельный момент. Её проще реализовать поверх IP-сети, в рамках UDP multicast (если абонентов шины больше двух). Чтоб все слышали всех. Соответсвенно разные абоненты -- разные процессы/программы или даже компьютеры. Симуляция множественного доступа к среде передачи может осуществляться отбрасыванием принятых пакетов в течении какого-то времени после любой передачи, что реализуется непосредственно в драйвере, прилинкованном к каждому абоненту.
По-моему у тебя архитектурный оверинжинеринг (на картинке, где сервер, роутер, и всё такое прочее). Зачем что-то выносить на какой-то сервер? Зачем вначале GPIO, UART и SPI попадают в роутер, клиент, потом на сервер, а потом обратно разбиваются на составляющие? Что мешает связать прямо в compile time с нужными элементами "виртуального окружения", намертво прикомпилированныи к "синтетическому порту". С сервером как минимум отлаживать невозможно: ты в gdb остановил (все потоки текущего процесса) -- а он молотит дальше. И кстати функция получения времени должна понимать, сколько она в gdb простояла, чтоб таймауты не срабатывали. У меня таймер в линуксе программировался на ~1000 раз в секунду и обработчик сигнала (как будто прерывания) просто инкрементировал переменную счётчика времени. Соответственно, в gdb пока стоит -- сигналы не обрабатываются, и время вперёд не идёт.