diff --git a/Makefile b/Makefile index 7985ff4..42876e2 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ target: date proto $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) @echo -e '\033[1;32mELF\t'$(OBJECTS)'\n\t\t\t->\t'$@'\033[0m' - @$(CC) $(LFLAGS) $(OBJECTS) -o $(BUILD_DIR)/$(TARGET).elf + @$(CC) $(LFLAGS) $(OBJECTS) $(LDLIBS) -o $(BUILD_DIR)/$(TARGET).elf deps: @make -C deps all diff --git a/devices/avr_generic/src/device.c b/devices/avr_generic/src/device.c new file mode 100644 index 0000000..59f6c46 --- /dev/null +++ b/devices/avr_generic/src/device.c @@ -0,0 +1,764 @@ +#include +#include + +#include "device.h" +#include "mem.h" +#include "runner.h" +#include "instr.h" +#include "addrs.h" + + +uint64_t memSegToGlobal(device_specs_t* spec, uint8_t seg, uint64_t localaddr) +{ + uint64_t offset = 0; + for (uint8_t i = 0; i < seg; i++) + { + offset += spec->memSpecs[i]->len * spec->memSpecs[i]->wordLen; + } + return offset + localaddr; +} + + +void freeDevMem(device_mem_t* devMem) +{ + free(devMem->memsegShifts); + free(devMem->rawCells); + free(devMem->memreadCellAddrs); + free(devMem->memwriteCellAddrs); + free(devMem->cells); + free(devMem->smartAddrReadHandlers); + free(devMem->smartAddrWriteHandlers); + free(devMem); +} + +void freeDevSpec(void* _specs) +{ + device_specs_t* specs = _specs; + for (uint8_t i = 0; i < specs->memSpecsCount; i++) + { + free(specs->memSpecs[i]); + } + free(specs->memSpecs); + free(specs->executableSegments); + free(specs); +} + + +device_mem_t* genDevMem(device_specs_t* devSpec, char* errbuf) +{ + if (devSpec->memSpecsCount < MEMDATA_OPSIZE) + { + sprintf(errbuf, "invalid amount of mem specs: %u", devSpec->memSpecsCount); + return NULL; + } + + device_mem_t* devMem = (device_mem_t*)malloc(sizeof(device_mem_t)); + if (devMem == NULL) + { + sprintf(errbuf, "unable to allocate dev memory struct"); + return NULL; + } + + uint64_t memTotalSize = 0; + for (uint8_t i = 0; i < devSpec->memSpecsCount; i++) + { + size_t tmp = devSpec->memSpecs[i]->start + devSpec->memSpecs[i]->len * devSpec->memSpecs[i]->wordLen; + if (memTotalSize < tmp) + { + memTotalSize = tmp; + } + } + + void* rawCells = (void*)malloc(memTotalSize); + if (rawCells == NULL) + { + sprintf(errbuf, "unable to allocate raw memory buf"); + free(devMem); + return NULL; + } + + for (size_t i = 0; i < memTotalSize; i++) + { + ((uint8_t*)rawCells)[i] = 0; + } + + devMem->memsegShifts = malloc(devSpec->memSpecsCount * sizeof(uint64_t)); + + if(devMem->memsegShifts == NULL) + { + sprintf(errbuf, "unable to allocate segment shift buffers"); + free(rawCells); + free(devMem); + return NULL; + } + + void** cells = malloc(devSpec->memSpecsCount * sizeof(void*)); + + if (cells == NULL) + { + sprintf(errbuf, "unable to allocate segment pointers"); + free(rawCells); + free(devMem->memsegShifts); + free(devMem); + return NULL; + } + + for (uint8_t i = 0; i < devSpec->memSpecsCount; i++) + { + cells[i] = rawCells + devSpec->memSpecs[i]->start; + } + + char** cellNames = malloc(sizeof(char*) * devSpec->memSpecsCount); + + if(cellNames == NULL) + { + sprintf(errbuf, "unable to allocate segment names map"); + free(devMem->memsegShifts); + free(devMem); + free(rawCells); + free(cells); + return NULL; + } + + for(size_t i = 0; i < devSpec->memSpecsCount; i++) + { + cellNames[i] = devSpec->memSpecs[i]->name; + } + + uint64_t* memreadCellAddrs = malloc(64 * sizeof(uint64_t)); + if (memreadCellAddrs == NULL) + { + sprintf(errbuf, "unable to allocate read interception addrs"); + free(devMem->memsegShifts); + free(devMem); + free(rawCells); + free(cells); + free(cellNames); + return NULL; + } + uint64_t* memwriteCellAddrs = malloc(64 * sizeof(uint64_t)); + + if (memwriteCellAddrs == NULL) + { + sprintf(errbuf, "unable to allocate write interception addrs"); + free(devMem->memsegShifts); + free(devMem); + free(rawCells); + free(memreadCellAddrs); + free(cells); + free(cellNames); + return NULL; + } + + uint64_t smartAddrReadMask = 0; + // memSegToGlobal(devSpec, MEMDATA_IO_REGS, 0x16) + // | memSegToGlobal(devSpec, MEMDATA_IO_REGS, 0x17) + // | memSegToGlobal(devSpec, MEMDATA_IO_REGS, 0x18); + + uint64_t smartAddrWriteMask = 0; + // memSegToGlobal(devSpec, MEMDATA_IO_REGS, 0x16) + // | memSegToGlobal(devSpec, MEMDATA_IO_REGS, 0x17) + // | memSegToGlobal(devSpec, MEMDATA_IO_REGS, 0x18); + + mem_h_read_handler* smartAddrReadHandlers = malloc(sizeof(mem_h_read_handler) * memTotalSize); + + + if (smartAddrReadHandlers == NULL) + { + sprintf(errbuf, "unable to allocate read interception handlers"); + free(memwriteCellAddrs); + free(devMem->memsegShifts); + free(devMem); + free(rawCells); + free(memreadCellAddrs); + free(cells); + free(cellNames); + return NULL; + } + + mem_h_write_handler* smartAddrWriteHandlers = malloc(sizeof(mem_h_write_handler) * memTotalSize); + + + if (smartAddrWriteHandlers == NULL) + { + sprintf(errbuf, "unable to allocate write interception handlers"); + free(smartAddrReadHandlers); + free(memwriteCellAddrs); + free(devMem->memsegShifts); + free(devMem); + free(rawCells); + free(memreadCellAddrs); + free(cells); + free(cellNames); + return NULL; + } + + + for(uint64_t i = 0; i < memTotalSize; i++) + { + smartAddrReadHandlers[i].func = NULL; + smartAddrReadHandlers[i].ident = 0; + + smartAddrWriteHandlers[i].func = NULL; + smartAddrWriteHandlers[i].ident = 0; + } + + + for(uint64_t i = 0; i < memTotalSize; i++) + { + if((i & smartAddrReadMask) == smartAddrReadMask) + { + smartAddrReadHandlers[i].func = NULL; + } + } + + + if (devSpec->smartReadSpecsCount > 0) + { + for(uint64_t i = 0; i < devSpec->smartReadSpecsCount; i++) + { + smart_read_spec_t t = devSpec->smartReadSpecs[i]; + uint64_t addr; + if (t.addrType == SMART_ADDR_TYPE_GLOBAL) + { + addr = t.addr; + } + else + { + addr = memSegToGlobal(devSpec, t.segno, t.localAddr); + } + smartAddrReadHandlers[addr].func = *t.handler; + smartAddrReadHandlers[addr].ident = t.ident; + smartAddrReadMask |= addr; + } + } + + + if (devSpec->smartWriteSpecsCount > 0) + { + for(uint64_t i = 0; i < devSpec->smartWriteSpecsCount; i++) + { + smart_write_spec_t t = devSpec->smartWriteSpecs[i]; + + uint64_t addr; + if (t.addrType == SMART_ADDR_TYPE_GLOBAL) + { + addr = t.addr; + } + else + { + addr = memSegToGlobal(devSpec, t.segno, t.localAddr); + } + smartAddrWriteHandlers[addr].func = *t.handler; + smartAddrWriteHandlers[addr].ident = t.ident; + smartAddrWriteMask |= t.addr; + } + } + + + devMem->cells = cells; + devMem->rawCells = rawCells; + devMem->memreadCellAddrs = memreadCellAddrs; + devMem->memwriteCellAddrs = memwriteCellAddrs; + devMem->memreadLen = 0; + devMem->memwriteLen = 0; + devMem->smartAddrReadMask = smartAddrReadMask; + devMem->smartAddrReadHandlers = smartAddrReadHandlers; + devMem->smartAddrWriteMask = smartAddrWriteMask; + devMem->smartAddrWriteHandlers = smartAddrWriteHandlers; + devMem->memsegNames = cellNames; + + for(uint8_t i = 0; i < devSpec->memSpecsCount; i++) + { + devMem->memsegShifts[i] = memSegToGlobal(devSpec, i, 0); + } + + setOpcodeSizes((uint8_t*)(devMem->cells[MEMDATA_OPSIZE])); + + return devMem; +} + + +uint8_t makeDeviceTick(device_public_context_t* devContext) +{ + device_info_t* devInfo = (device_info_t*)devContext->deviceInfo; + return makeTick(devInfo->pc, devInfo->instr, devInfo->deviceMem); +} + +device_info_t* initSpecs(device_specs_t* specs, char* errbuf) +{ + device_info_t* devInfo = malloc(sizeof(device_info_t)); + if (devInfo == NULL) + { + sprintf(errbuf, "unable to allocate dev info"); + return NULL; + } + + char genErrBuf[200]; + device_mem_t* devMem = genDevMem(specs, genErrBuf); + + if (devMem == NULL) + { + sprintf(errbuf, "unable to generate device memory: %s", genErrBuf); + free(devInfo); + return NULL; + } + + devInfo->pc = (prog_counter_t*)(devMem->rawCells + specs->pcAddr); + *(devInfo->pc) = 0; + devInfo->specs = specs; + + devInfo->deviceMem = devMem; + + + instr_h_func* instrs = genInstrArray(genErrBuf); + + if (instrs == NULL) + { + sprintf(errbuf, "unable to initialize instructions: %s", genErrBuf); + freeDevMem(devInfo->deviceMem); + free(devInfo); + return NULL; + } + + devInfo->instr = instrs; + + return devInfo; +} + +void error(const char* err, char* errbuf) +{ + strcpy(errbuf, err); +} + +device_specs_t* parseSpecsFromConfig(const conf_dev_t* devConf, char* errbuf) +{ + conf_mem_seg_t** segments = devConf->memConf->memSegConfs; + device_specs_t* specs = malloc(sizeof(device_specs_t)); + if (specs == NULL) + { + error("unable to allocate mem specs struct", errbuf); + return NULL; + } + uint8_t specCount = 0; + specs->executableSegmentsCount = 0; + + while (segments[specCount] != NULL) + { + if(segments[specCount]->isExecutable) + { + specs->executableSegmentsCount++; + } + specCount++; + } + specs->memSpecsCount = specCount; + + specs->memSpecs = malloc(specCount * sizeof(memseg_spec_t*)); + if (specs->memSpecs == NULL) + { + free(specs); + error("unable to allocate mem segment specs", errbuf); + return NULL; + } + + specs->executableSegments = malloc(sizeof(uint8_t) * specs->executableSegmentsCount); + if (specs->executableSegments == NULL) + { + error("unable to allocate mem executable specs", errbuf); + free(specs->memSpecs); + free(specs); + return NULL; + } + + + for (uint8_t i = 0; i < specCount; i++) + { + memseg_spec_t* spec = (memseg_spec_t*)malloc(sizeof(memseg_spec_t)); + if (spec == NULL) + { + sprintf(errbuf, "unable to allocate spec %d", i); + + for (uint8_t j = 0; j < i; j++) + { + free(specs->memSpecs[j]); + } + free(specs->memSpecs); + free(specs->executableSegments); + free(specs); + return NULL; + } + spec->name = NULL; + + specs->memSpecs[i] = spec; + } + + uint8_t foundSegments = 0; + uint8_t executableSegmentsFound = 0; + + for (uint8_t i = 0; i < specCount; i++) + { + uint8_t specNum = 0xFF; + if (strcmp(segments[i]->name, "reg_gp") == 0) + { + specNum = MEMDATA_GP_REGS; + } + else if (strcmp(segments[i]->name, "reg_io") == 0) + { + specNum = MEMDATA_IO_REGS; + } + else if (strcmp(segments[i]->name, "ds") == 0) + { + specNum = MEMDATA_DS; + } + else if (strcmp(segments[i]->name, "ps") == 0) + { + specNum = MEMDATA_PS; + } + else + { + sprintf(errbuf, "invalid segment: %s", segments[i]->name); + for(size_t j = 0; j < specCount; j++) + { + if(specs->memSpecs[j]->name != NULL) + { + free(specs->memSpecs[j]->name); + } + free(specs->memSpecs[j]); + } + free(specs->executableSegments); + free(specs->memSpecs); + free(specs); + return NULL; + } + specs->memSpecs[specNum]->name = malloc(sizeof(char) * (strlen(segments[i]->name) + 1)); + if(specs->memSpecs[specNum]->name == NULL) + { + sprintf(errbuf, "unable to allocate spec %d name", i); + for(size_t j = 0; j < specCount; j++) + { + if(specs->memSpecs[j]->name != NULL) + { + free(specs->memSpecs[j]->name); + } + free(specs->memSpecs[j]); + } + free(specs->executableSegments); + free(specs->memSpecs); + free(specs); + return NULL; + } + + strcpy(specs->memSpecs[specNum]->name, segments[i]->name); + specs->memSpecs[specNum]->start = segments[i]->start; + specs->memSpecs[specNum]->len = segments[i]->len; + specs->memSpecs[specNum]->wordLen = segments[i]->wordLen; + if(segments[i]->isExecutable) + { + specs->executableSegments[executableSegmentsFound] = specNum; + executableSegmentsFound++; + } + foundSegments += 1; + } + + if(executableSegmentsFound < specs->executableSegmentsCount) + { + sprintf(errbuf, "Not all executable segments found"); + for(size_t j = 0; j < specCount; j++) + { + if(specs->memSpecs[j]->name != NULL) + { + free(specs->memSpecs[j]->name); + } + free(specs->memSpecs[j]); + } + free(specs->executableSegments); + free(specs->memSpecs); + free(specs); + return NULL; + } + + if (foundSegments < 4) + { + sprintf(errbuf, "invalid amount of segments: must be 4"); + for(size_t k = 0; k < specs->memSpecsCount; k++) + { + if(specs->memSpecs[k]->name != NULL) + { + free(specs->memSpecs[k]->name); + } + free(specs->memSpecs[k]); + } + free(specs->executableSegments); + free(specs->memSpecs); + free(specs); + return NULL; + } + + return specs; +} + +void freeDevSpecs(device_specs_t* specs) +{ + for(size_t k = 0; k < specs->memSpecsCount; k++) + { + if(specs->memSpecs[k]->name != NULL) + { + free(specs->memSpecs[k]->name); + } + free(specs->memSpecs[k]); + } + free(specs->executableSegments); + free(specs->memSpecs); + free(specs); +} + +void fillSmartReadSpecs(device_specs_t* specs, smart_read_spec_t* smartReadSpecs, uint64_t smartReadSpecsCount) +{ + specs->smartReadSpecs = smartReadSpecs; + specs->smartReadSpecsCount = smartReadSpecsCount; +} + +void fillSmartWriteSpecs(device_specs_t* specs, smart_write_spec_t* smartWriteSpecs, uint64_t smartWriteSpecsCount) +{ + specs->smartWriteSpecs = smartWriteSpecs; + specs->smartWriteSpecsCount = smartWriteSpecsCount; +} + +device_public_context_t* initDefault(smart_read_spec_t* smartReadSpecs, uint64_t smartReadSpecsCount, smart_write_spec_t* smartWriteSpecs, uint64_t smartWriteSpecsCount, char* errbuf) +{ + + device_specs_t* specs = malloc(sizeof(device_specs_t)); + if (specs == NULL) + { + return NULL; + } + + + + specs->memSpecsCount = 4; + specs->memSpecs = malloc(specs->memSpecsCount * sizeof(memseg_spec_t*)); + if (specs->memSpecs == NULL) + { + sprintf(errbuf, "unable to allocate default mem segment specs"); + free(specs); + return NULL; + } + + + specs->executableSegmentsCount = 1; + specs->executableSegments = malloc(sizeof(uint8_t) * 1); + if (specs->executableSegments == NULL) + { + sprintf(errbuf, "unable to allocate default executable segments"); + free(specs->memSpecs); + free(specs); + return NULL; + } + specs->executableSegments[0] = 0; + + for (uint8_t i = 0; i < specs->memSpecsCount; i++) + { + specs->memSpecs[i] = malloc(sizeof(memseg_spec_t)); + if (specs->memSpecs[i] == NULL) + { + sprintf(errbuf, "unable to allocate default mem seg spec %u", i); + for (uint8_t j = 0; j < i; j++) + { + free(specs->memSpecs[j]); + } + free(specs->memSpecs); + free(specs->executableSegments); + free(specs); + return NULL; + } + } + + specs->smartReadSpecs = smartReadSpecs; + specs->smartReadSpecsCount = smartReadSpecsCount; + + specs->smartWriteSpecs = smartWriteSpecs; + specs->smartWriteSpecsCount = smartWriteSpecsCount; + + specs->memSpecs[0]->len = 1024; + specs->memSpecs[0]->start = 0; + specs->memSpecs[0]->wordLen = OPCODE_WORDSIZE; + + specs->memSpecs[1]->len = 32; + specs->memSpecs[1]->start = (1024 * OPCODE_WORDSIZE); + specs->memSpecs[1]->wordLen = GP_REG_CELL_WORDS; + + specs->memSpecs[2]->len = 0xFF; + specs->memSpecs[2]->start = (1024 * OPCODE_WORDSIZE) + (32 * GP_REG_CELL_WORDS); + specs->memSpecs[2]->wordLen = IO_REG_CELL_WORDS; + + specs->memSpecs[3]->len = 0xFFFF; + specs->memSpecs[3]->start = (1024 * OPCODE_WORDSIZE) + (32 * GP_REG_CELL_WORDS) + (0xFF * IO_REG_CELL_WORDS); + specs->memSpecs[3]->wordLen = RAM_CELL_WORDS; + + char initErrbuf[200]; + device_public_context_t* ret = init(specs, initErrbuf); + + if (ret == NULL) + { + sprintf(errbuf, "unable to init default: %s", initErrbuf); + freeDevSpec(specs); + return NULL; + } + free(specs->memSpecs); + free(specs->executableSegments); + free(specs); + + return ret; +} + + +device_public_context_t* init(device_specs_t* specs, char* errbuf) +{ + if (specs->memSpecsCount >= 0xFF - 2) + { + sprintf(errbuf, "Too many mem specifications"); + return NULL; + } + + device_specs_t* realSpecs = malloc(sizeof(device_specs_t)); + if (realSpecs == NULL) + { + sprintf(errbuf, "unable to allocate spec struct"); + return NULL; + } + + uint8_t specCount = specs->memSpecsCount + 2; + realSpecs->memSpecsCount = specCount; + realSpecs->memSpecs = (memseg_spec_t**)malloc(realSpecs->memSpecsCount * sizeof(memseg_spec_t*)); + if (realSpecs->memSpecs == NULL) + { + sprintf(errbuf, "unable to allocate mem specs"); + free(realSpecs); + return NULL; + } + + realSpecs->executableSegments = malloc(sizeof(uint8_t) * specs->executableSegmentsCount); + if (realSpecs->executableSegments == NULL) + { + sprintf(errbuf, "unable to allocate executable segments"); + free(realSpecs->memSpecs); + free(realSpecs); + return NULL; + } + for (uint8_t i = 0; i < specs->executableSegmentsCount; i++) + { + realSpecs->executableSegments[i] = specs->executableSegments[i]; + } + realSpecs->executableSegmentsCount = specs->executableSegmentsCount; + + + realSpecs->smartReadSpecs = specs->smartReadSpecs; + realSpecs->smartReadSpecsCount = specs->smartReadSpecsCount; + + realSpecs->smartWriteSpecs = specs->smartWriteSpecs; + realSpecs->smartWriteSpecsCount = specs->smartWriteSpecsCount; + + uint64_t maxAddr = 0; + + + + for (uint8_t i = 0; i < specCount; i++) + { + memseg_spec_t *segSpec = (memseg_spec_t*)malloc(sizeof(memseg_spec_t)); + realSpecs->memSpecs[i] = segSpec; + if (segSpec == NULL) + { + + sprintf(errbuf, "unable to allocate mem spec segment %u", i); + for (uint8_t j = 0; j < i; j++) + { + free(realSpecs->memSpecs[j]); + } + free(realSpecs->memSpecs); + free(realSpecs->executableSegments); + free(realSpecs); + return NULL; + } + + if (i < specCount - 2) + { + realSpecs->memSpecs[i]->name = specs->memSpecs[i]->name; + realSpecs->memSpecs[i]->len = specs->memSpecs[i]->len; + realSpecs->memSpecs[i]->start = specs->memSpecs[i]->start; + realSpecs->memSpecs[i]->wordLen = specs->memSpecs[i]->wordLen; + uint64_t testMaxAddr = realSpecs->memSpecs[i]->start + (realSpecs->memSpecs[i]->len * realSpecs->memSpecs[i]->wordLen); + if (testMaxAddr > maxAddr) + { + maxAddr = testMaxAddr; + } + } + + } + + + + + uint8_t pcSpecSegNum = specs->memSpecsCount; + + realSpecs->memSpecs[MEMDATA_OPSIZE]->len = ((opcode_t)~0); + realSpecs->memSpecs[MEMDATA_OPSIZE]->start = maxAddr + PC_WORDSIZE; + realSpecs->memSpecs[MEMDATA_OPSIZE]->wordLen = 1; + realSpecs->memSpecs[MEMDATA_OPSIZE]->name = NULL; + + realSpecs->memSpecs[specCount - 2]->len = 1; + realSpecs->memSpecs[specCount - 2]->start = maxAddr; + realSpecs->memSpecs[specCount - 2]->wordLen = PC_WORDSIZE; + realSpecs->memSpecs[specCount - 2]->name = NULL; + + + realSpecs->pcAddr = memSegToGlobal(realSpecs, pcSpecSegNum, 0); + + device_public_context_t* pubDevContext = malloc(sizeof(device_public_context_t)); + if (pubDevContext == NULL) + { + sprintf(errbuf, "unable to allocate public context"); + freeDevSpec(realSpecs); + return NULL; + } + + char initErrbuf[200]; + device_info_t* devInfo = initSpecs(realSpecs, initErrbuf); + if (devInfo == NULL) + { + sprintf(errbuf, "unable to init specs: %s", initErrbuf); + freeDevSpec(realSpecs); + free(pubDevContext); + return NULL; + } + + pubDevContext->deviceInfo = (void*)devInfo; + pubDevContext->deviceMem = devInfo->deviceMem; + + return pubDevContext; +} + + +size_t pubExtractPcounter(device_public_context_t* devContext) +{ + device_info_t* devInfo = (device_info_t*)devContext->deviceInfo; + return (size_t)(*devInfo->pc); + +} + + +void* pubExtractPcounterPtr(device_public_context_t* devContext) +{ + device_info_t* devInfo = (device_info_t*)devContext->deviceInfo; + return (void*)(devInfo->pc); + +} +uint8_t pubExtractPcounterSizeWords() +{ + return sizeof(prog_counter_t); +} + +uint8_t pubDeviceType() +{ + return EXTENDED_DEVICE_TYPE_INSTR_SIMUL; +} + diff --git a/flatbuffers/config/config.fbs b/flatbuffers/config/config.fbs index 3a299ba..66e683d 100644 --- a/flatbuffers/config/config.fbs +++ b/flatbuffers/config/config.fbs @@ -4,17 +4,22 @@ include "clock.fbs"; namespace hmmmm.config; -// Top-level emulator / system configuration. -// Equivalent to glob.toml — describes a full composite device tree. -// -// File use: flatcc -a config/config.fbs → binary system config files -// WS use: embed in ConfigCtrlMessage when config-change protocol is ready +// Top-level emulation configuration sent by the client via ConfigCtrlMessage. +// Contains the root composite device and simulation parameters. +table EmulationConfig { + sim_rate_limit: uint64; // max virtual-seconds per real-second (0 = unlimited) + root_id: string; // ID of the root compose device + root: ComposeDeviceConfig; // the root device tree + mem_setup: [MemSetup]; // firmware / memory init instructions +} + +// Legacy: flat system configuration for standalone config files. table SystemConfig { - devices: [DeviceEntry]; // ordered list; id must be unique + devices: [DeviceEntry]; clock: ClockConfig; projections: [Projection]; intercepts: [Intercept]; mem_setup: [MemSetup]; } -root_type SystemConfig; +root_type EmulationConfig; diff --git a/flatbuffers/config/device.fbs b/flatbuffers/config/device.fbs index 8a97afa..9352dbf 100644 --- a/flatbuffers/config/device.fbs +++ b/flatbuffers/config/device.fbs @@ -10,26 +10,36 @@ table BaseDeviceConfig { mem_segments: [MemSegment]; } +// A composite device that contains other devices. +table ComposeDeviceConfig { + devices: [DeviceEntry]; // child devices (base or compose) + projections: [Projection]; // memory projections between children + intercepts: [Intercept]; // memory intercepts between children +} + +// A device can be either a leaf (base) or a container (compose). +union DeviceConfig { + BaseDeviceConfig, + ComposeDeviceConfig, +} + // Override for one memory segment within a child device. // Only fields that need changing from the base config must be set. table MemSegOverride { segment: string; - start: uint32; + addr: uint32; len: uint32; word_len: uint8; executable: bool; } -// One device entry in a composite configuration. +// One device entry in a device tree. table DeviceEntry { // Local identifier, unique within this composite (e.g. "core", "gpio_a"). id: string; - // Exactly one of config or config_path must be set. - // config: inline base device configuration. - // config_path: path to a serialised BaseDeviceConfig FlatBuffer file. - config: BaseDeviceConfig; - config_path: string; + // Inline device configuration — either base or compose. + config: DeviceConfig; clock: DeviceClockConfig; overrides: [MemSegOverride]; diff --git a/flatbuffers/config/mem_config.fbs b/flatbuffers/config/mem_config.fbs index 6bbe901..1e4a5d1 100644 --- a/flatbuffers/config/mem_config.fbs +++ b/flatbuffers/config/mem_config.fbs @@ -10,7 +10,7 @@ table NamedOffset { // A contiguous memory segment within a base device. table MemSegment { name: string; - start: uint32; // base address in device flat address space + addr: uint32; // base address in device flat address space len: uint32; word_len: uint8 = 1; // word size in bytes executable: bool = false; diff --git a/flatbuffers/control/config_ctrl.fbs b/flatbuffers/control/config_ctrl.fbs index 8ad337a..d0c7949 100644 --- a/flatbuffers/control/config_ctrl.fbs +++ b/flatbuffers/control/config_ctrl.fbs @@ -1,8 +1,10 @@ -// Config change control — WIP. -// Schema stub; content will be defined when the config-change sub-protocol -// is specified (requires device-loading control in the protocol first). +include "config/config.fbs"; + namespace hmmmm.ctrl.config_ctrl; +// Client → Server: load a new emulation configuration. +// Only allowed when the emulator is in STILL state. +// Completely replaces any previously loaded configuration. table ConfigCtrlMessage { - // TODO + config: hmmmm.config.EmulationConfig; } diff --git a/flatbuffers/control/config_notif.fbs b/flatbuffers/control/config_notif.fbs index 67b095d..e7f01a0 100644 --- a/flatbuffers/control/config_notif.fbs +++ b/flatbuffers/control/config_notif.fbs @@ -15,7 +15,7 @@ table SegIdEntry { // Maps a hierarchical device path to a compact numeric device_id + segment IDs. // Clients use these IDs in stream and mem packets instead of string paths. table DeviceIdEntry { - path: [string]; // hierarchical device id, e.g. ["core"] + path: [string]; // hierarchical device id, e.g. ["sys", "core"] device_id: uint32; seg_ids: [SegIdEntry]; } @@ -26,9 +26,15 @@ table DeviceIdMappingNotif { entries: [DeviceIdEntry]; } +// Sent when a config load request fails. +table ConfigLoadError { + message: string; +} + union ConfigNotifPayload { DeviceConfigUpdateNotif, DeviceIdMappingNotif, + ConfigLoadError, } table ConfigNotifMessage { diff --git a/inc/context.h b/inc/context.h index f5230bf..f5a5831 100644 --- a/inc/context.h +++ b/inc/context.h @@ -31,6 +31,7 @@ typedef struct { DeviceSegStreamReg** deviceStreamRegs; uint8_t** devicesMem; size_t devicesCount; + void** deviceHandles; // device_handle_t** — dynamically loaded devices flatcc_builder_t stream_builder; } EmulContext; diff --git a/inc/proto/handlers/config.h b/inc/proto/handlers/config.h new file mode 100644 index 0000000..831d8b5 --- /dev/null +++ b/inc/proto/handlers/config.h @@ -0,0 +1,14 @@ +#ifndef __PROTO_HANDLERS_CONFIG_H__ +#define __PROTO_HANDLERS_CONFIG_H__ + +#include "context.h" +#include "proto/handlers/ws.h" +#include "config_ctrl_reader.h" + +void handleConfigCtrlMessage( + hmmmm_ctrl_config_ctrl_ConfigCtrlMessage_table_t msg, + uint64_t nonce, + ClientContext* ctx, + EmulContext* emulContext); + +#endif // __PROTO_HANDLERS_CONFIG_H__ diff --git a/inc/proto/msg.h b/inc/proto/msg.h index c7e9174..0c37827 100644 --- a/inc/proto/msg.h +++ b/inc/proto/msg.h @@ -57,4 +57,14 @@ uint8_t* fb_build_stream_reg_confirm( uint32_t device_id, uint32_t seg_id, uint32_t offset, uint32_t length, uint8_t mode, size_t* len_out); +// Build a ServerMessage{CtrlServerMessage{ConfigNotifMessage{DeviceIdMappingNotif}}} frame. +// paths: array of NULL-terminated string arrays; path_lens: component count per path. +uint8_t* fb_build_config_device_id_mapping( + uint64_t nonce, + char** paths[], size_t path_lens[], + size_t device_count, size_t* len_out); + +// Build a ServerMessage{CtrlServerMessage{ConfigNotifMessage{ConfigLoadError}}} frame. +uint8_t* fb_build_config_error(uint64_t nonce, const char* message, size_t* len_out); + #endif // __PROTO_MSG_H__ diff --git a/src/base_device.c b/src/base_device.c index b47fd0d..05b2bfe 100644 --- a/src/base_device.c +++ b/src/base_device.c @@ -25,7 +25,6 @@ device_handle_t* openBaseDeviceFromConfig(const char* configPath, char* errbuf) if(ret == NULL) { freeConf(devConf); - free(devConf); } return ret; diff --git a/src/main.c b/src/main.c index 4218203..42e3a0f 100644 --- a/src/main.c +++ b/src/main.c @@ -30,6 +30,7 @@ #include "compose_device.h" +#include "base_device.h" #include "linkedlist.h" @@ -309,67 +310,22 @@ void dispatchMemAccessNotifications(EmulContext* emulContext, DeviceSegStreamReg int main(int argc, char** argv) { + (void)argc; (void)argv; char errbuf[1024]; pthread_mutex_t mtx; pthread_mutex_init(&mtx, NULL); ptQueue* regQ = ptQueueCreate(errbuf); NULL_GUARD(regQ, "Unable to create reg q: %s\n", errbuf); - - size_t deviceCount = 2; - DeviceSegStreamReg* device0SegStreamRegs = malloc(sizeof(DeviceSegStreamReg) * 4); - NULL_GUARD(device0SegStreamRegs); - - device0SegStreamRegs->allocatedSize = 4; - device0SegStreamRegs->regCount = 0; - device0SegStreamRegs->regs = malloc(sizeof(StreamReg) * 4); - NULL_GUARD(device0SegStreamRegs->regs); - - DeviceSegStreamReg* device1SegStreamRegs = malloc(sizeof(DeviceSegStreamReg) * 4); - NULL_GUARD(device1SegStreamRegs); - - device1SegStreamRegs->allocatedSize = 4; - device1SegStreamRegs->regCount = 0; - device1SegStreamRegs->regs = malloc(sizeof(StreamReg) * 4); - NULL_GUARD(device1SegStreamRegs->regs); - - DeviceSegStreamReg** deviceStreamRegs = malloc(sizeof(DeviceSegStreamReg*) * deviceCount); - NULL_GUARD(deviceStreamRegs); - - deviceStreamRegs[0] = device0SegStreamRegs; - deviceStreamRegs[1] = device1SegStreamRegs; + size_t deviceCount = 0; + DeviceSegStreamReg** deviceStreamRegs = NULL; + uint8_t** devicesMem = NULL; + void** deviceHandlesArr = NULL; uint8_t emulState = EMUL_STATE_STILL; - uint8_t* device0mem = malloc(sizeof(uint8_t) * 1024 * 128); - NULL_GUARD(device0mem); - - uint8_t* device1mem = malloc(sizeof(uint8_t) * 1024 * 128); - NULL_GUARD(device1mem); - - uint8_t** devicesMem = malloc(sizeof(uint8_t*) * deviceCount); - NULL_GUARD(devicesMem); - devicesMem[0] = device0mem; - devicesMem[1] = device1mem; - - uint64_t* device0readAddrs = malloc(sizeof(uint64_t) * 128); - NULL_GUARD(device0readAddrs); - size_t device0readAddrsLen = 0; - uint64_t* device0writeAddrs = malloc(sizeof(uint64_t) * 128); - NULL_GUARD(device0writeAddrs); - size_t device0writeAddrsLen = 0; - - - uint64_t* device1readAddrs = malloc(sizeof(uint64_t) * 128); - NULL_GUARD(device1readAddrs); - size_t device1readAddrsLen = 0; - uint64_t* device1writeAddrs = malloc(sizeof(uint64_t) * 128); - NULL_GUARD(device1writeAddrs); - size_t device1writeAddrsLen = 0; - - uint8_t outBufsCount = 16; SizedPtr* bufs = malloc(sizeof(SizedPtr) * outBufsCount); NULL_GUARD(bufs); @@ -412,6 +368,7 @@ int main(int argc, char** argv) deviceStreamRegs, devicesMem, deviceCount, + deviceHandlesArr, {0} /* stream_builder — initialized below */ }; if (flatcc_builder_init(&emulContext.stream_builder)) { @@ -493,23 +450,20 @@ int main(int argc, char** argv) } } - if(emulState == EMUL_STATE_EXEC) + if(emulState == EMUL_STATE_EXEC && emulContext.devicesCount > 0) { - // printf("Running...\n"); - device0readAddrsLen = 0; - device0writeAddrsLen = 0; - - device1readAddrsLen = 0; - device1writeAddrsLen = 0; - - mockDevice0(device0mem, device0readAddrs, &device0readAddrsLen, device0writeAddrs, &device0writeAddrsLen); - mockDevice1(device1mem, device1readAddrs, &device1readAddrsLen, device1writeAddrs, &device1writeAddrsLen); + for (size_t di = 0; di < emulContext.devicesCount; di++) + { + device_handle_t* dev = (device_handle_t*)emulContext.deviceHandles[di]; + device_mem_t* devMem = dev->ctx->deviceMem; + devMem->memreadLen = 0; + devMem->memwriteLen = 0; - dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[0], device0mem, device0readAddrs, device0readAddrsLen, STREAM_MODE_READ); - dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[0], device0mem, device0writeAddrs, device0writeAddrsLen, STREAM_MODE_WRITE); + dev->lib->makeDeviceTick(dev->ctx); - dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[1], device1mem, device1readAddrs, device1readAddrsLen, STREAM_MODE_READ); - dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[1], device1mem, device1writeAddrs, device1writeAddrsLen, STREAM_MODE_WRITE); + dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[di], devMem->rawCells, devMem->memreadCellAddrs, (size_t)devMem->memreadLen, STREAM_MODE_READ); + dispatchMemAccessNotifications(&emulContext, emulContext.deviceStreamRegs[di], devMem->rawCells, devMem->memwriteCellAddrs, (size_t)devMem->memwriteLen, STREAM_MODE_WRITE); + } clockCounter++; } diff --git a/src/proto/handlers/config.c b/src/proto/handlers/config.c new file mode 100644 index 0000000..b6b6a14 --- /dev/null +++ b/src/proto/handlers/config.c @@ -0,0 +1,314 @@ +#include "proto/handlers/config.h" + +#include +#include +#include + +#include "state.h" +#include "base_device.h" +#include "proto/msg.h" +#include "proto/dial.h" + +#include "config_ctrl_reader.h" +#include "config_reader.h" +#include "device_reader.h" +#include "mem_config_reader.h" + +#define MAX_DEVICES 64 +#define MAX_DEPTH 16 + + +// Converts a FlatBuffer BaseDeviceConfig into a heap-allocated conf_dev_t +// suitable for openBaseDevice(). Caller must call freeConf() when done. +static conf_dev_t* conf_from_fb( + hmmmm_config_BaseDeviceConfig_table_t base, + char* errbuf) +{ + conf_dev_t* dc = calloc(1, sizeof(conf_dev_t)); + if (!dc) { sprintf(errbuf, "alloc conf_dev_t"); return NULL; } + + dc->clockDivider = 1; + dc->clockMultipler = 1; + + flatbuffers_string_t lp = hmmmm_config_BaseDeviceConfig_libpath(base); + if (!lp) { sprintf(errbuf, "missing libpath"); free(dc); return NULL; } + dc->libPath = strdup(lp); + + hmmmm_config_MemSegment_vec_t segs = hmmmm_config_BaseDeviceConfig_mem_segments(base); + size_t seg_n = segs ? hmmmm_config_MemSegment_vec_len(segs) : 0; + + dc->memConf = calloc(1, sizeof(conf_mem_t)); + if (!dc->memConf) { free(dc->libPath); free(dc); sprintf(errbuf, "alloc memConf"); return NULL; } + + dc->memConf->memSegConfs = calloc(seg_n + 1, sizeof(conf_mem_seg_t*)); + if (!dc->memConf->memSegConfs) { + free(dc->memConf); free(dc->libPath); free(dc); + sprintf(errbuf, "alloc memSegConfs"); + return NULL; + } + + for (size_t i = 0; i < seg_n; i++) { + hmmmm_config_MemSegment_table_t seg = hmmmm_config_MemSegment_vec_at(segs, i); + conf_mem_seg_t* s = calloc(1, sizeof(conf_mem_seg_t)); + if (!s) { sprintf(errbuf, "alloc seg %zu", i); goto fail; } + + flatbuffers_string_t sname = hmmmm_config_MemSegment_name(seg); + s->name = strdup(sname ? sname : ""); + s->start = hmmmm_config_MemSegment_addr(seg); + s->len = hmmmm_config_MemSegment_len(seg); + s->wordLen = hmmmm_config_MemSegment_word_len(seg); + s->isExecutable = hmmmm_config_MemSegment_executable(seg); + dc->memConf->memSegConfs[i] = s; + } + dc->memConf->memSegConfs[seg_n] = NULL; + return dc; + +fail: + freeConf(dc); // freeConf() already calls free(dc) + return NULL; +} + + +typedef struct { + device_handle_t* handles[MAX_DEVICES]; + const char* path_stack[MAX_DEPTH]; // current path components + size_t depth; + // For building the DeviceIdMappingNotif response: + // store copies of hierarchical path per device + char** paths[MAX_DEVICES]; // each is a NULL-terminated string array + size_t path_lens[MAX_DEVICES]; // number of components per path + size_t count; +} LoadState; + + +static int load_devices_recursive( + hmmmm_config_ComposeDeviceConfig_table_t compose, + LoadState* st, + char* errbuf) +{ + hmmmm_config_DeviceEntry_vec_t entries = + hmmmm_config_ComposeDeviceConfig_devices(compose); + size_t n = entries ? hmmmm_config_DeviceEntry_vec_len(entries) : 0; + + for (size_t i = 0; i < n; i++) { + hmmmm_config_DeviceEntry_table_t entry = + hmmmm_config_DeviceEntry_vec_at(entries, i); + + flatbuffers_string_t id = hmmmm_config_DeviceEntry_id(entry); + if (!id) { sprintf(errbuf, "device entry missing id"); return -1; } + + if (st->depth >= MAX_DEPTH) { + sprintf(errbuf, "device tree too deep"); + return -1; + } + st->path_stack[st->depth] = id; + st->depth++; + + hmmmm_config_DeviceConfig_union_type_t ctype = + hmmmm_config_DeviceEntry_config_type(entry); + + if (ctype == hmmmm_config_DeviceConfig_BaseDeviceConfig) { + if (st->count >= MAX_DEVICES) { + sprintf(errbuf, "too many devices"); + return -1; + } + + hmmmm_config_BaseDeviceConfig_table_t base = + (hmmmm_config_BaseDeviceConfig_table_t) + hmmmm_config_DeviceEntry_config(entry); + + conf_dev_t* dc = conf_from_fb(base, errbuf); + if (!dc) return -1; + + device_handle_t* dev = openBaseDevice(dc, errbuf); + freeConf(dc); // freeConf() already calls free(dc) + if (!dev) return -1; + + dev->lib->fillSmartReadSpecs(dev->specs, NULL, 0); + dev->lib->fillSmartWriteSpecs(dev->specs, NULL, 0); + + dev->ctx = dev->lib->init(dev->specs, errbuf); + if (!dev->ctx) { + closeBaseDevice(dev); + free(dev); + return -1; + } + + size_t idx = st->count; + st->handles[idx] = dev; + + // Copy path + st->path_lens[idx] = st->depth; + st->paths[idx] = calloc(st->depth + 1, sizeof(char*)); + if (!st->paths[idx]) { + sprintf(errbuf, "alloc path array"); + return -1; + } + for (size_t p = 0; p < st->depth; p++) { + st->paths[idx][p] = strdup(st->path_stack[p]); + } + st->paths[idx][st->depth] = NULL; + + st->count++; + + } else if (ctype == hmmmm_config_DeviceConfig_ComposeDeviceConfig) { + hmmmm_config_ComposeDeviceConfig_table_t child = + (hmmmm_config_ComposeDeviceConfig_table_t) + hmmmm_config_DeviceEntry_config(entry); + + if (load_devices_recursive(child, st, errbuf) != 0) { + return -1; + } + } else { + sprintf(errbuf, "unknown device config type %u", ctype); + return -1; + } + + st->depth--; + } + return 0; +} + + +static void free_load_state_paths(LoadState* st) +{ + for (size_t i = 0; i < st->count; i++) { + if (st->paths[i]) { + for (size_t j = 0; j < st->path_lens[i]; j++) { + free(st->paths[i][j]); + } + free(st->paths[i]); + } + } +} + + +static void free_old_config(EmulContext* emulContext) +{ + if (emulContext->devicesCount == 0) return; + + for (size_t i = 0; i < emulContext->devicesCount; i++) { + device_handle_t* dev = (device_handle_t*)emulContext->deviceHandles[i]; + closeBaseDevice(dev); + free(dev); + + if (emulContext->deviceStreamRegs[i]) { + free(emulContext->deviceStreamRegs[i]->regs); + free(emulContext->deviceStreamRegs[i]); + } + } + free(emulContext->deviceHandles); + free(emulContext->devicesMem); + free(emulContext->deviceStreamRegs); + + emulContext->deviceHandles = NULL; + emulContext->devicesMem = NULL; + emulContext->deviceStreamRegs = NULL; + emulContext->devicesCount = 0; +} + + +void handleConfigCtrlMessage( + hmmmm_ctrl_config_ctrl_ConfigCtrlMessage_table_t msg, + uint64_t nonce, + ClientContext* ctx, + EmulContext* emulContext) +{ + printf("[CTRL/CONFIG] received config load request\n"); + + char errbuf[1024]; + + // Must be in STILL state + if (*emulContext->emulState != EMUL_STATE_STILL) { + sprintf(errbuf, "config load requires STILL state"); + printf("[CTRL/CONFIG] error: %s\n", errbuf); + + size_t msg_len; + uint8_t* out = fb_build_config_error(nonce, errbuf, &msg_len); + dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len); + return; + } + + hmmmm_config_EmulationConfig_table_t econf = + hmmmm_ctrl_config_ctrl_ConfigCtrlMessage_config(msg); + + if (!econf) { + sprintf(errbuf, "missing EmulationConfig"); + printf("[CTRL/CONFIG] error: %s\n", errbuf); + + size_t msg_len; + uint8_t* out = fb_build_config_error(nonce, errbuf, &msg_len); + dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len); + return; + } + + flatbuffers_string_t root_id = hmmmm_config_EmulationConfig_root_id(econf); + hmmmm_config_ComposeDeviceConfig_table_t root = + hmmmm_config_EmulationConfig_root(econf); + + if (!root) { + sprintf(errbuf, "missing root ComposeDeviceConfig"); + printf("[CTRL/CONFIG] error: %s\n", errbuf); + + size_t msg_len; + uint8_t* out = fb_build_config_error(nonce, errbuf, &msg_len); + dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len); + return; + } + + // Free old config + free_old_config(emulContext); + + // Load new config + LoadState st = {0}; + if (root_id) { + st.path_stack[0] = root_id; + st.depth = 1; + } + + if (load_devices_recursive(root, &st, errbuf) != 0) { + printf("[CTRL/CONFIG] load error: %s\n", errbuf); + + // Close any devices that were opened before the failure + for (size_t i = 0; i < st.count; i++) { + closeBaseDevice(st.handles[i]); + free(st.handles[i]); + } + free_load_state_paths(&st); + + size_t msg_len; + uint8_t* out = fb_build_config_error(nonce, errbuf, &msg_len); + dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len); + return; + } + + printf("[CTRL/CONFIG] loaded %zu devices\n", st.count); + + // Allocate new arrays for EmulContext + size_t dc = st.count; + emulContext->devicesCount = dc; + + emulContext->deviceHandles = calloc(dc, sizeof(void*)); + emulContext->devicesMem = calloc(dc, sizeof(uint8_t*)); + emulContext->deviceStreamRegs = calloc(dc, sizeof(DeviceSegStreamReg*)); + + for (size_t i = 0; i < dc; i++) { + emulContext->deviceHandles[i] = st.handles[i]; + emulContext->devicesMem[i] = st.handles[i]->ctx->deviceMem->rawCells; + + DeviceSegStreamReg* dsr = calloc(1, sizeof(DeviceSegStreamReg)); + dsr->allocatedSize = 4; + dsr->regCount = 0; + dsr->regs = calloc(4, sizeof(StreamReg)); + emulContext->deviceStreamRegs[i] = dsr; + } + + // Build DeviceIdMappingNotif response + size_t msg_len; + uint8_t* out = fb_build_config_device_id_mapping( + nonce, st.paths, st.path_lens, dc, &msg_len); + + free_load_state_paths(&st); + + dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len); +} diff --git a/src/proto/handlers/control.c b/src/proto/handlers/control.c index 732e303..4b2648a 100644 --- a/src/proto/handlers/control.c +++ b/src/proto/handlers/control.c @@ -1,4 +1,5 @@ #include "proto/handlers/control.h" +#include "proto/handlers/config.h" #include #include "state.h" @@ -7,6 +8,7 @@ #include "control_reader.h" #include "exec_ctrl_reader.h" +#include "config_ctrl_reader.h" #include "setup_buf_reader.h" #include "orphaned_reader.h" #include "lost_reader.h" @@ -90,6 +92,13 @@ void handleIncomingCtrlMessage( uint8_t* out = fb_build_orphaned_response(nonce, &msg_len); dispatchOutgoingMessage(emulContext->outBufs, ctx->clientId, out, msg_len); } + else if (ptype == hmmmm_ctrl_CtrlClientPayload_ConfigCtrlMessage) + { + handleConfigCtrlMessage( + (hmmmm_ctrl_config_ctrl_ConfigCtrlMessage_table_t) + hmmmm_ctrl_CtrlClientMessage_payload(msg), + nonce, ctx, emulContext); + } else if (ptype == hmmmm_ctrl_CtrlClientPayload_LostMessagesRequest) { hmmmm_ctrl_lost_LostMessagesRequest_table_t req = diff --git a/src/proto/handlers/mem.c b/src/proto/handlers/mem.c index a93308a..8cf3a16 100644 --- a/src/proto/handlers/mem.c +++ b/src/proto/handlers/mem.c @@ -6,7 +6,7 @@ #include "proto/dial.h" #include "mem_reader.h" -#define DEVICE_MEM_SIZE ((size_t)(128 * 1024)) +#define DEVICE_MEM_SIZE ((size_t)(256 * 1024)) void handleIncomingMemMessage( diff --git a/src/proto/msg.c b/src/proto/msg.c index 6f2133f..5e25112 100644 --- a/src/proto/msg.c +++ b/src/proto/msg.c @@ -248,3 +248,105 @@ uint8_t* fb_build_stream_reg_confirm( NULL_GUARD(buf); return buf; } + + +uint8_t* fb_build_config_device_id_mapping( + uint64_t nonce, + char** paths[], size_t path_lens[], + size_t device_count, size_t* len_out) +{ + flatcc_builder_t B; + if (flatcc_builder_init(&B)) { + panic("flatcc_builder_init failed\n"); + } + + // Pre-create DeviceIdEntry refs (bottom-up: strings first, then tables) + hmmmm_ctrl_config_notif_DeviceIdEntry_ref_t entry_refs[device_count]; + + for (size_t i = 0; i < device_count; i++) { + // Build string vector for path + flatbuffers_string_vec_start(&B); + for (size_t j = 0; j < path_lens[i]; j++) { + flatbuffers_string_ref_t sref = flatbuffers_string_create_str(&B, paths[i][j]); + flatbuffers_string_vec_push(&B, sref); + } + flatbuffers_string_vec_ref_t path_vec = flatbuffers_string_vec_end(&B); + + // Empty seg_ids vector + hmmmm_ctrl_config_notif_SegIdEntry_vec_start(&B); + hmmmm_ctrl_config_notif_SegIdEntry_vec_ref_t seg_ids_vec = + hmmmm_ctrl_config_notif_SegIdEntry_vec_end(&B); + + entry_refs[i] = hmmmm_ctrl_config_notif_DeviceIdEntry_create( + &B, path_vec, (uint32_t)i, seg_ids_vec); + } + + // Build entries vector + hmmmm_ctrl_config_notif_DeviceIdEntry_vec_start(&B); + for (size_t i = 0; i < device_count; i++) { + hmmmm_ctrl_config_notif_DeviceIdEntry_vec_push(&B, entry_refs[i]); + } + hmmmm_ctrl_config_notif_DeviceIdEntry_vec_ref_t entries_vec = + hmmmm_ctrl_config_notif_DeviceIdEntry_vec_end(&B); + + hmmmm_ctrl_config_notif_DeviceIdMappingNotif_ref_t mapping = + hmmmm_ctrl_config_notif_DeviceIdMappingNotif_create(&B, entries_vec); + + hmmmm_ctrl_config_notif_ConfigNotifPayload_union_ref_t notif_payload = + hmmmm_ctrl_config_notif_ConfigNotifPayload_as_DeviceIdMappingNotif(mapping); + + hmmmm_ctrl_config_notif_ConfigNotifMessage_ref_t notif_msg = + hmmmm_ctrl_config_notif_ConfigNotifMessage_create(&B, 0, notif_payload); + + hmmmm_ctrl_CtrlServerPayload_union_ref_t ctrl_payload = + hmmmm_ctrl_CtrlServerPayload_as_ConfigNotifMessage(notif_msg); + + hmmmm_ctrl_CtrlServerMessage_ref_t ctrl_msg = + hmmmm_ctrl_CtrlServerMessage_create(&B, ctrl_payload); + + hmmmm_ServerPayload_union_ref_t payload = + hmmmm_ServerPayload_as_CtrlServerMessage(ctrl_msg); + + hmmmm_ServerMessage_create_as_root(&B, nonce, payload); + + uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out); + flatcc_builder_clear(&B); + NULL_GUARD(buf); + return buf; +} + + +uint8_t* fb_build_config_error(uint64_t nonce, const char* message, size_t* len_out) +{ + flatcc_builder_t B; + if (flatcc_builder_init(&B)) { + panic("flatcc_builder_init failed\n"); + } + + flatbuffers_string_ref_t msg_str = flatbuffers_string_create_str(&B, message); + + hmmmm_ctrl_config_notif_ConfigLoadError_ref_t err = + hmmmm_ctrl_config_notif_ConfigLoadError_create(&B, msg_str); + + hmmmm_ctrl_config_notif_ConfigNotifPayload_union_ref_t notif_payload = + hmmmm_ctrl_config_notif_ConfigNotifPayload_as_ConfigLoadError(err); + + hmmmm_ctrl_config_notif_ConfigNotifMessage_ref_t notif_msg = + hmmmm_ctrl_config_notif_ConfigNotifMessage_create(&B, 0, notif_payload); + + hmmmm_ctrl_CtrlServerPayload_union_ref_t ctrl_payload = + hmmmm_ctrl_CtrlServerPayload_as_ConfigNotifMessage(notif_msg); + + hmmmm_ctrl_CtrlServerMessage_ref_t ctrl_msg = + hmmmm_ctrl_CtrlServerMessage_create(&B, ctrl_payload); + + hmmmm_ServerPayload_union_ref_t payload = + hmmmm_ServerPayload_as_CtrlServerMessage(ctrl_msg); + + hmmmm_ServerMessage_create_as_root(&B, nonce, payload); + + uint8_t* buf = flatcc_builder_finalize_buffer(&B, len_out); + flatcc_builder_clear(&B); + NULL_GUARD(buf); + return buf; +}