CXX := g++
CXXFLAGS := -std=c++20 -O2 -Wall -Wextra -Wpedantic -pthread -MMD -MP
LDFLAGS := -pthread -lrt
ORCH_LDFLAGS := $(LDFLAGS) -lusb-1.0
VISA_CXXFLAGS ?= -I/usr/include/ni-visa
VISA_LDFLAGS := $(LDFLAGS) -lvisa

BUILD_DIR := build
BIN_DIR := $(BUILD_DIR)/bin

INCLUDES := \
	-Idata_acq_and_processing/common_cpp/ipc/include \
	-Idata_acq_and_processing/common_cpp/config/include \
	-Idata_acq_and_processing/third_party \
	-Idata_acq_and_processing/third_party/eigen \
	-Idata_acq_and_processing/sweep_orchestrator/include \
	-Idata_acq_and_processing/sweep_orchestrator/device_drivers/interfaces \
	-Idata_acq_and_processing/sweep_orchestrator/device_drivers/radar \
	-Idata_acq_and_processing/sweep_orchestrator/device_drivers/switches \
	-Idata_acq_and_processing/preprocessing/calibration_master/include \
	-Idata_acq_and_processing/preprocessing/reference_master/include \
	-Idata_acq_and_processing/preprocessing/data_preprocessor/include \
	-Idata_acq_and_processing/processing/processors/include \
	-Idata_acq_and_processing/processing/data_processor/include \
	-Idata_acq_and_processing/processing/locator/include

COMMON_SOURCES := \
	data_acq_and_processing/common_cpp/ipc/src/shm_ring.cpp \
	data_acq_and_processing/common_cpp/ipc/src/shared_types.cpp \
	data_acq_and_processing/common_cpp/config/src/run_config.cpp

ORCH_SOURCES := \
	data_acq_and_processing/sweep_orchestrator/device_drivers/radar/librevna/librevna_minimal_driver_lifecycle.cpp \
	data_acq_and_processing/sweep_orchestrator/device_drivers/radar/librevna/librevna_minimal_driver_transport.cpp \
	data_acq_and_processing/sweep_orchestrator/device_drivers/radar/librevna/librevna_minimal_driver_protocol.cpp \
	data_acq_and_processing/sweep_orchestrator/device_drivers/radar/remote_compact_m_k209/remote_compact_m_k209_driver.cpp \
	data_acq_and_processing/sweep_orchestrator/device_drivers/switches/h7992_minimal_driver.cpp \
	data_acq_and_processing/sweep_orchestrator/device_drivers/switches/hmc349a_minimal_driver.cpp \
	data_acq_and_processing/sweep_orchestrator/src/sweep_orchestrator.cpp \
	data_acq_and_processing/sweep_orchestrator/src/main.cpp

PREPROC_SOURCES := \
	data_acq_and_processing/preprocessing/calibration_master/src/calibration_master.cpp \
	data_acq_and_processing/preprocessing/calibration_master/src/channel_bundle_support.cpp \
	data_acq_and_processing/preprocessing/calibration_master/src/through_calibrator.cpp \
	data_acq_and_processing/preprocessing/reference_master/src/reference_master.cpp \
	data_acq_and_processing/preprocessing/data_preprocessor/src/data_preprocessor.cpp \
	data_acq_and_processing/preprocessing/data_preprocessor/src/main.cpp

LOCATOR_SOURCES := \
	data_acq_and_processing/processing/locator/src/payload_builder.cpp \
	data_acq_and_processing/processing/locator/src/tcp_server.cpp

PROCESSOR_SOURCES := \
	data_acq_and_processing/processing/processors/src/bscan_processor.cpp \
	data_acq_and_processing/processing/processors/src/gpr_processor.cpp \
	data_acq_and_processing/processing/processors/src/passthrough_processor.cpp \
	data_acq_and_processing/processing/data_processor/src/processing_live_config.cpp \
	data_acq_and_processing/processing/data_processor/src/data_processor.cpp \
	data_acq_and_processing/processing/data_processor/src/main.cpp \
	$(LOCATOR_SOURCES)

# Kamil ADC collector: standalone L-Card E-502 acquisition binary. It loads the
# proprietary libx502api/libe502api at runtime via dlopen, so it builds anywhere
# from the vendored headers alone and only needs those libraries present at run
# time. Built on demand (not part of `all`) for radar.model == kamil_adc.
KAMIL_COLLECTOR_DIR := data_acq_and_processing/kamil_adc_collector
KAMIL_COLLECTOR_INCLUDES := -I$(KAMIL_COLLECTOR_DIR)/include -I$(KAMIL_COLLECTOR_DIR)/vendor/lcard
KAMIL_COLLECTOR_LDFLAGS := -pthread -ldl -lutil
KAMIL_COLLECTOR_SOURCES := \
	$(KAMIL_COLLECTOR_DIR)/src/main.cpp \
	$(KAMIL_COLLECTOR_DIR)/src/tty_protocol_writer.cpp \
	$(KAMIL_COLLECTOR_DIR)/src/capture_file_writer.cpp

SWEEP_ORCH_OBJS := $(addprefix $(BUILD_DIR)/,$(COMMON_SOURCES:.cpp=.o) $(ORCH_SOURCES:.cpp=.o))
PREPROCESSOR_OBJS := $(addprefix $(BUILD_DIR)/,$(COMMON_SOURCES:.cpp=.o) $(PREPROC_SOURCES:.cpp=.o))
DATA_PROCESSOR_OBJS := $(addprefix $(BUILD_DIR)/,$(COMMON_SOURCES:.cpp=.o) $(PROCESSOR_SOURCES:.cpp=.o))
KAMIL_COLLECTOR_OBJS := $(addprefix $(BUILD_DIR)/,$(KAMIL_COLLECTOR_SOURCES:.cpp=.o))
DEPFILES := $(sort $(SWEEP_ORCH_OBJS:.o=.d) $(PREPROCESSOR_OBJS:.o=.d) $(DATA_PROCESSOR_OBJS:.o=.d) $(KAMIL_COLLECTOR_OBJS:.o=.d))

TARGETS := \
	$(BIN_DIR)/sweep_orchestrator \
	$(BIN_DIR)/data_preprocessor \
	$(BIN_DIR)/data_processor

.PHONY: all clean kamil_adc_collector

all: $(TARGETS)

kamil_adc_collector: $(BIN_DIR)/kamil_adc_collector

$(BIN_DIR)/sweep_orchestrator: $(SWEEP_ORCH_OBJS)
	@mkdir -p $(BIN_DIR)
	$(CXX) $(SWEEP_ORCH_OBJS) -o $@ $(ORCH_LDFLAGS)

$(BIN_DIR)/data_preprocessor: $(PREPROCESSOR_OBJS)
	@mkdir -p $(BIN_DIR)
	$(CXX) $(PREPROCESSOR_OBJS) -o $@ $(LDFLAGS)

$(BIN_DIR)/data_processor: $(DATA_PROCESSOR_OBJS)
	@mkdir -p $(BIN_DIR)
	$(CXX) $(DATA_PROCESSOR_OBJS) -o $@ $(LDFLAGS)

# The collector is self-contained: compile its objects with only the vendored
# L-Card headers (no project/VISA includes) by overriding the generic rule's
# variables for these objects, then link with dlopen/openpty support.
$(KAMIL_COLLECTOR_OBJS): INCLUDES := $(KAMIL_COLLECTOR_INCLUDES)
$(KAMIL_COLLECTOR_OBJS): VISA_CXXFLAGS :=

$(BIN_DIR)/kamil_adc_collector: $(KAMIL_COLLECTOR_OBJS)
	@mkdir -p $(BIN_DIR)
	$(CXX) $(KAMIL_COLLECTOR_OBJS) -o $@ $(KAMIL_COLLECTOR_LDFLAGS)

$(BUILD_DIR)/%.o: %.cpp
	@mkdir -p $(dir $@)
	$(CXX) $(CXXFLAGS) $(VISA_CXXFLAGS) $(INCLUDES) -c $< -o $@

-include $(DEPFILES)

clean:
	rm -rf $(BUILD_DIR)
