Compare commits

...

3 Commits

  1. 23
      backend/monsun_backend/command_execution.py
  2. 174
      backend/monsun_backend/commands.py
  3. 2
      nucleo-wb55-ble/Core/Inc/main.h
  4. 23
      nucleo-wb55-ble/Core/Inc/pump_control.h
  5. 21
      nucleo-wb55-ble/Core/Inc/pump_control.hpp
  6. 13
      nucleo-wb55-ble/Core/Src/main.c
  7. 65
      nucleo-wb55-ble/Core/Src/pump_control.cpp
  8. 59
      nucleo-wb55-ble/commands/PumpCommand.cpp
  9. 48
      nucleo-wb55-ble/commands/PumpCommand.hpp
  10. 4
      nucleo-wb55-ble/commands/dispatch.cpp
  11. 51
      nucleo-wb55-ble/nucleo-wb55-ble.ioc
  12. 2
      nucleo-wb55-dongle-ble/shared_commands/commands.hpp

23
backend/monsun_backend/command_execution.py

@ -22,6 +22,7 @@ from .commands import CommandId
from .commands import CommandTarget
from .commands import Request
from .commands import Response
from .commands import get_response_class
from .container import get_initialize_container
_logger = logging.getLogger(__file__)
@ -343,21 +344,17 @@ class SerialReceiver:
data=command_interpreter.payload,
)
commands_received.append(command)
elif command_id == CommandId.command_heartbeat_response:
responses_received.append(
commands.HeartbeatResponse(command_interpreter.payload),
)
elif command_id == CommandId.command_led_response:
responses_received.append(
commands.LEDResponse(command_interpreter.payload),
)
elif command_id == CommandId.command_gp_response:
responses_received.append(
commands.GPResponse(command_interpreter.payload),
)
else:
continue
try:
response_class = get_response_class(command_id=command_id)
except KeyError:
raise RuntimeError
responses_received.append(
response_class(command_interpreter.payload),
)
return commands_received, responses_received

174
backend/monsun_backend/commands.py

@ -5,6 +5,8 @@ from enum import Enum
from random import randint
from struct import pack
from struct import unpack
from typing import Dict
from typing import Type
from typing import Union
from serial import Serial
@ -25,41 +27,15 @@ class CommandId(Enum):
command_gp_request = 0x6
command_gp_response = 0x7
command_pump_request = 0x8
command_pump_response = 0x9
class CommandTarget(Enum):
client = 0
server = 1
def get_command_id_from_name(name: str) -> CommandId:
return {
"log": CommandId.command_log,
"led": CommandId.command_led_request,
"gp": CommandId.command_gp_request,
}[name]
def get_request_class(
command_id: CommandId,
):
return {
CommandId.command_log: LogCommand,
CommandId.command_heartbeat_request: HeartbeatRequest,
CommandId.command_led_request: LEDRequest,
CommandId.command_gp_request: GPRequest,
}[command_id]
def get_response_class(
command_id: CommandId,
):
return {
CommandId.command_heartbeat_response: HeartbeatResponse,
CommandId.command_led_response: LEDResponse,
CommandId.command_gp_response: GPResponse,
}[command_id]
class Response(abc.ABC):
identifier: int
@ -148,6 +124,43 @@ class Request(Command):
)
__command_alias: Dict[str, CommandId] = dict()
__request_by_id: Dict[CommandId, Type[Request]] = dict()
__response_by_id: Dict[CommandId, Type[Response]] = dict()
def get_command_id_from_name(name: str) -> CommandId:
return __command_alias[name]
def get_request_class(
command_id: CommandId,
):
return __request_by_id[command_id]
def get_response_class(
command_id: CommandId,
):
return __response_by_id[command_id]
def register_request(
cls: Type[Request],
command_id: CommandId,
alias: str,
):
__command_alias[alias] = command_id
__request_by_id[command_id] = cls
def register_response(
cls: Type[Response],
command_id: CommandId,
):
__response_by_id[command_id] = cls
@dataclass
class LogCommand(Command):
"""Command ID: command_log"""
@ -216,6 +229,17 @@ class HeartbeatRequest(Request):
)
register_request(
cls=HeartbeatRequest,
command_id=CommandId.command_heartbeat_request,
alias="hp",
)
register_response(
cls=HeartbeatResponse,
command_id=CommandId.command_heartbeat_response,
)
class LEDResponse(Response):
was_successful = True
@ -293,6 +317,17 @@ class LEDRequest(Request):
)
register_request(
cls=LEDRequest,
command_id=CommandId.command_led_request,
alias="led",
)
register_response(
cls=LEDResponse,
command_id=CommandId.command_led_response,
)
class GPResponse(Response):
was_successful = True
@ -333,3 +368,84 @@ class GPRequest(Request):
payload=payload,
serial=serial,
)
register_request(
cls=GPRequest,
command_id=CommandId.command_gp_request,
alias="gp",
)
register_response(
cls=GPResponse,
command_id=CommandId.command_gp_response,
)
class PumpResponse(Response):
was_successful = True
def unpack_payload(
self,
data: bytes,
):
self.was_successful = bool(data[0])
self.is_on = bool(data[1])
class PumpRequest(Request):
def __init__(self, do: str, timeout: Union[int, str] = 60, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
try:
self.do = {
"turn_off": 0,
"turn_on": 1,
"is_on": 2,
}[do]
except KeyError:
self.do = int(do)
self.pump_timeout = int(timeout)
@property
def identifier(self) -> CommandId:
return CommandId.command_pump_request
@property
def timeout(self) -> float:
return 1
def process_response(self, response: Response):
if not isinstance(response, PumpResponse):
raise TypeError(f"{response} is not a {PumpResponse}")
if response.was_successful:
self._logger.debug("Pump command was successful")
else:
self._logger.debug("Pump command was not successful")
if response.is_on:
self._logger.debug("Pump is on")
else:
self._logger.debug("Pump is off")
def execute(self, serial: Serial):
payload = pack(
">BH",
self.do,
self.pump_timeout,
)
self.send_command(
payload=payload,
serial=serial,
)
register_request(
cls=PumpRequest,
command_id=CommandId.command_pump_request,
alias="pump",
)
register_response(
cls=PumpResponse,
command_id=CommandId.command_pump_response,
)

2
nucleo-wb55-ble/Core/Inc/main.h

@ -61,6 +61,8 @@ void Error_Handler(void);
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define RELAY_12V_OUT1_Pin GPIO_PIN_2
#define RELAY_12V_OUT1_GPIO_Port GPIOC
#define SW1_Pin GPIO_PIN_4
#define SW1_GPIO_Port GPIOC
#define SW1_EXTI_IRQn EXTI4_IRQn

23
nucleo-wb55-ble/Core/Inc/pump_control.h

@ -0,0 +1,23 @@
/*
* pump_control.h
*
* Created on: Jul 27, 2021
* Author: Andreas Berthoud
*/
#ifndef INC_PUMP_CONTROL_H_
#define INC_PUMP_CONTROL_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
uint8_t pump_init();
#ifdef __cplusplus
}
#endif
#endif /* INC_PUMP_CONTROL_H_ */

21
nucleo-wb55-ble/Core/Inc/pump_control.hpp

@ -0,0 +1,21 @@
/*
* pump_control.hpp
*
* Created on: Jul 27, 2021
* Author: Andreas Berthoud
*/
#ifndef INC_PUMP_CONTROL_H_
#define INC_PUMP_CONTROL_H_
#include <stdint.h>
namespace pump {
void turn_on(uint16_t timeout);
uint8_t is_on();
void turn_off();
}
#endif /* INC_PUMP_CONTROL_H_ */

13
nucleo-wb55-ble/Core/Src/main.c

@ -29,6 +29,7 @@
#include "dbg_trace.h"
#include "hw_conf.h"
#include "otp.h"
#include "pump_control.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@ -104,7 +105,7 @@ int main(void)
MX_RTC_Init();
MX_USB_Device_Init();
/* USER CODE BEGIN 2 */
pump_init();
/* USER CODE END 2 */
/* Init code for STM32_WPAN */
@ -259,9 +260,19 @@ static void MX_GPIO_Init(void)
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(RELAY_12V_OUT1_GPIO_Port, RELAY_12V_OUT1_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, LED_GREEN_Pin|LED_RED_Pin|LED_BLUE_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : RELAY_12V_OUT1_Pin */
GPIO_InitStruct.Pin = RELAY_12V_OUT1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(RELAY_12V_OUT1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : SW1_Pin */
GPIO_InitStruct.Pin = SW1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

65
nucleo-wb55-ble/Core/Src/pump_control.cpp

@ -0,0 +1,65 @@
/*
* pump_control.cpp
*
* Created on: Jul 27, 2021
* Author: Andreas Berthoud
*/
#include "pump_control.h"
#include "pump_control.hpp"
#include "main.h"
#include "stm32wbxx_hal.h"
#include "hw_if.h"
#include "LogCommand.hpp"
namespace pump {
typedef struct {
bool is_on;
uint8_t timer_id;
} pump_state_t;
pump_state_t pump_state {
.is_on=false
};
void turn_on(uint16_t timeout) {
uint32_t ticks = (timeout*1000*1000/CFG_TS_TICK_VAL);
if (ticks > 0xFFFF0000) {
log_error("pump::turn_on", "max timout exceeded", 0);
return;
}
HW_TS_Start(pump_state.timer_id, ticks);
HAL_GPIO_WritePin(RELAY_12V_OUT1_GPIO_Port, RELAY_12V_OUT1_Pin, GPIO_PIN_SET);
pump_state.is_on = true;
log_debug("pump", "turned on", 0);
}
uint8_t is_on() {
return (uint8_t)pump_state.is_on;
}
void turn_off() {
pump_state.is_on = false;
HAL_GPIO_WritePin(RELAY_12V_OUT1_GPIO_Port, RELAY_12V_OUT1_Pin, GPIO_PIN_RESET);
HW_TS_Stop(pump_state.timer_id);
log_debug("pump", "turned off", 0);
}
uint8_t init() {
HW_TS_ReturnStatus_t return_status = HW_TS_Create(CFG_TIM_PROC_ID_ISR, &(pump_state.timer_id), hw_ts_SingleShot, turn_off);
if (return_status == hw_ts_Failed) {
log_error("pump::init", "Creating hardware timer failed", 0);
return 1;
}
return 0;
}
}
uint8_t pump_init() {
return pump::init();
}

59
nucleo-wb55-ble/commands/PumpCommand.cpp

@ -0,0 +1,59 @@
/*
* PumpCommand.cpp
*
* Created on: Jul 27, 2021
* Author: Andreas Berthoud
*/
#include "PumpCommand.hpp"
#include "pump_control.hpp"
#include "main.h"
PumpResponse::PumpResponse(com_channel_type_t com_channel_type, uint16_t response_identifier, bool was_successful, bool is_on)
: Response(com_channel_type, response_identifier) {
uint8_t * next_free_payload = this->payload_ptr + this->get_payload_size();
next_free_payload[0] = (uint8_t)was_successful;
next_free_payload[1] = (uint8_t)is_on;
this->add_to_payload_size(2);
}
PumpRequest::PumpRequest(com_channel_type_t com_channel_type, uint8_t * payload_ptr, uint16_t size)
: Request(com_channel_type, payload_ptr, size) {
uint16_t expected_length = this->buffer_offset + 3;
if (expected_length != size) {
this->has_error = true;
return;
}
uint8_t * data_ptr = payload_ptr + this->buffer_offset;
this->pump_command = static_cast<PumpCommand>(data_ptr[0]);
this->timeout = data_ptr[1] << 8 | data_ptr[2];
}
PumpResponse * PumpRequest::execute_request(com_channel_type_t com_channel_type, uint16_t response_identifier) {
bool was_successful = true;
if (this->pump_command >= pump_command_max) {
was_successful = false;
} else {
switch (this->pump_command)
{
case pump_command_turn_off:
pump::turn_on(this->timeout);
break;
case pump_command_turn_on:
pump::turn_off();
break;
case pump_command_get_state:
break;
default:
was_successful = false;
break;
}
}
bool is_on = pump::is_on();
return new PumpResponse(com_channel_type, response_identifier, was_successful, is_on);
}

48
nucleo-wb55-ble/commands/PumpCommand.hpp

@ -0,0 +1,48 @@
/*
* PumpCommand.hpp
*
* Created on: Jul 27, 2021
* Author: Andreas Berthoud
*/
#ifndef PUMPCOMMAND_HPP_
#define PUMPCOMMAND_HPP_
#include "Request.hpp"
#include "Response.hpp"
class PumpResponse : public Response {
public:
PumpResponse(com_channel_type_t com_channel_type, uint16_t response_identifier, bool was_successful, bool is_on);
CommandId get_command_id() override { return COMMAND_PUMP_RESPONSE; }
private:
bool was_successful = false;
bool is_on = false;
};
class PumpRequest : public Request {
public:
PumpRequest(com_channel_type_t com_channel_type, uint8_t * payload_ptr, uint16_t size);
PumpResponse * execute_request(com_channel_type_t com_channel_type, uint16_t response_identifier) override;
CommandId get_command_id() override { return COMMAND_PUMP_REQUEST; }
private:
enum PumpCommand {
pump_command_turn_on,
pump_command_turn_off,
pump_command_get_state,
pump_command_max,
};
bool has_error = false;
PumpCommand pump_command = pump_command_turn_off;
uint16_t timeout; /* timeout in seconds until the pump is turned off again */
};
#endif /* PUMPCOMMAND_HPP_ */

4
nucleo-wb55-ble/commands/dispatch.cpp

@ -10,6 +10,7 @@
#include "HeartbeatCommand.hpp"
#include "LedCommand.hpp"
#include "GPCommand.hpp"
#include "PumpCommand.hpp"
void handle_received_command(uint8_t command_id, uint8_t * payload_ptr, uint16_t size, com_channel_type_t com_channel_type ) {
switch (command_id)
@ -23,6 +24,9 @@ void handle_received_command(uint8_t command_id, uint8_t * payload_ptr, uint16_t
case COMMAND_GP_REQUEST:
push_command(new GPRequest(com_channel_type, payload_ptr, size));
break;
case COMMAND_PUMP_REQUEST:
push_command(new PumpRequest(com_channel_type, payload_ptr, size));
break;
default:
break;

51
nucleo-wb55-ble/nucleo-wb55-ble.ioc

@ -12,7 +12,7 @@ RCC.RFWKPFreq_Value=32768
RCC.SMPSCLockSelectionVirtualVirtual=RCC_SMPSCLKSOURCE_HSI
RCC.PLLSAI1RoutputFreq_Value=48000000
PA14.GPIO_Label=JTCK
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_RF_Init-RF-false-HAL-true,4-MX_RTC_Init-RTC-false-HAL-true,5-APPE_Init-STM32_WPAN-false-HAL-false,0-MX_HSEM_Init-HSEM-false-HAL-true
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_RF_Init-RF-false-HAL-true,4-MX_RTC_Init-RTC-false-HAL-true,5-APPE_Init-STM32_WPAN-false-HAL-false,6-MX_USB_Device_Init-USB_DEVICE-false-HAL-false,0-MX_HSEM_Init-HSEM-false-HAL-true
PD0.GPIO_Label=SW2
VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
PA11.Mode=Device
@ -45,20 +45,20 @@ STM32_WPAN.LOCAL_NAME=Travis
ProjectManager.PreviousToolchain=
RCC.APB2TimFreq_Value=32000000
PCC.Ble.PowerLevel=Min
Mcu.Pin6=PB0
Mcu.Pin6=OSC_IN
PD0.Signal=GPIO_Input
Mcu.Pin7=PB1
Mcu.Pin8=PA11
Mcu.Pin7=PB0
Mcu.Pin8=PB1
OSC_OUT.Mode=HSE-External-Oscillator
Mcu.Pin9=PA12
Mcu.Pin9=PA11
OSC_OUT.Signal=RCC_OSC_OUT
RCC.AHBFreq_Value=32000000
Mcu.Pin0=PC14-OSC32_IN
Mcu.Pin1=PC15-OSC32_OUT
Mcu.Pin2=PC4
Mcu.Pin3=RF1
Mcu.Pin4=OSC_OUT
Mcu.Pin5=OSC_IN
Mcu.Pin2=PC2
Mcu.Pin3=PC4
Mcu.Pin4=RF1
Mcu.Pin5=OSC_OUT
ProjectManager.ProjectBuild=false
RCC.HSE_VALUE=32000000
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
@ -109,6 +109,7 @@ PC4.Locked=true
RCC.LPUART1Freq_Value=32000000
RCC.CK48CLockSelection=RCC_USBCLKSOURCE_HSI48
RCC.SMPSDivider=1
PC2.GPIO_Label=RELAY_12V_OUT1
ProjectManager.CustomerFirmwarePackage=
PC4.GPIOParameters=GPIO_Label
RCC.HSI48_VALUE=48000000
@ -122,10 +123,11 @@ NVIC.EXTI4_IRQn=true\:0\:0\:false\:false\:true\:true\:true
RCC.PLLQoutputFreq_Value=16000000
ProjectManager.ProjectFileName=nucleo-wb55-ble.ioc
VP_STM32_WPAN_VS_BLE_HOST.Mode=STM32_WPAN_Enabled
Mcu.PinsNb=23
Mcu.PinsNb=24
ProjectManager.NoMain=false
USB_DEVICE.VirtualModeFS=Cdc_FS
RCC.HCLK3Freq_Value=32000000
PC2.Signal=GPIO_Output
PC4.Signal=GPXTI4
PD1.Signal=GPIO_Input
ProjectManager.DefaultFWLocation=true
@ -142,6 +144,7 @@ STM32_WPAN.LOCAL_NAME_FORMATTED=,'T','r','a','v','i','s'
RCC.HCLKRFFreq_Value=16000000
VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS
PB5.Locked=true
PC2.Locked=true
ProjectManager.RegisterCallBack=
OSC_IN.Signal=RCC_OSC_IN
RCC.USBFreq_Value=48000000
@ -161,6 +164,7 @@ PCC.Ble.DataLength=6
RCC.I2C1Freq_Value=32000000
RCC.LCDFreq_Value=32768
RCC.RNGFreq_Value=32000
PC2.GPIOParameters=GPIO_Label
RCC.PLLSAI1QoutputFreq_Value=48000000
RCC.ADCFreq_Value=48000000
VP_SYS_VS_Systick.Mode=SysTick
@ -181,9 +185,10 @@ ProjectManager.CoupleFile=false
PB3.Signal=SYS_JTDO-SWO
RCC.SYSCLKFreq_VALUE=32000000
PB5.Signal=GPIO_Output
Mcu.Pin22=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
Mcu.Pin20=VP_SYS_VS_Systick
Mcu.Pin21=VP_TINY_LPM_VS_TINY_LPM
Mcu.Pin22=VP_TINY_LPM_VS_TINY_LPM
Mcu.Pin23=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
Mcu.Pin20=VP_STM32_WPAN_VS_BLE_HOST
Mcu.Pin21=VP_SYS_VS_Systick
SH.GPXTI4.0=GPIO_EXTI4
PA12.Mode=Device
PCC.Ble.ConnectionInterval=1000.0
@ -199,22 +204,22 @@ RF1.Mode=RF1_Activate
PA11.Signal=USB_DM
PA14.Signal=SYS_JTCK-SWCLK
ProjectManager.HeapSize=0x200
Mcu.Pin15=PB5
Mcu.Pin15=PB3
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
Mcu.Pin16=VP_HSEM_VS_HSEM
Mcu.Pin16=PB5
SH.GPXTI4.ConfNb=1
Mcu.Pin13=PD1
Mcu.Pin14=PB3
Mcu.Pin19=VP_STM32_WPAN_VS_BLE_HOST
Mcu.Pin13=PD0
Mcu.Pin14=PD1
Mcu.Pin19=VP_SEQUENCER_VS_SEQUENCER
ProjectManager.ComputerToolchain=false
Mcu.Pin17=VP_RTC_VS_RTC_Activate
Mcu.Pin17=VP_HSEM_VS_HSEM
RCC.HSI_VALUE=16000000
Mcu.Pin18=VP_SEQUENCER_VS_SEQUENCER
Mcu.Pin18=VP_RTC_VS_RTC_Activate
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
Mcu.Pin11=PA14
Mcu.Pin12=PD0
Mcu.Pin11=PA13
PD0.GPIOParameters=GPIO_Label
Mcu.Pin10=PA13
Mcu.Pin12=PA14
Mcu.Pin10=PA12
RCC.PWRFreq_Value=32000000
VP_TINY_LPM_VS_TINY_LPM.Signal=TINY_LPM_VS_TINY_LPM
RCC.APB1Freq_Value=32000000

2
nucleo-wb55-dongle-ble/shared_commands/commands.hpp

@ -19,6 +19,8 @@ typedef enum : uint8_t {
COMMAND_LED_RESPONSE = 0x5,
COMMAND_GP_REQUEST = 0x6,
COMMAND_GP_RESPONSE = 0x7,
COMMAND_PUMP_REQUEST = 0x8,
COMMAND_PUMP_RESPONSE = 0x9,
} CommandId;
#endif /* COMMANDS_HPP_ */

Loading…
Cancel
Save