diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.cpp b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.cpp index cc969b7..7c21f0e 100644 --- a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.cpp +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.cpp @@ -9,15 +9,15 @@ extern SPI_HandleTypeDef hspi1; extern UART_HandleTypeDef huart3; // Chip Select GPIO definitions -static const struct { - GPIO_TypeDef* port; - uint16_t pin; -} CHIP_SELECTS[4] = { - {GPIOA, GPIO_PIN_0}, // ADAR1000 #1 - {GPIOA, GPIO_PIN_1}, // ADAR1000 #2 - {GPIOA, GPIO_PIN_2}, // ADAR1000 #3 - {GPIOA, GPIO_PIN_3} // ADAR1000 #4 -}; +static const struct { + GPIO_TypeDef* port; + uint16_t pin; +} CHIP_SELECTS[4] = { + {ADAR_1_CS_3V3_GPIO_Port, ADAR_1_CS_3V3_Pin}, // ADAR1000 #1 + {ADAR_2_CS_3V3_GPIO_Port, ADAR_2_CS_3V3_Pin}, // ADAR1000 #2 + {ADAR_3_CS_3V3_GPIO_Port, ADAR_3_CS_3V3_Pin}, // ADAR1000 #3 + {ADAR_4_CS_3V3_GPIO_Port, ADAR_4_CS_3V3_Pin} // ADAR1000 #4 +}; // Vector Modulator lookup tables const uint8_t ADAR1000Manager::VM_I[128] = { @@ -162,15 +162,15 @@ bool ADAR1000Manager::setBeamAngle(float angle_degrees, BeamDirection direction) for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t ch = 0; ch < 4; ++ch) { - if (direction == BeamDirection::TX) { - adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF); - adarSetTxVgaGain(dev, ch + 1, 0x7F, BROADCAST_OFF); - } else { - adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF); - adarSetRxVgaGain(dev, ch + 1, 30, BROADCAST_OFF); - } - } - } + if (direction == BeamDirection::TX) { + adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF); + adarSetTxVgaGain(dev, ch + 1, kDefaultTxVgaGain, BROADCAST_OFF); + } else { + adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF); + adarSetRxVgaGain(dev, ch + 1, kDefaultRxVgaGain, BROADCAST_OFF); + } + } + } return true; } @@ -326,59 +326,57 @@ bool ADAR1000Manager::initializeADTR1107Sequence() { const uint8_t msg[] = "Starting ADTR1107 Power Sequence...\r\n"; HAL_UART_Transmit(&huart3, msg, sizeof(msg) - 1, 1000); - // Step 1: Connect all GND pins to ground (assumed in hardware) - - // Step 2: Set VDD_SW to 3.3V - HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET); // EN_P_3V3_VDD_SW - HAL_Delay(1); - - // Step 3: Set VSS_SW to -3.3V - HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET); // EN_P_3V3_SW - HAL_Delay(1); + // Step 1: Connect all GND pins to ground (assumed in hardware) + + // Step 2: Set VDD_SW to 3.3V + HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_SET); + HAL_Delay(1); + + // Step 3: Set VSS_SW to -3.3V + HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_SET); + HAL_Delay(1); // Step 4: Set CTRL_SW to RX mode initially via GPIO setADTR1107Control(false); // RX mode HAL_Delay(1); // Step 5: Set VGG_LNA to 0 - uint8_t lna_bias_voltage = 0x00; // Example value, adjust based on your LNA requirements - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_LNA_BIAS_ON, lna_bias_voltage, BROADCAST_OFF); - adarWrite(dev, REG_LNA_BIAS_OFF, 0x00, BROADCAST_OFF); - } - - // Step 6: Set VDD_LNA to 0V for TX mode - HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // EN_P_3V3_LNA - HAL_Delay(2); + uint8_t lna_bias_voltage = kLnaBiasOff; + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_LNA_BIAS_ON, lna_bias_voltage, BROADCAST_OFF); + adarWrite(dev, REG_LNA_BIAS_OFF, kLnaBiasOff, BROADCAST_OFF); + } + + // Step 6: Set VDD_LNA to 0V for TX mode + HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_RESET); + HAL_Delay(2); // Step 7: Set VGG_PA to safe negative voltage (PA off for TX mode) /*A 0x00 value in the on or off bias registers, correspond to a 0 V output. A 0xFF in the on or off bias registers correspond to a −4.8 V output.*/ - uint8_t safe_pa_bias = 0x5D; // Safe negative voltage (-1.75V) to keep PA off - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF); - adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF); + uint8_t safe_pa_bias = kPaBiasTxSafe; // Safe negative voltage (-1.75V) to keep PA off + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF); + adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF); } - HAL_Delay(10); - - // Step 8: Set VDD_PA to 0V (PA powered up for TX mode) - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET); - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET); - HAL_Delay(50); + HAL_Delay(10); + + // Step 8: Set VDD_PA to 0V (PA powered up for TX mode) + enablePASupplies(); + HAL_Delay(50); // Step 9: Adjust VGG_PA voltage between −1.75 V and −0.25 V to achieve the desired IDQ_PA=220mA //Set VGG_PA to safe negative voltage (PA off for TX mode) /*A 0x00 value in the on or off bias registers, correspond to a 0 V output. A 0xFF in the on or off bias registers correspond to a −4.8 V output.*/ - uint8_t Idq_pa_bias = 0x0D; // Safe negative voltage (-0.2447V) to keep PA off - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_PA_CH1_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); - adarWrite(dev, REG_PA_CH2_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); + uint8_t Idq_pa_bias = kPaBiasIdqCalibration; // Safe negative voltage (-0.2447V) to keep PA off + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_PA_CH1_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); + adarWrite(dev, REG_PA_CH2_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); } @@ -429,30 +427,28 @@ bool ADAR1000Manager::setAllDevicesRXMode() { } void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) { - if (direction == BeamDirection::TX) { - setADTR1107Control(true); // TX mode - - // Step 1: Disable LNA power first - HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // Disable LNA power - HAL_Delay(5); - - // Step 2: Set LNA bias to safe off value - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_LNA_BIAS_ON, 0x00, BROADCAST_OFF); // Turn off LNA bias - } - HAL_Delay(5); - - // Step 3: Enable PA power - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET); - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET); - HAL_Delay(10); - - // Step 4: Set PA bias to operational value - uint8_t operational_pa_bias = 0x7F; // Maximum bias for full power - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_PA_CH1_BIAS_ON, operational_pa_bias, BROADCAST_OFF); - adarWrite(dev, REG_PA_CH2_BIAS_ON, operational_pa_bias, BROADCAST_OFF); + if (direction == BeamDirection::TX) { + setADTR1107Control(true); // TX mode + + // Step 1: Disable LNA power first + disableLNASupplies(); + HAL_Delay(5); + + // Step 2: Set LNA bias to safe off value + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_LNA_BIAS_ON, kLnaBiasOff, BROADCAST_OFF); // Turn off LNA bias + } + HAL_Delay(5); + + // Step 3: Enable PA power + enablePASupplies(); + HAL_Delay(10); + + // Step 4: Set PA bias to operational value + uint8_t operational_pa_bias = kPaBiasOperational; // Maximum bias for full power + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_PA_CH1_BIAS_ON, operational_pa_bias, BROADCAST_OFF); + adarWrite(dev, REG_PA_CH2_BIAS_ON, operational_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, operational_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, operational_pa_bias, BROADCAST_OFF); } @@ -466,33 +462,31 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) { } else { // RECEIVE MODE: Enable LNA, Disable PA - setADTR1107Control(false); // RX mode - - // Step 1: Disable PA power first - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_RESET); // EN_P_5V0_PA - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_RESET); - HAL_Delay(5); - - // Step 2: Set PA bias to safe negative voltage - uint8_t safe_pa_bias = 0x20; - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF); - adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF); + setADTR1107Control(false); // RX mode + + // Step 1: Disable PA power first + disablePASupplies(); + HAL_Delay(5); + + // Step 2: Set PA bias to safe negative voltage + uint8_t safe_pa_bias = kPaBiasRxSafe; + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF); + adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF); } - HAL_Delay(5); - - // Step 3: Enable LNA power - HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET); // EN_P_3V3_LNA - HAL_Delay(10); - - // Step 4: Set LNA bias to operational value - uint8_t operational_lna_bias = 0x30; // Adjust based on your LNA requirements - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_LNA_BIAS_ON, operational_lna_bias, BROADCAST_OFF); - } + HAL_Delay(5); + + // Step 3: Enable LNA power + enableLNASupplies(); + HAL_Delay(10); + + // Step 4: Set LNA bias to operational value + uint8_t operational_lna_bias = kLnaBiasOperational; + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_LNA_BIAS_ON, operational_lna_bias, BROADCAST_OFF); + } HAL_Delay(5); // Step 5: Set TR switch to RX mode @@ -535,42 +529,42 @@ bool ADAR1000Manager::setCustomBeamPattern16(const uint8_t phase_pattern[16], Be return true; } -void ADAR1000Manager::enablePASupplies() { - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET); - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET); -} - -void ADAR1000Manager::disablePASupplies() { - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_RESET); // EN_P_5V0_PA - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_RESET); -} - -void ADAR1000Manager::enableLNASupplies() { - HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET); // EN_P_3V3_LNA -} - -void ADAR1000Manager::disableLNASupplies() { - HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // EN_P_3V3_LNA -} - -void ADAR1000Manager::setPABias(bool enable) { - uint8_t pa_bias = enable ? 0x7F : 0x20; // Operational vs safe bias - - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_PA_CH1_BIAS_ON, pa_bias, BROADCAST_OFF); +void ADAR1000Manager::enablePASupplies() { + HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(EN_P_5V0_PA2_GPIO_Port, EN_P_5V0_PA2_Pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(EN_P_5V0_PA3_GPIO_Port, EN_P_5V0_PA3_Pin, GPIO_PIN_SET); +} + +void ADAR1000Manager::disablePASupplies() { + HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(EN_P_5V0_PA2_GPIO_Port, EN_P_5V0_PA2_Pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(EN_P_5V0_PA3_GPIO_Port, EN_P_5V0_PA3_Pin, GPIO_PIN_RESET); +} + +void ADAR1000Manager::enableLNASupplies() { + HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_SET); +} + +void ADAR1000Manager::disableLNASupplies() { + HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_RESET); +} + +void ADAR1000Manager::setPABias(bool enable) { + uint8_t pa_bias = enable ? kPaBiasOperational : kPaBiasRxSafe; // Operational vs safe bias + + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_PA_CH1_BIAS_ON, pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH2_BIAS_ON, pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, pa_bias, BROADCAST_OFF); } -} - -void ADAR1000Manager::setLNABias(bool enable) { - uint8_t lna_bias = enable ? 0x30 : 0x00; // Operational vs off - - for (uint8_t dev = 0; dev < devices_.size(); ++dev) { - adarWrite(dev, REG_LNA_BIAS_ON, lna_bias, BROADCAST_OFF); +} + +void ADAR1000Manager::setLNABias(bool enable) { + uint8_t lna_bias = enable ? kLnaBiasOperational : kLnaBiasOff; // Operational vs off + + for (uint8_t dev = 0; dev < devices_.size(); ++dev) { + adarWrite(dev, REG_LNA_BIAS_ON, lna_bias, BROADCAST_OFF); } } @@ -739,11 +733,11 @@ void ADAR1000Manager::adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uin adarWrite(deviceIndex, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast); } -void ADAR1000Manager::adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast) { - adarWrite(deviceIndex, REG_BIAS_CURRENT_TX, 0x2D, broadcast); - adarWrite(deviceIndex, REG_BIAS_CURRENT_TX_DRV, 0x06, broadcast); - adarWrite(deviceIndex, REG_LOAD_WORKING, 0x2, broadcast); -} +void ADAR1000Manager::adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast) { + adarWrite(deviceIndex, REG_BIAS_CURRENT_TX, kTxBiasCurrent, broadcast); + adarWrite(deviceIndex, REG_BIAS_CURRENT_TX_DRV, kTxDriverBiasCurrent, broadcast); + adarWrite(deviceIndex, REG_LOAD_WORKING, 0x2, broadcast); +} uint8_t ADAR1000Manager::adarAdcRead(uint8_t deviceIndex, uint8_t broadcast) { adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast); diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.h index 165c5c5..506e0d8 100644 --- a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.h +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADAR1000_Manager.h @@ -116,13 +116,25 @@ public: bool beam_sweeping_active_ = false; uint32_t last_beam_update_time_ = 0; - // Lookup tables - static const uint8_t VM_I[128]; - static const uint8_t VM_Q[128]; - static const uint8_t VM_GAIN[128]; - - // Private Methods - bool initializeSingleDevice(uint8_t deviceIndex); + // Lookup tables + static const uint8_t VM_I[128]; + static const uint8_t VM_Q[128]; + static const uint8_t VM_GAIN[128]; + + // Named defaults for the ADTR1107 and ADAR1000 power sequence. + static constexpr uint8_t kDefaultTxVgaGain = 0x7F; + static constexpr uint8_t kDefaultRxVgaGain = 30; + static constexpr uint8_t kLnaBiasOff = 0x00; + static constexpr uint8_t kLnaBiasOperational = 0x30; + static constexpr uint8_t kPaBiasTxSafe = 0x5D; + static constexpr uint8_t kPaBiasIdqCalibration = 0x0D; + static constexpr uint8_t kPaBiasOperational = 0x7F; + static constexpr uint8_t kPaBiasRxSafe = 0x20; + static constexpr uint8_t kTxBiasCurrent = 0x2D; + static constexpr uint8_t kTxDriverBiasCurrent = 0x06; + + // Private Methods + bool initializeSingleDevice(uint8_t deviceIndex); bool initializeADTR1107Sequence(); void calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]); void delayUs(uint32_t microseconds); diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.c b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.c index 2c735fd..6f6c8e9 100644 --- a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.c +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.c @@ -1,121 +1,173 @@ -#include "GY_85_HAL.h" +#include "GY_85_HAL.h" + +static int16_t g_offx = 0, g_offy = 0, g_offz = 0; + +// ---------------- Internal Functions ---------------- // +static bool GY85_SetAccelerometer(void); +static bool GY85_ReadAccelerometer(GY85_t *imu); +static bool GY85_SetCompass(void); +static bool GY85_ReadCompass(GY85_t *imu); +static bool GY85_SetGyro(void); +static bool GY85_GyroCalibrate(void); +static bool GY85_ReadGyro(GY85_t *imu); +static bool GY85_WriteRegister(uint16_t address, uint8_t reg, uint8_t value); +static bool GY85_ReadRegisters(uint16_t address, uint8_t reg, uint8_t *buffer, uint16_t length); + +// ---------------- Initialization ---------------- // +bool GY85_Init(void) +{ + if (!GY85_SetAccelerometer()) { + return false; + } + if (!GY85_SetCompass()) { + return false; + } + return GY85_SetGyro(); +} + +// ---------------- Update All Sensors ---------------- // +bool GY85_Update(GY85_t *imu) +{ + GY85_t next_sample; + + if (imu == NULL) { + return false; + } + + next_sample = *imu; + + if (!GY85_ReadAccelerometer(&next_sample)) { + return false; + } + if (!GY85_ReadCompass(&next_sample)) { + return false; + } + if (!GY85_ReadGyro(&next_sample)) { + return false; + } + + *imu = next_sample; + return true; +} + +// ---------------- Accelerometer ---------------- // +static bool GY85_SetAccelerometer(void) +{ + if (!GY85_WriteRegister(ADXL345_ADDR, 0x31, 0x01)) { + return false; + } + + return GY85_WriteRegister(ADXL345_ADDR, 0x2D, 0x08); +} + +static bool GY85_ReadAccelerometer(GY85_t *imu) +{ + uint8_t buf[6]; + + if (imu == NULL || !GY85_ReadRegisters(ADXL345_ADDR, 0x32, buf, sizeof(buf))) { + return false; + } + + imu->ax = (int16_t)((buf[1] << 8) | buf[0]); + imu->ay = (int16_t)((buf[3] << 8) | buf[2]); + imu->az = (int16_t)((buf[5] << 8) | buf[4]); + return true; +} + +// ---------------- Compass ---------------- // +static bool GY85_SetCompass(void) +{ + return GY85_WriteRegister(HMC5883_ADDR, 0x02, 0x00); +} + +static bool GY85_ReadCompass(GY85_t *imu) +{ + uint8_t buf[6]; + + if (imu == NULL || !GY85_ReadRegisters(HMC5883_ADDR, 0x03, buf, sizeof(buf))) { + return false; + } + + imu->mx = (int16_t)((buf[0] << 8) | buf[1]); + imu->mz = (int16_t)((buf[2] << 8) | buf[3]); + imu->my = (int16_t)((buf[4] << 8) | buf[5]); + return true; +} + +// ---------------- Gyroscope ---------------- // +static bool GY85_SetGyro(void) +{ + if (!GY85_WriteRegister(ITG3200_ADDR, 0x3E, 0x00)) { + return false; + } + + if (!GY85_WriteRegister(ITG3200_ADDR, 0x15, 0x07)) { + return false; + } + + if (!GY85_WriteRegister(ITG3200_ADDR, 0x16, 0x1E)) { + return false; + } + + if (!GY85_WriteRegister(ITG3200_ADDR, 0x17, 0x00)) { + return false; + } + + HAL_Delay(10); + return GY85_GyroCalibrate(); +} + +static bool GY85_GyroCalibrate(void) +{ + int32_t tmpx = 0, tmpy = 0, tmpz = 0; + GY85_t imu; -static int16_t g_offx = 0, g_offy = 0, g_offz = 0; - -// ---------------- Internal Functions ---------------- // -static void GY85_SetAccelerometer(void); -static void GY85_ReadAccelerometer(GY85_t *imu); -static void GY85_SetCompass(void); -static void GY85_ReadCompass(GY85_t *imu); -static void GY85_SetGyro(void); -static void GY85_GyroCalibrate(void); -static void GY85_ReadGyro(GY85_t *imu); - -// ---------------- Initialization ---------------- // -void GY85_Init(void) -{ - GY85_SetAccelerometer(); - GY85_SetCompass(); - GY85_SetGyro(); -} - -// ---------------- Update All Sensors ---------------- // -void GY85_Update(GY85_t *imu) -{ - GY85_ReadAccelerometer(imu); - GY85_ReadCompass(imu); - GY85_ReadGyro(imu); -} - -// ---------------- Accelerometer ---------------- // -static void GY85_SetAccelerometer(void) -{ - uint8_t data[2]; - data[0] = 0x31; data[1] = 0x01; - HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, data, 2, HAL_MAX_DELAY); - - data[0] = 0x2D; data[1] = 0x08; - HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, data, 2, HAL_MAX_DELAY); -} - -static void GY85_ReadAccelerometer(GY85_t *imu) -{ - uint8_t reg = 0x32; - uint8_t buf[6]; - HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, ®, 1, HAL_MAX_DELAY); - HAL_I2C_Master_Receive(&hi2c3, ADXL345_ADDR, buf, 6, HAL_MAX_DELAY); - - imu->ax = (int16_t)((buf[1] << 8) | buf[0]); - imu->ay = (int16_t)((buf[3] << 8) | buf[2]); - imu->az = (int16_t)((buf[5] << 8) | buf[4]); -} - -// ---------------- Compass ---------------- // -static void GY85_SetCompass(void) -{ - uint8_t data[2] = {0x02, 0x00}; - HAL_I2C_Master_Transmit(&hi2c3, HMC5883_ADDR, data, 2, HAL_MAX_DELAY); -} - -static void GY85_ReadCompass(GY85_t *imu) -{ - uint8_t reg = 0x03; - uint8_t buf[6]; - HAL_I2C_Master_Transmit(&hi2c3, HMC5883_ADDR, ®, 1, HAL_MAX_DELAY); - HAL_I2C_Master_Receive(&hi2c3, HMC5883_ADDR, buf, 6, HAL_MAX_DELAY); - - imu->mx = (int16_t)((buf[0] << 8) | buf[1]); - imu->mz = (int16_t)((buf[2] << 8) | buf[3]); - imu->my = (int16_t)((buf[4] << 8) | buf[5]); -} - -// ---------------- Gyroscope ---------------- // -static void GY85_SetGyro(void) -{ - uint8_t data[2]; - data[0] = 0x3E; data[1] = 0x00; - HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY); - - data[0] = 0x15; data[1] = 0x07; - HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY); - - data[0] = 0x16; data[1] = 0x1E; - HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY); - - data[0] = 0x17; data[1] = 0x00; - HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY); - - HAL_Delay(10); - GY85_GyroCalibrate(); -} - -static void GY85_GyroCalibrate(void) -{ - int32_t tmpx = 0, tmpy = 0, tmpz = 0; - GY85_t imu; - - for(uint8_t i = 0; i < 10; i++) - { - HAL_Delay(10); - GY85_ReadGyro(&imu); - tmpx += imu.gx; - tmpy += imu.gy; - tmpz += imu.gz; + for(uint8_t i = 0; i < 10; i++) + { + HAL_Delay(10); + if (!GY85_ReadGyro(&imu)) { + return false; + } + tmpx += imu.gx; + tmpy += imu.gy; + tmpz += imu.gz; } - g_offx = tmpx / 10; - g_offy = tmpy / 10; - g_offz = tmpz / 10; -} - -static void GY85_ReadGyro(GY85_t *imu) -{ - uint8_t reg = 0x1B; - uint8_t buf[8]; - HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, ®, 1, HAL_MAX_DELAY); - HAL_I2C_Master_Receive(&hi2c3, ITG3200_ADDR, buf, 8, HAL_MAX_DELAY); - - imu->gx = ((int16_t)((buf[2] << 8) | buf[3])) - g_offx; - imu->gy = ((int16_t)((buf[4] << 8) | buf[5])) - g_offy; - imu->gz = ((int16_t)((buf[6] << 8) | buf[7])) - g_offz; -} + g_offx = tmpx / 10; + g_offy = tmpy / 10; + g_offz = tmpz / 10; + return true; +} + +static bool GY85_ReadGyro(GY85_t *imu) +{ + uint8_t buf[8]; + + if (imu == NULL || !GY85_ReadRegisters(ITG3200_ADDR, 0x1B, buf, sizeof(buf))) { + return false; + } + + imu->gx = ((int16_t)((buf[2] << 8) | buf[3])) - g_offx; + imu->gy = ((int16_t)((buf[4] << 8) | buf[5])) - g_offy; + imu->gz = ((int16_t)((buf[6] << 8) | buf[7])) - g_offz; + return true; +} + +static bool GY85_WriteRegister(uint16_t address, uint8_t reg, uint8_t value) +{ + uint8_t data[2] = {reg, value}; + return HAL_I2C_Master_Transmit(&hi2c3, address, data, sizeof(data), HAL_MAX_DELAY) == HAL_OK; +} + +static bool GY85_ReadRegisters(uint16_t address, uint8_t reg, uint8_t *buffer, uint16_t length) +{ + if (buffer == NULL) { + return false; + } + + if (HAL_I2C_Master_Transmit(&hi2c3, address, ®, 1, HAL_MAX_DELAY) != HAL_OK) { + return false; + } + + return HAL_I2C_Master_Receive(&hi2c3, address, buffer, length, HAL_MAX_DELAY) == HAL_OK; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.h index 9af4e50..085572e 100644 --- a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.h +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.h @@ -2,6 +2,7 @@ #define __GY_85_HAL_H__ #include "stm32f7xx_hal.h" // change depending on MCU family +#include #include #define ADXL345_ADDR (0x53 << 1) @@ -18,8 +19,8 @@ typedef struct { } GY85_t; // Public API -void GY85_Init(void); -void GY85_Update(GY85_t *imu); // reads all sensors and stores in struct +bool GY85_Init(void); +bool GY85_Update(GY85_t *imu); // reads all sensors and stores in struct #endif diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.cpp b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.cpp index 2b15cc2..11e0b0c 100644 --- a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.cpp +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.cpp @@ -1,6 +1,7 @@ -// gps_handler.cpp -#include "gps_handler.h" -#include +// gps_handler.cpp +#include "gps_handler.h" +#include +#include // UART handle for communication with GUI static UART_HandleTypeDef* gui_huart = NULL; @@ -14,40 +15,46 @@ void GPS_Init(UART_HandleTypeDef* huart) memset(¤t_gps, 0, sizeof(GPS_Data_t)); } -uint8_t GPS_IsDataValid(GPS_Data_t* gps_data) -{ - // Check if GPS data is within valid ranges - if (gps_data->latitude < -90.0 || gps_data->latitude > 90.0) - return 0; +uint8_t GPS_IsDataValid(GPS_Data_t* gps_data) +{ + if (gps_data == NULL) { + return 0; + } + + // Check if GPS data is within valid ranges + if (gps_data->latitude < -90.0 || gps_data->latitude > 90.0) + return 0; if (gps_data->longitude < -180.0 || gps_data->longitude > 180.0) return 0; if (gps_data->altitude < -1000.0 || gps_data->altitude > 10000.0) // -1km to 10km return 0; - return 1; -} - -void GPS_ProcessData(GPS_Data_t* gps_data) -{ - // Validate GPS data - if (!GPS_IsDataValid(gps_data)) { - return; - } - - // Update current GPS data - memcpy(¤t_gps, gps_data, sizeof(GPS_Data_t)); - current_gps.timestamp = HAL_GetTick(); - - // Send to GUI - GPS_SendToGUI(¤t_gps); -} - -void GPS_SendToGUI(GPS_Data_t* gps_data) -{ - if (gui_huart == NULL) return; - - // Create packet: "GPS:lat,lon,alt\r\n" - char buffer[64]; + return 1; +} + +bool GPS_ProcessData(GPS_Data_t* gps_data) +{ + // Validate GPS data + if (!GPS_IsDataValid(gps_data)) { + return false; + } + + // Update current GPS data + memcpy(¤t_gps, gps_data, sizeof(GPS_Data_t)); + current_gps.timestamp = HAL_GetTick(); + + // Send to GUI + return GPS_SendToGUI(¤t_gps); +} + +bool GPS_SendToGUI(GPS_Data_t* gps_data) +{ + if (gui_huart == NULL || gps_data == NULL) { + return false; + } + + // Create packet: "GPS:lat,lon,alt\r\n" + char buffer[64]; // Convert double and float to string with high precision int len = snprintf(buffer, sizeof(buffer), "GPS:%.8f,%.8f,%.2f\r\n", @@ -55,19 +62,23 @@ void GPS_SendToGUI(GPS_Data_t* gps_data) gps_data->longitude, gps_data->altitude); - if (len > 0 && len < (int)sizeof(buffer)) { - // Send via UART3 to GUI - HAL_UART_Transmit(gui_huart, (uint8_t*)buffer, len, 1000); - } -} - -// Alternative binary protocol version (more efficient) -void GPS_SendBinaryToGUI(GPS_Data_t* gps_data) -{ - if (gui_huart == NULL) return; - - // Binary packet structure: - // [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes] + if (len <= 0 || len >= (int)sizeof(buffer)) { + return false; + } + + // Send via UART3 to GUI + return HAL_UART_Transmit(gui_huart, (uint8_t*)buffer, len, 1000) == HAL_OK; +} + +// Alternative binary protocol version (more efficient) +bool GPS_SendBinaryToGUI(GPS_Data_t* gps_data) +{ + if (gui_huart == NULL || gps_data == NULL) { + return false; + } + + // Binary packet structure: + // [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes] uint8_t packet[30]; // 4 + 8 + 8 + 4 + 4 + 2 = 30 bytes uint16_t crc = 0; @@ -99,10 +110,10 @@ void GPS_SendBinaryToGUI(GPS_Data_t* gps_data) packet[20 + i] = (alt_bits >> (24 - i*8)) & 0xFF; } - // Convert float altitude to bytes (big-endian) - uint32_t pitch_bits; - memcpy(&pitch_bits, &gps_data->pitch, sizeof(float)); - for(int i = 0; i < 4; i++) { + // Convert float pitch to bytes (big-endian) + uint32_t pitch_bits; + memcpy(&pitch_bits, &gps_data->pitch, sizeof(float)); + for(int i = 0; i < 4; i++) { packet[24 + i] = (pitch_bits >> (24 - i*8)) & 0xFF; } @@ -112,8 +123,8 @@ void GPS_SendBinaryToGUI(GPS_Data_t* gps_data) } packet[28] = (crc >> 8) & 0xFF; - packet[29] = crc & 0xFF; - - // Send binary packet - CDC_Transmit_FS(packet, sizeof(packet)); -} + packet[29] = crc & 0xFF; + + // Send binary packet + return CDC_Transmit_FS(packet, sizeof(packet)) == USBD_OK; +} diff --git a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.h b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.h index 0425698..73f7b02 100644 --- a/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.h +++ b/9_Firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/gps_handler.h @@ -3,10 +3,11 @@ #define GPS_HANDLER_H #include "main.h" -#include "usb_device.h" -#include "usbd_cdc_if.h" -#include -#include +#include "usb_device.h" +#include "usbd_cdc_if.h" +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -20,11 +21,11 @@ typedef struct { uint32_t timestamp; } GPS_Data_t; -void GPS_Init(UART_HandleTypeDef* huart); -void GPS_ProcessData(GPS_Data_t* gps_data); -void GPS_SendToGUI(GPS_Data_t* gps_data); -void GPS_SendBinaryToGUI(GPS_Data_t* gps_data); -uint8_t GPS_IsDataValid(GPS_Data_t* gps_data); +void GPS_Init(UART_HandleTypeDef* huart); +bool GPS_ProcessData(GPS_Data_t* gps_data); +bool GPS_SendToGUI(GPS_Data_t* gps_data); +bool GPS_SendBinaryToGUI(GPS_Data_t* gps_data); +uint8_t GPS_IsDataValid(GPS_Data_t* gps_data); #ifdef __cplusplus } diff --git a/9_Firmware/9_1_Microcontroller/9_1_3_C_Cpp_Code/main.cpp b/9_Firmware/9_1_Microcontroller/9_1_3_C_Cpp_Code/main.cpp index 0daa07d..ef1be6e 100644 --- a/9_Firmware/9_1_Microcontroller/9_1_3_C_Cpp_Code/main.cpp +++ b/9_Firmware/9_1_Microcontroller/9_1_3_C_Cpp_Code/main.cpp @@ -617,14 +617,13 @@ SystemError_t checkSystemHealth(void) { } } - // 4. Check IMU Communication - static uint32_t last_imu_check = 0; - if (HAL_GetTick() - last_imu_check > 10000) { - GY85_Update(&imu); - if (isnan(imu.ax) || isnan(imu.ay) || isnan(imu.az)) { - current_error = ERROR_IMU_COMM; - } - last_imu_check = HAL_GetTick(); + // 4. Check IMU Communication + static uint32_t last_imu_check = 0; + if (HAL_GetTick() - last_imu_check > 10000) { + if (!GY85_Update(&imu)) { + current_error = ERROR_IMU_COMM; + } + last_imu_check = HAL_GetTick(); } // 5. Check BMP180 Communication @@ -1274,14 +1273,18 @@ int main(void) HAL_Delay(100); HAL_GPIO_WritePin(EN_P_3V3_FPGA_GPIO_Port,EN_P_3V3_FPGA_Pin,GPIO_PIN_SET); HAL_Delay(100); - - -// Initialize module IMU - GY85_Init(); - for(int i=0; i<10;i++){ - GY85_Update(&imu); - - ax = imu.ax; + + +// Initialize module IMU + if (!GY85_Init()) { + Error_Handler(); + } + for(int i=0; i<10;i++){ + if (!GY85_Update(&imu)) { + Error_Handler(); + } + + ax = imu.ax; ay = imu.ay; az = imu.az; gx = -imu.gx; @@ -1524,11 +1527,14 @@ int main(void) /**********wait for GUI start flag and Send Lat/Long/alt********/ /***************************************************************/ - GPS_Data_t gps_data; - // Binary packet structure: - // [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][CRC 2 bytes] - gps_data = {RADAR_Latitude, RADAR_Longitude, RADAR_Altitude, Pitch_Sensor, HAL_GetTick()}; - GPS_SendBinaryToGUI(&gps_data); + GPS_Data_t gps_data; + // Binary packet structure: + // [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes] + gps_data = {RADAR_Latitude, RADAR_Longitude, RADAR_Altitude, Pitch_Sensor, HAL_GetTick()}; + if (!GPS_SendBinaryToGUI(&gps_data)) { + const uint8_t gps_send_error[] = "GPS binary send failed\r\n"; + HAL_UART_Transmit(&huart3, (uint8_t*)gps_send_error, sizeof(gps_send_error) - 1, 1000); + } // Check if start flag was received and settings are ready do{ diff --git a/9_Firmware/9_3_GUI/GUI_V5.py b/9_Firmware/9_3_GUI/GUI_V5.py index 336a143..972e6ae 100644 --- a/9_Firmware/9_3_GUI/GUI_V5.py +++ b/9_Firmware/9_3_GUI/GUI_V5.py @@ -47,10 +47,23 @@ DARK_ACCENT = "#3c3f41" DARK_HIGHLIGHT = "#4e5254" DARK_BORDER = "#555555" DARK_TEXT = "#cccccc" -DARK_BUTTON = "#3c3f41" -DARK_BUTTON_HOVER = "#4e5254" -DARK_TREEVIEW = "#3c3f41" -DARK_TREEVIEW_ALT = "#404040" +DARK_BUTTON = "#3c3f41" +DARK_BUTTON_HOVER = "#4e5254" +DARK_TREEVIEW = "#3c3f41" +DARK_TREEVIEW_ALT = "#404040" + +RADAR_SETTINGS_LIMITS = { + 'system_frequency': (1e9, 100e9), + 'chirp_duration_1': (1e-6, 1000e-6), + 'chirp_duration_2': (0.1e-6, 10e-6), + 'chirps_per_position': (1, 256), + 'freq_min': (1e6, 100e6), + 'freq_max': (1e6, 100e6), + 'prf1': (100, 10000), + 'prf2': (100, 10000), + 'max_distance': (100, 100000), + 'map_size': (1000, 200000), +} @dataclass class RadarTarget: @@ -1125,10 +1138,10 @@ class RadarGUI: self.map_info_label = ttk.Label(info_frame, text="No GPS data received yet", font=('Arial', 10)) self.map_info_label.pack() - def setup_settings_tab(self): - """Setup the settings tab with additional chirp durations and map size""" - settings_frame = ttk.Frame(self.tab_settings) - settings_frame.pack(fill='both', expand=True, padx=10, pady=10) + def setup_settings_tab(self): + """Setup the settings tab with additional chirp durations and map size""" + settings_frame = ttk.Frame(self.tab_settings) + settings_frame.pack(fill='both', expand=True, padx=10, pady=10) entries = [ ('System Frequency (Hz):', 'system_frequency', 10e9), @@ -1153,8 +1166,40 @@ class RadarGUI: entry.grid(row=i, column=1, padx=5, pady=5) self.settings_vars[attr] = var - ttk.Button(settings_frame, text="Apply Settings", - command=self.apply_settings).grid(row=len(entries), column=0, columnspan=2, pady=10) + ttk.Button(settings_frame, text="Apply Settings", + command=self.apply_settings).grid(row=len(entries), column=0, columnspan=2, pady=10) + + def _parse_settings_from_form(self): + """Read settings from the UI and return a validated RadarSettings instance.""" + parsed_settings = RadarSettings( + system_frequency=float(self.settings_vars['system_frequency'].get()), + chirp_duration_1=float(self.settings_vars['chirp_duration_1'].get()), + chirp_duration_2=float(self.settings_vars['chirp_duration_2'].get()), + chirps_per_position=int(self.settings_vars['chirps_per_position'].get()), + freq_min=float(self.settings_vars['freq_min'].get()), + freq_max=float(self.settings_vars['freq_max'].get()), + prf1=float(self.settings_vars['prf1'].get()), + prf2=float(self.settings_vars['prf2'].get()), + max_distance=float(self.settings_vars['max_distance'].get()), + map_size=float(self.settings_vars['map_size'].get()), + ) + + self._validate_radar_settings(parsed_settings) + return parsed_settings + + def _validate_radar_settings(self, settings): + """Mirror the firmware-side range checks before sending settings to STM32.""" + for field_name, (minimum, maximum) in RADAR_SETTINGS_LIMITS.items(): + value = getattr(settings, field_name) + if value < minimum or value > maximum: + raise ValueError( + f"{field_name} must be between {minimum:g} and {maximum:g}." + ) + + if settings.freq_max <= settings.freq_min: + raise ValueError("freq_max must be greater than freq_min.") + + return True def apply_pitch_correction(self, raw_elevation, pitch_angle): """ @@ -1262,29 +1307,28 @@ class RadarGUI: logging.info("Radar system stopped") - def apply_settings(self): - """Step 13: Apply and send radar settings via USB""" - try: - self.settings.system_frequency = float(self.settings_vars['system_frequency'].get()) - self.settings.chirp_duration_1 = float(self.settings_vars['chirp_duration_1'].get()) - self.settings.chirp_duration_2 = float(self.settings_vars['chirp_duration_2'].get()) - self.settings.chirps_per_position = int(self.settings_vars['chirps_per_position'].get()) - self.settings.freq_min = float(self.settings_vars['freq_min'].get()) - self.settings.freq_max = float(self.settings_vars['freq_max'].get()) - self.settings.prf1 = float(self.settings_vars['prf1'].get()) - self.settings.prf2 = float(self.settings_vars['prf2'].get()) - self.settings.max_distance = float(self.settings_vars['max_distance'].get()) - self.settings.map_size = float(self.settings_vars['map_size'].get()) - self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get() - - if self.stm32_usb_interface.is_open: - self.stm32_usb_interface.send_settings(self.settings) - - messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB") - logging.info("Radar settings applied via USB") - - except ValueError as e: - messagebox.showerror("Error", f"Invalid setting value: {e}") + def apply_settings(self): + """Step 13: Apply and send radar settings via USB""" + try: + parsed_settings = self._parse_settings_from_form() + self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get() + + self.settings = parsed_settings + + if self.stm32_usb_interface.is_open: + if not self.stm32_usb_interface.send_settings(self.settings): + messagebox.showerror("Error", "Failed to send settings to STM32 via USB") + logging.error("Radar settings validation passed, but USB send failed") + return + + messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB") + logging.info("Radar settings applied and sent via USB") + else: + messagebox.showinfo("Success", "Settings applied locally") + logging.info("Radar settings applied locally; STM32 USB is not connected") + + except ValueError as e: + messagebox.showerror("Error", f"Invalid setting value: {e}") def start_background_threads(self): """Start background data processing threads""" diff --git a/Licence b/Licence new file mode 100644 index 0000000..53167e5 --- /dev/null +++ b/Licence @@ -0,0 +1,154 @@ +CERN Open Hardware Licence Version 2 - Permissive + +Preamble + +CERN has developed this licence to promote collaboration among +hardware designers and to provide a legal tool for the dissemination +of hardware designs. The CERN Open Hardware Licence Version 2 is +available in two variants: Weakly Reciprocal (CERN-OHL-W) and +Permissive (CERN-OHL-P). The CERN-OHL-P is for you if you want to +maximise the ability of people to use your hardware design +including for use in commercial applications with a minimum of +obligations. It is a continuation of the CERN Open Hardware Licence +version 1 (but with a new structure) and is focused more narrowly +on the design itself and what you must do to give proper credit and +to allow others to build and modify the design. + +Please see the CERN-OHL version 2 family page (www.ohwr.org/cernohl) +for more information. + +Terms and conditions + +1. Definitions + +In this Licence, the following terms have the following meanings: + +“Additive” means something you add to the Design that was not part +of it when it was first published by the Licensor. + +“Design” means the design documentation for the hardware that is +licensed under this Licence, in any format or medium. It may +include both the Hardware Description and the Modifications. + +“Documentation” means all the materials that are provided by the +Licensor or any Contributor to describe the Design, including +schematics, netlists, PCB layout files, bills of materials, +drawings, specifications, and the like, and also includes the +Modifications. + +“Hardware” means any physical device that embodies the Design or +any part thereof, in any form. + +“Hardware Description” means the files that specify the Hardware in +a form that can be read by a computer and that, when used +appropriately, can be used to fabricate Hardware, for example in +whole or in part. + +“Licence” means this licence (the CERN-OHL-P). + +“Licensor” means the person or entity that first publishes the +Design under the terms of this Licence. + +“Modification” means any change to the Design, including changes to +the Hardware Description. + +“Product” means either an unchanged Design or a Design with +Modifications, that is offered for sale, or otherwise made +available for commercial use, whether as Hardware or in other forms. + +“Source” means the format of the Design that is preferred for +making Modifications, including all the files that are provided for +that purpose. + +“You” means any person or entity that exercises any right under +this Licence. + +2. What this Licence covers + +The Licensor grants you a worldwide, royalty-free, non-exclusive, +perpetual licence to: + +a) use the Design and any associated Documentation, +b) make Modifications, +c) communicate the Design and any Documentation, including by + making it available for copying and modification, +d) manufacture and distribute Hardware that implements the Design + or any part thereof, +e) sell Products, and +f) otherwise deal in the Design or any part thereof, + +all in each case subject to the conditions set out in this Licence. + +3. Conditions + +3.1. Availability of Source + +The Design and any Documentation that is made available under this +Licence must be made available in Source format. If the Design is +available in a format that is not Source, you must also make a +version of the Design in Source format available, and you must +inform others of how to obtain it. + +3.2. Retention of copyright and other notices + +You must retain all copyright and other notices that appear in the +Design or Documentation. + +3.3. Notice of Modifications + +If you make Modifications, you must include a notice in any +Distribution of the Design or Documentation, stating that +Modifications have been made, by whom, and in what they consist. + +3.4. Distribution of Modifications + +If you distribute any Design or Documentation, whether unchanged or +with Modifications, you must distribute it under this Licence, and +you must inform the recipient that the Design or Documentation is +licensed under this Licence. + +3.5. No implicit approval + +The Licensor shall not be taken to have approved any Modifications +unless the Licessor expressly approves them in writing. + +4. Disclaimer of warranty + +THE DESIGN AND ANY DOCUMENTATION IS PROVIDED "AS IS" AND THE +LICENSOR MAKES NO WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY, +NON-INFRINGEMENT, TITLE, AND FITNESS FOR A PARTICULAR PURPOSE. THE +DESIGN MAY CONTAIN DESIGN DEFECTS OR ERRORS THAT MAKE IT +UNSUITABLE FOR USE IN CERTAIN APPLICATIONS. THE ENTIRE RISK AS TO +ITS QUALITY AND PERFORMANCE REMAINS WITH YOU. + +5. Limitation of liability + +TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL THE LICENSOR +BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION +LOST PROFITS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR ANY +OTHER LOSSES ARISING OUT OF THE USE OF THE DESIGN OR ANY +DOCUMENTATION, HOWEVER CAUSED, WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY, OR OTHERWISE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +6. Termination + +This Licence is perpetual except that if you fail to comply with +its terms, your rights under this Licence will terminate immediately. +If you bring or defend any litigation or other claim alleging that +the Design or any part thereof infringes any intellectual property +right, all your rights under this Licence granted by the Licensor +will terminate forty-five days after you bring or defend such claim. + +7. General + +This Licence shall be governed by the laws of the country of the +Licensor, without reference to its conflict of laws provisions. +If any part of this Licence is held to be invalid or unenforceable, +the remaining parts shall remain in full force and effect. + +--------------------------------------------------------------------- + +CERN-OHL-P is a variant of the CERN-OHL family. For more information +see www.ohwr.org/cernohl. diff --git a/README.md b/README.md index 7bb7ecd..86d2147 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # AERIS-10: Open Source Pulse Linear Frequency Modulated Phased Array Radar -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Hardware: CERN-OHL-P](https://img.shields.io/badge/Hardware-CERN--OHL--P-blue.svg)](https://ohwr.org/cern_ohl_p_v2.txt) +[![Software: MIT](https://img.shields.io/badge/Software-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Status: Alpha](https://img.shields.io/badge/Status-Alpha-orange)](https://github.com/NawfalMotii79/PLFM_RADAR) [![Frequency: 10.5GHz](https://img.shields.io/badge/Frequency-10.5GHz-blue)](https://github.com/NawfalMotii79/PLFM_RADAR)) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/NawfalMotii79/PLFM_RADAR/pulls) @@ -142,3 +143,41 @@ The AERIS-10 main sub-systems are: 4. **Antenna**: Choose appropriate array for your version 5. **Enclosure**: 3D printable files in `/10_docs/Hardware/Enclosure` +## 📜 License + +This project is open-source but uses **different licenses for hardware and software** to ensure proper legal coverage. + +### Hardware Documentation +The hardware design files—including: +- Schematics and PCB layouts (in `/4_Schematics and Boards Layout`) +- Bill of Materials (BOM) files +- Gerber files and manufacturing outputs +- Mechanical drawings and enclosure designs + +are licensed under the **CERN Open Hardware Licence Version 2 – Permissive (CERN-OHL-P)** . + +This is a hardware-specific license that: +- ✅ Clearly defines "Hardware," "Documentation," and "Products" +- ✅ Includes explicit patent protection for contributors and users +- ✅ Provides stronger liability limitations (important for high-power RF) +- ✅ Aligns with professional open-hardware standards (CERN, OSHWA) + +You may use, modify, and sell products based on these designs, provided you: +- Maintain the original copyright notices +- Distribute any modified designs under the same license +- Make your modifications available in Source format + +### Software and Firmware +The software components—including: +- FPGA code (VHDL/Verilog in `/9_Firmware`) +- Microcontroller firmware (STM32) +- Python GUI and utilities + +remain under the **MIT License** for maximum flexibility. + +### Full License Texts +- The complete CERN-OHL-P license text is in the `LICENSE` file +- MIT license terms apply to software where not otherwise specified + +### Why This Change? +Originally, the entire project used the MIT license. The community (special thanks to [GitHub Username]!) pointed out that MIT lacks legal protections needed for physical hardware. The switch to CERN-OHL-P ensures the project is properly protected while maintaining the same permissive spirit.