Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
674806b
feature: add module for BME280 sensor.
Vavat Jul 24, 2022
1e3a824
feature: transfer Sam's code unmodified to a new module.
Vavat Jul 24, 2022
852b544
feature: add sensor initialisation method
Vavat Jul 25, 2022
7c55e7f
docs: add doxygen headers to methods.
Vavat Jul 25, 2022
4780510
feature: add conversion of raw data stream into raw structured data.
Vavat Jul 25, 2022
59dfe1f
feature: add basic state machine to run sensor.
Vavat Jul 25, 2022
65d9806
wip
Vavat Jul 25, 2022
0f24701
wip.
Vavat Jul 28, 2022
65218ba
feature: add ADC data receive functionality.
Vavat Jul 30, 2022
661c567
feature: enable IRQ for SPI2 engine.
Vavat Jul 30, 2022
e260093
feature: add IRQ callback via static method.
Vavat Jul 30, 2022
b1a5ac6
wip.
Vavat Jul 30, 2022
4254bc6
feature: modify calibration from integer to float.
Vavat Aug 7, 2022
d37fde7
feature: implement raw data calibration for T, P, and H measurements.
Vavat Aug 7, 2022
53006bd
central sensor version
samkno1 Aug 24, 2022
7da5c58
feature: humidity controller setup
samkno1 Aug 24, 2022
c28330b
feature: humidity controller
samkno1 Aug 28, 2022
1d31b19
Merge branch 'develop' into samk_humidity_control
samkno1 Aug 29, 2022
b9f5c75
WIP: Humidity controller
samkno1 Sep 30, 2022
7541937
feature: add humidifier interface methods to the hardware maps.
Vavat Oct 2, 2022
fd3b55f
feature: add real hardware map implementation of the humidifier.
Vavat Oct 2, 2022
609e31d
Merge pull request #122 from Niuslar/feature/srm_humidifier_hardware
samkno1 Oct 8, 2022
eabb573
Implemented with 1 channel and humidifier abstracted by Hardware Map …
samkno1 Oct 16, 2022
b829813
Fixed commenting
samkno1 Oct 16, 2022
8d051b0
fix: Early SPI initialization error
samkno1 Dec 28, 2022
1fe05a7
feature: getHumidifierPower
samkno1 Dec 28, 2022
e7eac1c
fix: HumidityController
samkno1 Dec 29, 2022
ae24b4b
fix: HumidityController
samkno1 Dec 29, 2022
e358cf0
fix: Early SPI initialization error
samkno1 Dec 29, 2022
78eac06
format: changed variable types for safer implementation
samkno1 Feb 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions Controllers/CHumidityController.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* CHumidityController.cpp
*
* Created on: Aug. 11, 2022
* Author: samk
*/

#include "CHumidityController.h"
#include <stdio.h>

CHumidityController::CHumidityController(IHardwareMap *p_hardware,
etl::string<MAX_STRING_SIZE> name,
uint32_t run_period_ms,
SPI_HandleTypeDef *p_spi,
GPIO_TypeDef *p_slave_select_port,
uint16_t slave_select_pin)
: CController(name, run_period_ms),
mp_hw(p_hardware)
{
// TODO Auto-generated constructor stub
reset();

// TODO Fix this constructor
// CBME280 humidity_sensor(p_spi, p_slave_select_port, slave_select_pin);
// mp_humidity_sensor = &humidity_sensor;
}

/**
* @brief Run all repeated humidity control activities.
*
*/
void CHumidityController::run()
{
float power = 0;
if (m_power_override == DISABLE_OVERRIDE)
{
if (m_target_humidity != DISABLE_TARGET)
{
float actual_humidity = mp_humidity_sensor->getHumidity();
power = m_control_loop.run(m_target_humidity, actual_humidity);
}
}
else
{
power = m_power_override;
}
mp_hw->setHumidifierPower(power);
}

bool CHumidityController::newCommand(ICommand *p_command,
IComChannel *p_comchannel)
{
bool b_command_recognised = false;
ICommand::command_error_code_t result = ICommand::COMMAND_OK;
if (p_command->getName()->compare("?humidity") == 0)
{
sendStatus(p_comchannel);
b_command_recognised = true;
}

if (p_command->getName()->compare("humidity") == 0)
{
result = setHumidity(p_command);
b_command_recognised = true;
}

if (p_command->getName()->compare("heater") == 0)
{
result = overrideHumidifier(p_command);
b_command_recognised = true;
}
if (b_command_recognised)
{
switch (result)
{
case ICommand::COMMAND_OK:
// p_comchannel->send("OK.\n");
break;
case ICommand::ERROR_ARG_COUNT:
p_comchannel->send("Wrong number of arguments.\n");
break;
case ICommand::ERROR_OUT_OF_BOUNDS:
p_comchannel->send("Argument out of bounds.\n");
break;
case ICommand::ERROR_TYPE_MISMATCH:
p_comchannel->send("Argument type mismatch.\n");
break;
default:
p_comchannel->send("Non-specific error with the command.");
}
}
return b_command_recognised;
}

void CHumidityController::reset()
{
m_target_humidity = DISABLE_TARGET;
m_power_override = DISABLE_OVERRIDE;
m_control_loop.reset();
}

void CHumidityController::sendStatus(IComChannel *p_comchannel)
{
etl::string<MAX_STRING_SIZE> message;
char value[10];
// send target humidity
message.assign("Target: ");
sprintf(value, "%2.1f", m_target_humidity);
message.append(value);
p_comchannel->send(message);
// Send actual humidity
message.assign("Humidity: ");
sprintf(value, "%2.1f, ", mp_humidity_sensor->getHumidity());
message.append(value);
p_comchannel->send(message);
// Send heater power
message.assign("Power: ");
float power;
if (m_power_override == DISABLE_OVERRIDE)
{
power = mp_hw->getHardPwmOutput(CHANNEL_NUMBER - 1);
}
else
{
power = m_power_override;
}
sprintf(value, "%4.1f, ", power);
message.append(value);
p_comchannel->send(message);
}

/**
* @brief Set humidity value
*/
ICommand::command_error_code_t CHumidityController::setHumidity(
ICommand *p_command)
{
// Sanitise command arguments
if (p_command->getArgumentCount() != 1)
{
return ICommand::ERROR_ARG_COUNT;
}
m_target_humidity = (*p_command)[0];

if (m_target_humidity > MAX_HUMIDITY)
{
m_target_humidity = MAX_HUMIDITY;
}
if ((m_target_humidity < MIN_HUMIDITY) &&
(m_target_humidity != DISABLE_TARGET))
{
m_target_humidity = MIN_HUMIDITY;
}

return ICommand::COMMAND_OK;
}

ICommand::command_error_code_t CHumidityController::overrideHumidifier(
ICommand *p_command)
{
// Sanitise command arguments
if (p_command->getArgumentCount() != 1)
{
return ICommand::ERROR_ARG_COUNT;
}
float power = (*p_command)[0];

// Execute command
if (power > MAX_POWER)
{
power = MAX_POWER;
}
if ((power < MIN_POWER) && (power != DISABLE_OVERRIDE))
{
power = MIN_POWER;
}
m_power_override = power;
return ICommand::COMMAND_OK;
}
51 changes: 51 additions & 0 deletions Controllers/CHumidityController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* CHumidityController.h
*
* Created on: Aug. 11, 2022
* Author: samk
*/

#ifndef CHUMIDITYCONTROLLER_H_
#define CHUMIDITYCONTROLLER_H_

#include "CBME280.h"
#include "CController.h"
#include "CHumidifier.h"
#include "CPIDLoop.h"
#include "IHardwareMap.h"

class CHumidityController : public CController
{
public:
CHumidityController(IHardwareMap *p_hardwaremap,
etl::string<MAX_STRING_SIZE> name,
uint32_t run_period_ms,
SPI_HandleTypeDef *p_spi,
GPIO_TypeDef *p_slave_select_port,
uint16_t slave_select_pin);
virtual void run();
virtual bool newCommand(ICommand *p_command, IComChannel *p_comchannel);
virtual void reset();

private:
static constexpr uint8_t CHANNEL_NUMBER = 1;
static constexpr uint8_t MAX_HUMIDITY = 95;
static constexpr uint8_t MIN_HUMIDITY = 85;
static constexpr uint8_t MAX_POWER = 100;
static constexpr uint8_t MIN_POWER = 0;
static constexpr uint8_t DISABLE_OVERRIDE = -1;
static constexpr uint8_t DISABLE_TARGET = 0;
void sendStatus(IComChannel *p_comchannel);
ICommand::command_error_code_t setHumidity(ICommand *p_command);
ICommand::command_error_code_t overrideHumidifier(ICommand *p_command);

IHardwareMap *mp_hw;

CBME280 *mp_humidity_sensor;

float m_target_humidity;
float m_power_override;
CPIDLoop m_control_loop;
};

#endif /* CHUMIDITYCONTROLLER_H_ */
1 change: 1 addition & 0 deletions Core/Inc/stm32f4xx_it.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void SPI2_IRQHandler(void);
void USART1_IRQHandler(void);
void USART2_IRQHandler(void);
void DMA2_Stream0_IRQHandler(void);
Expand Down
5 changes: 5 additions & 0 deletions Core/Src/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/* SPI2 interrupt Init */
HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI2_IRQn);
/* USER CODE BEGIN SPI2_MspInit 1 */

/* USER CODE END SPI2_MspInit 1 */
Expand All @@ -110,6 +113,8 @@ void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_12|GPIO_PIN_14|GPIO_PIN_15);

/* SPI2 interrupt Deinit */
HAL_NVIC_DisableIRQ(SPI2_IRQn);
/* USER CODE BEGIN SPI2_MspDeInit 1 */

/* USER CODE END SPI2_MspDeInit 1 */
Expand Down
15 changes: 15 additions & 0 deletions Core/Src/stm32f4xx_it.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@

/* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_adc1;
extern SPI_HandleTypeDef hspi2;
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart2;
/* USER CODE BEGIN EV */
Expand Down Expand Up @@ -200,6 +201,20 @@ void SysTick_Handler(void)
/* please refer to the startup file (startup_stm32f4xx.s). */
/******************************************************************************/

/**
* @brief This function handles SPI2 global interrupt.
*/
void SPI2_IRQHandler(void)
{
/* USER CODE BEGIN SPI2_IRQn 0 */

/* USER CODE END SPI2_IRQn 0 */
HAL_SPI_IRQHandler(&hspi2);
/* USER CODE BEGIN SPI2_IRQn 1 */

/* USER CODE END SPI2_IRQn 1 */
}

/**
* @brief This function handles USART1 global interrupt.
*/
Expand Down
5 changes: 5 additions & 0 deletions Hardware/CMockHardwareMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ void CMockHardwareMap::enableControlPower(bool b_enable)
mb_power_enable = b_enable;
}

void CMockHardwareMap::setHumidifierPower(float power)
{
// TODO: This should modify internal model variables for humidity.
}

void CMockHardwareMap::run()
{
float total_radiator_flow = 0;
Expand Down
2 changes: 2 additions & 0 deletions Hardware/CMockHardwareMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class CMockHardwareMap : public IHardwareMap, public CController
#endif
virtual void setBreathingLight(float duty_cycle);
virtual void enableControlPower(bool b_enable);
virtual void setHumidifierPower(float power);
virtual bool getHumidifierPower();
/* CController methods. */
// etl::string<MAX_STRING_SIZE> getName() const;
// virtual bool tick(uint32_t current_time);
Expand Down
39 changes: 38 additions & 1 deletion Hardware/CRealHardwareMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
#define AD22100_SCALE ((V_REF / 5.0) * (1 / 22.5E-3))
#define AD22100_OFFSET ((V_REF / 5.0) * (-1.375 / 22.5E-3))

/* This section maps generic names of the pins to something that makes sense.
* We'll do it this way for now until hardware configuration settles down at
* which point the pin names will be renamed. */
#define EVAPORATOR_GPIO_Port ENABLE_8_GPIO_Port
#define EVAPORATOR_Pin ENABLE_8_Pin

const CRealHardwareMap::timer_init_map_t CRealHardwareMap::s_timer_init_map[] =
{{&htim1, TIM_CHANNEL_1},
{&htim4, TIM_CHANNEL_1},
Expand Down Expand Up @@ -76,7 +82,8 @@ void CRealHardwareMap::init()
s_gpio_init_map[i].pin);
}
m_breathing_light.init(&htim2, TIM_CHANNEL_1);
m_power_enable.init(BREATHING_GPIO_Port, BREATHING_Pin);
m_power_enable.init(PWR_EN_GPIO_Port, PWR_EN_Pin);
m_humidifier_enable.init(EVAPORATOR_GPIO_Port, EVAPORATOR_Pin);
}

/**
Expand Down Expand Up @@ -167,3 +174,33 @@ void CRealHardwareMap::enableControlPower(bool b_enable)
{
m_power_enable.set(b_enable);
}

/**
* @brief This assumes that the humidifier is implemented as an atomiser.
* @note The longer the atomiser is enabled the more vapour it'll generate. This
* way PID control is still possible, but care should be taken to not set
* integral component too high since atomiser itself will work as an integrator.
*
* @param power Is essentially a boolean value. Anything above zero enables
* atomiser.
*/
void CRealHardwareMap::setHumidifierPower(float power)
{
if (power > 0)
{
m_humidifier_enable.set(true);
}
else
{
m_humidifier_enable.set(false);
}
}
/**
* @brief Get the power state of the humidifier.
*
* @return True: Humidifier active. False: Humidifier inactive.
*/
bool CRealHardwareMap::getHumidifierPower()
{
return m_humidifier_enable.get();
}
3 changes: 3 additions & 0 deletions Hardware/CRealHardwareMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class CRealHardwareMap : public IHardwareMap
#endif
virtual void setBreathingLight(float duty_cycle);
virtual void enableControlPower(bool b_enable);
virtual void setHumidifierPower(float power);
virtual bool getHumidifierPower();

private:
typedef struct TIMER_INIT_MAP_T
Expand All @@ -60,6 +62,7 @@ class CRealHardwareMap : public IHardwareMap
CGpioWrapper m_polarity_switch[HARD_PWM_OUTPUTS];
CHardPwmOutput m_breathing_light;
CGpioWrapper m_power_enable;
CGpioWrapper m_humidifier_enable;
#ifdef SOFT_PWM_OUTPUTS
CSoftPwmOutput m_soft_pwm_output[SOFT_PWM_OUTPUTS];
#endif
Expand Down
Loading