Add Windows client

This commit is contained in:
fvanroie 2021-02-15 03:09:17 +01:00
parent 027ffa983f
commit a70eb1fd5f
26 changed files with 2155 additions and 48 deletions

75
hal/sdl2/app_hal.c Normal file
View File

@ -0,0 +1,75 @@
#include <unistd.h>
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
#include <SDL2/SDL.h>
#include "display/monitor.h"
#include "indev/mouse.h"
#include "indev/mousewheel.h"
#include "indev/keyboard.h"
/**
* A task to measure the elapsed time for LittlevGL
* @param data unused
* @return never return
*/
static int tick_thread(void * data)
{
(void)data;
while(1) {
SDL_Delay(5); /*Sleep for 5 millisecond*/
lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
}
return 0;
}
void hal_setup(void)
{
// Workaround for sdl2 `-m32` crash
// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7
#ifndef WIN32
setenv("DBUS_FATAL_WARNINGS", "0", 1);
#endif
/* Add a display
* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/
monitor_init();
/* Tick init.
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed
* Create an SDL thread to do this*/
SDL_CreateThread(tick_thread, "tick", NULL);
lv_init();
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10]; /*Declare a buffer for 10 lines*/
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.flush_cb = monitor_flush; /*Used when `LV_VDB_SIZE != 0` in lv_conf.h (buffered drawing)*/
disp_drv.buffer = &disp_buf;
//disp_drv.disp_fill = monitor_fill; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/
//disp_drv.disp_map = monitor_map; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/
lv_disp_drv_register(&disp_drv);
/* Add the mouse as input device
* Use the 'mouse' driver which reads the PC's mouse*/
mouse_init();
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = mouse_read; /*This function will be called periodically (by the library) to get the mouse position and state*/
lv_indev_drv_register(&indev_drv);
}
void hal_loop(void)
{
/*while(1)*/ {
SDL_Delay(5);
lv_task_handler();
}
}

17
hal/sdl2/app_hal.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef DRIVER_H
#define DRIVER_H
#ifdef __cplusplus
extern "C" {
#endif
void hal_setup(void);
void hal_loop(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*DRIVER_H*/

View File

@ -0,0 +1,50 @@
#include "Arduino.h"
#include "stm32f4xx.h"
//#include "stm32f429i_discovery.h"
#include "tft.h"
//#include "touchpad.h"
#ifdef USE_RTOS_SYSTICK
#include <cmsis_os.h>
#endif
void hal_setup(void)
{
pinMode(PD12, OUTPUT);
digitalWrite(PD12, HIGH);
// HAL_Init();
// /* Configure the system clock to 180 MHz */
// SystemClock_Config();
// /* Start up indication */
// BSP_LED_Init(LED3);
// for (uint8_t i = 0; i < 8; i++) { BSP_LED_Toggle(LED3); delay(50); }
tft_init();
//touchpad_init();
}
// void SysTick_Handler(void)
// {
// HAL_IncTick();
// HAL_SYSTICK_IRQHandler();
// lv_tick_inc(1);
// #ifdef USE_RTOS_SYSTICK
// osSystickHandler();
// #endif
// }
void hal_loop(void)
{
//while (1)
{
delay(5);
lv_task_handler();
}
}

View File

@ -0,0 +1,17 @@
#ifndef DRIVER_H
#define DRIVER_H
#ifdef __cplusplus
extern "C" {
#endif
void hal_setup(void);
void hal_loop(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*DRIVER_H*/

65
hal/stm32f407_btt/tft.c Normal file
View File

@ -0,0 +1,65 @@
/**
* @file disp.c
*
*/
/*********************
* INCLUDES
*********************/
#include <string.h>
#include "tft.h"
#include "stm32f4xx.h"
#include "fsmc_ssd1963.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static lv_disp_drv_t disp_drv;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize your display here
*/
void tft_init(void)
{
static lv_color_t disp_buf1[TFT_HOR_RES * 40];
static lv_disp_buf_t buf;
lv_disp_buf_init(&buf, disp_buf1, NULL, TFT_HOR_RES * 40);
lv_disp_drv_init(&disp_drv);
fsmc_ssd1963_init(0, false);
disp_drv.buffer = &buf;
disp_drv.flush_cb = fsmc_ssd1963_flush;
disp_drv.hor_res = TFT_HOR_RES;
disp_drv.ver_res = TFT_VER_RES;
#if TFT_USE_GPU != 0
DMA2D_Config();
disp_drv.gpu_blend_cb = gpu_mem_blend;
disp_drv.gpu_fill_cb = gpu_mem_fill;
#endif
lv_disp_drv_register(&disp_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/

37
hal/stm32f407_btt/tft.h Normal file
View File

@ -0,0 +1,37 @@
/**
* @file disp.h
*
*/
#ifndef DISP_H
#define DISP_H
/*********************
* INCLUDES
*********************/
#include <stdint.h>
#include "lvgl.h"
/*********************
* DEFINES
*********************/
#define TFT_HOR_RES TFT_WIDTH
#define TFT_VER_RES TFT_HEIGHT
#define TFT_EXT_FB 1 /*Frame buffer is located into an external SDRAM*/
#define TFT_USE_GPU 0 /*Enable hardware accelerator*/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void tft_init(void);
/**********************
* MACROS
**********************/
#endif

View File

@ -0,0 +1,123 @@
#include "stm32f4xx.h"
#include "stm32f429i_discovery.h"
#include "tft.h"
#include "touchpad.h"
#ifdef USE_RTOS_SYSTICK
#include <cmsis_os.h>
#endif
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 180000000
* HCLK(Hz) = 180000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 360
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* The LTDC Clock is configured as follow :
* PLLSAIN = 192
* PLLSAIR = 4
* PLLSAIDivR = 8
* @param None
* @retval None
*/
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/*##-1- System Clock Configuration #########################################*/
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* Activate the Over-Drive mode */
HAL_PWREx_EnableOverDrive();
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
/*##-2- LTDC Clock Configuration ###########################################*/
/* LCD clock configuration */
/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 MHz */
/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 MHz */
/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 MHz */
/* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDIVR_8 = 48/8 = 6 MHz */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
PeriphClkInitStruct.PLLSAI.PLLSAIR = 4;
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
}
void hal_setup(void)
{
HAL_Init();
/* Configure the system clock to 180 MHz */
SystemClock_Config();
/* Start up indication */
BSP_LED_Init(LED3);
for (uint8_t i = 0; i < 8; i++) { BSP_LED_Toggle(LED3); HAL_Delay(50); }
tft_init();
touchpad_init();
}
void SysTick_Handler(void)
{
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
lv_tick_inc(1);
#ifdef USE_RTOS_SYSTICK
osSystickHandler();
#endif
}
void hal_loop(void)
{
while(1) {
HAL_Delay(5);
lv_task_handler();
}
}

View File

@ -0,0 +1,17 @@
#ifndef DRIVER_H
#define DRIVER_H
#ifdef __cplusplus
extern "C" {
#endif
void hal_setup(void);
void hal_loop(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*DRIVER_H*/

236
hal/stm32f429_disco/tft.c Normal file
View File

@ -0,0 +1,236 @@
/**
* @file disp.c
*
*/
/*********************
* INCLUDES
*********************/
#include <string.h>
#include "tft.h"
#include "stm32f4xx.h"
#include "stm32f429i_discovery_lcd.h"
#include "ili9341.h"
/*********************
* DEFINES
*********************/
#define SDRAM_BANK_ADDR ((uint32_t)0xD0000000)
#define DMA_STREAM DMA2_Stream0
#define DMA_CHANNEL DMA_CHANNEL_0
#define DMA_STREAM_IRQ DMA2_Stream0_IRQn
#define DMA_STREAM_IRQHANDLER DMA2_Stream0_IRQHandler
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void tft_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p);
/**********************
* STATIC VARIABLES
**********************/
extern LTDC_HandleTypeDef LtdcHandler;
#if TFT_USE_GPU != 0
static DMA2D_HandleTypeDef Dma2dHandle;
#endif
#if TFT_EXT_FB != 0
static __IO uint16_t *my_fb = (__IO uint16_t *)(SDRAM_BANK_ADDR);
#else
static uint16_t my_fb[TFT_HOR_RES * TFT_VER_RES];
#endif
/*DMA to flush to frame buffer*/
static void DMA_Config(void);
static void DMA_TransferComplete(DMA_HandleTypeDef *han);
static void DMA_TransferError(DMA_HandleTypeDef *han);
DMA_HandleTypeDef DmaHandle;
static lv_disp_drv_t disp_drv;
static int32_t x1_flush;
static int32_t y1_flush;
static int32_t x2_flush;
static int32_t y2_fill;
static int32_t y_fill_act;
static const lv_color_t *buf_to_flush;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize your display here
*/
void tft_init(void)
{
static lv_color_t disp_buf1[TFT_HOR_RES * 40];
static lv_disp_buf_t buf;
lv_disp_buf_init(&buf, disp_buf1, NULL, TFT_HOR_RES * 40);
lv_disp_drv_init(&disp_drv);
BSP_LCD_Init();
BSP_LCD_LayerDefaultInit(0, (uint32_t)my_fb);
HAL_LTDC_SetPixelFormat(&LtdcHandler, LTDC_PIXEL_FORMAT_RGB565, 0);
DMA_Config();
disp_drv.buffer = &buf;
disp_drv.flush_cb = tft_flush;
disp_drv.hor_res = TFT_HOR_RES;
disp_drv.ver_res = TFT_VER_RES;
#if TFT_USE_GPU != 0
DMA2D_Config();
disp_drv.gpu_blend_cb = gpu_mem_blend;
disp_drv.gpu_fill_cb = gpu_mem_fill;
#endif
lv_disp_drv_register(&disp_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Flush a color buffer
* @param x1 left coordinate of the rectangle
* @param x2 right coordinate of the rectangle
* @param y1 top coordinate of the rectangle
* @param y2 bottom coordinate of the rectangle
* @param color_p pointer to an array of colors
*/
static void tft_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p)
{
/*Return if the area is out the screen*/
if (area->x2 < 0)
return;
if (area->y2 < 0)
return;
if (area->x1 > TFT_HOR_RES - 1)
return;
if (area->y1 > TFT_VER_RES - 1)
return;
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > TFT_HOR_RES - 1 ? TFT_HOR_RES - 1 : area->x2;
int32_t act_y2 = area->y2 > TFT_VER_RES - 1 ? TFT_VER_RES - 1 : area->y2;
x1_flush = act_x1;
y1_flush = act_y1;
x2_flush = act_x2;
y2_fill = act_y2;
y_fill_act = act_y1;
buf_to_flush = color_p;
/*##-7- Start the DMA transfer using the interrupt mode #*/
/* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */
/* Enable All the DMA interrupts */
HAL_StatusTypeDef err;
err = HAL_DMA_Start_IT(&DmaHandle, (uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush],
(x2_flush - x1_flush + 1));
if (err != HAL_OK)
{
while (1)
; /*Halt on error*/
}
}
static void DMA_Config(void)
{
/*## -1- Enable DMA2 clock #################################################*/
__HAL_RCC_DMA2_CLK_ENABLE();
/*##-2- Select the DMA functional Parameters ###############################*/
DmaHandle.Init.Channel = DMA_CHANNEL; /* DMA_CHANNEL_0 */
DmaHandle.Init.Direction = DMA_MEMORY_TO_MEMORY; /* M2M transfer mode */
DmaHandle.Init.PeriphInc = DMA_PINC_ENABLE; /* Peripheral increment mode Enable */
DmaHandle.Init.MemInc = DMA_MINC_ENABLE; /* Memory increment mode Enable */
DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* Peripheral data alignment : 16bit */
DmaHandle.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD; /* memory data alignment : 16bit */
DmaHandle.Init.Mode = DMA_NORMAL; /* Normal DMA mode */
DmaHandle.Init.Priority = DMA_PRIORITY_HIGH; /* priority level : high */
DmaHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* FIFO mode enabled */
DmaHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; /* FIFO threshold: 1/4 full */
DmaHandle.Init.MemBurst = DMA_MBURST_SINGLE; /* Memory burst */
DmaHandle.Init.PeriphBurst = DMA_PBURST_SINGLE; /* Peripheral burst */
/*##-3- Select the DMA instance to be used for the transfer : DMA2_Stream0 #*/
DmaHandle.Instance = DMA_STREAM;
/*##-4- Initialize the DMA stream ##########################################*/
if (HAL_DMA_Init(&DmaHandle) != HAL_OK)
{
while (1)
;
}
/*##-5- Select Callbacks functions called after Transfer complete and Transfer error */
HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_CPLT_CB_ID, DMA_TransferComplete);
HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_ERROR_CB_ID, DMA_TransferError);
/*##-6- Configure NVIC for DMA transfer complete/error interrupts ##########*/
HAL_NVIC_SetPriority(DMA_STREAM_IRQ, 0, 0);
HAL_NVIC_EnableIRQ(DMA_STREAM_IRQ);
}
/**
* @brief DMA conversion complete callback
* @note This function is executed when the transfer complete interrupt
* is generated
* @retval None
*/
static void DMA_TransferComplete(DMA_HandleTypeDef *han)
{
y_fill_act++;
if (y_fill_act > y2_fill)
{
lv_disp_flush_ready(&disp_drv);
}
else
{
buf_to_flush += x2_flush - x1_flush + 1;
/*##-7- Start the DMA transfer using the interrupt mode ####################*/
/* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */
/* Enable All the DMA interrupts */
if (HAL_DMA_Start_IT(han, (uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush],
(x2_flush - x1_flush + 1)) != HAL_OK)
{
while (1)
; /*Halt on error*/
}
}
}
/**
* @brief DMA conversion error callback
* @note This function is executed when the transfer error interrupt
* is generated during DMA transfer
* @retval None
*/
static void DMA_TransferError(DMA_HandleTypeDef *han)
{
}
/**
* @brief This function handles DMA Stream interrupt request.
* @param None
* @retval None
*/
void DMA_STREAM_IRQHANDLER(void)
{
/* Check the interrupt and clear flag */
HAL_DMA_IRQHandler(&DmaHandle);
}

37
hal/stm32f429_disco/tft.h Normal file
View File

@ -0,0 +1,37 @@
/**
* @file disp.h
*
*/
#ifndef DISP_H
#define DISP_H
/*********************
* INCLUDES
*********************/
#include <stdint.h>
#include "lvgl.h"
/*********************
* DEFINES
*********************/
#define TFT_HOR_RES 240
#define TFT_VER_RES 320
#define TFT_EXT_FB 1 /*Frame buffer is located into an external SDRAM*/
#define TFT_USE_GPU 0 /*Enable hardware accelerator*/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void tft_init(void);
/**********************
* MACROS
**********************/
#endif

View File

@ -0,0 +1,144 @@
/**
* @file indev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "tft.h"
#include "lvgl.h"
#include "stm32f4xx.h"
#include "stm32f429i_discovery.h"
#include "stmpe811.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static bool touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t *data);
static bool touchpad_get_xy(int16_t *x, int16_t *y);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize your input devices here
*/
void touchpad_init(void)
{
stmpe811_Init(TS_I2C_ADDRESS);
stmpe811_TS_Start(TS_I2C_ADDRESS);
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.read_cb = touchpad_read;
indev_drv.type = LV_INDEV_TYPE_POINTER;
lv_indev_drv_register(&indev_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Read an input device
* @param indev_id id of the input device to read
* @param x put the x coordinate here
* @param y put the y coordinate here
* @return true: the device is pressed, false: released
*/
static bool touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t *data)
{
static int16_t last_x = 0;
static int16_t last_y = 0;
bool detected;
int16_t x;
int16_t y;
detected = touchpad_get_xy(&x, &y);
if(detected) {
data->point.x = x;
data->point.y = y;
last_x = data->point.x;
last_y = data->point.y;
data->state = LV_INDEV_STATE_PR;
} else {
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_REL;
}
return false;
}
static bool touchpad_get_xy(int16_t *x, int16_t *y)
{
static int32_t _x = 0, _y = 0;
int16_t xDiff, yDiff, xr, yr, x_raw, y_raw;;
bool detected;
detected = stmpe811_TS_DetectTouch(TS_I2C_ADDRESS);
if(!detected) return false;
stmpe811_TS_GetXY(TS_I2C_ADDRESS, &x_raw, &y_raw);
/* Y value first correction */
y_raw -= 360;
/* Y value second correction */
yr = y_raw / 11;
/* Return y_raw position value */
if(yr <= 0) yr = 0;
else if (yr > TFT_VER_RES) yr = TFT_VER_RES - 1;
y_raw = yr;
/* X value first correction */
if(x_raw <= 3000) x_raw = 3870 - x_raw;
else x_raw = 3800 - x_raw;
/* X value second correction */
xr = x_raw / 15;
/* Return X position value */
if(xr <= 0) xr = 0;
else if (xr > TFT_HOR_RES) xr = TFT_HOR_RES - 1;
x_raw = xr;
xDiff = x_raw > _x? (x_raw - _x): (_x - x_raw);
yDiff = y_raw > _y? (y_raw - _y): (_y - y_raw);
if (xDiff + yDiff > 5) {
_x = x_raw;
_y = y_raw;
}
/* Update the X and Y position */
*x = _x;
*y = _y;
return true;
}

View File

@ -0,0 +1,32 @@
/**
* @file indev.h
*
*/
#ifndef INDEV_H
#define INDEV_H
/*********************
* INCLUDES
*********************/
#include <stdbool.h>
#include <stdint.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void touchpad_init(void);
/**********************
* MACROS
**********************/
#endif

7
include/VersionInfo.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef VERSIONINFO_H
#define VERSIONINFO_H
#define BUILD_TIMESTAMP "@BUILD_TIMESTAMP@"
#define CLIENT_VERSION "@CLIENT_VERSION@"
#endif /* VERSIONINFO_H */

View File

@ -1,6 +1,9 @@
#ifndef HASP_CONF_H
#define HASP_CONF_H
// language specific defines
#include "lang/lang.h"
#define HASP_USE_APP 1
#ifndef HASP_USE_DEBUG
@ -101,7 +104,12 @@
#define HASP_OBJECT_NOTATION "p%ub%u"
/* Includes */
#include <Arduino.h>
#ifdef WINDOWS
#include "winsock2.h"
#include "Windows.h"
#else
#include "Arduino.h"
#endif
#if HASP_USE_SPIFFS > 0
// #if defined(ARDUINO_ARCH_ESP32)
@ -132,7 +140,7 @@
#endif
#if HASP_USE_WIFI > 0
#include "net/hasp_wifi.h"
#include "sys/net/hasp_wifi.h"
#if defined(STM32F4xx)
#include "WiFiSpi.h"
@ -173,11 +181,18 @@ static WiFiSpiClass WiFi;
#endif
#if HASP_USE_MQTT > 0
#include "svc/hasp_mqtt.h"
#include "mqtt/hasp_mqtt.h"
#ifdef WINDOWS
#define USE_PAHO
#else
#define USE_PUBSUBCLIENT
#endif
#endif
#if HASP_USE_GPIO > 0
#include "hasp_gpio.h"
#include "sys/gpio/hasp_gpio.h"
#endif
#if HASP_USE_HTTP > 0
@ -215,4 +230,54 @@ static WiFiSpiClass WiFi;
#define PGM_P const char *
#endif
#ifndef __FlashStringHelper
#define __FlashStringHelper char
#endif
#ifndef FPSTR
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
#endif
#ifndef PGM_P
#define PGM_P const char *
#endif
#ifndef F
#define F(x) (x)
#endif
#ifndef PSTR
#define PSTR(x) x
#endif
#ifndef PROGMEM
#define PROGMEM
#endif
#ifdef WINDOWS
#include <string.h>
#include <stdio.h>
#include <Windows.h>
#include <SDL2/SDL.h>
#define snprintf_P snprintf
#define memcpy_P memcpy
#define strcasecmp_P strcmp // TODO: should be strcasecmp
#define strcmp_P strcmp
#define strstr_P strstr
#define halRestartMcu()
#define delay Sleep
#define millis SDL_GetTicks
#define DEC 10
#define HEX 16
#define BIN 2
#define guiGetDim() 255
#define guiSetDim(x)
#define guiGetBacklight() 1
#define guiSetBacklight(x)
#define guiCalibrate()
#endif
#endif // HASP_CONF_H

View File

@ -1,65 +1,72 @@
#ifndef HASP_MACRO_H
#define HASP_MACRO_H
#if HASP_LOG_LEVEL > LOG_LEVEL_FATAL
#define LOG_FATAL(...) \
Log.fatal(__VA_ARGS__); \
while(true) { \
}
#ifdef WINDOWS
#define LOG_OUTPUT(x, ...) printf(__VA_ARGS__)
#else
#define LOG_FATAL(...) \
do { \
} while(0)
#define LOG_OUTPUT(...) Log.output(...)
#if HASP_LOG_LEVEL > LOG_LEVEL_FATAL
#define LOG_FATAL(...) \
Log.fatal(__VA_ARGS__); \
while (true) \
{ \
}
#else
#define LOG_FATAL(...) \
do \
{ \
} while (0)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_ALERT
#define LOG_ALERT(...) Log.alert(__VA_ARGS__)
#define LOG_ALERT(...) Log.alert(__VA_ARGS__)
#else
#define LOG_ALERT(...)
#define LOG_ALERT(...)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_CRITICAL
#define LOG_CRITICAL(...) Log.critical(__VA_ARGS__)
#define LOG_CRITICAL(...) Log.critical(__VA_ARGS__)
#else
#define LOG_CRITICAL(...)
#define LOG_CRITICAL(...)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_ERROR
#define LOG_ERROR(...) Log.error(__VA_ARGS__)
#define LOG_ERROR(...) Log.error(__VA_ARGS__)
#else
#define LOG_ERROR(...)
#define LOG_ERROR(...)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_WARNING
#define LOG_WARNING(...) Log.warning(__VA_ARGS__)
#define LOG_WARNING(...) Log.warning(__VA_ARGS__)
#else
#define LOG_WARNING(...)
#define LOG_WARNING(...)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_INFO
#define LOG_INFO(...) Log.notice(__VA_ARGS__)
#define LOG_INFO(...) Log.notice(__VA_ARGS__)
#else
#define LOG_INFO(...)
#define LOG_INFO(...)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_TRACE
#define LOG_TRACE(...) Log.trace(__VA_ARGS__)
#define LOG_TRACE(...) Log.trace(__VA_ARGS__)
#else
#define LOG_TRACE(...)
#define LOG_TRACE(...)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_VERBOSE
#define LOG_VERBOSE(...) Log.verbose(__VA_ARGS__)
#define LOG_VERBOSE(...) Log.verbose(__VA_ARGS__)
#else
#define LOG_VERBOSE(...)
#define LOG_VERBOSE(...)
#endif
#if HASP_LOG_LEVEL > LOG_LEVEL_DEBUG
#define LOG_DEBUG(...) Log.debug(__VA_ARGS__)
#define LOG_DEBUG(...) Log.debug(__VA_ARGS__)
#else
#define LOG_DEBUG(...)
#define LOG_DEBUG(...)
#endif
#define LOG_OUTPUT(...) Log.output(...)
#endif
#endif

View File

@ -26,6 +26,8 @@
/* Maximal horizontal and vertical resolution to support by the library.*/
#define LV_HOR_RES_MAX (TFT_WIDTH)
#define LV_VER_RES_MAX (TFT_HEIGHT)
#define LV_HOR_RES (TFT_WIDTH)
#define LV_VER_RES (TFT_HEIGHT)
/* Color depth:
* - 1: 1 byte per pixel
@ -181,7 +183,7 @@ typedef void* lv_group_user_data_t;
typedef void* lv_fs_drv_user_data_t;
/*File system interface*/
#define LV_USE_FS_IF 1
#define LV_USE_FS_IF 0
#if LV_USE_FS_IF
# define LV_FS_IF_FATFS '\0'
#if defined(ARDUINO_ARCH_ESP32) // || defined(ARDUINO_ARCH_ESP8266)
@ -251,12 +253,18 @@ typedef void* lv_img_decoder_user_data_t;
/* 1: use a custom tick source.
* It removes the need to manually update the tick with `lv_tick_inc`) */
#ifdef ARDUINO
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the sys time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/
#endif /*LV_TICK_CUSTOM*/
#else
#define LV_TICK_CUSTOM 0
#endif
typedef void* lv_disp_drv_user_data_t; /*Type of user data in the display driver*/
typedef void* lv_indev_drv_user_data_t; /*Type of user data in the input device driver*/
@ -280,7 +288,7 @@ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the in
/* 1: Print the log with 'printf';
* 0: user need to register a callback with `lv_log_register_print_cb`*/
# define LV_LOG_PRINTF 0
# define LV_LOG_PRINTF 1
#endif /*LV_USE_LOG*/
/*=================
@ -431,7 +439,7 @@ typedef void* lv_font_user_data_t;
/*Always enable at least on theme*/
#define LV_USE_THEME_MATERIAL 1 /*A fast and impressive theme*/
#define LV_THEME_DEFAULT_INIT lv_theme_hasp_init // We init the theme ourselves
#define LV_THEME_DEFAULT_INIT lv_theme_material_init // lv_theme_hasp_init // We init the theme ourselves
#define LV_THEME_DEFAULT_COLOR_PRIMARY LV_COLOR_RED
#define LV_THEME_DEFAULT_COLOR_SECONDARY LV_COLOR_BLUE
#define LV_THEME_DEFAULT_FLAG 0 //LV_THEME_MATERIAL_FLAG_NONE

View File

@ -34,7 +34,6 @@ extra_default_envs =
; Common environment settings
;***************************************************
[env]
framework = arduino
upload_speed = 921600
monitor_speed = 115200
@ -49,21 +48,20 @@ build_flags =
-D LV_CONF_INCLUDE_SIMPLE ; for lvgl
-D LV_LVGL_H_INCLUDE_SIMPLE ; for lv_drivers
-D LV_COMP_CONF_INCLUDE_SIMPLE ; for components
; -- littlevgl build options ------------------------------
; -- ESP build options ------------------------------------
-D SPIFFS_TEMPORAL_FD_CACHE ; speedup opening recent files
; -- ArduinoJson build options ----------------------------
-D ARDUINOJSON_DECODE_UNICODE=1 ; for utf-8 symbols
-D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments
;-D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments
; -- StreamUtils build options ----------------------------
-D STREAMUTILS_ENABLE_EEPROM=1 ; for STM32, it also supports EEPROM
; -- Hasp build options ----------------------------
-D HASP_VER_MAJ=0
-D HASP_VER_MIN=3
-D HASP_VER_REV=3
-D HASP_VER_MIN=4
-D HASP_VER_REV=0
-D HASP_LOG_LEVEL=9
-D HASP_USE_CONFIG=1 ; Native application, not library
${override.build_flags}
; -- Shared library dependencies in all environments
@ -93,6 +91,7 @@ extra_scripts = tools/copy_fw.py ; tools/pre:extra_script.py
; -- Platform specific build flags
[esp32]
framework = arduino
build_flags =
${env.build_flags}
-D HTTP_UPLOAD_BUFLEN=1024 ; lower http upload buffer
@ -108,6 +107,7 @@ build_flags =
;-D HASP_USE_SPIFFS=1
-D HASP_USE_LITTLEFS=1
;-D HASP_USE_EEPROM=1
-D HASP_USE_CONFIG=1 ; Native application, not library
; -- LittleFS build options ------------------------
-D CONFIG_LITTLEFS_FOR_IDF_3_2
@ -146,6 +146,7 @@ hspi =
-D TFT_SCLK=14
[esp8266]
framework = arduino
build_flags=
-D HTTP_UPLOAD_BUFLEN=512 ; lower http upload buffer
-D MQTT_MAX_PACKET_SIZE=1024 ; longer PubSubClient messages
@ -163,6 +164,7 @@ build_flags=
-D HASP_USE_LITTLEFS=1
-D HASP_USE_EEPROM=1
-D HASP_USE_ETHERNET=0
-D HASP_USE_CONFIG=1 ; Native application, not library
lib_ignore =
ESP32 BLE Arduino
@ -174,6 +176,7 @@ lib_ignore =
lib_deps =
[stm32f4]
framework = arduino
build_flags=
-I include/stm32f4
-D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages
@ -187,6 +190,7 @@ build_flags=
-D HASP_USE_SYSLOG=0 ; Needs UDP
-D HASP_USE_SPIFFS=0
-D HASP_USE_LITTLEFS=0
-D HASP_USE_CONFIG=1 ; Native application, not library
lib_deps =
; sstaub/Ticker @ ^3.2.0
@ -219,3 +223,122 @@ lib_deps =
; ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/master.zip
; lv_drivers@^6.0.2
;src_filter = +<*> +<../drivers/sdl2>
[env:emulator_64bits]
platform = native@^1.1.3
extra_scripts = tools/sdl2_build_extra.py
build_flags =
${env.build_flags}
; ----- Monitor
-D TFT_WIDTH=800
-D TFT_HEIGHT=480
; SDL drivers options
;-D LV_LVGL_H_INCLUDE_SIMPLE
;-D LV_DRV_NO_CONF
-D USE_MONITOR
-D MONITOR_ZOOM=1 ; 2
-D USE_MOUSE
-D USE_MOUSEWHEEL
-D USE_KEYBOARD
; ----- ArduinoJson
-D ARDUINOJSON_DECODE_UNICODE=1
-D HASP_NUM_PAGES=4
-D HASP_USE_SPIFFS=0
-D HASP_USE_LITTLEFS=0
-D HASP_USE_EEPROM=0
-D HASP_USE_GPIO=0
-D HASP_USE_CONFIG=0 ; Standalone application, as library
-D HASP_USE_DEBUG=1
-D HASP_USE_MQTT=1
-D MQTT_MAX_PACKET_SIZE=2048
;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO
;-D LV_LOG_PRINTF=1
; Add recursive dirs for hal headers search
!python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))"
-mconsole
-lSDL2
-D PAHO_MQTT_STATIC
-D _WIN64
-D WINDOWS ; We add this for code branching in hasp
-D WIN32_LEAN_AND_MEAN
-DPAHO_WITH_SSL=FALSE
-DPAHO_BUILD_DOCUMENTATION=FALSE
-DPAHO_BUILD_SAMPLES=FALSE
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_VERBOSE_MAKEFILE=TRUE
;-D NO_PERSISTENCE
-I.pio/libdeps/emulator_64bits/paho/src
-I.pio/libdeps/emulator_64bits/ArduinoJson/src
-I lib/ArduinoJson/src
-I lib/lv_fs_if
-l"ws2_32"
-lrpcrt4
-lcrypt32
-lmingw32
-lSDL2main
-lSDL2
-mwindows
-lm
-ldinput8
-ldxguid
-ldxerr8
-luser32
-lgdi32
-lwinmm
-limm32
-lole32
-loleaut32
-lshell32
-lversion
-luuid
-lsetupapi
-lhid
;-v
lib_deps =
${env.lib_deps}
lv_drivers@~7.9.0
;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip
https://github.com/eclipse/paho.mqtt.c.git
bblanchon/ArduinoJson@^6.17.2 ; Json(l) parser
lib_ignore = paho
src_filter =
+<*>
-<*.h>
+<../hal/sdl2>
+<../.pio/libdeps/emulator_64bits/paho/src/*.c>
-<../.pio/libdeps/emulator_64bits/paho/src/MQTTClient.c>
-<../.pio/libdeps/emulator_64bits/paho/src/MQTTVersion.c>
-<../.pio/libdeps/emulator_64bits/paho/src/SSLSocket.c>
-<MQTTClient.c>
-<MQTTVersion.c>
-<SSLSocket.c>
-<../.pio/libdeps/emulator_64bits/lv_fs_if/lv_fs_pc.c>
-<../.pio/libdeps/emulator_64bits/ArduinoLog/ArduinoLog.cpp>
-<sys>
-<hal>
-<drv>
-<drv/touch>
-<drv/tft>
-<dev>
-<hal>
-<svc>
-<hasp_filesystem.cpp>
-<hasp_gui.cpp>
-<hasp_gui.h>
+<font>
+<hasp>
+<lang>
-<log>
+<mqtt>
-<lib/ArduinoLog>
-<lib/lv_fs_if>
-<../lib/lv_fs_if>
-<../lib/lv_fs_if/lv_fs_if.cpp>
-<../lib/lv_fs_if/lv_fs_if.h>
-<../lib/lv_fs_if/lv_fs_spiffs.cpp>
-<../lib/lv_fs_if/lv_fs_spiffs.h>
+<../.pio/libdeps/emulator_64bits/ArduinoJson/src/ArduinoJson.h>

View File

@ -1,18 +1,26 @@
/* MIT License - Copyright (c) 2020 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifdef ARDUINO
#include <Arduino.h>
#include "hasp_conf.h" // load first
#include "hasp_debug.h"
#include "hasp_config.h"
#include "hasp_gui.h"
#if HASP_USE_CONFIG > 0
#include "hasp_debug.h"
#endif
#if HASP_USE_CONFIG > 0
#include "hasp_config.h"
#include "hasp_gui.h"
#endif
#include "hasp_oobe.h"
#include "hasp/hasp_dispatch.h"
#include "hasp/hasp.h"
#include "net/hasp_network.h"
#include "sys/net/hasp_network.h"
#include "dev/device.h"
@ -49,6 +57,7 @@ void setup()
dispatchSetup();
guiSetup();
debugSetup(); // Init the console
#if HASP_USE_GPIO > 0
gpioSetup();
#endif
@ -137,7 +146,7 @@ void loop()
/* Timer Loop */
if(millis() - mainLastLoopTime >= 1000) {
/* Runs Every Second */
haspEverySecond();
haspEverySecond(); // sleep timer
debugEverySecond(); // statusupdate
#if HASP_USE_OTA > 0
@ -177,4 +186,6 @@ void loop()
#else
delay(6);
#endif
}
}
#endif

120
src/main_windows.cpp Normal file
View File

@ -0,0 +1,120 @@
/* MIT License - Copyright (c) 2020 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifdef WINDOWS
#include "lvgl.h"
#include "app_hal.h"
#include "hasp_conf.h"
#include "hasp_debug.h"
#include "hasp/hasp_dispatch.h"
#include "hasp/hasp.h"
#include "dev/device.h"
#include "app_hal.h"
bool isConnected;
uint8_t mainLoopCounter = 0;
unsigned long mainLastLoopTime = 0;
void debugLvglLogEvent(lv_log_level_t level, const char * file, uint32_t line, const char * funcname,
const char * descr)
{
printf("%s %d\n", file, line);
}
void setup()
{
printf("%s %d\n", __FILE__, __LINE__);
fflush(stdout);
lv_init();
lv_log_register_print_cb(debugLvglLogEvent);
printf("%s %d\n", __FILE__, __LINE__);
fflush(stdout);
hal_setup();
printf("%s %d\n", __FILE__, __LINE__);
haspDevice.pre_setup();
printf("%s %d\n", __FILE__, __LINE__);
dispatchSetup();
// debugSetup(); // Init the console
#if HASP_USE_MQTT > 0
printf("%s %d\n", __FILE__, __LINE__);
mqttSetup(); // Load Hostname before starting WiFi
#endif
printf("%s %d\n", __FILE__, __LINE__);
haspSetup();
mainLastLoopTime = millis() - 1000; // reset loop counter
delay(250);
mqttStart();
}
void loop()
{
haspLoop();
// debugLoop(); // Console
haspDevice.loop();
/* Timer Loop */
if(millis() - mainLastLoopTime >= 1000) {
/* Runs Every Second */
haspEverySecond(); // sleep timer
#if HASP_USE_OTA > 0
otaEverySecond(); // progressbar
#endif
/* Runs Every 5 Seconds */
if(mainLoopCounter == 0 || mainLoopCounter == 5) {
haspDevice.loop_5s();
}
/* Reset loop counter every 10 seconds */
if(mainLoopCounter >= 9) {
mainLoopCounter = 0;
} else {
mainLoopCounter++;
}
mainLastLoopTime += 1000;
}
delay(6);
}
#ifdef WINDOWS
int main(int argv, char ** args)
{
printf("%s %d\n", __FILE__, __LINE__);
fflush(stdout);
setup();
std::cout << "HSetup OK\n";
while(1) {
SDL_Delay(5);
lv_task_handler();
fflush(stdout);
}
std::cout << "Hloop OK\n";
return 0;
}
#else
void loop()
{
delay(5);
lv_task_handler();
}
#endif
#endif

View File

@ -4,7 +4,11 @@
#ifndef HASP_MQTT_H
#define HASP_MQTT_H
#include "ArduinoJson.h"
#include <stdint.h>
#include "hasp_conf.h"
#define __FlashStringHelper char
void mqttSetup();
void mqttLoop();
@ -22,6 +26,6 @@ bool mqttGetConfig(const JsonObject & settings);
bool mqttSetConfig(const JsonObject & settings);
#endif
String mqttGetNodename(void);
//String mqttGetNodename(void);
#endif

View File

@ -35,7 +35,7 @@ EthernetClient mqttNetworkClient;
#endif
#include "hasp_hal.h"
#include "hasp_debug.h"
#include "log/hasp_debug.h"
#include "hasp_config.h"
#include "../hasp/hasp_dispatch.h"

View File

@ -3,7 +3,8 @@
#include "ArduinoJson.h"
#include "hasp_conf.h"
#if HASP_USE_MQTT > 0
#if 0 && HASP_USE_MQTT > 0
#include "PubSubClient.h"

423
src/mqtt/hasp_mqtt_paho.cpp Normal file
View File

@ -0,0 +1,423 @@
/* MIT License - Copyright (c) 2020 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include <stdint.h>
#include "hasp_conf.h"
#if HASP_USE_MQTT > 0
#ifdef USE_PAHO
/*******************************************************************************
* Copyright (c) 2012, 2020 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* https://www.eclipse.org/legal/epl-2.0/
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial contribution
*******************************************************************************/
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "MQTTAsync.h"
#include "hasp_mqtt.h" // functions to implement here
#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload
#include "hasp_debug.h" // for logging
#if !defined(_WIN32)
#include <unistd.h>
#else
#include <windows.h>
#endif
#if defined(_WRS_KERNEL)
#include <OsWrapper.h>
#endif
#define ADDRESS "10.4.0.5:1883"
#define CLIENTID "ExampleClientSub"
#define TOPIC "hasp/plate35/"
#define QOS 1
#define TIMEOUT 10000L
const char * mqttNodeTopic = TOPIC;
const char * mqttGroupTopic = TOPIC;
// char mqttNodeTopic[24];
// char mqttGroupTopic[24];
bool mqttEnabled = false;
bool mqttHAautodiscover = true;
////////////////////////////////////////////////////////////////////////////////////////////////////
// These defaults may be overwritten with values saved by the web interface
#ifndef MQTT_HOST
#define MQTT_HOST "";
#endif
#ifndef MQTT_PORT
#define MQTT_PORT 1883;
#endif
#ifndef MQTT_USER
#define MQTT_USER "";
#endif
#ifndef MQTT_PASSW
#define MQTT_PASSW "";
#endif
#ifndef MQTT_NODENAME
#define MQTT_NODENAME "";
#endif
#ifndef MQTT_GROUPNAME
#define MQTT_GROUPNAME "";
#endif
#ifndef MQTT_PREFIX
#define MQTT_PREFIX "hasp"
#endif
#define LWT_TOPIC "LWT"
char mqttServer[16] = MQTT_HOST;
char mqttUser[23] = MQTT_USER;
char mqttPassword[32] = MQTT_PASSW;
char mqttNodeName[16] = MQTT_NODENAME;
char mqttGroupName[16] = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT;
MQTTAsync mqtt_client;
int disc_finished = 0;
int subscribed = 0;
int connected = 0;
static bool mqttPublish(const char * topic, const char * payload, size_t len, bool retain = false);
/* ===== Paho event callbacks ===== */
void connlost(void * context, char * cause)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
int rc;
connected = 0;
printf("\nConnection lost\n");
if(cause) printf(" cause: %s\n", cause);
printf("Reconnecting\n");
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
if((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start connect, return code %d\n", rc);
}
}
// Receive incoming messages
static void mqtt_message_cb(char * topic, char * payload, unsigned int length)
{ // Handle incoming commands from MQTT
if(length + 1 >= MQTT_MAX_PACKET_SIZE) {
LOG_ERROR(TAG_MQTT_RCV, F("Payload too long (%d bytes)"), length);
return;
} else {
payload[length] = '\0';
}
LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char *)payload);
if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic
// Node topic
topic += strlen(mqttNodeTopic); // shorten topic
} else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic
// Group topic
topic += strlen(mqttGroupTopic); // shorten topic
dispatch_topic_payload(topic, (const char *)payload);
return;
} else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic
if(mqttHAautodiscover && !strcasecmp_P((char *)payload, PSTR("online"))) {
// dispatch_current_state();
// mqtt_ha_register_auto_discovery();
}
return;
} else {
// Other topic
LOG_ERROR(TAG_MQTT, F(D_MQTT_INVALID_TOPIC));
return;
}
// catch a dangling LWT from a previous connection if it appears
if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT
if(!strcasecmp_P((char *)payload, PSTR("offline"))) {
{
char msg[8];
char tmp_topic[strlen(mqttNodeTopic) + 8];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic);
snprintf_P(msg, sizeof(msg), PSTR("online"));
// /*bool res =*/mqttClient.publish(tmp_topic, msg, true);
mqttPublish(tmp_topic, msg, true);
}
} else {
// LOG_TRACE(TAG_MQTT, F("ignoring LWT = online"));
}
} else {
dispatch_topic_payload(topic, (const char *)payload);
}
}
int msgarrvd(void * context, char * topicName, int topicLen, MQTTAsync_message * message)
{
printf("MQT RCV >> ");
printf("%s => %.*s (%d)\n", topicName, message->payloadlen, (char *)message->payload, message->payloadlen);
char msg[message->payloadlen + 1];
memcpy(msg, (char *)message->payload, message->payloadlen);
msg[message->payloadlen] = '\0';
mqtt_message_cb(topicName, (char *)message->payload, message->payloadlen);
MQTTAsync_freeMessage(&message);
MQTTAsync_free(topicName);
return 1;
}
void onDisconnectFailure(void * context, MQTTAsync_failureData * response)
{
printf("Disconnect failed, rc %d\n", response->code);
disc_finished = 1;
}
void onDisconnect(void * context, MQTTAsync_successData * response)
{
printf("Successful disconnection\n");
disc_finished = 1;
connected = 0;
}
void onSubscribe(void * context, MQTTAsync_successData * response)
{
printf("Subscribe succeeded %d\n", response->token);
subscribed = 1;
}
void onSubscribeFailure(void * context, MQTTAsync_failureData * response)
{
printf("Subscribe failed, rc %d\n", response->code);
}
void onConnectFailure(void * context, MQTTAsync_failureData * response)
{
connected = 0;
printf("Connect failed, rc %d\n", response->code);
}
void mqtt_subscribe(void * context, const char * topic)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
int rc;
printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n", topic, CLIENTID, QOS);
opts.onSuccess = onSubscribe;
opts.onFailure = onSubscribeFailure;
opts.context = client;
if((rc = MQTTAsync_subscribe(client, topic, QOS, &opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start subscribe, return code %d\n", rc);
}
}
void onConnect(void * context, MQTTAsync_successData * response)
{
MQTTAsync client = (MQTTAsync)context;
connected = 1;
printf("Successful connection\n");
mqtt_subscribe(context, TOPIC "command/#");
mqtt_subscribe(context, TOPIC "command");
mqtt_subscribe(context, TOPIC "light");
mqtt_subscribe(context, TOPIC "dim");
mqtt_send_object_state(0, 0, "connected");
std::cout << std::endl;
}
void onSendFailure(void * context, MQTTAsync_failureData * response)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
int rc;
printf("Message send failed token %d error code %d\n", response->token, response->code);
opts.onSuccess = onDisconnect;
opts.onFailure = onDisconnectFailure;
opts.context = client;
if((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start disconnect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
}
void onSend(void * context, MQTTAsync_successData * response)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
int rc;
printf("Message with token value %d delivery confirmed\n", response->token);
// opts.onSuccess = onDisconnect;
// opts.onFailure = onDisconnectFailure;
// opts.context = client;
// if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
// {
// printf("Failed to start disconnect, return code %d\n", rc);
// exit(EXIT_FAILURE);
// }
}
/* ===== Local HASP MQTT functions ===== */
static bool mqttPublish(const char * topic, const char * payload, size_t len, bool retain)
{
if(mqttIsConnected()) {
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
int rc;
opts.onSuccess = onSend;
opts.onFailure = onSendFailure;
opts.context = mqtt_client;
pubmsg.payload = (char *)payload;
pubmsg.payloadlen = (int)strlen(payload);
pubmsg.qos = QOS;
pubmsg.retained = 0;
if((rc = MQTTAsync_sendMessage(mqtt_client, topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS) {
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), topic, payload);
} else {
LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), topic, payload);
return true;
}
} else {
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED));
}
return false;
}
/* ===== Public HASP MQTT functions ===== */
bool mqttIsConnected()
{
return connected == 1;
}
void mqtt_send_state(const __FlashStringHelper * subtopic, const char * payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
printf(("%sstate/%s\n"), mqttNodeTopic, subtopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), ("%sstate/%s"), mqttNodeTopic, subtopic);
mqttPublish(tmp_topic, payload, false);
}
void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char * payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid);
mqttPublish(tmp_topic, payload, false);
}
void mqttStart()
{
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
int rc;
int ch;
if((rc = MQTTAsync_create(&mqtt_client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) !=
MQTTASYNC_SUCCESS) {
printf("Failed to create client, return code %d\n", rc);
rc = EXIT_FAILURE;
return;
}
if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, msgarrvd, NULL)) != MQTTASYNC_SUCCESS) {
printf("Failed to set callbacks, return code %d\n", rc);
rc = EXIT_FAILURE;
return;
}
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.onSuccess = onConnect;
conn_opts.onFailure = onConnectFailure;
conn_opts.context = mqtt_client;
if((rc = MQTTAsync_connect(mqtt_client, &conn_opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start connect, return code %d\n", rc);
rc = EXIT_FAILURE;
// goto destroy_exit;
} else {
}
// while (!subscribed && !finished)
// #if defined(_WIN32)
// Sleep(100);
// #else
// usleep(10000L);
// #endif
// if (finished)
// goto exit;
}
void mqttStop()
{
int rc;
MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer;
disc_opts.onSuccess = onDisconnect;
disc_opts.onFailure = onDisconnectFailure;
if((rc = MQTTAsync_disconnect(mqtt_client, &disc_opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start disconnect, return code %d\n", rc);
rc = EXIT_FAILURE;
// goto destroy_exit;
}
// while (!disc_finished)
// {
// #if defined(_WIN32)
// Sleep(100);
// #else
// usleep(10000L);
// #endif
// }
// destroy_exit:
// MQTTAsync_destroy(&client);
// exit:
// return rc;
}
void mqttSetup(){};
void mqttLoop(){};
void mqttEvery5Seconds(bool wifiIsConnected){};
// String mqttGetNodename(void){return "palte35"};
#endif // USE_PAHO
#endif // USE_MQTT

View File

@ -0,0 +1,455 @@
/* MIT License - Copyright (c) 2020 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
#if HASP_USE_MQTT > 0
#ifdef USE_PUBSUBCLIENT
#include "PubSubClient.h"
#include "hasp/hasp.h"
#include "hasp_mqtt.h"
#include "hasp_mqtt_ha.h"
#if defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
WiFiClient mqttNetworkClient;
#elif defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#include <EEPROM.h>
#include <Esp.h>
WiFiClient mqttNetworkClient;
#else
#if defined(STM32F4xx) && HASP_USE_WIFI > 0
// #include <WiFi.h>
WiFiSpiClient mqttNetworkClient;
#else
#if defined(W5500_MOSI) && defined(W5500_MISO) && defined(W5500_SCLK)
#define W5500_LAN
#include <Ethernet.h>
#else
#include <STM32Ethernet.h>
#endif
EthernetClient mqttNetworkClient;
#endif
#endif
#include "hasp_hal.h"
#include "log/hasp_debug.h"
#include "hasp_config.h"
#include "../hasp/hasp_dispatch.h"
#ifdef USE_CONFIG_OVERRIDE
#include "user_config_override.h"
#endif
char mqttNodeTopic[24];
char mqttGroupTopic[24];
bool mqttEnabled = false;
bool mqttHAautodiscover = true;
////////////////////////////////////////////////////////////////////////////////////////////////////
// These defaults may be overwritten with values saved by the web interface
#ifndef MQTT_HOST
#define MQTT_HOST "";
#endif
#ifndef MQTT_PORT
#define MQTT_PORT 1883;
#endif
#ifndef MQTT_USER
#define MQTT_USER "";
#endif
#ifndef MQTT_PASSW
#define MQTT_PASSW "";
#endif
#ifndef MQTT_NODENAME
#define MQTT_NODENAME "";
#endif
#ifndef MQTT_GROUPNAME
#define MQTT_GROUPNAME "";
#endif
#ifndef MQTT_PREFIX
#define MQTT_PREFIX "hasp"
#endif
#define LWT_TOPIC "LWT"
char mqttServer[16] = MQTT_HOST;
char mqttUser[23] = MQTT_USER;
char mqttPassword[32] = MQTT_PASSW;
char mqttNodeName[16] = MQTT_NODENAME;
char mqttGroupName[16] = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT;
PubSubClient mqttClient(mqttNetworkClient);
static bool mqttPublish(const char * topic, const char * payload, size_t len, bool retain = false)
{
if(mqttIsConnected()) {
if(mqttClient.beginPublish(topic, len, retain)) {
mqttClient.write((uint8_t *)payload, len);
mqttClient.endPublish();
LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), topic, payload);
return true;
} else {
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), topic, payload);
}
} else {
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED));
}
return false;
}
static bool mqttPublish(const char * topic, const char * payload, bool retain = false)
{
return mqttPublish(topic, payload, strlen(payload), retain);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Send changed values OUT
bool mqttIsConnected()
{
return mqttEnabled && mqttClient.connected();
}
void mqtt_send_lwt(bool online)
{
char tmp_payload[8];
char tmp_topic[strlen(mqttNodeTopic) + 4];
strncpy(tmp_topic, mqttNodeTopic, sizeof(tmp_topic));
strncat_P(tmp_topic, PSTR(LWT_TOPIC), sizeof(tmp_topic));
// snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic);
size_t len = snprintf_P(tmp_payload, sizeof(tmp_payload), online ? PSTR("online") : PSTR("offline"));
bool res = mqttPublish(tmp_topic, tmp_payload, len, true);
}
void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char * payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 16];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/" HASP_OBJECT_NOTATION), mqttNodeTopic, pageid, btnid);
mqttPublish(tmp_topic, payload);
}
void mqtt_send_state(const __FlashStringHelper * subtopic, const char * payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/%s"), mqttNodeTopic, subtopic);
mqttPublish(tmp_topic, payload);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Receive incoming messages
static void mqtt_message_cb(char * topic, byte * payload, unsigned int length)
{ // Handle incoming commands from MQTT
if(length + 1 >= mqttClient.getBufferSize()) {
LOG_ERROR(TAG_MQTT_RCV, F("Payload too long (%d bytes)"), length);
return;
} else {
payload[length] = '\0';
}
LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char *)payload);
if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic
// Node topic
topic += strlen(mqttNodeTopic); // shorten topic
} else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic
// Group topic
topic += strlen(mqttGroupTopic); // shorten topic
dispatch_topic_payload(topic, (const char *)payload);
return;
} else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic
if(mqttHAautodiscover && !strcasecmp_P((char *)payload, PSTR("online"))) {
dispatch_current_state();
mqtt_ha_register_auto_discovery();
}
return;
} else {
// Other topic
LOG_ERROR(TAG_MQTT, F(D_MQTT_INVALID_TOPIC));
return;
}
// catch a dangling LWT from a previous connection if it appears
if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT
if(!strcasecmp_P((char *)payload, PSTR("offline"))) {
{
char msg[8];
char tmp_topic[strlen(mqttNodeTopic) + 8];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic);
snprintf_P(msg, sizeof(msg), PSTR("online"));
// /*bool res =*/mqttClient.publish(tmp_topic, msg, true);
mqttPublish(tmp_topic, msg, true);
}
} else {
// LOG_TRACE(TAG_MQTT, F("ignoring LWT = online"));
}
} else {
dispatch_topic_payload(topic, (const char *)payload);
}
}
static void mqttSubscribeTo(const __FlashStringHelper * format, const char * data)
{
char tmp_topic[strlen_P((PGM_P)format) + 2 + strlen(data)];
snprintf_P(tmp_topic, sizeof(tmp_topic), (PGM_P)format, data);
if(mqttClient.subscribe(tmp_topic)) {
LOG_VERBOSE(TAG_MQTT, F(D_BULLET D_MQTT_SUBSCRIBED), tmp_topic);
} else {
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_SUBSCRIBED), tmp_topic);
}
}
void mqttStart()
{
char buffer[64];
char mqttClientId[64];
char lastWillPayload[8];
static uint8_t mqttReconnectCount = 0;
// bool mqttFirstConnect = true;
mqttClient.setServer(mqttServer, 1883);
// mqttClient.setSocketTimeout(10); //in seconds
/* Construct unique Client ID*/
{
String mac = halGetMacAddress(3, "");
mac.toLowerCase();
memset(mqttClientId, 0, sizeof(mqttClientId));
snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR(D_MQTT_DEFAULT_NAME), mac.c_str());
LOG_INFO(TAG_MQTT, mqttClientId);
}
// Attempt to connect and set LWT and Clean Session
snprintf_P(buffer, sizeof(buffer), PSTR("%s" LWT_TOPIC), mqttNodeTopic); // lastWillTopic
snprintf_P(lastWillPayload, sizeof(lastWillPayload), PSTR("offline")); // lastWillPayload
haspProgressMsg(F(D_MQTT_CONNECTING));
haspProgressVal(mqttReconnectCount * 5);
if(!mqttClient.connect(mqttClientId, mqttUser, mqttPassword, buffer, 0, true, lastWillPayload, true)) {
// Retry until we give up and restart after connectTimeout seconds
mqttReconnectCount++;
switch(mqttClient.state()) {
case MQTT_CONNECTION_TIMEOUT:
LOG_WARNING(TAG_MQTT, F("Connection timeout"));
break;
case MQTT_CONNECTION_LOST:
LOG_WARNING(TAG_MQTT, F("Connection lost"));
break;
case MQTT_CONNECT_FAILED:
LOG_WARNING(TAG_MQTT, F("Connection failed"));
break;
case MQTT_DISCONNECTED:
snprintf_P(buffer, sizeof(buffer), PSTR(D_MQTT_DISCONNECTED));
break;
case MQTT_CONNECTED:
break;
case MQTT_CONNECT_BAD_PROTOCOL:
LOG_WARNING(TAG_MQTT, F("MQTT version not suported"));
break;
case MQTT_CONNECT_BAD_CLIENT_ID:
LOG_WARNING(TAG_MQTT, F("Client ID rejected"));
break;
case MQTT_CONNECT_UNAVAILABLE:
LOG_WARNING(TAG_MQTT, F("Server unavailable"));
break;
case MQTT_CONNECT_BAD_CREDENTIALS:
LOG_WARNING(TAG_MQTT, F("Bad credentials"));
break;
case MQTT_CONNECT_UNAUTHORIZED:
LOG_WARNING(TAG_MQTT, F("Unauthorized"));
break;
default:
LOG_WARNING(TAG_MQTT, F("Unknown failure"));
}
if(mqttReconnectCount > 20) {
LOG_ERROR(TAG_MQTT, F("Retry count exceeded, rebooting..."));
dispatch_reboot(false);
}
return;
}
LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTED), mqttServer, mqttClientId);
// Subscribe to our incoming topics
const __FlashStringHelper * F_topic;
F_topic = F("%scommand/#");
mqttSubscribeTo(F_topic, mqttGroupTopic);
mqttSubscribeTo(F_topic, mqttNodeTopic);
F_topic = F("%sconfig/#");
mqttSubscribeTo(F_topic, mqttGroupTopic);
mqttSubscribeTo(F_topic, mqttNodeTopic);
mqttSubscribeTo(F("%slight/#"), mqttNodeTopic);
mqttSubscribeTo(F("%sbrightness/#"), mqttNodeTopic);
// mqttSubscribeTo(F("%s"LWT_TOPIC), mqttNodeTopic);
mqttSubscribeTo(F("hass/status"), mqttClientId);
/* Home Assistant auto-configuration */
if(mqttHAautodiscover) mqttSubscribeTo(F("homeassistant/status"), mqttClientId);
// Force any subscribed clients to toggle offline/online when we first connect to
// make sure we get a full panel refresh at power on. Sending offline,
// "online" will be sent by the mqttStatusTopic subscription action.
mqtt_send_lwt(true);
// mqttFirstConnect = false;
mqttReconnectCount = 0;
haspReconnect();
haspProgressVal(255);
dispatch_current_state();
}
void mqttSetup()
{
mqttEnabled = strlen(mqttServer) > 0 && mqttPort > 0;
if(mqttEnabled) {
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(mqtt_message_cb);
// if(!mqttClient.setBufferSize(1024)) {
// LOG_ERROR(TAG_MQTT, F("Buffer allocation failed"));
// } else {
LOG_INFO(TAG_MQTT, F(D_MQTT_STARTED), mqttClient.getBufferSize());
// }
} else {
LOG_WARNING(TAG_MQTT, F(D_MQTT_NOT_CONFIGURED));
}
}
void mqttLoop(void)
{
if(mqttEnabled) mqttClient.loop();
}
void mqttEvery5Seconds(bool networkIsConnected)
{
if(mqttEnabled && networkIsConnected && !mqttClient.connected()) {
LOG_TRACE(TAG_MQTT, F(D_MQTT_RECONNECTING));
mqttStart();
}
}
String mqttGetNodename()
{
return mqttNodeName;
}
void mqttStop()
{
if(mqttEnabled && mqttClient.connected()) {
LOG_TRACE(TAG_MQTT, F(D_MQTT_DISCONNECTING));
mqtt_send_lwt(false);
mqttClient.disconnect();
LOG_INFO(TAG_MQTT, F(D_MQTT_DISCONNECTED));
}
}
#if HASP_USE_CONFIG > 0
bool mqttGetConfig(const JsonObject & settings)
{
bool changed = false;
if(strcmp(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_NAME)] = mqttNodeName;
if(strcmp(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName;
if(strcmp(mqttServer, settings[FPSTR(FP_CONFIG_HOST)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_HOST)] = mqttServer;
if(mqttPort != settings[FPSTR(FP_CONFIG_PORT)].as<uint16_t>()) changed = true;
settings[FPSTR(FP_CONFIG_PORT)] = mqttPort;
if(strcmp(mqttUser, settings[FPSTR(FP_CONFIG_USER)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_USER)] = mqttUser;
if(strcmp(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_PASS)] = mqttPassword;
if(changed) configOutput(settings, TAG_MQTT);
return changed;
}
/** Set MQTT Configuration.
*
* Read the settings from json and sets the application variables.
*
* @note: data pixel should be formated to uint32_t RGBA. Imagemagick requirements.
*
* @param[in] settings JsonObject with the config settings.
**/
bool mqttSetConfig(const JsonObject & settings)
{
configOutput(settings, TAG_MQTT);
bool changed = false;
changed |= configSet(mqttPort, settings[FPSTR(FP_CONFIG_PORT)], F("mqttPort"));
if(!settings[FPSTR(FP_CONFIG_NAME)].isNull()) {
changed |= strcmp(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)]) != 0;
strncpy(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)], sizeof(mqttNodeName));
}
// Prefill node name
if(strlen(mqttNodeName) == 0) {
String mac = halGetMacAddress(3, "");
mac.toLowerCase();
snprintf_P(mqttNodeName, sizeof(mqttNodeName), PSTR(D_MQTT_DEFAULT_NAME), mac.c_str());
changed = true;
}
if(!settings[FPSTR(FP_CONFIG_GROUP)].isNull()) {
changed |= strcmp(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)]) != 0;
strncpy(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)], sizeof(mqttGroupName));
}
if(strlen(mqttGroupName) == 0) {
strcpy_P(mqttGroupName, PSTR("plates"));
changed = true;
}
if(!settings[FPSTR(FP_CONFIG_HOST)].isNull()) {
changed |= strcmp(mqttServer, settings[FPSTR(FP_CONFIG_HOST)]) != 0;
strncpy(mqttServer, settings[FPSTR(FP_CONFIG_HOST)], sizeof(mqttServer));
}
if(!settings[FPSTR(FP_CONFIG_USER)].isNull()) {
changed |= strcmp(mqttUser, settings[FPSTR(FP_CONFIG_USER)]) != 0;
strncpy(mqttUser, settings[FPSTR(FP_CONFIG_USER)], sizeof(mqttUser));
}
if(!settings[FPSTR(FP_CONFIG_PASS)].isNull() &&
settings[FPSTR(FP_CONFIG_PASS)].as<String>() != String(FPSTR(D_PASSWORD_MASK))) {
changed |= strcmp(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)]) != 0;
strncpy(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)], sizeof(mqttPassword));
}
snprintf_P(mqttNodeTopic, sizeof(mqttNodeTopic), PSTR(MQTT_PREFIX "/%s/"), mqttNodeName);
snprintf_P(mqttGroupTopic, sizeof(mqttGroupTopic), PSTR(MQTT_PREFIX "/%s/"), mqttGroupName);
return changed;
}
#endif // HASP_USE_CONFIG
#endif // PUBSUBCLIENT
#endif // HASP_USE_MQTT

33
tools/sdl2_build_extra.py Normal file
View File

@ -0,0 +1,33 @@
Import("env", "projenv")
for e in [ env, projenv ]:
# If compiler uses `-m32`, propagate it to linker.
# Add via script, because `-Wl,-m32` does not work.
if "-m32" in e['CCFLAGS']:
e.Append(LINKFLAGS = ["-m32"])
env.Append(
LINKFLAGS=[
"-static",
"-static-libgcc",
"-static-libstdc++"
]
)
# Override unused "upload" to execute compiled binary
from SCons.Script import AlwaysBuild
AlwaysBuild(env.Alias("build", "$BUILD_DIR/${PROGNAME}", "$BUILD_DIR/${PROGNAME}"))
# Add custom target to explorer
env.AddTarget(
name = "execute",
dependencies = "$BUILD_DIR\${PROGNAME}.exe",
actions = "$BUILD_DIR\${PROGNAME}.exe",
# actions = 'cmd.exe /C "start cmd.exe /C $BUILD_DIR\${PROGNAME}.exe"',
title = "Execute",
description = "Build and execute",
group="General"
)
#print('=====================================')
#print(env.Dump())