From: penglei <1624952103@qq.com> Date: Mon, 9 Jun 2025 07:51:57 +0000 (+0800) Subject: 添加原像心率 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=refs%2Fheads%2Fsdk602patch1126;p=mirrors%2FFD230.git 添加原像心率 --- diff --git a/code/sdk/build/config/target_config/brandy/config.py b/code/sdk/build/config/target_config/brandy/config.py index 1312d53d4..8bc109dd3 100644 --- a/code/sdk/build/config/target_config/brandy/config.py +++ b/code/sdk/build/config/target_config/brandy/config.py @@ -569,6 +569,7 @@ target = { 'CYWEE_SPORT', 'CYWEE_MAC_ACTIVE', 'SUPPORT_CAT1_SERVICE', + 'SUPPORT_CYWEE_SERVICE', 'SUPPORT_TCPIP', 'SUPPORT_HID_SERVICE', 'SUPPORT_BAIDU_MAP', @@ -591,7 +592,7 @@ target = { 'NANDFLASH_F35UQA', 'BLE_INSTRUCT', 'FACTORYTEST_SERVICE', - 'PPG_GH3X2X', + #'PPG_GH3X2X', 'GYRO_SH5001', 'ROTARYENCODER_MIXO', ], @@ -628,7 +629,8 @@ target = { "cywee", "ppg_sensor_gh3x2x", "bp_sensor", - 'gyro', + "gyro", + "ppg_sensor_pah8009", ], 'image_analysis': False, 'fs_image_path':'fd230', diff --git a/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h b/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h index d43bff4a8..4939b1c76 100644 --- a/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h +++ b/code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h @@ -15,7 +15,7 @@ extern void bp_int_callback(pin_t pin, uintptr_t param); #endif -#ifdef PPG_GH3X2X +#ifdef SUPPORT_PPG_SERVICE extern void ppg_int_callback(pin_t pin, uintptr_t param); #endif @@ -24,9 +24,12 @@ extern void gyro_int_callback(pin_t pin, uintptr_t param); #endif #ifdef ROTARYENCODER_MIXO -extern void mixo_int_callback(pin_t pin, uintptr_t param); +// extern void mixo_int_callback(pin_t pin, uintptr_t param); #endif +#ifdef SUPPORT_CYWEE_SERVICE +extern void cywee_int_callback(pin_t pin, uintptr_t param); +#endif /** * @addtogroup connectivity_config_boards @@ -225,7 +228,7 @@ const hal_pio_config_t g_pio_function_config[PIN_MAX_NUMBER] = { { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_DISABLE }, // S_AGPIO_R3 NC { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_DISABLE }, // S_AGPIO_R4 tp reset { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_AGPIO_R5 touch int - { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_DISABLE }, // S_AGPIO_R6 PRG_INT 心率中断 + { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_AGPIO_R6 PRG_INT 心率中断 { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_DISABLE }, // S_AGPIO_R7 GYRO_INT2 #ifdef ENABLE_GYRO { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_AGPIO_R8 GYRO_INT1 @@ -316,11 +319,11 @@ const hal_gpio_config_t g_gpio_function_config[PIN_MAX_NUMBER] = { //默认开启 EXT LDO V3.0 V1.8 { S_AGPIO_L18, HAL_GPIO_DIRECTION_OUTPUT, HAL_GPIO_LEVEL_HIGH, 0, NULL }, -#ifdef ENABLE_CYWEE +#ifdef SUPPORT_CYWEE_SERVICE /**G sensor G_INT1 S_AGPIO_L11 G_INT2 S_AGPIO_L19 采用timer 时这些中断要屏蔽*/ - // { S_AGPIO_L11, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, cywee_int_callback }, + { S_AGPIO_L11, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, cywee_int_callback }, //{ S_AGPIO_L19, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_DEDGE, cywee_int_callback }, -#endif +#endif /**S_AGPIO_R1 GPO alipay默认resetpin*/ { S_AGPIO_R1, HAL_GPIO_DIRECTION_OUTPUT, HAL_GPIO_LEVEL_HIGH, 0, NULL }, #ifdef SUPPORT_CAT1_SERVICE @@ -338,8 +341,12 @@ const hal_gpio_config_t g_gpio_function_config[PIN_MAX_NUMBER] = { #ifdef ENABLE_BN02 { S_AGPIO_R3, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, bp_int_callback }, #endif +#ifdef SUPPORT_PPG_SERVICE #ifdef PPG_GH3X2X - // { S_AGPIO_R6, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, ppg_int_callback}, + { S_AGPIO_R6, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, ppg_int_callback}, +#elif defined PPG_PAH8009 + { S_AGPIO_R6, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_FALLING_EDGE, ppg_int_callback}, +#endif #endif #ifdef ROTARYENCODER_MIXO // { S_AGPIO_L0, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_DEDGE, mixo_int_callback}, diff --git a/code/sdk/drivers/drivers/driver/touch/cst86xx_touch/cst86xx_touch1.c b/code/sdk/drivers/drivers/driver/touch/cst86xx_touch/cst86xx_touch1.c index c3944210f..e1aaa3ea5 100644 --- a/code/sdk/drivers/drivers/driver/touch/cst86xx_touch/cst86xx_touch1.c +++ b/code/sdk/drivers/drivers/driver/touch/cst86xx_touch/cst86xx_touch1.c @@ -172,7 +172,7 @@ static ext_errno cst86xx_suspend(void) return EXT_ERR_SUCCESS; } - cst86xx_reset();//唤醒IC + // cst86xx_reset();//唤醒IC /* Send Sleep Cmd */ reg_write = CST86XX_SLEEP_CMD; diff --git a/code/sdk/zhihui/UI/producttest/include/testPresenter.h b/code/sdk/zhihui/UI/producttest/include/testPresenter.h index 15eeac51c..694f380b7 100644 --- a/code/sdk/zhihui/UI/producttest/include/testPresenter.h +++ b/code/sdk/zhihui/UI/producttest/include/testPresenter.h @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-08-23 10:50:37 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2025-05-13 18:35:42 + * @LastEditTime: 2025-06-06 16:20:02 * @FilePath: /FD230/code/sdk/application/wearable/fd230/nativeapp/nativeui/producttest/include/testPresenter.h * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ diff --git a/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp b/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp index 6bde9cdf1..69b8824c5 100644 --- a/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp +++ b/code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp @@ -4,12 +4,6 @@ #include "producttest/include/testhrsenson.h" #include "AlarmClockModel.h" #include "cmsis_os2.h" -#ifdef SUPPORT_CAT1_SERVICE -#include "cat1_server.h" -#include "cat1_ctl.h" -#include "cat1_server_hal.h" -#endif -#include "ppg_service.h" #include "producttest/include/testView.h" #ifdef __cplusplus #if __cplusplus @@ -19,9 +13,12 @@ extern "C" #endif #include "pm_veto.h" #include "pm.h" -#ifdef PPG_VC9202 - #include "vc9202_user.h" + +#ifdef SUPPORT_PPG_SERVICE +#include "ppg_service.h" +#include "ppg_hal.h" #endif + #ifdef __cplusplus #if __cplusplus } @@ -100,50 +97,25 @@ namespace OHOS static bool button_falg=true; void testhrsenson1View:: setgrayvalue(int g,int r,int ir) { -#ifdef PPG_HX3695 - if(label_hrsenson_value_vison!=NULL) - { - - char buf[124]={0}; - sprintf(buf,"gray:\n green:%d\nred:%d\nir:%d",g,r,ir); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s",buf); - label_hrsenson_value_vison->SetText(buf); - RootView::GetInstance()->Invalidate(); - int8_t md = PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST; - send_ppg_cmd_msg(md); - button_falg=true; - } -#endif } void testhrsenson1View:: setlightvalue(int g,int r,int ir) { char buf[124]={0}; - if(label_hrsenson_value_vison!=nullptr) { -#ifdef PPG_HX3695 - sprintf(buf,"leaklight:\ngreen:%d\nred:%d\nir:%d",g,r,ir); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s",buf); - label_hrsenson_value_vison->SetText(buf); - RootView::GetInstance()->Invalidate(); - int8_t md = PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST; - send_ppg_cmd_msg(md); - button_falg=true; -#elif defined PPG_VC9202 - //漏光测试 - // send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST); - LOS_Msleep(500); - uint32_t led_cur = 0; - uint32_t apre_val = 0; - uint32_t aps_val = 9; - vc9202_get_leaklight_data(&led_cur,&apre_val,&aps_val); +#ifdef SUPPORT_PPG_SERVICE + LOS_Msleep(1000); + uint32_t ch0 = 0; + uint32_t ch1 = 0; + uint32_t ch2 = 0; + ppg_get_leaklight_data(&ch0,&ch1,&ch2); send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); - sprintf(buf,"leaklight:\ngreen:%d\nred:%d\nir:%d",led_cur,apre_val,aps_val); + sprintf(buf,"leaklight:\ngreen:%d\nred:%d\nir:%d",ch0,ch1,ch2); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s",buf); label_hrsenson_value_vison->SetText(buf); RootView::GetInstance()->Invalidate(); button_falg=true; -#endif +#endif } } @@ -197,9 +169,7 @@ namespace OHOS int8_t md = PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST; send_ppg_cmd_msg(md); button_falg=false; -#ifdef PPG_VC9202 testhrsenson1View::setlightvalue(0,0,0); -#endif } } diff --git a/code/sdk/zhihui/drivers/bp/bn02/bn02.c b/code/sdk/zhihui/drivers/bp/bn02/bn02.c index 7d2de8c69..6f0edafd1 100644 --- a/code/sdk/zhihui/drivers/bp/bn02/bn02.c +++ b/code/sdk/zhihui/drivers/bp/bn02/bn02.c @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2025-01-16 12:35:15 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2025-05-24 14:43:40 + * @LastEditTime: 2025-06-04 15:00:26 * @FilePath: /sdk615/code/sdk/zhihui/drivers/bp/bn02/bn02.c * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -24,6 +24,24 @@ #define POWER_EN S_AGPIO_R0 +#define BN02_FILE "user/userdata/bn02.bin" + +static int DATA_HANDLE = 1 << 24; + +static FILE *fp = NULL; + +static int data_cnt = 0; +static int data[16 * 5 * 60] = {0}; + +// int data = ((rxByte[i] & 0xff) << 16) +// + ((rxByte[i + 1] & 0xff) << 8) +// + (rxByte[i + 2] & 0xff); +// if (data >= DATA_HANDLE / 2) { +// data -= DATA_HANDLE; +// } +// 其中:DATA_HANDLE = 2^24 + + bool Bn02_write_reg(uint8_t data) { uint8_t cnt = pm_veto_get_id_cnt(PM_ID_BP); @@ -127,10 +145,33 @@ void bn02_int_handle(void) memset(bn02_buf,0,sizeof(bn02_buf)); Bn02_reads(bn02_buf,48); - if(bn02_get_ble_status()) - { - bn02_replymsg(bn02_buf,sizeof(bn02_buf),1); - } + for(i = 0;i<48;i+=3) + { + + data[data_cnt] = ((bn02_buf[i] & 0xff) << 16) + + ((bn02_buf[i + 1] & 0xff) << 8) + + (bn02_buf[i + 2] & 0xff); + + if (data[data_cnt] >= DATA_HANDLE / 2) + data[data_cnt] -= DATA_HANDLE; + + data_cnt++; + + printf("0x%x 0x%x 0x%x 0x%x\n",i,bn02_buf[i],bn02_buf[i+1],bn02_buf[i+2],data[data_cnt]); + } + // if(bn02_get_ble_status()) + // { + // bn02_replymsg(bn02_buf,sizeof(bn02_buf),1); + // } + + // if(fp && data_cnt <= 48 * 300) + // { + // data_cnt += 48; + // if(fwrite(bn02_buf,1,48,fp) != 48) + // printf("bn02 fwrite failed\n"); + // else + // printf("bn02 fwrite succed data_cnt:%d\n",data_cnt); + // } // for(i = 0;i<48;i++) // { @@ -143,6 +184,9 @@ void bn02_start(void) Bn02_Power_Ctrl(1); bn02_int_init(); Bn02_write_reg(BN02_START_CMD); + + data_cnt = 0; + // fp = fopen(BN02_FILE, "wb"); } void bn02_stop(void) @@ -150,4 +194,10 @@ void bn02_stop(void) bn02_int_deinit(); Bn02_write_reg(BN02_STOP_CMD); Bn02_Power_Ctrl(0); + + // if(fp) + // { + // fclose(fp); + // fp = NULL; + // } } diff --git a/code/sdk/zhihui/drivers/mag/service/mag_service.c b/code/sdk/zhihui/drivers/mag/service/mag_service.c index b2561f258..ce7491490 100644 --- a/code/sdk/zhihui/drivers/mag/service/mag_service.c +++ b/code/sdk/zhihui/drivers/mag/service/mag_service.c @@ -1,47 +1,4 @@ -/** - * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n - * - * Description: Test adc source \n - * Author: @CompanyNameTag \n - * History: \n - * 2022-08-16, Create file. \n - */ - -#include "adc.h" -#define TEST_PARAM_ARGC_1 1 -#define TEST_PARAM_ARGC_2 2 -#define TEST_PARAM_ARGC_3 3 -#define TEST_PARAM_ARGC_4 4 -#define TEST_PARAM_ARGC_5 5 -#define TEST_PARAM_ARGC_6 6 -#define TEST_PARAM_ARGC_7 7 -#define TEST_PARAM_4_BYTES 4 -#define TEST_PARAM_8_BYTES 8 -typedef enum { - SUITE_OK = 0, - SUITE_UNKNOWN_FUNCTION = -1, - SUITE_ERROR_TIMED_OUT = -2, - SUITE_ERROR_BAD_PARAMS = -3, - SUITE_ERROR_PIN_ALLOCATION = -4, - SUITE_ERROR_PIN_DEALLOCATION = -5, - SUITE_ERROR_UNEXPECTED_INTERRUPT = -6, - SUITE_ALLOC_FAILED = -7, - SUITE_CONFIG_FAILED = -8, - SUITE_TEST_FAILED = -254, -} magservice_error_e; - -#if defined(CONFIG_ADC_SUPPORT_AFE) - -#error CONFIG_ADC_SUPPORT_AFE - -#include "hal_adc_v152.h" -#include "hal_adc_v152_regs_op.h" -#else -#include "hal_adc_v151.h" -#include "hal_adc_v151_regs_op.h" -#endif -#include "adc_porting.h" #include "pinctrl.h" #include "debug_print.h" #include "soc_osal.h" diff --git a/code/sdk/zhihui/drivers/ppg/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/CMakeLists.txt index 88975a2a8..360e652f4 100644 --- a/code/sdk/zhihui/drivers/ppg/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/ppg/CMakeLists.txt @@ -3,4 +3,5 @@ add_subdirectory_if_exist(hx3695) add_subdirectory_if_exist(ppgBleService) add_subdirectory_if_exist(vc9202) add_subdirectory_if_exist(vc921x) -add_subdirectory_if_exist(gh3x2x) \ No newline at end of file +add_subdirectory_if_exist(gh3x2x) +add_subdirectory_if_exist(pah8009) \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h index fce1cdf13..f9485fc23 100644 --- a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-06-07 11:18:26 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2025-01-13 14:09:50 + * @LastEditTime: 2025-06-06 11:23:50 * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.h * @Description: * @@ -18,7 +18,7 @@ extern "C" { #include "stdint.h" -typedef uint32_t PPG_CMD_TYPE_T ; +// typedef uint32_t PPG_CMD_TYPE_T ; void ppg_send_cmd_to_gh3x2x_driver(char* mode, uint8_t enable); diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c index 2a84d343e..385077b6b 100644 --- a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c +++ b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-03-13 15:08:38 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2025-05-13 16:48:04 + * @LastEditTime: 2025-05-28 14:13:17 * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c * @Description: * @@ -82,7 +82,7 @@ void ppg_send_cmd_to_gh3x2x_driver(char* mode, uint8_t enable) if (enable == 1) { // ppg_service_running_stat = true; - uapi_pm_control(PM_APP_WAKE_NEEDED); + // uapi_pm_control(PM_APP_WAKE_NEEDED); tyhx_poweron(); // GH3X2X_AFE_StartFunction(mode); GH3X2X_AFE_Init(); @@ -90,7 +90,7 @@ void ppg_send_cmd_to_gh3x2x_driver(char* mode, uint8_t enable) } else { - uapi_pm_control(PM_APP_WAKE_NONEED); + // uapi_pm_control(PM_APP_WAKE_NONEED); GH3X2X_AFE_StopSampling(); tyhx_poweroff(); } diff --git a/code/sdk/zhihui/drivers/ppg/hx3695/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/hx3695/CMakeLists.txt index c55141c0d..c11b318b8 100644 --- a/code/sdk/zhihui/drivers/ppg/hx3695/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/ppg/hx3695/CMakeLists.txt @@ -12,7 +12,7 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/hx3695_hrs_agc.c ${CMAKE_CURRENT_SOURCE_DIR}/hx3695_hrv_agc.c ${CMAKE_CURRENT_SOURCE_DIR}/hx3695_spo2_agc.c - ${CMAKE_CURRENT_SOURCE_DIR}/hx3695_hal.c + #${CMAKE_CURRENT_SOURCE_DIR}/hx3695_hal.c ${CMAKE_CURRENT_SOURCE_DIR}/hx3695_hrs_custom.c ) set(PUBLIC_HEADER diff --git a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.c b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.c index a847f5aa6..0045e149c 100644 --- a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.c +++ b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.c @@ -32,10 +32,15 @@ // #include "lv_dev.h" // #include "app_task.h" +#ifdef SUPPORT_CYWEE_SERVICE #include "cywee_hal.h" #include "cywee_service.h" #include "custom_utils.h" #include "custom_runtime.h" +#endif + +#include "ppg_hal.h" + FT_CUSTOM_RESULTS_t hrsresult ={0}; @@ -43,7 +48,9 @@ int16_t gsen_fifo_x[64]={0}; int16_t gsen_fifo_y[64]={0}; int16_t gsen_fifo_z[64]={0}; +#ifdef SUPPORT_CYWEE_SERVICE gsenson_t gsensordata[32]; +#endif static uint8_t msg_count = 0; @@ -125,9 +132,10 @@ uint8_t alg_ram[11 * 1024] __attribute__((aligned(4))); //uint8_t alg_ram[10] = {0}; ppg_sensor_data_t ppg_s_data; -static int cywee_hrs_data = 0; +static uint8_t hrs_result = 0; static int history_wear_status = -1; -static int cywee_wear_status = 0; +static uint8_t wear_status = 0; +static uint8_t spo2_result = 0; static uint8_t hx3695_chip_id = 0; @@ -364,7 +372,7 @@ void hx3695_gpioint_cfg(bool en) } #endif -bool hx3695_chip_check(void) +uint8_t hx3695_chip_check(void) { uint8_t i = 0; uint8_t chip_id = 0; @@ -380,13 +388,13 @@ bool hx3695_chip_check(void) //printf("hx3695_chip_check ok chip_id: 0x%x \r\n",chip_id); //Efuse_Mode_Check(); hx3695_chip_id = chip_id; - return true; + // return hx3695_chip_id; } } - printf(" hx3695_chip_check fail! chip_id: 0x%x \r\n", chip_id); + printf(" hx3695 chip_id: 0x%x \r\n", chip_id); - return false; + return chip_id; } void hx3695_get_id(uint8_t *ppg_id) @@ -2237,7 +2245,7 @@ void hx3695_check_touch_init(void) // // 初始化调用入口函数 bool hx3695_init(WORK_MODE_T mode) { - hx3695_msg_callback_t func; + // hx3695_msg_callback_t func; //TYHX_LOG("this chip hx3695_init mode: %d !! \r\n", mode); @@ -2328,11 +2336,11 @@ bool hx3695_init(WORK_MODE_T mode) //TYHX_LOG(" hx3695_init mode : LEAK_LIGHT_MODE \n"); hx3695_factroy_test(LEAK_LIGHT_TEST); - func = hx3695_get_send_msg_callback_func(); - if(func != NULL) - { - func(HX3695_MSG_TYPE_LEAKLIGHT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - } + // func = hx3695_get_send_msg_callback_func(); + // if(func != NULL) + // { + // func(HX3695_MSG_TYPE_LEAKLIGHT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // } break; case FT_GRAY_CARD_MODE: @@ -2344,11 +2352,11 @@ bool hx3695_init(WORK_MODE_T mode) //TYHX_LOG(" hx3695_init mode : GRAY_CARD_MODE \n"); hx3695_factroy_test(GRAY_CARD_TEST); - func = hx3695_get_send_msg_callback_func(); - if(func != NULL) - { - func(HX3695_MSG_TYPE_GRAYCARD_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - } + // func = hx3695_get_send_msg_callback_func(); + // if(func != NULL) + // { + // func(HX3695_MSG_TYPE_GRAYCARD_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // } break; case FT_INT_TEST_MODE: @@ -2717,7 +2725,18 @@ static void get_avg_hrs(int32_t hrs) uint8_t hx3695_get_hrs(void) { - return cywee_hrs_data; + return hrs_result; +} + +uint8_t hx3695_get_spo2(void) +{ + return spo2_result; +} + + +uint8_t hx3695_get_wear_status(void) +{ + return wear_status; } void hx3695_set_hrs_ble_swtich(uint8_t cmd) @@ -2734,33 +2753,35 @@ uint8_t hx3695_get_hrs_ble_swtich(void) void hx3695_wearstatus_update(void) { - if(history_wear_status != cywee_wear_status) + if(history_wear_status != wear_status) { - history_wear_status = cywee_wear_status; - do_cywee_service_check_msg(CYWEE_SERVICE_CMD_WEAR_STATUS_CHANGE,&cywee_wear_status); + history_wear_status = wear_status; +#ifdef SUPPORT_CYWEE_SERVICE + do_cywee_service_check_msg(CYWEE_SERVICE_CMD_WEAR_STATUS_CHANGE,&wear_status); +#endif } } //脱腕上报未佩戴信息 void hx3695_unwearstatus_update(void) { - hx3695_msg_callback_t func = hx3695_get_send_msg_callback_func(); - if(func != NULL && !uapi_dev_runtime_get_train_status()) - { - hrsresult.lastesthrs = 0; - hrsresult.wearstatus = 0; - //为了主界面脱腕灵敏;需要增加未佩戴 - func(HX3695_MSG_TYPE_HRS_UPDATE, &hrsresult, sizeof(FT_CUSTOM_RESULTS_t)); - func(HX3695_MSG_TYPE_WEARSTAT_UPDATE, &hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - } + // hx3695_msg_callback_t func = hx3695_get_send_msg_callback_func(); + // if(func != NULL && !uapi_dev_runtime_get_train_status()) + // { + // hrsresult.lastesthrs = 0; + // hrsresult.wearstatus = 0; + // //为了主界面脱腕灵敏;需要增加未佩戴 + // func(HX3695_MSG_TYPE_HRS_UPDATE, &hrsresult, sizeof(FT_CUSTOM_RESULTS_t)); + // func(HX3695_MSG_TYPE_WEARSTAT_UPDATE, &hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // } if(uapi_dev_runtime_get_train_status()) { - cywee_wear_status = 0; + wear_status = 0; hx3695_wearstatus_update(); - cywee_hrs_data = 0; - // do_cywee_service_check_msg(CYWEE_SERVICE_CMD_HRS_CHANGE,&cywee_data); + hrs_result = 0; + } } @@ -2847,9 +2868,10 @@ void hx3695_hrs_ppg_Int_handle(void) // { // return; // } + #ifdef SUPPORT_CYWEE_SERVICE memset(gsensordata,0.0f,sizeof(gsenson_t) * *count); - gsensor_get_n_data(*count,gsensordata); + cywee_get_gsensor_data(*count,gsensordata); for(ii=0; ii<*count; ii++) { @@ -2881,7 +2903,7 @@ void hx3695_hrs_ppg_Int_handle(void) gsen_fifo_z_send[ii] = gsensordata[ii].z * 4096 / 10; } - // gsensor_get_n_data(8,gsensordata); + // cywee_get_gsensor_data(8,gsensordata); // for(ii=0; ii<*count; ii++) // { // if(gsensordata[ii].x == 0.0f && gsensordata[ii].y == 0.0f && gsensordata[ii].z == 0.0f) @@ -2918,6 +2940,7 @@ void hx3695_hrs_ppg_Int_handle(void) //PRINT("hxdata:%d/%d %d %d %.3f %.3f %.3f %d\r\n" ,1+ii,*count,PPG_buf[ii],ir_buf[0],gsensordata[ii].x,gsensordata[ii].y,gsensordata[ii].z,ppg_s_data.green_cur); } +#endif hrs_wear_status = hx3695_hrs_get_wear_status(); //PRINT("hrs_wear_status: %d !!\r\n", hrs_wear_status); @@ -2962,45 +2985,39 @@ void hx3695_hrs_ppg_Int_handle(void) if(hrsresult.wearstatus == MSG_HRS_WEAR) { - if(hrsresult.hr_living == MSG_LIVING_TRUE) - { - cywee_wear_status = 1; - if(hrsresult.lastesthrs > 30 && hrsresult.lastesthrs < 220) - get_avg_hrs(hrsresult.lastesthrs); - } - else - { - cywee_wear_status = 0; - } + wear_status = 1; + if(hrsresult.lastesthrs > 30 && hrsresult.lastesthrs < 220) + get_avg_hrs(hrsresult.lastesthrs); } - else + else if(hrsresult.wearstatus == MSG_HRS_NO_WEAR || hrsresult.hr_living == MSG_LIVING_FAIL) { hrsresult.wearstatus = MSG_HRS_NO_WEAR; hrsresult.lastesthrs = 0; - cywee_wear_status = 0; + wear_status = 0; } - hx3695_msg_callback_t func = hx3695_get_send_msg_callback_func(); - if(func != NULL) - { - if(his_wear == hrsresult.wearstatus) - { - wear_cnt++; - if(wear_cnt >= 2 && !his_wear) //未佩戴超过2次 上报未佩戴信息 - { - func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - wear_cnt = 0; - } - } - else - { - his_wear = hrsresult.wearstatus; - wear_cnt = 0; - } - } + // hx3695_msg_callback_t func = hx3695_get_send_msg_callback_func(); + + // if(func != NULL) + // { + // if(his_wear == hrsresult.wearstatus) + // { + // wear_cnt++; + // if(wear_cnt >= 2 && !his_wear) //未佩戴超过2次 上报未佩戴信息 + // { + // func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // wear_cnt = 0; + // } + // } + // else + // { + // his_wear = hrsresult.wearstatus; + // wear_cnt = 0; + // } + // } //PRINT("hrsresult.wearstatus : %d , his_wear : %d , wear_cnt : %d \n",hrsresult.wearstatus,his_wear,wear_cnt); - // PRINT("hrsresult.wearstatus : %d , cywee_wear_status : %d , hr_living : %d \n",hrsresult.wearstatus,cywee_wear_status,hrsresult.hr_living); + // PRINT("hrsresult.wearstatus : %d , wear_status : %d , hr_living : %d \n",hrsresult.wearstatus,wear_status,hrsresult.hr_living); // if(hrs_wear_status == MSG_HRS_WEAR && hrsresult.hr_living == MSG_LIVING_TRUE) // { // if(hrsresult.lastesthrs > 30 && hrsresult.lastesthrs < 220) @@ -3014,24 +3031,27 @@ void hx3695_hrs_ppg_Int_handle(void) // hrsresult.lastesthrs = 0; // } + // PRINT("hrs : %d , wear_status : %d \n",hrsresult.lastesthrs,hrsresult.wearstatus); + hrs_result = hrsresult.lastesthrs; + msg_count++; if(msg_count >= 3) { msg_count = 0; - if(func != NULL) - { - //PRINT("hrsresult.lastesthrs : %d \n",hrsresult.lastesthrs); - func(HX3695_MSG_TYPE_HRS_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - if(uapi_get_cywee_static_state()) - { - func(HX3695_MSG_TYPE_STATIC_HRS_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - } - } + // if(func != NULL) + // { + // //PRINT("hrsresult.lastesthrs : %d \n",hrsresult.lastesthrs); + // func(HX3695_MSG_TYPE_HRS_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // if(uapi_get_cywee_static_state()) + // { + // func(HX3695_MSG_TYPE_STATIC_HRS_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // } + // } if(uapi_dev_runtime_get_train_status()) { hx3695_wearstatus_update(); - cywee_hrs_data = hrsresult.lastesthrs; + // hrs_result = hrsresult.lastesthrs; // do_cywee_service_check_msg(CYWEE_SERVICE_CMD_HRS_CHANGE,&cywee_data); } } @@ -3155,7 +3175,7 @@ void hx3695_hrs_ppg_Int_handle(void) encoded_hrm[15] = ppg_s_data.green_cur;//绿灯电流 encoded_hrm[16] = ppg_s_data.ir_cur;//红外电流 -#ifdef SUPPORT_BLE_SERVICE +#ifdef SUPPORT_PPG_BLE_SERVICE if(cm_custom_ble_service_on_flag()) ble_ppgtest_server_send_input_report(encoded_hrm,PPG_DATA_LEN_MAX); #endif @@ -3414,7 +3434,7 @@ void hx3695_spo2_ppg_Int_handle(void) { return; } - //gsensor_get_n_data(8,gsensordata); + //cywee_get_gsensor_data(8,gsensordata); for(ii=0; ii<*count; ii++) { @@ -3502,7 +3522,7 @@ void hx3695_spo2_ppg_Int_handle(void) DEBUG_PRINTF("block_cnt: %d, data_cnt:%d, hr_result:%d,ir_quality:%d,motion:%d,poor_signal:%d,reliable_score_result:%d,screen_up:%d,spo2_result:%d\r\n",spo2_alg_results.block_cnt,spo2_alg_results.data_cnt,spo2_alg_results.hr_result,spo2_alg_results.ir_quality,spo2_alg_results.motion,spo2_alg_results.poor_signal,spo2_alg_results.reliable_score_result,spo2_alg_results.screen_up,spo2_alg_results.spo2_result); hrsresult.lastestspo2 = spo2_alg_results.spo2_result; - + spo2_result = hrsresult.lastestspo2; // if(hrsresult.lastestspo2) { // store_latest_spo2(hrsresult.lastestspo2); @@ -3511,13 +3531,13 @@ void hx3695_spo2_ppg_Int_handle(void) // hr_sensor_notify_factory_test(); } - hx3695_msg_callback_t func = hx3695_get_send_msg_callback_func(); - if(func != NULL) - { - hrsresult.wearstatus = spo2_wear_status; - func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - func(HX3695_MSG_TYPE_SPO2_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); - } + // hx3695_msg_callback_t func = hx3695_get_send_msg_callback_func(); + // if(func != NULL) + // { + // hrsresult.wearstatus = spo2_wear_status; + // func(HX3695_MSG_TYPE_WEARSTAT_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // func(HX3695_MSG_TYPE_SPO2_UPDATE,&hrsresult,sizeof(FT_CUSTOM_RESULTS_t)); + // } @@ -3601,7 +3621,7 @@ if(hrs_ble_falg) encoded_hrm[15] = cal.R_LED; encoded_hrm[16] = cal.IR_LED1; -#ifdef SUPPORT_BLE_SERVICE +#ifdef SUPPORT_PPG_BLE_SERVICE if(cm_custom_ble_service_on_flag()) ble_ppgtest_server_send_input_report(encoded_hrm,PPG_DATA_LEN_MAX); #endif @@ -3794,7 +3814,7 @@ void hx3695_wear_ppg_Int_handle(void) hx3695_wear_msg_code_t hx3695_wear_status; hx3695_check_touch_read(&ppg_s_data); - cywee_wear_status = hx3695_check_touch_send_data(ir_buf,*count); + wear_status = hx3695_check_touch_send_data(ir_buf,*count); hx3695_wearstatus_update(); extern uint8_t notouch_cnt; extern uint8_t touch_cnt; @@ -3819,4 +3839,60 @@ void hx3695_lab_test_Int_handle(void) } #endif +void hx3695_control(char *mode,uint8_t enable) +{ + WORK_MODE_T md = NULL_MODE; + if (strcmp(mode, "hrs") == 0) { + md = HRS_MODE; + } else if (strcmp(mode, "hrv") == 0) { + md = HRV_MODE; + } else if (strcmp(mode, "spo2") == 0) { + md = SPO2_MODE; + } else if (strcmp(mode, "leaklight") == 0) { + md = FT_LEAK_LIGHT_MODE; + } else if (strcmp(mode, "graycard") == 0) { + md = FT_GRAY_CARD_MODE; + } else if (strcmp(mode, "ledoff") == 0) { + md = FT_LED_OFF_MODE; + } else if (strcmp(mode, "wear") == 0) { + md = WEAR_MODE; + } else if (strcmp(mode, "single") == 0) { + md = FT_SINGLE_CHECK_MODE; + } + + + if (enable == 1 || md == FT_LED_OFF_MODE) { + hx3695_init(md); + } else { + if(md == HRS_MODE|| md == FT_LEAK_LIGHT_MODE || md == FT_GRAY_CARD_MODE || md == WEAR_MODE || md == FT_SINGLE_CHECK_MODE) + { +#ifdef HRS_ALG_LIB + hx3695_hrs_disable(); + // PRINT("uapi_dev_runtime_get_sleep_monitoring_status : %d \n",uapi_dev_runtime_get_sleep_monitoring_status()); + // PRINT("uapi_dev_runtime_get_hrs_passivity_flag : %d \n",uapi_dev_runtime_get_hrs_passivity_flag()); + if(uapi_dev_runtime_get_sleep_monitoring_status() && uapi_dev_runtime_get_hrs_passivity_flag())//处于睡眠监测 且在心率周期检测期间 上报活体佩戴 + { + hx3695_wearstatus_update(); + uapi_dev_runtime_set_hrs_passivity(0);//清除被动检测runtime + } +#endif + }else if(md == HRV_MODE) + { +#ifdef HRV_ALG_LIB + hx3695_hrv_disable(); +#endif + }else if(md == SPO2_MODE) + { +#ifdef SPO2_ALG_LIB + hx3695_spo2_disable(); +#endif + } + else{ +#ifdef HRS_ALG_LIB + hx3695_hrs_disable(); +#endif + } + } +} + #endif //CHIP_HX3695 \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.h b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.h index 0e78bf5d0..32b00e010 100644 --- a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.h +++ b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695.h @@ -245,7 +245,7 @@ void hx3695_delay_ms(uint32_t ms); bool hx3695_write_reg(uint8_t addr, uint8_t data); uint8_t hx3695_read_reg(uint8_t addr); bool hx3695_brust_read_reg(uint8_t addr , uint8_t *buf, uint16_t length); -bool hx3695_chip_check(void); +uint8_t hx3695_chip_check(void); void hx3695_get_id(uint8_t *ppg_id); uint8_t hx3695_read_fifo_size(void); uint16_t hx3695_read_fifo_data(int32_t *s_buf, uint8_t size, uint8_t phase_num); @@ -302,6 +302,9 @@ void hx3695_unwearstatus_update(void); void hx3695_set_hrs_ble_swtich(uint8_t cmd); uint8_t hx3695_get_hrs_ble_swtich(void); uint8_t hx3695_get_hrs(void); -#include "hx3695_hal.h" +uint8_t hx3695_get_spo2(void); +uint8_t hx3695_get_wear_status(void); + +void hx3695_control(char *mode,uint8_t enable); #endif diff --git a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_check_touch.c b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_check_touch.c index 09e9a466d..dd10f20ff 100644 --- a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_check_touch.c +++ b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_check_touch.c @@ -9,7 +9,9 @@ #include "hx3695.h" #include "hx3695_check_touch.h" #include "hx3695_hrs_agc.h" +#ifdef SUPPORT_CYWEE_SERVICE #include "cywee_hal.h" +#endif hx3695_wear_msg_code_t hx3695_wear_status = MSG_NO_WEAR; hx3695_wear_msg_code_t hx3695_wear_status_pre = MSG_NO_WEAR; diff --git a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hal.c b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hal.c index 4bad4134c..038259e74 100644 --- a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hal.c +++ b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hal.c @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-03-13 15:08:38 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2024-11-19 19:40:35 + * @LastEditTime: 2025-05-15 17:02:49 * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c * @Description: * @@ -65,7 +65,7 @@ void ppg_send_cmd_to_driver(char* mode, uint8_t enable) if (enable == 1 || md == FT_LED_OFF_MODE) { // ppg_service_running_stat = true; - uapi_pm_control(PM_APP_WAKE_NEEDED); + // uapi_pm_control(PM_APP_WAKE_NEEDED); tyhx_poweron(); //custom_i2c_reset(); hx3695_init(md); @@ -100,7 +100,7 @@ void ppg_send_cmd_to_driver(char* mode, uint8_t enable) hx3695_hrs_disable(); #endif } - uapi_pm_control(PM_APP_WAKE_NONEED); + // uapi_pm_control(PM_APP_WAKE_NONEED); tyhx_poweroff(); } } \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hrs_custom.c b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hrs_custom.c index c78766d96..2347c705a 100644 --- a/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hrs_custom.c +++ b/code/sdk/zhihui/drivers/ppg/hx3695/hx3695_hrs_custom.c @@ -35,9 +35,9 @@ void tyhx_delay_ms(uint32_t ms) LOS_Mdelay(ms); } - - +#ifdef SUPPORT_PPG_SERVICE #include "ppg_service.h" +#endif #include "cmsis_os2.h" #define BUTTON_APP_TIMER_INTERVAL 20 osTimerId_t g_timer40_timer = NULL; @@ -47,19 +47,25 @@ static uint8_t g_hx3695_timer_installed = 0; static void timer40_func(void) { +#ifdef SUPPORT_PPG_SERVICE send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_PPG_40TIMER_CALLBACK); +#endif // agc_timeout_handler(NULL); } static void timer320_func(void) { +#ifdef SUPPORT_PPG_SERVICE send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_PPG_320TIMER_CALLBACK); +#endif // heart_rate_meas_timeout_handler(NULL); } static void timer5000_func(void) { +#ifdef SUPPORT_PPG_SERVICE send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_5000TIMER_CALLBACK); +#endif // heart_rate_meas_timeout_handler(NULL); } bool tyhx_timer_init(void) @@ -116,34 +122,5 @@ bool tyhx_timer_stop(uint32_t ms) return 1; } -// S_AGPIO_L26 心率复位 PPG reset -#define GPIO_PIN_PRG_RESET S_AGPIO_L26 -// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚 -#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0 - -uint32_t tyhx_poweron(void) -{ - uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); - uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); - uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_HIGH); - - uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); - uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); - uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH); - tyhx_delay_ms(100); - return 0; -} -uint32_t tyhx_poweroff(void) -{ - uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); - uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); - uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_LOW); - - uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); - uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); - uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW); - tyhx_delay_ms(50); - return 0; -} diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/pah8009/CMakeLists.txt new file mode 100644 index 000000000..31c7b91e9 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/CMakeLists.txt @@ -0,0 +1,52 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved. +#=============================================================================== +set(COMPONENT_NAME "ppg_sensor_pah8009") + +set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/sensor/pah_800x.c + ${CMAKE_CURRENT_SOURCE_DIR}/sensor/pah800x_bsp.c + ${CMAKE_CURRENT_SOURCE_DIR}/sensor/pah800x_main.c + ${CMAKE_CURRENT_SOURCE_DIR}/factory/pah800x_factory_test.c +) +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/sensor + ${CMAKE_CURRENT_SOURCE_DIR}/factory + ${CMAKE_CURRENT_SOURCE_DIR}/algorithm/pah_spo2/V703 + ${CMAKE_CURRENT_SOURCE_DIR}/algorithm/pah_stress/V6033 + ${CMAKE_CURRENT_SOURCE_DIR}/algorithm/pah_hr/V303009 +) + +set(PRIVATE_HEADER +) + +set(PRIVATE_DEFINES +) + +set(PUBLIC_DEFINES + PPG_PAH8009 +) + +# use this when you want to add ccflags like -include xxx +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS +) + +set(WHOLE_LINK + true +) + +set(MAIN_COMPONENT + false +) + +find_library(LIB_PATH_SPO2 algorithm/pah_spo2/V703/libv703_0_1.a ${CMAKE_CURRENT_SOURCE_DIR}) +find_library(LIB_PATH_HR algorithm/pah_hr/V303009/libv307009_4.a ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(${TARGET_NAME} PRIVATE -Wl,--whole-archive ${LIB_PATH_HR} ${LIB_PATH_SPO2} PRIVATE -Wl,--whole-archive) + +build_component() + diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/Interrupt_function.c b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/Interrupt_function.c new file mode 100644 index 000000000..6c91bba23 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/Interrupt_function.c @@ -0,0 +1,12 @@ +#include "pxi_interp.h" + + +void PXI_MEMS_interp(int16_t *src_data, size_t src_data_count, int16_t *dst_data, size_t dst_data_count) +{ + pxi_interp_ex1(src_data, src_data_count ,dst_data,dst_data_count ,3); + pxi_interp_ex1(&src_data[1], src_data_count ,&dst_data[1],dst_data_count ,3); + pxi_interp_ex1(&src_data[2], src_data_count ,&dst_data[2],dst_data_count ,3); +} + + + diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/pxi_interp.c b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/pxi_interp.c new file mode 100644 index 000000000..36ed8cd8c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/pxi_interp.c @@ -0,0 +1,42 @@ +#include "pxi_interp.h" + + +/***** +* @brief Example of Platform. In this function we initialize powerkey and register callback. +* @param None. +* @return None. +* +*****/ + +void pxi_interp_ex1(int16_t *src_data, size_t src_data_count, int16_t *dst_data, size_t dst_data_count, size_t offset) +{ + float pre_time_acc = 0.0f; + float time_acc = 0.0f; + float d_time = (float)dst_data_count / src_data_count; + size_t idx_ptr = 0; + + for (size_t i = 0; i < dst_data_count; ++i) + { + while (time_acc < (float)i) + { + pre_time_acc = time_acc; + time_acc = time_acc + d_time; + idx_ptr++; + } + + if (idx_ptr == 0) + { + dst_data[i * offset] = src_data[idx_ptr * offset]; + } + else if (idx_ptr == dst_data_count) + { + dst_data[i * offset] = src_data[(idx_ptr - 1) * offset]; + } + else + { + float time_ratio = ((float)i - pre_time_acc) / (time_acc - pre_time_acc); + dst_data[i * offset] = (int16_t)((float)src_data[(idx_ptr - 1) * offset] * (1.0f - time_ratio) + (float)src_data[idx_ptr * offset] * time_ratio + 0.5f); + } + } +} + diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/pxi_interp.h b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/pxi_interp.h new file mode 100644 index 000000000..15c4149b5 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/MEMS_INT/pxi_interp.h @@ -0,0 +1,7 @@ +//#pragma once + +#include +#include + +void pxi_interp_ex1(int16_t *src_data, size_t src_data_count, int16_t *dst_data, size_t dst_data_count, size_t offset); +void PXI_MEMS_interp(int16_t *src_data, size_t src_data_count, int16_t *dst_data, size_t dst_data_count); diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/libv307009_4.a b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/libv307009_4.a new file mode 100644 index 000000000..d0d7a954f Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/libv307009_4.a differ diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pah8009_testpattern_HRD.h b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pah8009_testpattern_HRD.h new file mode 100644 index 000000000..44b62ae41 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pah8009_testpattern_HRD.h @@ -0,0 +1,23944 @@ +#ifndef _PAH8009_TESTPATTERN_ +#define _PAH8009_TESTPATTERN_ + +#include +#define NF_PPG_CHANNEL 3 +#define NF_PPG_PER_CHANNEL 3 +static const int32_t PAH8009_rawdata_HRD[][NF_PPG_PER_CHANNEL*NF_PPG_CHANNEL] = +{ +{0, 123629, 5910}, +{0, 118569, 5918}, +{0, 113318, 5916}, +{0, 106371, 5944}, +{0, 105522, 5928}, +{0, 96770, 5938}, +{0, 91486, 5928}, +{0, 86122, 5918}, +{0, 81476, 5906}, +{0, 80788, 5908}, +{0, 80266, 5904}, +{0, 79770, 5909}, +{0, 79298, 5908}, +{0, 78950, 5892}, +{0, 78704, 5900}, +{0, 78700, 5897}, +{0, 78620, 5897}, +{0, 78202, 5900}, +{0, 77595, 5903}, +{0, 77266, 5899}, +{0, 77183, 5888}, +{0, 77194, 5893}, +{0, 77168, 5884}, +{0, 76801, 5883}, +{0, 76396, 5875}, +{0, 75904, 5877}, +{0, 75403, 5886}, +{0, 74506, 5860}, +{0, 72984, 5866}, +{0, 71718, 5857}, +{0, 70789, 5854}, +{0, 70106, 5851}, +{0, 69559, 5845}, +{0, 69000, 5840}, +{0, 68416, 5827}, +{0, 67926, 5840}, +{0, 67615, 5840}, +{0, 67369, 5826}, +{0, 66701, 5816}, +{0, 65556, 5820}, +{0, 64648, 5827}, +{0, 63936, 5806}, +{0, 63453, 5806}, +{0, 63170, 5815}, +{0, 62967, 5818}, +{0, 62761, 5801}, +{0, 62594, 5806}, +{0, 62541, 5807}, +{0, 62525, 5799}, +{0, 62088, 5792}, +{0, 61096, 5784}, +{0, 60432, 5782}, +{0, 60066, 5777}, +{0, 59871, 5789}, +{0, 59953, 5791}, +{0, 60000, 5791}, +{0, 60065, 5788}, +{0, 60235, 5786}, +{0, 60431, 5797}, +{0, 60713, 5797}, +{0, 60770, 5797}, +{0, 60015, 5801}, +{0, 59364, 5796}, +{0, 59129, 5776}, +{0, 59016, 5790}, +{0, 59049, 5791}, +{0, 59116, 5783}, +{0, 59132, 5786}, +{0, 59220, 5786}, +{0, 59394, 5795}, +{0, 59670, 5788}, +{0, 59727, 5788}, +{0, 59063, 5796}, +{0, 58552, 5788}, +{0, 58411, 5771}, +{0, 58361, 5771}, +{0, 58441, 5776}, +{0, 58643, 5771}, +{0, 58852, 5785}, +{0, 59047, 5777}, +{0, 59266, 5774}, +{0, 59575, 5779}, +{0, 59891, 5786}, +{0, 59477, 5801}, +{0, 58938, 5776}, +{0, 58697, 5772}, +{0, 58468, 5779}, +{0, 58370, 5771}, +{0, 58427, 5764}, +{0, 58382, 5775}, +{0, 58432, 5772}, +{0, 58479, 5781}, +{0, 58621, 5769}, +{0, 58790, 5773}, +{0, 58663, 5771}, +{0, 58086, 5758}, +{0, 57739, 5760}, +{0, 57461, 5759}, +{0, 57334, 5755}, +{0, 57343, 5751}, +{0, 57375, 5758}, +{0, 57431, 5746}, +{0, 57478, 5755}, +{0, 57565, 5755}, +{0, 57716, 5756}, +{0, 57982, 5749}, +{0, 57981, 5750}, +{0, 57916, 5757}, +{0, 57709, 5734}, +{0, 57546, 5743}, +{0, 57514, 5749}, +{0, 57607, 5742}, +{0, 57762, 5745}, +{0, 57895, 5749}, +{0, 58073, 5756}, +{0, 58254, 5751}, +{0, 58467, 5754}, +{0, 58649, 5742}, +{0, 58465, 5755}, +{0, 58106, 5747}, +{0, 57839, 5753}, +{0, 57640, 5741}, +{0, 57646, 5744}, +{0, 57765, 5744}, +{0, 57903, 5733}, +{0, 58067, 5750}, +{0, 58267, 5750}, +{0, 58492, 5758}, +{0, 58740, 5746}, +{0, 58888, 5746}, +{0, 58582, 5749}, +{0, 58189, 5741}, +{0, 58011, 5749}, +{0, 58024, 5743}, +{0, 58121, 5752}, +{0, 58343, 5745}, +{0, 58442, 5751}, +{0, 58542, 5750}, +{0, 58672, 5766}, +{0, 58794, 5753}, +{0, 58959, 5753}, +{0, 58984, 5760}, +{0, 58907, 5758}, +{0, 58684, 5751}, +{0, 58478, 5740}, +{0, 58365, 5746}, +{0, 58427, 5745}, +{0, 58506, 5751}, +{0, 58578, 5744}, +{0, 58631, 5751}, +{0, 58713, 5762}, +{0, 58823, 5748}, +{0, 58954, 5749}, +{0, 59096, 5754}, +{0, 58921, 5745}, +{0, 58644, 5748}, +{0, 58535, 5737}, +{0, 58464, 5744}, +{0, 58465, 5742}, +{0, 58579, 5748}, +{0, 58640, 5750}, +{0, 58767, 5753}, +{0, 58864, 5743}, +{0, 59022, 5758}, +{0, 59158, 5755}, +{0, 59290, 5754}, +{0, 59226, 5755}, +{0, 58941, 5751}, +{0, 58717, 5758}, +{0, 58687, 5748}, +{0, 58599, 5748}, +{0, 58670, 5744}, +{0, 58694, 5744}, +{0, 58653, 5730}, +{0, 58575, 5736}, +{0, 58443, 5738}, +{0, 58226, 5737}, +{0, 57957, 5731}, +{0, 57664, 5744}, +{0, 57410, 5727}, +{0, 57131, 5731}, +{0, 57002, 5729}, +{0, 56949, 5726}, +{0, 56996, 5734}, +{0, 57041, 5736}, +{0, 57073, 5740}, +{0, 57122, 5733}, +{0, 57229, 5737}, +{0, 57328, 5738}, +{0, 57443, 5738}, +{0, 57591, 5734}, +{0, 57670, 5737}, +{0, 57489, 5742}, +{0, 57335, 5727}, +{0, 57307, 5729}, +{0, 57370, 5730}, +{0, 57454, 5725}, +{0, 57553, 5731}, +{0, 57636, 5726}, +{0, 57694, 5731}, +{0, 57782, 5723}, +{0, 57860, 5731}, +{0, 57953, 5737}, +{0, 57978, 5735}, +{0, 57758, 5737}, +{0, 57593, 5730}, +{0, 57484, 5734}, +{0, 57454, 5735}, +{0, 57447, 5717}, +{0, 57429, 5728}, +{0, 57402, 5740}, +{0, 57444, 5734}, +{0, 57493, 5727}, +{0, 57583, 5723}, +{0, 57683, 5725}, +{0, 57812, 5729}, +{0, 57658, 5716}, +{0, 57615, 5722}, +{0, 57641, 5721}, +{0, 57787, 5715}, +{0, 57986, 5733}, +{0, 58116, 5725}, +{0, 58211, 5727}, +{0, 58335, 5724}, +{0, 58464, 5724}, +{0, 58575, 5719}, +{0, 58657, 5734}, +{0, 58753, 5740}, +{0, 58533, 5730}, +{0, 58259, 5721}, +{0, 58161, 5726}, +{0, 58156, 5737}, +{0, 58106, 5727}, +{0, 58076, 5737}, +{0, 58128, 5731}, +{0, 58129, 5735}, +{0, 58213, 5727}, +{0, 58282, 5733}, +{0, 58282, 5728}, +{0, 58252, 5728}, +{0, 57998, 5721}, +{0, 57697, 5706}, +{0, 57559, 5719}, +{0, 57528, 5713}, +{0, 57520, 5723}, +{0, 57651, 5727}, +{0, 57819, 5719}, +{0, 58009, 5717}, +{0, 58287, 5733}, +{0, 58597, 5741}, +{0, 58811, 5732}, +{0, 59046, 5744}, +{0, 59025, 5726}, +{0, 58912, 5734}, +{0, 58919, 5738}, +{0, 59012, 5732}, +{0, 59143, 5748}, +{0, 59188, 5745}, +{0, 59227, 5749}, +{0, 59316, 5743}, +{0, 59358, 5740}, +{0, 59496, 5750}, +{0, 59627, 5751}, +{0, 59740, 5746}, +{0, 59647, 5735}, +{0, 59492, 5738}, +{0, 59361, 5725}, +{0, 59307, 5727}, +{0, 59357, 5728}, +{0, 59335, 5731}, +{0, 59163, 5729}, +{0, 58947, 5736}, +{0, 58960, 5747}, +{0, 59110, 5739}, +{0, 59246, 5744}, +{0, 59243, 5742}, +{0, 58958, 5732}, +{0, 58742, 5735}, +{0, 58692, 5725}, +{0, 58708, 5746}, +{0, 58787, 5744}, +{0, 59036, 5750}, +{0, 59671, 5735}, +{0, 60295, 5756}, +{0, 60927, 5763}, +{0, 61483, 5775}, +{0, 62005, 5778}, +{0, 62364, 5775}, +{0, 62685, 5780}, +{0, 63073, 5793}, +{0, 63430, 5798}, +{0, 63809, 5806}, +{0, 64149, 5810}, +{0, 64475, 5804}, +{0, 64774, 5810}, +{0, 65019, 5809}, +{0, 65321, 5807}, +{0, 65612, 5812}, +{0, 65791, 5818}, +{0, 65710, 5815}, +{0, 65624, 5802}, +{0, 65575, 5809}, +{0, 65443, 5800}, +{0, 65313, 5812}, +{0, 65198, 5812}, +{0, 65152, 5796}, +{0, 65148, 5795}, +{0, 65237, 5799}, +{0, 65317, 5799}, +{0, 65423, 5803}, +{0, 65467, 5800}, +{0, 65256, 5792}, +{0, 65124, 5790}, +{0, 65061, 5803}, +{0, 65012, 5796}, +{0, 64980, 5796}, +{0, 64932, 5792}, +{0, 64922, 5795}, +{0, 64895, 5803}, +{0, 64900, 5798}, +{0, 64872, 5798}, +{0, 64872, 5793}, +{0, 64747, 5789}, +{0, 64413, 5798}, +{0, 64165, 5794}, +{0, 63986, 5790}, +{0, 63882, 5781}, +{0, 63760, 5789}, +{0, 63792, 5780}, +{0, 63732, 5794}, +{0, 63781, 5788}, +{0, 63736, 5803}, +{0, 63854, 5791}, +{0, 63865, 5789}, +{0, 63866, 5799}, +{0, 63594, 5778}, +{0, 63433, 5777}, +{0, 63378, 5791}, +{0, 63409, 5779}, +{0, 63463, 5764}, +{0, 63486, 5775}, +{0, 63487, 5787}, +{0, 63572, 5778}, +{0, 63735, 5783}, +{0, 63803, 5773}, +{0, 63922, 5785}, +{0, 64029, 5783}, +{0, 63849, 5789}, +{0, 63604, 5785}, +{0, 63504, 5782}, +{0, 63472, 5774}, +{0, 63538, 5777}, +{0, 63570, 5775}, +{0, 63577, 5784}, +{0, 63590, 5776}, +{0, 63669, 5778}, +{0, 63772, 5782}, +{0, 63856, 5779}, +{0, 63959, 5779}, +{0, 63837, 5784}, +{0, 63557, 5776}, +{0, 63414, 5778}, +{0, 63370, 5781}, +{0, 63343, 5787}, +{0, 63346, 5781}, +{0, 63259, 5773}, +{0, 63253, 5771}, +{0, 63201, 5782}, +{0, 63234, 5782}, +{0, 63266, 5773}, +{0, 63307, 5774}, +{0, 63246, 5774}, +{0, 62919, 5769}, +{0, 62727, 5774}, +{0, 62685, 5779}, +{0, 62739, 5766}, +{0, 62789, 5759}, +{0, 62847, 5762}, +{0, 63030, 5765}, +{0, 63262, 5770}, +{0, 63561, 5784}, +{0, 63943, 5792}, +{0, 64274, 5795}, +{0, 64520, 5789}, +{0, 64439, 5796}, +{0, 64276, 5802}, +{0, 64338, 5792}, +{0, 64500, 5801}, +{0, 64753, 5805}, +{0, 65005, 5806}, +{0, 65246, 5809}, +{0, 65430, 5798}, +{0, 65691, 5809}, +{0, 65870, 5815}, +{0, 66098, 5807}, +{0, 66239, 5814}, +{0, 65989, 5813}, +{0, 65656, 5812}, +{0, 65523, 5810}, +{0, 65470, 5802}, +{0, 65429, 5798}, +{0, 65380, 5802}, +{0, 65218, 5793}, +{0, 65087, 5787}, +{0, 64942, 5787}, +{0, 64877, 5793}, +{0, 64720, 5796}, +{0, 64662, 5780}, +{0, 64332, 5772}, +{0, 63902, 5763}, +{0, 63639, 5763}, +{0, 63495, 5766}, +{0, 63367, 5760}, +{0, 63324, 5764}, +{0, 63315, 5772}, +{0, 63263, 5764}, +{0, 63258, 5755}, +{0, 63344, 5763}, +{0, 63369, 5758}, +{0, 63416, 5762}, +{0, 63060, 5755}, +{0, 62872, 5763}, +{0, 62919, 5769}, +{0, 63045, 5764}, +{0, 63173, 5786}, +{0, 63278, 5775}, +{0, 63357, 5774}, +{0, 63445, 5773}, +{0, 63543, 5781}, +{0, 63648, 5780}, +{0, 63715, 5782}, +{0, 63488, 5777}, +{0, 62867, 5780}, +{0, 62518, 5783}, +{0, 62258, 5773}, +{0, 62083, 5771}, +{0, 61984, 5770}, +{0, 61896, 5759}, +{0, 61733, 5761}, +{0, 61567, 5759}, +{0, 61535, 5768}, +{0, 61595, 5758}, +{0, 61726, 5775}, +{0, 61675, 5762}, +{0, 61330, 5759}, +{0, 61190, 5756}, +{0, 61269, 5765}, +{0, 61508, 5774}, +{0, 61756, 5778}, +{0, 62028, 5785}, +{0, 62209, 5787}, +{0, 62461, 5787}, +{0, 62716, 5793}, +{0, 63008, 5787}, +{0, 63274, 5792}, +{0, 63253, 5789}, +{0, 62966, 5791}, +{0, 62966, 5788}, +{0, 62994, 5784}, +{0, 63066, 5796}, +{0, 63155, 5789}, +{0, 63205, 5792}, +{0, 63262, 5789}, +{0, 63272, 5793}, +{0, 63273, 5791}, +{0, 63206, 5779}, +{0, 63087, 5779}, +{0, 62588, 5777}, +{0, 62075, 5771}, +{0, 61794, 5769}, +{0, 61577, 5768}, +{0, 61466, 5766}, +{0, 61429, 5764}, +{0, 61455, 5758}, +{0, 61475, 5757}, +{0, 61626, 5755}, +{0, 61776, 5768}, +{0, 61934, 5752}, +{0, 61846, 5756}, +{0, 61389, 5753}, +{0, 61208, 5746}, +{0, 61084, 5748}, +{0, 61091, 5751}, +{0, 61154, 5746}, +{0, 61209, 5748}, +{0, 61262, 5759}, +{0, 61363, 5743}, +{0, 61588, 5752}, +{0, 61931, 5766}, +{0, 62269, 5764}, +{0, 62412, 5769}, +{0, 62312, 5770}, +{0, 62235, 5771}, +{0, 62334, 5778}, +{0, 62378, 5772}, +{0, 62394, 5772}, +{0, 62360, 5760}, +{0, 62291, 5763}, +{0, 62295, 5761}, +{0, 62378, 5751}, +{0, 62481, 5762}, +{0, 62624, 5774}, +{0, 62644, 5772}, +{0, 62389, 5770}, +{0, 62120, 5764}, +{0, 61878, 5753}, +{0, 61725, 5762}, +{0, 61746, 5757}, +{0, 61881, 5766}, +{0, 62153, 5760}, +{0, 62325, 5761}, +{0, 62548, 5761}, +{0, 62669, 5754}, +{0, 62879, 5764}, +{0, 62629, 5756}, +{0, 62332, 5769}, +{0, 62140, 5761}, +{0, 62120, 5757}, +{0, 62169, 5762}, +{0, 62272, 5766}, +{0, 62331, 5762}, +{0, 62382, 5769}, +{0, 62445, 5763}, +{0, 62407, 5762}, +{0, 62353, 5774}, +{0, 62361, 5773}, +{0, 62135, 5773}, +{0, 61827, 5766}, +{0, 61601, 5750}, +{0, 61589, 5761}, +{0, 61690, 5749}, +{0, 61801, 5744}, +{0, 61820, 5740}, +{0, 61842, 5747}, +{0, 61860, 5766}, +{0, 62029, 5760}, +{0, 62251, 5762}, +{0, 62550, 5769}, +{0, 62878, 5776}, +{0, 62925, 5768}, +{0, 62918, 5763}, +{0, 63128, 5777}, +{0, 63394, 5775}, +{0, 63669, 5780}, +{0, 63835, 5778}, +{0, 64013, 5789}, +{0, 64079, 5779}, +{0, 64186, 5784}, +{0, 64308, 5778}, +{0, 64334, 5784}, +{0, 64282, 5794}, +{0, 63926, 5776}, +{0, 63585, 5769}, +{0, 63334, 5760}, +{0, 63121, 5765}, +{0, 63129, 5768}, +{0, 63284, 5767}, +{0, 63503, 5765}, +{0, 63541, 5765}, +{0, 63550, 5769}, +{0, 63622, 5780}, +{0, 63724, 5771}, +{0, 63704, 5767}, +{0, 63429, 5774}, +{0, 63210, 5761}, +{0, 63150, 5774}, +{0, 63176, 5783}, +{0, 63244, 5765}, +{0, 63444, 5773}, +{0, 63690, 5795}, +{0, 63968, 5803}, +{0, 64241, 5807}, +{0, 64575, 5809}, +{0, 65009, 5814}, +{0, 65276, 5815}, +{0, 65257, 5803}, +{0, 65316, 5824}, +{0, 65368, 5818}, +{0, 65327, 5811}, +{0, 65260, 5814}, +{0, 65179, 5804}, +{0, 65040, 5801}, +{0, 64913, 5807}, +{0, 64802, 5797}, +{0, 64718, 5799}, +{0, 64611, 5797}, +{0, 64415, 5800}, +{0, 64046, 5793}, +{0, 63772, 5780}, +{0, 63499, 5775}, +{0, 63292, 5772}, +{0, 63055, 5758}, +{0, 62893, 5769}, +{0, 62851, 5762}, +{0, 62815, 5777}, +{0, 62848, 5775}, +{0, 62991, 5762}, +{0, 63131, 5772}, +{0, 62987, 5772}, +{0, 62700, 5771}, +{0, 62261, 5772}, +{0, 61915, 5753}, +{0, 61787, 5761}, +{0, 61831, 5763}, +{0, 61778, 5762}, +{0, 61723, 5754}, +{0, 61759, 5757}, +{0, 61860, 5750}, +{0, 61924, 5764}, +{0, 61758, 5756}, +{0, 61283, 5755}, +{0, 60873, 5753}, +{0, 60417, 5741}, +{0, 60167, 5751}, +{0, 59971, 5744}, +{0, 59851, 5749}, +{0, 59669, 5757}, +{0, 59506, 5756}, +{0, 59345, 5757}, +{0, 59243, 5752}, +{0, 59105, 5761}, +{0, 58659, 5769}, +{0, 57940, 5761}, +{0, 57566, 5749}, +{0, 57450, 5748}, +{0, 57445, 5745}, +{0, 57486, 5738}, +{0, 57651, 5744}, +{0, 57905, 5750}, +{0, 58216, 5751}, +{0, 58463, 5750}, +{0, 58707, 5755}, +{0, 58813, 5761}, +{0, 58531, 5752}, +{0, 58351, 5752}, +{0, 58368, 5753}, +{0, 58483, 5749}, +{0, 58537, 5752}, +{0, 58424, 5758}, +{0, 58200, 5751}, +{0, 58067, 5754}, +{0, 58120, 5753}, +{0, 58109, 5758}, +{0, 58206, 5758}, +{0, 58438, 5759}, +{0, 58333, 5757}, +{0, 58264, 5761}, +{0, 58408, 5762}, +{0, 58653, 5771}, +{0, 58882, 5773}, +{0, 59063, 5785}, +{0, 59244, 5778}, +{0, 59428, 5782}, +{0, 59686, 5780}, +{0, 59884, 5786}, +{0, 60120, 5780}, +{0, 59927, 5770}, +{0, 59720, 5783}, +{0, 59758, 5768}, +{0, 59921, 5776}, +{0, 60162, 5772}, +{0, 60400, 5777}, +{0, 60629, 5786}, +{0, 60963, 5788}, +{0, 61245, 5785}, +{0, 61478, 5798}, +{0, 61742, 5795}, +{0, 61906, 5801}, +{0, 61764, 5779}, +{0, 61563, 5771}, +{0, 61160, 5783}, +{0, 60853, 5774}, +{0, 60623, 5767}, +{0, 60401, 5764}, +{0, 60175, 5760}, +{0, 60017, 5747}, +{0, 59984, 5741}, +{0, 60044, 5749}, +{0, 60098, 5757}, +{0, 60058, 5750}, +{0, 59791, 5745}, +{0, 59593, 5738}, +{0, 59563, 5749}, +{0, 59562, 5745}, +{0, 59708, 5750}, +{0, 59850, 5761}, +{0, 60212, 5763}, +{0, 60788, 5772}, +{0, 61619, 5794}, +{0, 62580, 5807}, +{0, 63490, 5819}, +{0, 64080, 5810}, +{0, 64358, 5800}, +{0, 64702, 5810}, +{0, 65016, 5820}, +{0, 65346, 5815}, +{0, 65728, 5818}, +{0, 66106, 5825}, +{0, 66387, 5819}, +{0, 66487, 5803}, +{0, 66536, 5816}, +{0, 66665, 5812}, +{0, 66835, 5817}, +{0, 66918, 5815}, +{0, 66891, 5813}, +{0, 67104, 5823}, +{0, 67512, 5839}, +{0, 68016, 5847}, +{0, 68617, 5847}, +{0, 69134, 5837}, +{0, 69657, 5851}, +{0, 70277, 5850}, +{0, 70854, 5863}, +{0, 71531, 5868}, +{0, 72171, 5862}, +{0, 72584, 5858}, +{0, 72533, 5855}, +{0, 72529, 5860}, +{0, 72557, 5862}, +{0, 72559, 5848}, +{0, 72536, 5844}, +{0, 72540, 5857}, +{0, 72433, 5841}, +{0, 72360, 5839}, +{0, 72366, 5852}, +{0, 72429, 5853}, +{0, 72535, 5851}, +{0, 72559, 5844}, +{0, 72224, 5850}, +{0, 71803, 5831}, +{0, 71524, 5836}, +{0, 71237, 5830}, +{0, 70999, 5843}, +{0, 70703, 5831}, +{0, 70440, 5836}, +{0, 70200, 5825}, +{0, 70089, 5816}, +{0, 70102, 5825}, +{0, 70163, 5826}, +{0, 70264, 5824}, +{0, 69955, 5808}, +{0, 69458, 5817}, +{0, 69074, 5824}, +{0, 68792, 5815}, +{0, 68544, 5812}, +{0, 68363, 5816}, +{0, 68082, 5811}, +{0, 67793, 5806}, +{0, 67555, 5821}, +{0, 67313, 5802}, +{0, 67154, 5801}, +{0, 67135, 5806}, +{0, 66807, 5797}, +{0, 66342, 5796}, +{0, 65999, 5786}, +{0, 65750, 5789}, +{0, 65594, 5800}, +{0, 65564, 5798}, +{0, 65579, 5805}, +{0, 65708, 5793}, +{0, 65976, 5812}, +{0, 66309, 5818}, +{0, 66750, 5820}, +{0, 67196, 5828}, +{0, 67576, 5835}, +{0, 67401, 5824}, +{0, 67390, 5817}, +{0, 67687, 5828}, +{0, 68049, 5825}, +{0, 68289, 5837}, +{0, 68354, 5834}, +{0, 68266, 5829}, +{0, 68110, 5824}, +{0, 68086, 5824}, +{0, 68194, 5830}, +{0, 68355, 5820}, +{0, 68271, 5830}, +{0, 67668, 5818}, +{0, 67010, 5799}, +{0, 66590, 5790}, +{0, 66325, 5801}, +{0, 66197, 5803}, +{0, 66116, 5811}, +{0, 66067, 5796}, +{0, 66104, 5801}, +{0, 66128, 5794}, +{0, 66202, 5801}, +{0, 66259, 5798}, +{0, 66405, 5796}, +{0, 66178, 5803}, +{0, 65969, 5809}, +{0, 65970, 5826}, +{0, 66127, 5832}, +{0, 66350, 5823}, +{0, 66644, 5831}, +{0, 66948, 5833}, +{0, 67228, 5830}, +{0, 67423, 5831}, +{0, 67608, 5829}, +{0, 67628, 5835}, +{0, 67624, 5834}, +{0, 67072, 5819}, +{0, 66363, 5809}, +{0, 65909, 5814}, +{0, 65618, 5802}, +{0, 65434, 5811}, +{0, 65385, 5802}, +{0, 65371, 5799}, +{0, 65307, 5803}, +{0, 65389, 5807}, +{0, 65475, 5803}, +{0, 65600, 5797}, +{0, 65817, 5791}, +{0, 65903, 5795}, +{0, 65955, 5785}, +{0, 66018, 5803}, +{0, 66068, 5803}, +{0, 66256, 5823}, +{0, 66470, 5814}, +{0, 66754, 5827}, +{0, 66957, 5815}, +{0, 67166, 5819}, +{0, 67434, 5823}, +{0, 67766, 5814}, +{0, 67944, 5823}, +{0, 67453, 5815}, +{0, 66912, 5822}, +{0, 66562, 5816}, +{0, 66312, 5808}, +{0, 66113, 5809}, +{0, 66043, 5800}, +{0, 66037, 5791}, +{0, 66111, 5790}, +{0, 66138, 5798}, +{0, 66118, 5794}, +{0, 66166, 5803}, +{0, 65942, 5807}, +{0, 65162, 5806}, +{0, 64551, 5788}, +{0, 64171, 5790}, +{0, 64015, 5781}, +{0, 63944, 5776}, +{0, 63951, 5782}, +{0, 63982, 5786}, +{0, 64003, 5775}, +{0, 64111, 5764}, +{0, 64352, 5773}, +{0, 64586, 5778}, +{0, 64494, 5786}, +{0, 63841, 5793}, +{0, 63485, 5772}, +{0, 63356, 5772}, +{0, 63387, 5781}, +{0, 63461, 5781}, +{0, 63500, 5785}, +{0, 63508, 5800}, +{0, 63672, 5794}, +{0, 63958, 5790}, +{0, 64148, 5802}, +{0, 64287, 5803}, +{0, 64042, 5794}, +{0, 63661, 5795}, +{0, 63571, 5774}, +{0, 63626, 5783}, +{0, 63707, 5791}, +{0, 63814, 5801}, +{0, 63880, 5785}, +{0, 63927, 5803}, +{0, 64073, 5797}, +{0, 64378, 5796}, +{0, 64669, 5804}, +{0, 64946, 5804}, +{0, 64931, 5813}, +{0, 64756, 5802}, +{0, 64879, 5801}, +{0, 65114, 5806}, +{0, 65326, 5811}, +{0, 65482, 5805}, +{0, 65343, 5802}, +{0, 65069, 5793}, +{0, 64859, 5782}, +{0, 64643, 5790}, +{0, 64495, 5801}, +{0, 64215, 5786}, +{0, 63659, 5771}, +{0, 63267, 5771}, +{0, 63058, 5777}, +{0, 63026, 5772}, +{0, 63035, 5765}, +{0, 63062, 5765}, +{0, 62976, 5773}, +{0, 63006, 5776}, +{0, 63091, 5769}, +{0, 63301, 5774}, +{0, 63552, 5779}, +{0, 63545, 5769}, +{0, 63334, 5769}, +{0, 63208, 5782}, +{0, 63195, 5785}, +{0, 63141, 5778}, +{0, 63223, 5777}, +{0, 63365, 5770}, +{0, 63532, 5776}, +{0, 63595, 5770}, +{0, 63604, 5771}, +{0, 63612, 5767}, +{0, 63617, 5763}, +{0, 63330, 5759}, +{0, 63173, 5761}, +{0, 63254, 5759}, +{0, 63392, 5767}, +{0, 63557, 5776}, +{0, 63637, 5778}, +{0, 63674, 5785}, +{0, 63563, 5781}, +{0, 63390, 5773}, +{0, 63113, 5785}, +{0, 62949, 5781}, +{0, 62921, 5764}, +{0, 62731, 5772}, +{0, 62536, 5787}, +{0, 62566, 5779}, +{0, 62709, 5770}, +{0, 62973, 5761}, +{0, 62930, 5760}, +{0, 62722, 5768}, +{0, 62678, 5783}, +{0, 62750, 5773}, +{0, 62701, 5787}, +{0, 62641, 5766}, +{0, 62456, 5768}, +{0, 62061, 5769}, +{0, 61566, 5766}, +{0, 61094, 5759}, +{0, 60794, 5753}, +{0, 60716, 5763}, +{0, 60749, 5765}, +{0, 60691, 5766}, +{0, 60600, 5764}, +{0, 60608, 5762}, +{0, 60806, 5777}, +{0, 60900, 5761}, +{0, 60554, 5757}, +{0, 60184, 5767}, +{0, 60018, 5775}, +{0, 60038, 5756}, +{0, 60070, 5762}, +{0, 60201, 5765}, +{0, 60224, 5762}, +{0, 60226, 5762}, +{0, 60238, 5760}, +{0, 60294, 5759}, +{0, 60325, 5760}, +{0, 59975, 5763}, +{0, 59527, 5752}, +{0, 59243, 5747}, +{0, 59081, 5761}, +{0, 58982, 5754}, +{0, 59055, 5752}, +{0, 59020, 5769}, +{0, 58892, 5757}, +{0, 58811, 5770}, +{0, 58830, 5755}, +{0, 59012, 5760}, +{0, 58978, 5756}, +{0, 58707, 5739}, +{0, 58480, 5747}, +{0, 58500, 5750}, +{0, 58540, 5749}, +{0, 58683, 5751}, +{0, 58817, 5755}, +{0, 58919, 5747}, +{0, 59049, 5758}, +{0, 59185, 5754}, +{0, 59365, 5753}, +{0, 59505, 5756}, +{0, 59120, 5746}, +{0, 58775, 5738}, +{0, 58560, 5743}, +{0, 58458, 5742}, +{0, 58326, 5742}, +{0, 58099, 5744}, +{0, 57782, 5750}, +{0, 57663, 5747}, +{0, 57583, 5751}, +{0, 57501, 5759}, +{0, 57472, 5747}, +{0, 57352, 5762}, +{0, 57101, 5763}, +{0, 57000, 5754}, +{0, 57037, 5744}, +{0, 57180, 5745}, +{0, 57364, 5750}, +{0, 57533, 5755}, +{0, 57798, 5751}, +{0, 58047, 5752}, +{0, 58303, 5758}, +{0, 58605, 5755}, +{0, 58525, 5741}, +{0, 58442, 5743}, +{0, 58462, 5742}, +{0, 58490, 5739}, +{0, 58560, 5748}, +{0, 58525, 5749}, +{0, 58540, 5750}, +{0, 58503, 5746}, +{0, 58493, 5761}, +{0, 58545, 5739}, +{0, 58611, 5745}, +{0, 58398, 5744}, +{0, 58150, 5735}, +{0, 57974, 5747}, +{0, 57910, 5753}, +{0, 57873, 5755}, +{0, 57974, 5747}, +{0, 58039, 5739}, +{0, 58109, 5743}, +{0, 58262, 5747}, +{0, 58475, 5745}, +{0, 58743, 5746}, +{0, 58708, 5744}, +{0, 58682, 5740}, +{0, 58788, 5742}, +{0, 58870, 5735}, +{0, 59011, 5753}, +{0, 59102, 5744}, +{0, 59174, 5757}, +{0, 59160, 5765}, +{0, 59160, 5750}, +{0, 59133, 5736}, +{0, 59067, 5755}, +{0, 58809, 5752}, +{0, 58558, 5738}, +{0, 58407, 5739}, +{0, 58292, 5748}, +{0, 58251, 5740}, +{0, 58202, 5753}, +{0, 58198, 5752}, +{0, 58281, 5752}, +{0, 58366, 5745}, +{0, 58480, 5749}, +{0, 58661, 5750}, +{0, 58558, 5754}, +{0, 58560, 5735}, +{0, 58650, 5732}, +{0, 58802, 5744}, +{0, 59016, 5745}, +{0, 59198, 5744}, +{0, 59345, 5745}, +{0, 59413, 5746}, +{0, 59437, 5751}, +{0, 59463, 5743}, +{0, 59468, 5751}, +{0, 59121, 5749}, +{0, 58823, 5741}, +{0, 58629, 5749}, +{0, 58602, 5750}, +{0, 58552, 5750}, +{0, 58340, 5761}, +{0, 58175, 5760}, +{0, 58375, 5764}, +{0, 58742, 5756}, +{0, 59153, 5754}, +{0, 59574, 5776}, +{0, 59689, 5764}, +{0, 59730, 5765}, +{0, 59944, 5768}, +{0, 60291, 5767}, +{0, 60651, 5779}, +{0, 60970, 5778}, +{0, 61158, 5785}, +{0, 61301, 5789}, +{0, 61367, 5782}, +{0, 61452, 5783}, +{0, 61498, 5778}, +{0, 61177, 5765}, +{0, 60974, 5768}, +{0, 60937, 5779}, +{0, 60978, 5776}, +{0, 61039, 5773}, +{0, 61187, 5773}, +{0, 61391, 5770}, +{0, 61560, 5781}, +{0, 61708, 5771}, +{0, 61897, 5788}, +{0, 62062, 5781}, +{0, 61847, 5776}, +{0, 61679, 5774}, +{0, 61729, 5767}, +{0, 61817, 5762}, +{0, 62033, 5774}, +{0, 62435, 5781}, +{0, 62691, 5789}, +{0, 62874, 5778}, +{0, 62944, 5777}, +{0, 62923, 5779}, +{0, 62701, 5777}, +{0, 62265, 5769}, +{0, 61947, 5761}, +{0, 61728, 5770}, +{0, 61531, 5762}, +{0, 61388, 5766}, +{0, 61354, 5762}, +{0, 61261, 5760}, +{0, 61357, 5755}, +{0, 61658, 5767}, +{0, 61964, 5754}, +{0, 61978, 5752}, +{0, 61821, 5752}, +{0, 62047, 5752}, +{0, 62480, 5765}, +{0, 63117, 5784}, +{0, 63920, 5797}, +{0, 64722, 5820}, +{0, 65481, 5820}, +{0, 66153, 5840}, +{0, 66805, 5832}, +{0, 67430, 5830}, +{0, 67616, 5827}, +{0, 67176, 5799}, +{0, 66784, 5793}, +{0, 66504, 5784}, +{0, 66281, 5794}, +{0, 66279, 5800}, +{0, 66315, 5789}, +{0, 66427, 5794}, +{0, 66577, 5804}, +{0, 66901, 5812}, +{0, 67291, 5803}, +{0, 67197, 5807}, +{0, 66853, 5810}, +{0, 66640, 5799}, +{0, 66557, 5807}, +{0, 66489, 5808}, +{0, 66766, 5793}, +{0, 67121, 5817}, +{0, 67509, 5830}, +{0, 67877, 5826}, +{0, 68346, 5854}, +{0, 68755, 5840}, +{0, 68684, 5826}, +{0, 68376, 5810}, +{0, 68194, 5825}, +{0, 68102, 5820}, +{0, 68062, 5832}, +{0, 68109, 5815}, +{0, 68151, 5820}, +{0, 68191, 5810}, +{0, 68216, 5814}, +{0, 68286, 5829}, +{0, 68272, 5818}, +{0, 67857, 5811}, +{0, 67430, 5811}, +{0, 67198, 5808}, +{0, 67092, 5813}, +{0, 67054, 5812}, +{0, 67066, 5813}, +{0, 67162, 5817}, +{0, 67365, 5803}, +{0, 67515, 5823}, +{0, 67768, 5809}, +{0, 67856, 5817}, +{0, 67338, 5802}, +{0, 66942, 5818}, +{0, 66703, 5805}, +{0, 66609, 5818}, +{0, 66564, 5809}, +{0, 66526, 5814}, +{0, 66527, 5801}, +{0, 66432, 5804}, +{0, 66472, 5800}, +{0, 66588, 5799}, +{0, 66481, 5805}, +{0, 66056, 5796}, +{0, 65725, 5797}, +{0, 65665, 5795}, +{0, 65769, 5788}, +{0, 66041, 5791}, +{0, 66367, 5804}, +{0, 66625, 5811}, +{0, 66977, 5813}, +{0, 67326, 5818}, +{0, 67674, 5827}, +{0, 67523, 5818}, +{0, 67166, 5816}, +{0, 67022, 5814}, +{0, 67012, 5822}, +{0, 67069, 5810}, +{0, 67155, 5814}, +{0, 67175, 5823}, +{0, 67157, 5822}, +{0, 67220, 5814}, +{0, 67291, 5816}, +{0, 67360, 5808}, +{0, 66878, 5802}, +{0, 66324, 5808}, +{0, 65974, 5804}, +{0, 65771, 5792}, +{0, 65684, 5800}, +{0, 65698, 5797}, +{0, 65929, 5791}, +{0, 66161, 5804}, +{0, 66476, 5800}, +{0, 66790, 5811}, +{0, 66773, 5811}, +{0, 66449, 5805}, +{0, 66313, 5807}, +{0, 66311, 5804}, +{0, 66367, 5808}, +{0, 66407, 5801}, +{0, 66416, 5802}, +{0, 66329, 5807}, +{0, 66250, 5804}, +{0, 66168, 5804}, +{0, 65886, 5804}, +{0, 65142, 5794}, +{0, 64512, 5789}, +{0, 64154, 5792}, +{0, 63912, 5786}, +{0, 63745, 5783}, +{0, 63634, 5792}, +{0, 63618, 5781}, +{0, 63589, 5780}, +{0, 63621, 5784}, +{0, 63667, 5788}, +{0, 63723, 5775}, +{0, 63663, 5783}, +{0, 63543, 5781}, +{0, 63339, 5782}, +{0, 63415, 5785}, +{0, 63624, 5789}, +{0, 63856, 5790}, +{0, 64020, 5794}, +{0, 64166, 5786}, +{0, 64343, 5784}, +{0, 64011, 5788}, +{0, 63315, 5786}, +{0, 62970, 5781}, +{0, 62792, 5780}, +{0, 62726, 5779}, +{0, 62643, 5787}, +{0, 62619, 5769}, +{0, 62679, 5784}, +{0, 62745, 5781}, +{0, 62700, 5791}, +{0, 62715, 5785}, +{0, 62752, 5778}, +{0, 62799, 5784}, +{0, 62886, 5779}, +{0, 63014, 5777}, +{0, 63144, 5783}, +{0, 63154, 5773}, +{0, 63229, 5780}, +{0, 63342, 5798}, +{0, 63509, 5792}, +{0, 63717, 5777}, +{0, 63398, 5785}, +{0, 63108, 5783}, +{0, 63116, 5775}, +{0, 63216, 5775}, +{0, 63266, 5778}, +{0, 63243, 5771}, +{0, 63181, 5772}, +{0, 63147, 5782}, +{0, 63098, 5775}, +{0, 63081, 5767}, +{0, 62881, 5777}, +{0, 62521, 5773}, +{0, 62174, 5766}, +{0, 61926, 5762}, +{0, 62018, 5769}, +{0, 62183, 5772}, +{0, 62361, 5782}, +{0, 62569, 5774}, +{0, 62877, 5796}, +{0, 63329, 5813}, +{0, 63713, 5811}, +{0, 63611, 5812}, +{0, 63706, 5814}, +{0, 63983, 5806}, +{0, 64201, 5814}, +{0, 64393, 5814}, +{0, 64477, 5801}, +{0, 64463, 5795}, +{0, 64578, 5821}, +{0, 64567, 5806}, +{0, 64551, 5809}, +{0, 63995, 5803}, +{0, 63444, 5792}, +{0, 63179, 5788}, +{0, 63083, 5786}, +{0, 62980, 5785}, +{0, 63076, 5790}, +{0, 63157, 5795}, +{0, 63215, 5796}, +{0, 63245, 5782}, +{0, 63377, 5789}, +{0, 63108, 5779}, +{0, 62438, 5768}, +{0, 62142, 5767}, +{0, 62083, 5768}, +{0, 62217, 5782}, +{0, 62529, 5786}, +{0, 62895, 5785}, +{0, 63360, 5783}, +{0, 63766, 5790}, +{0, 63999, 5791}, +{0, 63939, 5785}, +{0, 63510, 5796}, +{0, 63254, 5793}, +{0, 63078, 5789}, +{0, 62948, 5798}, +{0, 62889, 5789}, +{0, 62802, 5789}, +{0, 62642, 5783}, +{0, 62496, 5771}, +{0, 62349, 5788}, +{0, 62173, 5776}, +{0, 61617, 5770}, +{0, 61141, 5772}, +{0, 60906, 5762}, +{0, 60834, 5761}, +{0, 60871, 5751}, +{0, 60932, 5757}, +{0, 61100, 5759}, +{0, 61308, 5760}, +{0, 61524, 5780}, +{0, 61754, 5773}, +{0, 61506, 5766}, +{0, 61086, 5773}, +{0, 61049, 5770}, +{0, 61115, 5770}, +{0, 61247, 5781}, +{0, 61427, 5769}, +{0, 61613, 5773}, +{0, 61668, 5765}, +{0, 61806, 5766}, +{0, 62008, 5774}, +{0, 61886, 5763}, +{0, 61188, 5751}, +{0, 60639, 5748}, +{0, 60412, 5752}, +{0, 60316, 5757}, +{0, 60310, 5761}, +{0, 60356, 5763}, +{0, 60405, 5761}, +{0, 60464, 5760}, +{0, 60630, 5762}, +{0, 60863, 5763}, +{0, 60954, 5765}, +{0, 60572, 5751}, +{0, 60416, 5757}, +{0, 60448, 5754}, +{0, 60505, 5759}, +{0, 60713, 5773}, +{0, 60769, 5766}, +{0, 60714, 5757}, +{0, 60657, 5755}, +{0, 60591, 5760}, +{0, 60567, 5755}, +{0, 60112, 5743}, +{0, 59439, 5753}, +{0, 59128, 5731}, +{0, 59000, 5746}, +{0, 59138, 5739}, +{0, 59421, 5744}, +{0, 59689, 5752}, +{0, 60117, 5751}, +{0, 60761, 5757}, +{0, 61771, 5789}, +{0, 62517, 5791}, +{0, 62664, 5798}, +{0, 62968, 5801}, +{0, 63303, 5791}, +{0, 63803, 5800}, +{0, 64494, 5805}, +{0, 65280, 5821}, +{0, 66256, 5819}, +{0, 67130, 5848}, +{0, 67923, 5853}, +{0, 68576, 5847}, +{0, 68487, 5828}, +{0, 67761, 5822}, +{0, 67183, 5810}, +{0, 66736, 5800}, +{0, 66396, 5800}, +{0, 66196, 5800}, +{0, 66150, 5812}, +{0, 66140, 5808}, +{0, 66223, 5807}, +{0, 66268, 5807}, +{0, 66370, 5801}, +{0, 65916, 5803}, +{0, 65289, 5797}, +{0, 64821, 5792}, +{0, 64674, 5784}, +{0, 64593, 5783}, +{0, 64812, 5790}, +{0, 65189, 5802}, +{0, 65670, 5820}, +{0, 66247, 5823}, +{0, 66900, 5832}, +{0, 67635, 5835}, +{0, 67749, 5830}, +{0, 67574, 5832}, +{0, 67596, 5835}, +{0, 67845, 5853}, +{0, 68130, 5834}, +{0, 68102, 5839}, +{0, 67864, 5832}, +{0, 67565, 5817}, +{0, 67381, 5813}, +{0, 67659, 5813}, +{0, 67756, 5819}, +{0, 67225, 5809}, +{0, 66788, 5813}, +{0, 66727, 5810}, +{0, 66886, 5812}, +{0, 67216, 5828}, +{0, 67493, 5832}, +{0, 67616, 5831}, +{0, 67729, 5828}, +{0, 67878, 5821}, +{0, 68146, 5828}, +{0, 68091, 5833}, +{0, 67867, 5838}, +{0, 68003, 5833}, +{0, 68079, 5834}, +{0, 67937, 5828}, +{0, 67850, 5834}, +{0, 67800, 5833}, +{0, 67676, 5819}, +{0, 67331, 5828}, +{0, 66976, 5818}, +{0, 66549, 5813}, +{0, 65528, 5792}, +{0, 64550, 5784}, +{0, 63974, 5792}, +{0, 63567, 5775}, +{0, 63210, 5783}, +{0, 63037, 5785}, +{0, 63024, 5771}, +{0, 62869, 5789}, +{0, 62621, 5779}, +{0, 62435, 5776}, +{0, 62339, 5775}, +{0, 61775, 5769}, +{0, 61353, 5765}, +{0, 61326, 5760}, +{0, 61299, 5772}, +{0, 61406, 5767}, +{0, 61483, 5767}, +{0, 61587, 5776}, +{0, 61659, 5764}, +{0, 61663, 5775}, +{0, 61582, 5779}, +{0, 61102, 5767}, +{0, 60299, 5770}, +{0, 59889, 5750}, +{0, 59580, 5755}, +{0, 59491, 5756}, +{0, 59531, 5760}, +{0, 59514, 5756}, +{0, 59516, 5766}, +{0, 59580, 5769}, +{0, 59621, 5763}, +{0, 59592, 5770}, +{0, 59062, 5761}, +{0, 58561, 5749}, +{0, 58431, 5756}, +{0, 58411, 5751}, +{0, 58573, 5750}, +{0, 58764, 5749}, +{0, 58822, 5753}, +{0, 58958, 5756}, +{0, 58950, 5749}, +{0, 58893, 5751}, +{0, 58397, 5752}, +{0, 57606, 5737}, +{0, 57424, 5743}, +{0, 57486, 5744}, +{0, 57633, 5747}, +{0, 57848, 5741}, +{0, 58040, 5749}, +{0, 58217, 5757}, +{0, 58392, 5764}, +{0, 58635, 5751}, +{0, 58852, 5764}, +{0, 58597, 5767}, +{0, 58185, 5757}, +{0, 58137, 5756}, +{0, 58330, 5762}, +{0, 58589, 5770}, +{0, 58916, 5764}, +{0, 59214, 5765}, +{0, 59515, 5769}, +{0, 59834, 5779}, +{0, 60227, 5769}, +{0, 60469, 5777}, +{0, 59967, 5764}, +{0, 59520, 5759}, +{0, 59356, 5752}, +{0, 59217, 5761}, +{0, 59071, 5750}, +{0, 59034, 5751}, +{0, 59003, 5744}, +{0, 58991, 5752}, +{0, 58937, 5750}, +{0, 58924, 5748}, +{0, 58454, 5738}, +{0, 58087, 5738}, +{0, 58107, 5734}, +{0, 58230, 5745}, +{0, 58340, 5740}, +{0, 58388, 5737}, +{0, 58381, 5745}, +{0, 58354, 5728}, +{0, 58366, 5737}, +{0, 58590, 5741}, +{0, 58713, 5734}, +{0, 58377, 5737}, +{0, 58177, 5748}, +{0, 58197, 5749}, +{0, 58062, 5748}, +{0, 57978, 5741}, +{0, 57882, 5752}, +{0, 57678, 5731}, +{0, 57587, 5724}, +{0, 57539, 5726}, +{0, 57666, 5733}, +{0, 57404, 5729}, +{0, 56725, 5725}, +{0, 56332, 5715}, +{0, 56194, 5713}, +{0, 56214, 5723}, +{0, 56322, 5732}, +{0, 56364, 5712}, +{0, 56641, 5722}, +{0, 57064, 5729}, +{0, 57575, 5739}, +{0, 57817, 5747}, +{0, 57687, 5748}, +{0, 57893, 5775}, +{0, 58419, 5768}, +{0, 58955, 5779}, +{0, 59378, 5779}, +{0, 59833, 5787}, +{0, 60090, 5779}, +{0, 60183, 5782}, +{0, 60170, 5779}, +{0, 60060, 5773}, +{0, 59675, 5754}, +{0, 59371, 5761}, +{0, 59183, 5759}, +{0, 59076, 5766}, +{0, 59091, 5759}, +{0, 59158, 5763}, +{0, 59216, 5767}, +{0, 59323, 5768}, +{0, 59399, 5748}, +{0, 59512, 5755}, +{0, 59429, 5746}, +{0, 59066, 5752}, +{0, 58959, 5743}, +{0, 59186, 5754}, +{0, 59638, 5765}, +{0, 60181, 5784}, +{0, 60936, 5800}, +{0, 61657, 5809}, +{0, 62331, 5817}, +{0, 62850, 5829}, +{0, 63079, 5819}, +{0, 62691, 5803}, +{0, 62403, 5797}, +{0, 62247, 5786}, +{0, 62108, 5783}, +{0, 61555, 5762}, +{0, 61147, 5759}, +{0, 61019, 5762}, +{0, 61070, 5766}, +{0, 61315, 5766}, +{0, 61772, 5788}, +{0, 61988, 5776}, +{0, 62173, 5791}, +{0, 62663, 5803}, +{0, 63542, 5812}, +{0, 64690, 5832}, +{0, 66229, 5843}, +{0, 67894, 5855}, +{0, 69538, 5866}, +{0, 71053, 5877}, +{0, 72442, 5889}, +{0, 73620, 5884}, +{0, 74230, 5880}, +{0, 74560, 5873}, +{0, 74737, 5875}, +{0, 74832, 5874}, +{0, 74956, 5873}, +{0, 74951, 5864}, +{0, 74822, 5857}, +{0, 74693, 5866}, +{0, 74461, 5861}, +{0, 74480, 5857}, +{0, 74253, 5856}, +{0, 74028, 5859}, +{0, 74087, 5863}, +{0, 74329, 5869}, +{0, 74604, 5869}, +{0, 74985, 5872}, +{0, 75312, 5874}, +{0, 75745, 5877}, +{0, 76194, 5893}, +{0, 76682, 5889}, +{0, 76737, 5877}, +{0, 76508, 5883}, +{0, 76662, 5895}, +{0, 76768, 5873}, +{0, 76785, 5878}, +{0, 76680, 5875}, +{0, 76524, 5863}, +{0, 76236, 5869}, +{0, 75933, 5864}, +{0, 75706, 5864}, +{0, 75246, 5848}, +{0, 74109, 5834}, +{0, 73140, 5829}, +{0, 72645, 5818}, +{0, 72371, 5817}, +{0, 72475, 5824}, +{0, 72654, 5823}, +{0, 72765, 5830}, +{0, 72691, 5835}, +{0, 72530, 5832}, +{0, 72256, 5837}, +{0, 71277, 5825}, +{0, 70128, 5815}, +{0, 69529, 5806}, +{0, 69262, 5810}, +{0, 69252, 5816}, +{0, 69429, 5813}, +{0, 69521, 5814}, +{0, 69398, 5808}, +{0, 69071, 5809}, +{0, 68771, 5810}, +{0, 68021, 5803}, +{0, 66642, 5792}, +{0, 65608, 5774}, +{0, 65018, 5777}, +{0, 64687, 5772}, +{0, 64674, 5762}, +{0, 65014, 5768}, +{0, 65759, 5787}, +{0, 66432, 5799}, +{0, 66646, 5787}, +{0, 67223, 5804}, +{0, 67929, 5815}, +{0, 68566, 5820}, +{0, 69257, 5830}, +{0, 69328, 5843}, +{0, 68808, 5829}, +{0, 68356, 5832}, +{0, 67702, 5829}, +{0, 67236, 5818}, +{0, 67059, 5822}, +{0, 67074, 5812}, +{0, 66592, 5811}, +{0, 66123, 5826}, +{0, 65668, 5814}, +{0, 65264, 5805}, +{0, 64861, 5811}, +{0, 64532, 5808}, +{0, 64333, 5818}, +{0, 64260, 5824}, +{0, 64172, 5831}, +{0, 64121, 5830}, +{0, 63886, 5824}, +{0, 63395, 5839}, +{0, 63283, 5831}, +{0, 63627, 5836}, +{0, 64740, 5851}, +{0, 66508, 5878}, +{0, 68738, 5908}, +{0, 70560, 5895}, +{0, 71276, 5922}, +{0, 72054, 5922}, +{0, 72124, 5912}, +{0, 71485, 5917}, +{0, 71691, 5902}, +{0, 70895, 5857}, +{0, 70368, 5851}, +{0, 70082, 5845}, +{0, 69925, 5843}, +{0, 69905, 5847}, +{0, 69942, 5852}, +{0, 70040, 5841}, +{0, 69994, 5837}, +{0, 69472, 5839}, +{0, 69057, 5846}, +{0, 68970, 5842}, +{0, 69231, 5851}, +{0, 69660, 5851}, +{0, 70155, 5869}, +{0, 70734, 5875}, +{0, 71378, 5881}, +{0, 72055, 5891}, +{0, 72588, 5879}, +{0, 72942, 5898}, +{0, 72781, 5882}, +{0, 73013, 5897}, +{0, 73351, 5887}, +{0, 73884, 5902}, +{0, 74289, 5901}, +{0, 74571, 5887}, +{0, 74683, 5891}, +{0, 74872, 5906}, +{0, 75047, 5900}, +{0, 74844, 5905}, +{0, 74167, 5891}, +{0, 73993, 5890}, +{0, 74094, 5896}, +{0, 74312, 5888}, +{0, 74558, 5894}, +{0, 74754, 5885}, +{0, 74920, 5899}, +{0, 75189, 5895}, +{0, 75489, 5888}, +{0, 75178, 5893}, +{0, 74596, 5882}, +{0, 74433, 5879}, +{0, 74408, 5886}, +{0, 74345, 5884}, +{0, 74341, 5877}, +{0, 74239, 5877}, +{0, 74135, 5869}, +{0, 74031, 5869}, +{0, 73905, 5879}, +{0, 73164, 5860}, +{0, 72268, 5851}, +{0, 71838, 5867}, +{0, 71706, 5854}, +{0, 71727, 5861}, +{0, 71907, 5857}, +{0, 72125, 5872}, +{0, 72408, 5868}, +{0, 72895, 5877}, +{0, 73338, 5881}, +{0, 73321, 5878}, +{0, 72919, 5878}, +{0, 72972, 5873}, +{0, 73083, 5870}, +{0, 73309, 5878}, +{0, 73530, 5869}, +{0, 73618, 5872}, +{0, 73596, 5885}, +{0, 73587, 5864}, +{0, 73547, 5868}, +{0, 73019, 5858}, +{0, 72151, 5853}, +{0, 71781, 5846}, +{0, 71687, 5852}, +{0, 71796, 5853}, +{0, 71949, 5857}, +{0, 72062, 5857}, +{0, 72167, 5856}, +{0, 72338, 5863}, +{0, 72655, 5873}, +{0, 72417, 5856}, +{0, 71948, 5861}, +{0, 71695, 5852}, +{0, 71640, 5850}, +{0, 71668, 5853}, +{0, 71761, 5849}, +{0, 71731, 5851}, +{0, 71692, 5849}, +{0, 71601, 5835}, +{0, 71472, 5843}, +{0, 70814, 5831}, +{0, 69756, 5818}, +{0, 69035, 5816}, +{0, 68569, 5805}, +{0, 68414, 5808}, +{0, 68345, 5801}, +{0, 68178, 5804}, +{0, 67999, 5794}, +{0, 67861, 5810}, +{0, 67663, 5807}, +{0, 66724, 5808}, +{0, 65861, 5795}, +{0, 65417, 5801}, +{0, 65260, 5785}, +{0, 65332, 5793}, +{0, 65283, 5795}, +{0, 64988, 5792}, +{0, 64675, 5786}, +{0, 64347, 5788}, +{0, 63951, 5783}, +{0, 62852, 5765}, +{0, 61867, 5770}, +{0, 61368, 5769}, +{0, 61239, 5778}, +{0, 61486, 5767}, +{0, 61988, 5774}, +{0, 62632, 5799}, +{0, 63408, 5796}, +{0, 64151, 5805}, +{0, 64517, 5813}, +{0, 63974, 5807}, +{0, 63699, 5805}, +{0, 63722, 5807}, +{0, 63989, 5806}, +{0, 64370, 5819}, +{0, 64688, 5805}, +{0, 64879, 5813}, +{0, 65024, 5816}, +{0, 65176, 5815}, +{0, 65004, 5808}, +{0, 64410, 5809}, +{0, 64106, 5817}, +{0, 63971, 5800}, +{0, 63992, 5799}, +{0, 64194, 5820}, +{0, 64332, 5812}, +{0, 64431, 5805}, +{0, 64604, 5800}, +{0, 64817, 5813}, +{0, 64292, 5806}, +{0, 63632, 5795}, +{0, 63383, 5804}, +{0, 63220, 5796}, +{0, 63175, 5793}, +{0, 63247, 5796}, +{0, 63233, 5804}, +{0, 63277, 5804}, +{0, 63287, 5797}, +{0, 63344, 5799}, +{0, 62868, 5787}, +{0, 62286, 5785}, +{0, 62076, 5784}, +{0, 62090, 5775}, +{0, 62301, 5781}, +{0, 62520, 5784}, +{0, 62761, 5789}, +{0, 62998, 5788}, +{0, 63236, 5788}, +{0, 63448, 5790}, +{0, 62970, 5788}, +{0, 62468, 5779}, +{0, 62254, 5775}, +{0, 62212, 5777}, +{0, 62281, 5775}, +{0, 62401, 5772}, +{0, 62447, 5780}, +{0, 62508, 5773}, +{0, 62578, 5768}, +{0, 62634, 5771}, +{0, 62224, 5761}, +{0, 61786, 5764}, +{0, 61571, 5758}, +{0, 61532, 5764}, +{0, 61525, 5764}, +{0, 61630, 5759}, +{0, 61746, 5766}, +{0, 61978, 5764}, +{0, 62241, 5771}, +{0, 62393, 5766}, +{0, 62041, 5760}, +{0, 61717, 5759}, +{0, 61744, 5750}, +{0, 61798, 5768}, +{0, 61958, 5764}, +{0, 62164, 5765}, +{0, 62281, 5764}, +{0, 62350, 5759}, +{0, 62417, 5768}, +{0, 62321, 5760}, +{0, 61874, 5756}, +{0, 61570, 5763}, +{0, 61516, 5769}, +{0, 61562, 5749}, +{0, 61738, 5742}, +{0, 61918, 5758}, +{0, 62105, 5751}, +{0, 62273, 5760}, +{0, 62529, 5749}, +{0, 62418, 5747}, +{0, 62035, 5750}, +{0, 61840, 5746}, +{0, 61803, 5759}, +{0, 61857, 5757}, +{0, 62023, 5745}, +{0, 62152, 5746}, +{0, 62293, 5747}, +{0, 62456, 5754}, +{0, 62602, 5756}, +{0, 62479, 5760}, +{0, 62059, 5758}, +{0, 61748, 5763}, +{0, 61755, 5754}, +{0, 62085, 5762}, +{0, 62519, 5778}, +{0, 63003, 5785}, +{0, 63486, 5788}, +{0, 63995, 5786}, +{0, 64508, 5784}, +{0, 64561, 5794}, +{0, 64397, 5786}, +{0, 64457, 5788}, +{0, 64575, 5796}, +{0, 64673, 5792}, +{0, 64803, 5785}, +{0, 64980, 5778}, +{0, 65071, 5783}, +{0, 65174, 5780}, +{0, 65294, 5781}, +{0, 65023, 5777}, +{0, 64700, 5781}, +{0, 64722, 5794}, +{0, 64954, 5779}, +{0, 65308, 5796}, +{0, 65654, 5803}, +{0, 66008, 5808}, +{0, 66386, 5811}, +{0, 66740, 5810}, +{0, 67062, 5798}, +{0, 66763, 5791}, +{0, 66183, 5779}, +{0, 65919, 5783}, +{0, 65646, 5777}, +{0, 65664, 5776}, +{0, 65711, 5785}, +{0, 65683, 5773}, +{0, 65671, 5785}, +{0, 65738, 5774}, +{0, 65819, 5787}, +{0, 65451, 5779}, +{0, 65118, 5771}, +{0, 65027, 5774}, +{0, 65271, 5782}, +{0, 65605, 5789}, +{0, 65948, 5793}, +{0, 66186, 5783}, +{0, 66328, 5788}, +{0, 66427, 5789}, +{0, 66466, 5792}, +{0, 65897, 5776}, +{0, 65270, 5771}, +{0, 64912, 5764}, +{0, 64731, 5766}, +{0, 64702, 5767}, +{0, 64758, 5761}, +{0, 64787, 5759}, +{0, 64938, 5753}, +{0, 65112, 5759}, +{0, 65230, 5762}, +{0, 65048, 5765}, +{0, 64882, 5767}, +{0, 64873, 5778}, +{0, 65103, 5769}, +{0, 65276, 5784}, +{0, 65464, 5784}, +{0, 65575, 5772}, +{0, 65649, 5774}, +{0, 65761, 5780}, +{0, 65777, 5775}, +{0, 65414, 5770}, +{0, 65099, 5769}, +{0, 65000, 5764}, +{0, 65025, 5770}, +{0, 65040, 5759}, +{0, 65073, 5765}, +{0, 65220, 5765}, +{0, 65406, 5760}, +{0, 65631, 5766}, +{0, 65865, 5770}, +{0, 65764, 5769}, +{0, 65743, 5777}, +{0, 65831, 5778}, +{0, 65952, 5775}, +{0, 66226, 5781}, +{0, 66401, 5784}, +{0, 66447, 5791}, +{0, 66398, 5780}, +{0, 66371, 5779}, +{0, 66423, 5780}, +{0, 66029, 5771}, +{0, 65662, 5765}, +{0, 65568, 5775}, +{0, 65594, 5771}, +{0, 65686, 5774}, +{0, 65890, 5776}, +{0, 66024, 5787}, +{0, 66182, 5775}, +{0, 66399, 5779}, +{0, 66569, 5771}, +{0, 66266, 5783}, +{0, 66114, 5786}, +{0, 66074, 5772}, +{0, 66060, 5784}, +{0, 66115, 5785}, +{0, 66105, 5783}, +{0, 66012, 5780}, +{0, 65946, 5782}, +{0, 65920, 5778}, +{0, 65734, 5790}, +{0, 65300, 5771}, +{0, 65110, 5768}, +{0, 65090, 5767}, +{0, 65144, 5777}, +{0, 65246, 5773}, +{0, 65414, 5770}, +{0, 65557, 5781}, +{0, 65740, 5768}, +{0, 65934, 5782}, +{0, 65981, 5768}, +{0, 65614, 5770}, +{0, 65409, 5768}, +{0, 65337, 5783}, +{0, 65317, 5779}, +{0, 65347, 5775}, +{0, 65401, 5779}, +{0, 65399, 5776}, +{0, 65420, 5777}, +{0, 65465, 5782}, +{0, 65206, 5776}, +{0, 64708, 5765}, +{0, 64445, 5773}, +{0, 64390, 5759}, +{0, 64474, 5761}, +{0, 64616, 5760}, +{0, 64708, 5766}, +{0, 64787, 5768}, +{0, 64904, 5764}, +{0, 65010, 5760}, +{0, 64665, 5743}, +{0, 64290, 5753}, +{0, 64118, 5758}, +{0, 64036, 5746}, +{0, 64071, 5753}, +{0, 64079, 5771}, +{0, 64008, 5758}, +{0, 63954, 5757}, +{0, 63947, 5762}, +{0, 63745, 5769}, +{0, 63147, 5749}, +{0, 62753, 5751}, +{0, 62511, 5745}, +{0, 62522, 5743}, +{0, 62658, 5738}, +{0, 62850, 5751}, +{0, 63096, 5758}, +{0, 63219, 5764}, +{0, 63397, 5760}, +{0, 63139, 5750}, +{0, 62637, 5742}, +{0, 62332, 5758}, +{0, 62161, 5737}, +{0, 62134, 5744}, +{0, 62162, 5727}, +{0, 62146, 5740}, +{0, 62211, 5742}, +{0, 62268, 5741}, +{0, 62296, 5735}, +{0, 61821, 5727}, +{0, 61329, 5731}, +{0, 61131, 5733}, +{0, 61167, 5723}, +{0, 61340, 5729}, +{0, 61444, 5732}, +{0, 61536, 5734}, +{0, 61631, 5747}, +{0, 61716, 5743}, +{0, 61505, 5735}, +{0, 60787, 5722}, +{0, 60345, 5731}, +{0, 60181, 5741}, +{0, 60248, 5729}, +{0, 60367, 5737}, +{0, 60461, 5731}, +{0, 60632, 5730}, +{0, 60762, 5744}, +{0, 60915, 5718}, +{0, 60493, 5732}, +{0, 60104, 5731}, +{0, 59990, 5723}, +{0, 60105, 5727}, +{0, 60318, 5729}, +{0, 60557, 5738}, +{0, 60774, 5735}, +{0, 60965, 5726}, +{0, 61098, 5739}, +{0, 60909, 5738}, +{0, 60327, 5738}, +{0, 59928, 5732}, +{0, 59877, 5738}, +{0, 59907, 5723}, +{0, 60155, 5737}, +{0, 60278, 5744}, +{0, 60408, 5733}, +{0, 60642, 5738}, +{0, 60747, 5738}, +{0, 60382, 5735}, +{0, 60107, 5730}, +{0, 60189, 5733}, +{0, 60398, 5731}, +{0, 60675, 5735}, +{0, 60925, 5743}, +{0, 61206, 5762}, +{0, 61511, 5754}, +{0, 61864, 5773}, +{0, 61935, 5746}, +{0, 61608, 5752}, +{0, 61605, 5754}, +{0, 61722, 5757}, +{0, 61819, 5756}, +{0, 61935, 5754}, +{0, 62005, 5755}, +{0, 62119, 5737}, +{0, 62356, 5755}, +{0, 62664, 5758}, +{0, 62743, 5758}, +{0, 62874, 5759}, +{0, 63192, 5772}, +{0, 63557, 5776}, +{0, 63993, 5791}, +{0, 64457, 5788}, +{0, 64667, 5808}, +{0, 64672, 5779}, +{0, 64583, 5778}, +{0, 64148, 5768}, +{0, 63687, 5762}, +{0, 63436, 5761}, +{0, 63363, 5751}, +{0, 63396, 5768}, +{0, 63591, 5753}, +{0, 63767, 5756}, +{0, 63919, 5763}, +{0, 64148, 5773}, +{0, 64423, 5776}, +{0, 64354, 5782}, +{0, 64326, 5774}, +{0, 64347, 5775}, +{0, 64417, 5781}, +{0, 64483, 5770}, +{0, 64511, 5768}, +{0, 64398, 5758}, +{0, 64234, 5750}, +{0, 64125, 5749}, +{0, 63702, 5748}, +{0, 63276, 5737}, +{0, 63115, 5742}, +{0, 63116, 5736}, +{0, 63333, 5760}, +{0, 63639, 5754}, +{0, 63971, 5768}, +{0, 64317, 5771}, +{0, 64662, 5779}, +{0, 64835, 5766}, +{0, 64640, 5774}, +{0, 64461, 5762}, +{0, 64329, 5772}, +{0, 64323, 5765}, +{0, 64358, 5771}, +{0, 64365, 5752}, +{0, 64315, 5762}, +{0, 64374, 5760}, +{0, 64409, 5775}, +{0, 64065, 5755}, +{0, 63710, 5764}, +{0, 63622, 5751}, +{0, 63622, 5763}, +{0, 63793, 5758}, +{0, 64031, 5763}, +{0, 64245, 5764}, +{0, 64488, 5756}, +{0, 64749, 5766}, +{0, 64617, 5757}, +{0, 64352, 5759}, +{0, 64136, 5758}, +{0, 64014, 5749}, +{0, 64040, 5754}, +{0, 64046, 5756}, +{0, 64095, 5763}, +{0, 64098, 5755}, +{0, 64138, 5759}, +{0, 63955, 5753}, +{0, 63361, 5760}, +{0, 63008, 5748}, +{0, 62864, 5747}, +{0, 62913, 5756}, +{0, 63108, 5748}, +{0, 63239, 5748}, +{0, 63376, 5747}, +{0, 63590, 5752}, +{0, 63659, 5756}, +{0, 63189, 5736}, +{0, 62855, 5750}, +{0, 62591, 5741}, +{0, 62464, 5747}, +{0, 62395, 5736}, +{0, 62361, 5739}, +{0, 62420, 5746}, +{0, 62539, 5740}, +{0, 62640, 5733}, +{0, 62287, 5744}, +{0, 61802, 5721}, +{0, 61712, 5732}, +{0, 61717, 5734}, +{0, 61936, 5731}, +{0, 62140, 5733}, +{0, 62389, 5746}, +{0, 62592, 5751}, +{0, 62793, 5754}, +{0, 62674, 5743}, +{0, 62331, 5746}, +{0, 62134, 5745}, +{0, 62047, 5740}, +{0, 62065, 5749}, +{0, 62175, 5738}, +{0, 62296, 5762}, +{0, 62479, 5745}, +{0, 62641, 5745}, +{0, 62776, 5754}, +{0, 62507, 5738}, +{0, 62360, 5742}, +{0, 62422, 5746}, +{0, 62578, 5742}, +{0, 62801, 5740}, +{0, 62981, 5744}, +{0, 63075, 5748}, +{0, 63254, 5757}, +{0, 63363, 5748}, +{0, 63030, 5745}, +{0, 62689, 5741}, +{0, 62470, 5740}, +{0, 62370, 5744}, +{0, 62403, 5750}, +{0, 62483, 5742}, +{0, 62575, 5738}, +{0, 62695, 5745}, +{0, 63069, 5756}, +{0, 63296, 5751}, +{0, 63314, 5749}, +{0, 63217, 5758}, +{0, 63309, 5760}, +{0, 63452, 5758}, +{0, 63635, 5744}, +{0, 63826, 5756}, +{0, 63935, 5759}, +{0, 63999, 5757}, +{0, 63655, 5750}, +{0, 63351, 5755}, +{0, 63208, 5745}, +{0, 63206, 5748}, +{0, 63277, 5749}, +{0, 63469, 5753}, +{0, 63729, 5755}, +{0, 63966, 5764}, +{0, 64137, 5752}, +{0, 64112, 5757}, +{0, 63987, 5759}, +{0, 63732, 5781}, +{0, 63601, 5766}, +{0, 63678, 5769}, +{0, 63797, 5772}, +{0, 63884, 5769}, +{0, 63884, 5768}, +{0, 63918, 5761}, +{0, 63836, 5765}, +{0, 63581, 5762}, +{0, 63400, 5760}, +{0, 63287, 5760}, +{0, 63299, 5762}, +{0, 63377, 5759}, +{0, 63602, 5756}, +{0, 63770, 5753}, +{0, 64167, 5770}, +{0, 64532, 5774}, +{0, 64516, 5779}, +{0, 64481, 5769}, +{0, 64437, 5773}, +{0, 64521, 5778}, +{0, 64509, 5767}, +{0, 64520, 5778}, +{0, 64447, 5777}, +{0, 64397, 5770}, +{0, 64370, 5765}, +{0, 64160, 5768}, +{0, 63821, 5759}, +{0, 63573, 5761}, +{0, 63482, 5763}, +{0, 63505, 5757}, +{0, 63565, 5761}, +{0, 63695, 5755}, +{0, 63855, 5770}, +{0, 63950, 5762}, +{0, 63716, 5763}, +{0, 63219, 5762}, +{0, 62846, 5748}, +{0, 62658, 5752}, +{0, 62592, 5761}, +{0, 62540, 5735}, +{0, 62563, 5750}, +{0, 62569, 5757}, +{0, 62628, 5747}, +{0, 62420, 5743}, +{0, 61910, 5741}, +{0, 61690, 5742}, +{0, 61672, 5757}, +{0, 61870, 5747}, +{0, 62132, 5740}, +{0, 62472, 5755}, +{0, 62911, 5765}, +{0, 63297, 5773}, +{0, 63437, 5765}, +{0, 63107, 5773}, +{0, 63006, 5772}, +{0, 62997, 5769}, +{0, 62962, 5762}, +{0, 63064, 5765}, +{0, 63159, 5763}, +{0, 63242, 5770}, +{0, 63358, 5761}, +{0, 63449, 5761}, +{0, 63321, 5766}, +{0, 63150, 5761}, +{0, 63133, 5762}, +{0, 63367, 5782}, +{0, 63649, 5759}, +{0, 64041, 5781}, +{0, 64376, 5779}, +{0, 64717, 5792}, +{0, 65015, 5789}, +{0, 64825, 5787}, +{0, 64526, 5781}, +{0, 64226, 5784}, +{0, 64006, 5777}, +{0, 63941, 5784}, +{0, 64014, 5776}, +{0, 64072, 5789}, +{0, 64077, 5770}, +{0, 64241, 5770}, +{0, 64040, 5772}, +{0, 63628, 5763}, +{0, 63414, 5762}, +{0, 63471, 5768}, +{0, 63684, 5773}, +{0, 63888, 5776}, +{0, 64024, 5770}, +{0, 64124, 5775}, +{0, 64260, 5777}, +{0, 64026, 5763}, +{0, 63414, 5776}, +{0, 62978, 5760}, +{0, 62713, 5760}, +{0, 62586, 5756}, +{0, 62588, 5743}, +{0, 62620, 5759}, +{0, 62765, 5748}, +{0, 62946, 5760}, +{0, 62902, 5754}, +{0, 62456, 5748}, +{0, 62211, 5749}, +{0, 62172, 5759}, +{0, 62189, 5746}, +{0, 62341, 5764}, +{0, 62470, 5762}, +{0, 62529, 5759}, +{0, 62579, 5764}, +{0, 62535, 5747}, +{0, 61983, 5739}, +{0, 61407, 5751}, +{0, 61151, 5747}, +{0, 61085, 5743}, +{0, 61183, 5736}, +{0, 61289, 5736}, +{0, 61472, 5737}, +{0, 61717, 5748}, +{0, 61983, 5754}, +{0, 61816, 5744}, +{0, 61361, 5754}, +{0, 61275, 5736}, +{0, 61235, 5741}, +{0, 61351, 5747}, +{0, 61462, 5755}, +{0, 61521, 5754}, +{0, 61551, 5747}, +{0, 61576, 5754}, +{0, 61585, 5764}, +{0, 61220, 5745}, +{0, 60991, 5743}, +{0, 61000, 5747}, +{0, 61196, 5740}, +{0, 61561, 5753}, +{0, 61866, 5754}, +{0, 62172, 5747}, +{0, 62484, 5759}, +{0, 62803, 5768}, +{0, 62628, 5752}, +{0, 62286, 5766}, +{0, 62272, 5762}, +{0, 62382, 5767}, +{0, 62551, 5763}, +{0, 62704, 5758}, +{0, 62756, 5755}, +{0, 62805, 5769}, +{0, 62874, 5762}, +{0, 62686, 5758}, +{0, 62017, 5756}, +{0, 61656, 5755}, +{0, 61481, 5747}, +{0, 61410, 5752}, +{0, 61404, 5751}, +{0, 61426, 5754}, +{0, 61636, 5756}, +{0, 61908, 5752}, +{0, 62211, 5760}, +{0, 62010, 5755}, +{0, 61685, 5756}, +{0, 61541, 5749}, +{0, 61511, 5746}, +{0, 61593, 5757}, +{0, 61610, 5760}, +{0, 61607, 5762}, +{0, 61511, 5753}, +{0, 61551, 5748}, +{0, 61497, 5747}, +{0, 61484, 5748}, +{0, 61526, 5750}, +{0, 61645, 5739}, +{0, 61786, 5751}, +{0, 62042, 5756}, +{0, 62390, 5757}, +{0, 62832, 5771}, +{0, 63289, 5769}, +{0, 63709, 5784}, +{0, 63647, 5782}, +{0, 63323, 5767}, +{0, 63181, 5771}, +{0, 63174, 5771}, +{0, 63162, 5763}, +{0, 63154, 5768}, +{0, 63011, 5762}, +{0, 63026, 5759}, +{0, 63142, 5753}, +{0, 62934, 5757}, +{0, 62515, 5760}, +{0, 62312, 5757}, +{0, 62297, 5754}, +{0, 62433, 5751}, +{0, 62682, 5754}, +{0, 62858, 5770}, +{0, 63028, 5755}, +{0, 63303, 5764}, +{0, 63398, 5755}, +{0, 62993, 5757}, +{0, 62608, 5753}, +{0, 62458, 5751}, +{0, 62346, 5743}, +{0, 62280, 5754}, +{0, 62242, 5763}, +{0, 62303, 5758}, +{0, 62358, 5765}, +{0, 62472, 5752}, +{0, 62424, 5752}, +{0, 62311, 5755}, +{0, 62270, 5752}, +{0, 62418, 5742}, +{0, 62654, 5760}, +{0, 62962, 5759}, +{0, 63310, 5777}, +{0, 63590, 5766}, +{0, 63899, 5772}, +{0, 64095, 5770}, +{0, 63684, 5757}, +{0, 63343, 5759}, +{0, 63230, 5759}, +{0, 63190, 5761}, +{0, 63277, 5762}, +{0, 63404, 5762}, +{0, 63526, 5775}, +{0, 63639, 5768}, +{0, 63752, 5771}, +{0, 63594, 5767}, +{0, 63147, 5760}, +{0, 62958, 5761}, +{0, 63029, 5754}, +{0, 63132, 5751}, +{0, 63350, 5763}, +{0, 63580, 5762}, +{0, 63728, 5762}, +{0, 63925, 5768}, +{0, 63941, 5769}, +{0, 63374, 5768}, +{0, 63028, 5750}, +{0, 62776, 5750}, +{0, 62640, 5756}, +{0, 62609, 5752}, +{0, 62681, 5755}, +{0, 62738, 5758}, +{0, 62820, 5763}, +{0, 62920, 5766}, +{0, 62639, 5759}, +{0, 62154, 5747}, +{0, 61864, 5743}, +{0, 61888, 5754}, +{0, 61960, 5753}, +{0, 62239, 5756}, +{0, 62466, 5758}, +{0, 62673, 5744}, +{0, 62900, 5764}, +{0, 62949, 5756}, +{0, 62397, 5750}, +{0, 61978, 5739}, +{0, 61755, 5753}, +{0, 61742, 5750}, +{0, 61845, 5753}, +{0, 62054, 5757}, +{0, 62186, 5766}, +{0, 62475, 5747}, +{0, 62930, 5770}, +{0, 63060, 5779}, +{0, 63022, 5779}, +{0, 63195, 5789}, +{0, 63697, 5783}, +{0, 64224, 5793}, +{0, 64910, 5810}, +{0, 65466, 5818}, +{0, 65995, 5809}, +{0, 66372, 5816}, +{0, 66701, 5813}, +{0, 66300, 5808}, +{0, 65946, 5809}, +{0, 65914, 5801}, +{0, 66021, 5804}, +{0, 66248, 5800}, +{0, 66482, 5807}, +{0, 66756, 5813}, +{0, 67131, 5814}, +{0, 67588, 5818}, +{0, 67899, 5825}, +{0, 67683, 5829}, +{0, 67813, 5826}, +{0, 68164, 5831}, +{0, 68446, 5820}, +{0, 68572, 5827}, +{0, 68717, 5829}, +{0, 68651, 5818}, +{0, 68414, 5813}, +{0, 67988, 5809}, +{0, 66941, 5788}, +{0, 65900, 5771}, +{0, 65298, 5767}, +{0, 64972, 5767}, +{0, 64967, 5779}, +{0, 65180, 5779}, +{0, 65468, 5791}, +{0, 65798, 5789}, +{0, 66108, 5798}, +{0, 66179, 5801}, +{0, 65593, 5790}, +{0, 65138, 5785}, +{0, 64874, 5788}, +{0, 64714, 5776}, +{0, 64530, 5775}, +{0, 64268, 5760}, +{0, 63955, 5763}, +{0, 63708, 5756}, +{0, 63417, 5753}, +{0, 62657, 5751}, +{0, 61682, 5742}, +{0, 61233, 5736}, +{0, 61069, 5742}, +{0, 61310, 5746}, +{0, 61715, 5746}, +{0, 62000, 5746}, +{0, 62230, 5752}, +{0, 62449, 5757}, +{0, 62507, 5774}, +{0, 61654, 5746}, +{0, 60821, 5744}, +{0, 60387, 5737}, +{0, 59880, 5735}, +{0, 59496, 5728}, +{0, 59358, 5732}, +{0, 59354, 5723}, +{0, 59329, 5742}, +{0, 59331, 5737}, +{0, 59350, 5734}, +{0, 58819, 5728}, +{0, 58525, 5740}, +{0, 58515, 5728}, +{0, 58705, 5738}, +{0, 59026, 5744}, +{0, 59270, 5742}, +{0, 59452, 5751}, +{0, 59545, 5756}, +{0, 59445, 5766}, +{0, 58818, 5743}, +{0, 58052, 5742}, +{0, 57569, 5734}, +{0, 57291, 5741}, +{0, 57174, 5719}, +{0, 57123, 5728}, +{0, 57029, 5735}, +{0, 57037, 5725}, +{0, 57128, 5732}, +{0, 57275, 5739}, +{0, 57110, 5733}, +{0, 56866, 5719}, +{0, 56784, 5736}, +{0, 56829, 5726}, +{0, 56994, 5735}, +{0, 57163, 5734}, +{0, 57203, 5731}, +{0, 57254, 5731}, +{0, 57384, 5735}, +{0, 57097, 5737}, +{0, 56576, 5730}, +{0, 56363, 5713}, +{0, 56377, 5712}, +{0, 56788, 5709}, +{0, 57322, 5724}, +{0, 57840, 5728}, +{0, 58287, 5746}, +{0, 58599, 5765}, +{0, 58873, 5755}, +{0, 58992, 5759}, +{0, 59133, 5769}, +{0, 59547, 5776}, +{0, 59909, 5776}, +{0, 60181, 5785}, +{0, 60555, 5793}, +{0, 61020, 5794}, +{0, 61340, 5797}, +{0, 61674, 5807}, +{0, 62036, 5793}, +{0, 61854, 5794}, +{0, 61705, 5814}, +{0, 61585, 5800}, +{0, 61722, 5805}, +{0, 62005, 5809}, +{0, 62302, 5810}, +{0, 62595, 5805}, +{0, 62918, 5820}, +{0, 63313, 5820}, +{0, 63635, 5831}, +{0, 63577, 5836}, +{0, 63674, 5823}, +{0, 64003, 5819}, +{0, 64328, 5816}, +{0, 64621, 5828}, +{0, 64843, 5829}, +{0, 64937, 5817}, +{0, 65114, 5801}, +{0, 65204, 5813}, +{0, 64832, 5809}, +{0, 64433, 5810}, +{0, 64394, 5802}, +{0, 64461, 5801}, +{0, 64496, 5809}, +{0, 64595, 5796}, +{0, 64774, 5791}, +{0, 65024, 5797}, +{0, 65207, 5801}, +{0, 65222, 5796}, +{0, 64850, 5784}, +{0, 64501, 5796}, +{0, 64304, 5796}, +{0, 64228, 5791}, +{0, 64207, 5780}, +{0, 64083, 5781}, +{0, 63955, 5779}, +{0, 63836, 5782}, +{0, 63848, 5786}, +{0, 63637, 5773}, +{0, 63210, 5761}, +{0, 62985, 5764}, +{0, 63039, 5767}, +{0, 63197, 5760}, +{0, 63341, 5778}, +{0, 63544, 5769}, +{0, 63739, 5767}, +{0, 63995, 5772}, +{0, 64323, 5767}, +{0, 64049, 5771}, +{0, 63642, 5765}, +{0, 63411, 5776}, +{0, 63356, 5765}, +{0, 63354, 5760}, +{0, 63317, 5751}, +{0, 63314, 5766}, +{0, 63295, 5763}, +{0, 63400, 5766}, +{0, 63437, 5758}, +{0, 63369, 5753}, +{0, 63327, 5767}, +{0, 63399, 5759}, +{0, 63467, 5750}, +{0, 63522, 5749}, +{0, 63643, 5760}, +{0, 63746, 5760}, +{0, 63901, 5755}, +{0, 63995, 5758}, +{0, 63701, 5752}, +{0, 63011, 5745}, +{0, 62404, 5752}, +{0, 62038, 5750}, +{0, 61801, 5749}, +{0, 61751, 5745}, +{0, 61743, 5751}, +{0, 61793, 5749}, +{0, 61898, 5745}, +{0, 62023, 5747}, +{0, 61989, 5745}, +{0, 61826, 5761}, +{0, 61562, 5750}, +{0, 61468, 5744}, +{0, 61576, 5749}, +{0, 61709, 5746}, +{0, 61772, 5750}, +{0, 61894, 5748}, +{0, 62009, 5755}, +{0, 61689, 5750}, +{0, 60954, 5751}, +{0, 60651, 5746}, +{0, 60585, 5749}, +{0, 60813, 5753}, +{0, 61144, 5773}, +{0, 61595, 5769}, +{0, 62118, 5771}, +{0, 62545, 5772}, +{0, 63013, 5782}, +{0, 62921, 5776}, +{0, 62850, 5789}, +{0, 63039, 5782}, +{0, 63403, 5789}, +{0, 63687, 5795}, +{0, 64014, 5791}, +{0, 64196, 5800}, +{0, 64372, 5798}, +{0, 64558, 5792}, +{0, 64607, 5795}, +{0, 64151, 5787}, +{0, 63895, 5787}, +{0, 63954, 5799}, +{0, 64189, 5779}, +{0, 64587, 5797}, +{0, 64970, 5815}, +{0, 65360, 5812}, +{0, 65723, 5796}, +{0, 66100, 5807}, +{0, 65975, 5796}, +{0, 65534, 5808}, +{0, 65351, 5795}, +{0, 65235, 5793}, +{0, 65136, 5783}, +{0, 64956, 5786}, +{0, 64777, 5778}, +{0, 64592, 5776}, +{0, 64480, 5778}, +{0, 64341, 5773}, +{0, 63685, 5778}, +{0, 63290, 5765}, +{0, 63096, 5767}, +{0, 63082, 5765}, +{0, 63151, 5769}, +{0, 63320, 5775}, +{0, 63511, 5790}, +{0, 63711, 5780}, +{0, 63809, 5779}, +{0, 63518, 5773}, +{0, 63015, 5767}, +{0, 62667, 5757}, +{0, 62371, 5760}, +{0, 62291, 5769}, +{0, 62318, 5751}, +{0, 62416, 5759}, +{0, 62491, 5772}, +{0, 62615, 5768}, +{0, 62820, 5780}, +{0, 62766, 5766}, +{0, 62747, 5767}, +{0, 63006, 5772}, +{0, 63298, 5786}, +{0, 63805, 5800}, +{0, 64308, 5792}, +{0, 64580, 5798}, +{0, 64543, 5797}, +{0, 64519, 5794}, +{0, 64231, 5788}, +{0, 63415, 5779}, +{0, 62813, 5780}, +{0, 62529, 5770}, +{0, 62474, 5761}, +{0, 62398, 5768}, +{0, 62397, 5763}, +{0, 62343, 5759}, +{0, 62261, 5762}, +{0, 62380, 5747}, +{0, 62215, 5753}, +{0, 61797, 5751}, +{0, 61596, 5748}, +{0, 61604, 5756}, +{0, 61836, 5762}, +{0, 62020, 5772}, +{0, 62051, 5761}, +{0, 62117, 5753}, +{0, 62315, 5767}, +{0, 62360, 5753}, +{0, 61815, 5764}, +{0, 61413, 5765}, +{0, 61228, 5760}, +{0, 61243, 5763}, +{0, 61355, 5763}, +{0, 61465, 5763}, +{0, 61588, 5761}, +{0, 61827, 5756}, +{0, 62006, 5774}, +{0, 61740, 5766}, +{0, 61107, 5748}, +{0, 60842, 5763}, +{0, 60838, 5763}, +{0, 60879, 5764}, +{0, 60958, 5768}, +{0, 61025, 5765}, +{0, 61060, 5758}, +{0, 61128, 5766}, +{0, 61120, 5766}, +{0, 60481, 5756}, +{0, 59914, 5755}, +{0, 59784, 5756}, +{0, 59777, 5762}, +{0, 59909, 5754}, +{0, 60083, 5757}, +{0, 60273, 5750}, +{0, 60514, 5752}, +{0, 60767, 5765}, +{0, 60808, 5754}, +{0, 60216, 5760}, +{0, 59910, 5738}, +{0, 59901, 5752}, +{0, 60023, 5769}, +{0, 60248, 5747}, +{0, 60533, 5744}, +{0, 60757, 5758}, +{0, 60971, 5770}, +{0, 61228, 5762}, +{0, 61118, 5753}, +{0, 60529, 5747}, +{0, 60192, 5745}, +{0, 60154, 5760}, +{0, 60270, 5749}, +{0, 60504, 5748}, +{0, 60755, 5762}, +{0, 60987, 5762}, +{0, 61232, 5763}, +{0, 61545, 5772}, +{0, 61119, 5764}, +{0, 60678, 5754}, +{0, 60493, 5762}, +{0, 60521, 5758}, +{0, 60591, 5754}, +{0, 60694, 5764}, +{0, 60803, 5757}, +{0, 60882, 5765}, +{0, 61101, 5764}, +{0, 61053, 5762}, +{0, 60476, 5753}, +{0, 60163, 5745}, +{0, 60176, 5754}, +{0, 60286, 5753}, +{0, 60471, 5761}, +{0, 60597, 5762}, +{0, 60765, 5750}, +{0, 60997, 5761}, +{0, 61186, 5760}, +{0, 61057, 5762}, +{0, 60504, 5741}, +{0, 60319, 5755}, +{0, 60354, 5755}, +{0, 60391, 5750}, +{0, 60439, 5751}, +{0, 60638, 5759}, +{0, 60767, 5754}, +{0, 60935, 5758}, +{0, 61126, 5760}, +{0, 60949, 5745}, +{0, 60527, 5750}, +{0, 60443, 5760}, +{0, 60562, 5750}, +{0, 60801, 5748}, +{0, 61128, 5754}, +{0, 61414, 5750}, +{0, 61637, 5757}, +{0, 61799, 5764}, +{0, 61925, 5765}, +{0, 61318, 5750}, +{0, 60805, 5743}, +{0, 60637, 5753}, +{0, 60530, 5749}, +{0, 60663, 5751}, +{0, 60765, 5756}, +{0, 60836, 5761}, +{0, 61034, 5764}, +{0, 61247, 5756}, +{0, 61305, 5746}, +{0, 60906, 5748}, +{0, 60653, 5750}, +{0, 60763, 5755}, +{0, 60995, 5751}, +{0, 61257, 5750}, +{0, 61507, 5756}, +{0, 61611, 5763}, +{0, 61801, 5767}, +{0, 62006, 5761}, +{0, 61518, 5762}, +{0, 60908, 5756}, +{0, 60678, 5741}, +{0, 60636, 5741}, +{0, 60638, 5755}, +{0, 60782, 5742}, +{0, 60932, 5749}, +{0, 61152, 5753}, +{0, 61356, 5757}, +{0, 61590, 5752}, +{0, 61185, 5753}, +{0, 60885, 5744}, +{0, 60924, 5749}, +{0, 61051, 5745}, +{0, 61224, 5755}, +{0, 61432, 5758}, +{0, 61663, 5753}, +{0, 61788, 5757}, +{0, 61848, 5763}, +{0, 61655, 5762}, +{0, 61100, 5749}, +{0, 60799, 5753}, +{0, 60930, 5756}, +{0, 61177, 5769}, +{0, 61555, 5760}, +{0, 61857, 5761}, +{0, 62092, 5772}, +{0, 62220, 5776}, +{0, 62445, 5767}, +{0, 62334, 5773}, +{0, 61905, 5771}, +{0, 61789, 5772}, +{0, 61878, 5775}, +{0, 62054, 5771}, +{0, 62205, 5772}, +{0, 62328, 5766}, +{0, 62407, 5769}, +{0, 62495, 5765}, +{0, 62495, 5759}, +{0, 62005, 5761}, +{0, 61616, 5767}, +{0, 61503, 5766}, +{0, 61602, 5758}, +{0, 61782, 5765}, +{0, 61961, 5753}, +{0, 62120, 5769}, +{0, 62290, 5768}, +{0, 62478, 5762}, +{0, 62490, 5762}, +{0, 61913, 5760}, +{0, 61594, 5758}, +{0, 61515, 5765}, +{0, 61640, 5761}, +{0, 61692, 5759}, +{0, 61827, 5755}, +{0, 61797, 5751}, +{0, 61813, 5742}, +{0, 62036, 5745}, +{0, 61561, 5728}, +{0, 61086, 5738}, +{0, 60923, 5739}, +{0, 60929, 5749}, +{0, 61136, 5744}, +{0, 61373, 5761}, +{0, 61605, 5756}, +{0, 61880, 5768}, +{0, 62064, 5774}, +{0, 62169, 5777}, +{0, 61895, 5761}, +{0, 62248, 5790}, +{0, 62649, 5785}, +{0, 63056, 5790}, +{0, 63459, 5794}, +{0, 63755, 5790}, +{0, 63968, 5803}, +{0, 63975, 5787}, +{0, 64034, 5803}, +{0, 63465, 5792}, +{0, 62798, 5789}, +{0, 62708, 5780}, +{0, 62791, 5788}, +{0, 62952, 5778}, +{0, 63170, 5772}, +{0, 63326, 5790}, +{0, 63500, 5789}, +{0, 63731, 5793}, +{0, 63953, 5791}, +{0, 63556, 5791}, +{0, 63278, 5797}, +{0, 63188, 5799}, +{0, 63161, 5783}, +{0, 63197, 5793}, +{0, 63261, 5793}, +{0, 63118, 5795}, +{0, 63035, 5797}, +{0, 62978, 5804}, +{0, 62831, 5781}, +{0, 62288, 5783}, +{0, 61923, 5779}, +{0, 61893, 5786}, +{0, 62082, 5781}, +{0, 62299, 5780}, +{0, 62488, 5772}, +{0, 62663, 5784}, +{0, 62891, 5785}, +{0, 63095, 5783}, +{0, 62599, 5780}, +{0, 62140, 5774}, +{0, 61934, 5768}, +{0, 61857, 5781}, +{0, 61991, 5782}, +{0, 62116, 5770}, +{0, 62133, 5780}, +{0, 62187, 5793}, +{0, 62388, 5779}, +{0, 62226, 5771}, +{0, 61572, 5774}, +{0, 61252, 5767}, +{0, 61281, 5764}, +{0, 61458, 5774}, +{0, 61656, 5776}, +{0, 61844, 5780}, +{0, 62050, 5790}, +{0, 62420, 5782}, +{0, 62644, 5777}, +{0, 62145, 5781}, +{0, 61751, 5780}, +{0, 61625, 5777}, +{0, 61618, 5789}, +{0, 61696, 5782}, +{0, 61788, 5782}, +{0, 61874, 5777}, +{0, 62052, 5785}, +{0, 62266, 5778}, +{0, 62277, 5786}, +{0, 61693, 5772}, +{0, 61435, 5778}, +{0, 61478, 5774}, +{0, 61711, 5764}, +{0, 61963, 5774}, +{0, 62215, 5776}, +{0, 62488, 5775}, +{0, 62743, 5788}, +{0, 63075, 5777}, +{0, 62594, 5783}, +{0, 62240, 5774}, +{0, 62145, 5775}, +{0, 62187, 5777}, +{0, 62278, 5776}, +{0, 62370, 5787}, +{0, 62541, 5776}, +{0, 62705, 5782}, +{0, 62874, 5783}, +{0, 62884, 5776}, +{0, 62389, 5773}, +{0, 62256, 5777}, +{0, 62397, 5768}, +{0, 62622, 5762}, +{0, 62894, 5773}, +{0, 63120, 5786}, +{0, 63277, 5773}, +{0, 63460, 5786}, +{0, 63655, 5783}, +{0, 63108, 5776}, +{0, 62718, 5775}, +{0, 62604, 5767}, +{0, 62563, 5769}, +{0, 62588, 5765}, +{0, 62552, 5769}, +{0, 62597, 5777}, +{0, 62628, 5780}, +{0, 62750, 5772}, +{0, 62529, 5768}, +{0, 61909, 5758}, +{0, 61576, 5762}, +{0, 61491, 5766}, +{0, 61657, 5759}, +{0, 61816, 5770}, +{0, 61928, 5765}, +{0, 62069, 5770}, +{0, 62260, 5770}, +{0, 62413, 5767}, +{0, 61801, 5770}, +{0, 61443, 5760}, +{0, 61378, 5762}, +{0, 61482, 5765}, +{0, 61646, 5765}, +{0, 61804, 5770}, +{0, 61832, 5771}, +{0, 61897, 5765}, +{0, 62009, 5767}, +{0, 61689, 5760}, +{0, 61014, 5750}, +{0, 60775, 5767}, +{0, 60705, 5755}, +{0, 60819, 5763}, +{0, 61163, 5762}, +{0, 61478, 5768}, +{0, 61753, 5764}, +{0, 62056, 5767}, +{0, 62274, 5765}, +{0, 61735, 5768}, +{0, 61425, 5760}, +{0, 61502, 5765}, +{0, 61651, 5762}, +{0, 61912, 5769}, +{0, 62253, 5775}, +{0, 62469, 5770}, +{0, 62734, 5774}, +{0, 62879, 5780}, +{0, 62580, 5783}, +{0, 61939, 5776}, +{0, 61669, 5771}, +{0, 61602, 5767}, +{0, 61671, 5786}, +{0, 61839, 5781}, +{0, 61977, 5771}, +{0, 62185, 5776}, +{0, 62400, 5783}, +{0, 62562, 5778}, +{0, 61962, 5760}, +{0, 61616, 5757}, +{0, 61672, 5776}, +{0, 61838, 5778}, +{0, 62090, 5758}, +{0, 62358, 5772}, +{0, 62582, 5779}, +{0, 62693, 5792}, +{0, 62966, 5791}, +{0, 62697, 5791}, +{0, 62455, 5783}, +{0, 62467, 5769}, +{0, 62605, 5783}, +{0, 62840, 5782}, +{0, 63168, 5786}, +{0, 63532, 5784}, +{0, 63896, 5794}, +{0, 64291, 5805}, +{0, 64758, 5804}, +{0, 64611, 5794}, +{0, 64211, 5797}, +{0, 64158, 5792}, +{0, 64267, 5801}, +{0, 64491, 5802}, +{0, 64811, 5805}, +{0, 65062, 5815}, +{0, 65306, 5812}, +{0, 65441, 5804}, +{0, 65284, 5799}, +{0, 64434, 5774}, +{0, 63854, 5784}, +{0, 63529, 5769}, +{0, 63279, 5760}, +{0, 63190, 5774}, +{0, 63219, 5760}, +{0, 63263, 5769}, +{0, 63351, 5765}, +{0, 63564, 5787}, +{0, 63277, 5774}, +{0, 62796, 5769}, +{0, 62506, 5764}, +{0, 62471, 5767}, +{0, 62562, 5770}, +{0, 62702, 5773}, +{0, 62732, 5769}, +{0, 62756, 5769}, +{0, 62713, 5764}, +{0, 62552, 5751}, +{0, 61826, 5756}, +{0, 61372, 5737}, +{0, 61237, 5751}, +{0, 61209, 5748}, +{0, 61388, 5754}, +{0, 61627, 5755}, +{0, 61730, 5766}, +{0, 61872, 5759}, +{0, 62014, 5754}, +{0, 61843, 5745}, +{0, 61188, 5759}, +{0, 60888, 5747}, +{0, 60594, 5760}, +{0, 60498, 5748}, +{0, 60528, 5757}, +{0, 60562, 5760}, +{0, 60561, 5753}, +{0, 60578, 5761}, +{0, 60557, 5750}, +{0, 59837, 5740}, +{0, 59182, 5725}, +{0, 58867, 5734}, +{0, 58708, 5732}, +{0, 58715, 5737}, +{0, 59117, 5744}, +{0, 59494, 5750}, +{0, 59745, 5759}, +{0, 60013, 5751}, +{0, 60076, 5742}, +{0, 59533, 5746}, +{0, 59173, 5744}, +{0, 59078, 5750}, +{0, 59113, 5750}, +{0, 59176, 5736}, +{0, 59239, 5744}, +{0, 59261, 5742}, +{0, 59241, 5745}, +{0, 59107, 5738}, +{0, 58684, 5723}, +{0, 58056, 5724}, +{0, 58010, 5735}, +{0, 58179, 5725}, +{0, 58548, 5737}, +{0, 59193, 5734}, +{0, 60022, 5738}, +{0, 61146, 5744}, +{0, 62468, 5761}, +{0, 63258, 5771}, +{0, 63210, 5769}, +{0, 63247, 5785}, +{0, 63493, 5783}, +{0, 63955, 5803}, +{0, 64734, 5807}, +{0, 65604, 5823}, +{0, 66555, 5835}, +{0, 67298, 5832}, +{0, 68032, 5844}, +{0, 68529, 5855}, +{0, 68500, 5848}, +{0, 68548, 5838}, +{0, 68630, 5840}, +{0, 68718, 5842}, +{0, 68746, 5839}, +{0, 68648, 5832}, +{0, 68411, 5830}, +{0, 68303, 5823}, +{0, 68230, 5824}, +{0, 67843, 5833}, +{0, 67282, 5807}, +{0, 67002, 5809}, +{0, 66832, 5822}, +{0, 66800, 5821}, +{0, 66781, 5823}, +{0, 66724, 5813}, +{0, 66764, 5822}, +{0, 66858, 5811}, +{0, 67014, 5811}, +{0, 66649, 5821}, +{0, 66162, 5810}, +{0, 65993, 5806}, +{0, 65948, 5800}, +{0, 66044, 5805}, +{0, 66143, 5811}, +{0, 66272, 5808}, +{0, 66337, 5807}, +{0, 66426, 5796}, +{0, 66364, 5809}, +{0, 65737, 5791}, +{0, 65333, 5797}, +{0, 65088, 5803}, +{0, 65079, 5785}, +{0, 65175, 5788}, +{0, 65235, 5798}, +{0, 65320, 5797}, +{0, 65371, 5797}, +{0, 65491, 5798}, +{0, 65058, 5780}, +{0, 64592, 5780}, +{0, 64366, 5793}, +{0, 64345, 5779}, +{0, 64479, 5778}, +{0, 64627, 5785}, +{0, 64727, 5778}, +{0, 64825, 5788}, +{0, 64874, 5782}, +{0, 64721, 5783}, +{0, 63950, 5786}, +{0, 63438, 5779}, +{0, 63242, 5777}, +{0, 63245, 5777}, +{0, 63368, 5781}, +{0, 63546, 5783}, +{0, 63663, 5789}, +{0, 63828, 5786}, +{0, 63995, 5789}, +{0, 63575, 5788}, +{0, 62933, 5784}, +{0, 62672, 5774}, +{0, 62758, 5769}, +{0, 62906, 5767}, +{0, 63141, 5777}, +{0, 63371, 5775}, +{0, 63553, 5780}, +{0, 63762, 5789}, +{0, 63802, 5792}, +{0, 62974, 5774}, +{0, 62377, 5777}, +{0, 62180, 5768}, +{0, 62152, 5770}, +{0, 62287, 5782}, +{0, 62424, 5782}, +{0, 62565, 5777}, +{0, 62763, 5785}, +{0, 62931, 5785}, +{0, 62525, 5779}, +{0, 61871, 5769}, +{0, 61663, 5767}, +{0, 61701, 5765}, +{0, 61877, 5774}, +{0, 62115, 5768}, +{0, 62270, 5775}, +{0, 62541, 5777}, +{0, 62833, 5772}, +{0, 62867, 5769}, +{0, 62178, 5770}, +{0, 61743, 5766}, +{0, 61632, 5765}, +{0, 61631, 5767}, +{0, 61840, 5772}, +{0, 61915, 5773}, +{0, 62116, 5774}, +{0, 62273, 5785}, +{0, 62462, 5782}, +{0, 62189, 5763}, +{0, 61577, 5771}, +{0, 61343, 5765}, +{0, 61373, 5776}, +{0, 61595, 5779}, +{0, 61835, 5772}, +{0, 62136, 5770}, +{0, 62389, 5774}, +{0, 62707, 5767}, +{0, 62890, 5778}, +{0, 62388, 5772}, +{0, 62031, 5768}, +{0, 61919, 5766}, +{0, 62038, 5766}, +{0, 62217, 5767}, +{0, 62342, 5770}, +{0, 62421, 5779}, +{0, 62534, 5775}, +{0, 62860, 5787}, +{0, 62865, 5785}, +{0, 62653, 5787}, +{0, 62773, 5770}, +{0, 63067, 5791}, +{0, 63408, 5789}, +{0, 63896, 5794}, +{0, 64195, 5796}, +{0, 64389, 5795}, +{0, 64516, 5796}, +{0, 64547, 5792}, +{0, 63648, 5790}, +{0, 62962, 5769}, +{0, 62591, 5780}, +{0, 62426, 5771}, +{0, 62464, 5774}, +{0, 62530, 5775}, +{0, 62655, 5774}, +{0, 62848, 5764}, +{0, 63071, 5762}, +{0, 62915, 5775}, +{0, 62279, 5765}, +{0, 62044, 5761}, +{0, 62044, 5760}, +{0, 62180, 5768}, +{0, 62331, 5767}, +{0, 62405, 5779}, +{0, 62539, 5781}, +{0, 62760, 5778}, +{0, 62957, 5778}, +{0, 62434, 5768}, +{0, 61954, 5766}, +{0, 61722, 5762}, +{0, 61691, 5765}, +{0, 61757, 5767}, +{0, 61894, 5758}, +{0, 62029, 5770}, +{0, 62164, 5769}, +{0, 62290, 5776}, +{0, 62143, 5773}, +{0, 61442, 5766}, +{0, 61082, 5754}, +{0, 61039, 5755}, +{0, 61151, 5761}, +{0, 61337, 5762}, +{0, 61538, 5760}, +{0, 61818, 5772}, +{0, 62053, 5768}, +{0, 62239, 5763}, +{0, 61566, 5760}, +{0, 60885, 5753}, +{0, 60757, 5757}, +{0, 60844, 5753}, +{0, 61042, 5757}, +{0, 61332, 5756}, +{0, 61622, 5756}, +{0, 61812, 5770}, +{0, 61931, 5763}, +{0, 61776, 5761}, +{0, 61115, 5756}, +{0, 60638, 5749}, +{0, 60487, 5749}, +{0, 60707, 5761}, +{0, 60958, 5741}, +{0, 61158, 5756}, +{0, 61232, 5749}, +{0, 61287, 5747}, +{0, 61422, 5757}, +{0, 60814, 5744}, +{0, 60165, 5735}, +{0, 59844, 5727}, +{0, 59797, 5725}, +{0, 59908, 5732}, +{0, 59991, 5739}, +{0, 59970, 5736}, +{0, 60230, 5727}, +{0, 60650, 5722}, +{0, 60913, 5729}, +{0, 60711, 5720}, +{0, 60289, 5718}, +{0, 59960, 5734}, +{0, 59757, 5715}, +{0, 59668, 5722}, +{0, 59582, 5723}, +{0, 59557, 5726}, +{0, 59620, 5734}, +{0, 59743, 5732}, +{0, 59203, 5731}, +{0, 58719, 5717}, +{0, 58536, 5716}, +{0, 58412, 5724}, +{0, 58451, 5723}, +{0, 58468, 5720}, +{0, 58452, 5733}, +{0, 58319, 5726}, +{0, 58223, 5732}, +{0, 58068, 5725}, +{0, 57694, 5717}, +{0, 57391, 5719}, +{0, 57123, 5707}, +{0, 57030, 5715}, +{0, 56991, 5721}, +{0, 57046, 5732}, +{0, 57170, 5730}, +{0, 57315, 5726}, +{0, 57433, 5728}, +{0, 57085, 5717}, +{0, 56826, 5730}, +{0, 56789, 5732}, +{0, 56786, 5714}, +{0, 56961, 5734}, +{0, 57075, 5743}, +{0, 57095, 5732}, +{0, 57127, 5726}, +{0, 57015, 5728}, +{0, 56576, 5730}, +{0, 55986, 5730}, +{0, 55667, 5724}, +{0, 55510, 5734}, +{0, 55469, 5732}, +{0, 55538, 5731}, +{0, 55559, 5733}, +{0, 55658, 5733}, +{0, 55836, 5742}, +{0, 56030, 5735}, +{0, 55839, 5739}, +{0, 55578, 5724}, +{0, 55592, 5732}, +{0, 55720, 5734}, +{0, 55944, 5735}, +{0, 56176, 5745}, +{0, 56352, 5748}, +{0, 56539, 5737}, +{0, 56714, 5750}, +{0, 56522, 5728}, +{0, 56097, 5738}, +{0, 55919, 5735}, +{0, 55870, 5735}, +{0, 55922, 5740}, +{0, 56056, 5751}, +{0, 56190, 5758}, +{0, 56245, 5751}, +{0, 56441, 5750}, +{0, 56457, 5745}, +{0, 56152, 5742}, +{0, 55996, 5746}, +{0, 56028, 5738}, +{0, 56175, 5745}, +{0, 56364, 5746}, +{0, 56600, 5746}, +{0, 56790, 5741}, +{0, 57027, 5749}, +{0, 57145, 5758}, +{0, 56925, 5744}, +{0, 56706, 5738}, +{0, 56700, 5745}, +{0, 56700, 5735}, +{0, 56770, 5746}, +{0, 56851, 5742}, +{0, 56970, 5743}, +{0, 57079, 5742}, +{0, 57204, 5748}, +{0, 57197, 5756}, +{0, 56916, 5738}, +{0, 56684, 5732}, +{0, 56706, 5730}, +{0, 56826, 5735}, +{0, 57092, 5732}, +{0, 57270, 5748}, +{0, 57462, 5739}, +{0, 57681, 5743}, +{0, 57812, 5743}, +{0, 57435, 5732}, +{0, 57147, 5740}, +{0, 57097, 5731}, +{0, 57157, 5734}, +{0, 57390, 5735}, +{0, 57618, 5750}, +{0, 57691, 5749}, +{0, 57788, 5748}, +{0, 57849, 5754}, +{0, 57736, 5756}, +{0, 57358, 5752}, +{0, 57049, 5732}, +{0, 56992, 5749}, +{0, 57064, 5739}, +{0, 57221, 5745}, +{0, 57493, 5737}, +{0, 57816, 5739}, +{0, 57955, 5753}, +{0, 57976, 5752}, +{0, 57485, 5749}, +{0, 57193, 5732}, +{0, 57121, 5742}, +{0, 56931, 5745}, +{0, 56800, 5743}, +{0, 56758, 5740}, +{0, 56842, 5736}, +{0, 56831, 5736}, +{0, 56778, 5749}, +{0, 56617, 5737}, +{0, 56046, 5736}, +{0, 55890, 5734}, +{0, 56052, 5730}, +{0, 56415, 5740}, +{0, 56673, 5735}, +{0, 56920, 5747}, +{0, 57196, 5743}, +{0, 57563, 5739}, +{0, 57915, 5749}, +{0, 57932, 5749}, +{0, 57920, 5732}, +{0, 57985, 5747}, +{0, 58101, 5759}, +{0, 58398, 5756}, +{0, 58657, 5749}, +{0, 59000, 5760}, +{0, 59327, 5760}, +{0, 59683, 5764}, +{0, 59682, 5757}, +{0, 59383, 5768}, +{0, 59284, 5749}, +{0, 59326, 5754}, +{0, 59510, 5762}, +{0, 59662, 5765}, +{0, 59903, 5764}, +{0, 60130, 5764}, +{0, 60352, 5753}, +{0, 60435, 5782}, +{0, 60048, 5753}, +{0, 59756, 5758}, +{0, 59621, 5756}, +{0, 59580, 5752}, +{0, 59641, 5761}, +{0, 59830, 5760}, +{0, 59982, 5766}, +{0, 60149, 5766}, +{0, 60287, 5766}, +{0, 60185, 5761}, +{0, 59823, 5761}, +{0, 59783, 5752}, +{0, 59734, 5753}, +{0, 59608, 5752}, +{0, 59343, 5744}, +{0, 59035, 5766}, +{0, 58994, 5754}, +{0, 59095, 5757}, +{0, 58951, 5751}, +{0, 58311, 5753}, +{0, 57810, 5751}, +{0, 57513, 5739}, +{0, 57431, 5744}, +{0, 57433, 5757}, +{0, 57538, 5760}, +{0, 57600, 5756}, +{0, 57706, 5760}, +{0, 57906, 5766}, +{0, 57933, 5761}, +{0, 57692, 5753}, +{0, 57595, 5759}, +{0, 57634, 5749}, +{0, 57804, 5753}, +{0, 57975, 5766}, +{0, 58127, 5756}, +{0, 58261, 5764}, +{0, 58500, 5764}, +{0, 58681, 5764}, +{0, 58418, 5741}, +{0, 58108, 5760}, +{0, 57945, 5755}, +{0, 57934, 5753}, +{0, 58145, 5755}, +{0, 58416, 5773}, +{0, 58614, 5759}, +{0, 58815, 5765}, +{0, 58994, 5764}, +{0, 58933, 5762}, +{0, 58552, 5761}, +{0, 58483, 5755}, +{0, 58520, 5769}, +{0, 58665, 5753}, +{0, 58897, 5752}, +{0, 59088, 5760}, +{0, 59329, 5766}, +{0, 59615, 5761}, +{0, 59787, 5763}, +{0, 59506, 5768}, +{0, 59280, 5761}, +{0, 59177, 5762}, +{0, 59261, 5756}, +{0, 59249, 5760}, +{0, 59316, 5765}, +{0, 59307, 5767}, +{0, 59357, 5772}, +{0, 59403, 5771}, +{0, 59406, 5764}, +{0, 59254, 5754}, +{0, 59190, 5761}, +{0, 59291, 5763}, +{0, 59545, 5762}, +{0, 59840, 5762}, +{0, 60165, 5765}, +{0, 60390, 5763}, +{0, 60620, 5769}, +{0, 60771, 5775}, +{0, 60512, 5761}, +{0, 60360, 5761}, +{0, 60213, 5770}, +{0, 60156, 5766}, +{0, 60120, 5765}, +{0, 60130, 5784}, +{0, 60283, 5778}, +{0, 60401, 5769}, +{0, 60492, 5776}, +{0, 60330, 5764}, +{0, 60068, 5763}, +{0, 59978, 5767}, +{0, 59953, 5759}, +{0, 60063, 5773}, +{0, 60169, 5752}, +{0, 60333, 5762}, +{0, 60513, 5755}, +{0, 60772, 5757}, +{0, 60695, 5764}, +{0, 60163, 5752}, +{0, 59778, 5756}, +{0, 59684, 5753}, +{0, 59685, 5753}, +{0, 59651, 5761}, +{0, 59614, 5756}, +{0, 59552, 5757}, +{0, 59510, 5753}, +{0, 59595, 5755}, +{0, 59255, 5753}, +{0, 58770, 5759}, +{0, 58577, 5757}, +{0, 58560, 5755}, +{0, 58583, 5753}, +{0, 58583, 5752}, +{0, 58582, 5750}, +{0, 58583, 5757}, +{0, 58737, 5757}, +{0, 58552, 5744}, +{0, 58014, 5751}, +{0, 57624, 5744}, +{0, 57584, 5737}, +{0, 57686, 5745}, +{0, 57722, 5751}, +{0, 57675, 5747}, +{0, 57624, 5748}, +{0, 57671, 5756}, +{0, 57748, 5740}, +{0, 57307, 5740}, +{0, 56921, 5737}, +{0, 56786, 5749}, +{0, 56851, 5745}, +{0, 57043, 5747}, +{0, 57191, 5747}, +{0, 57347, 5734}, +{0, 57539, 5741}, +{0, 57752, 5738}, +{0, 57509, 5721}, +{0, 57133, 5731}, +{0, 56986, 5728}, +{0, 56996, 5738}, +{0, 57230, 5743}, +{0, 57410, 5739}, +{0, 57515, 5739}, +{0, 57627, 5743}, +{0, 57699, 5740}, +{0, 57510, 5735}, +{0, 57097, 5742}, +{0, 56980, 5734}, +{0, 56984, 5725}, +{0, 57093, 5748}, +{0, 57203, 5733}, +{0, 57436, 5742}, +{0, 57640, 5750}, +{0, 57861, 5746}, +{0, 57906, 5730}, +{0, 57431, 5722}, +{0, 57308, 5725}, +{0, 57289, 5729}, +{0, 57486, 5730}, +{0, 57666, 5740}, +{0, 57832, 5742}, +{0, 58065, 5735}, +{0, 58216, 5731}, +{0, 58216, 5734}, +{0, 57671, 5735}, +{0, 57250, 5733}, +{0, 57038, 5727}, +{0, 57094, 5731}, +{0, 57244, 5733}, +{0, 57376, 5728}, +{0, 57454, 5735}, +{0, 57602, 5727}, +{0, 57737, 5719}, +{0, 57455, 5718}, +{0, 57109, 5721}, +{0, 57022, 5720}, +{0, 57099, 5732}, +{0, 57309, 5724}, +{0, 57564, 5732}, +{0, 57830, 5735}, +{0, 57975, 5728}, +{0, 58161, 5740}, +{0, 58118, 5737}, +{0, 57710, 5719}, +{0, 57527, 5728}, +{0, 57501, 5724}, +{0, 57592, 5722}, +{0, 57661, 5727}, +{0, 57671, 5732}, +{0, 57641, 5741}, +{0, 57605, 5734}, +{0, 57559, 5734}, +{0, 57396, 5723}, +{0, 57569, 5738}, +{0, 58093, 5756}, +{0, 58718, 5779}, +{0, 59324, 5776}, +{0, 59817, 5780}, +{0, 60291, 5792}, +{0, 60676, 5785}, +{0, 60910, 5786}, +{0, 60723, 5785}, +{0, 60731, 5783}, +{0, 60825, 5783}, +{0, 60989, 5788}, +{0, 61151, 5780}, +{0, 61360, 5794}, +{0, 61532, 5795}, +{0, 61786, 5794}, +{0, 61971, 5790}, +{0, 61843, 5791}, +{0, 61696, 5798}, +{0, 61734, 5793}, +{0, 61824, 5790}, +{0, 61995, 5783}, +{0, 62082, 5795}, +{0, 62183, 5798}, +{0, 62341, 5794}, +{0, 62467, 5798}, +{0, 62186, 5797}, +{0, 61929, 5794}, +{0, 61792, 5793}, +{0, 61775, 5788}, +{0, 61872, 5790}, +{0, 61929, 5782}, +{0, 61920, 5787}, +{0, 61914, 5790}, +{0, 61872, 5778}, +{0, 61670, 5778}, +{0, 61182, 5774}, +{0, 60971, 5761}, +{0, 60887, 5776}, +{0, 60914, 5772}, +{0, 61053, 5777}, +{0, 61298, 5777}, +{0, 61471, 5766}, +{0, 61733, 5766}, +{0, 61731, 5761}, +{0, 61416, 5763}, +{0, 61276, 5766}, +{0, 60872, 5759}, +{0, 60318, 5765}, +{0, 59821, 5768}, +{0, 59663, 5762}, +{0, 59724, 5768}, +{0, 59571, 5774}, +{0, 59225, 5767}, +{0, 58531, 5752}, +{0, 58153, 5761}, +{0, 58064, 5755}, +{0, 58052, 5752}, +{0, 58131, 5769}, +{0, 58161, 5762}, +{0, 58336, 5765}, +{0, 58513, 5767}, +{0, 58586, 5757}, +{0, 58015, 5762}, +{0, 57681, 5744}, +{0, 57555, 5753}, +{0, 57602, 5755}, +{0, 57802, 5748}, +{0, 57908, 5763}, +{0, 58042, 5768}, +{0, 58226, 5754}, +{0, 58298, 5745}, +{0, 57702, 5743}, +{0, 57215, 5751}, +{0, 57052, 5760}, +{0, 56961, 5749}, +{0, 57115, 5746}, +{0, 57342, 5768}, +{0, 57435, 5762}, +{0, 57506, 5762}, +{0, 57588, 5764}, +{0, 57205, 5760}, +{0, 56804, 5761}, +{0, 56664, 5745}, +{0, 56707, 5753}, +{0, 56811, 5762}, +{0, 56943, 5762}, +{0, 57149, 5754}, +{0, 57383, 5758}, +{0, 57559, 5767}, +{0, 57256, 5752}, +{0, 56872, 5742}, +{0, 56762, 5746}, +{0, 56790, 5745}, +{0, 56834, 5749}, +{0, 57029, 5737}, +{0, 57260, 5736}, +{0, 57682, 5739}, +{0, 58314, 5754}, +{0, 58656, 5770}, +{0, 58643, 5764}, +{0, 58539, 5761}, +{0, 58542, 5768}, +{0, 58596, 5765}, +{0, 58691, 5765}, +{0, 58731, 5774}, +{0, 58934, 5772}, +{0, 59123, 5761}, +{0, 59054, 5768}, +{0, 58660, 5759}, +{0, 58449, 5757}, +{0, 58359, 5759}, +{0, 58418, 5751}, +{0, 58399, 5759}, +{0, 58423, 5759}, +{0, 58394, 5764}, +{0, 58424, 5756}, +{0, 58387, 5754}, +{0, 58087, 5749}, +{0, 57859, 5749}, +{0, 57822, 5747}, +{0, 57919, 5751}, +{0, 58108, 5753}, +{0, 58344, 5748}, +{0, 58588, 5747}, +{0, 58813, 5756}, +{0, 58906, 5751}, +{0, 58689, 5746}, +{0, 58544, 5744}, +{0, 58565, 5745}, +{0, 58666, 5745}, +{0, 58771, 5744}, +{0, 58778, 5738}, +{0, 58750, 5758}, +{0, 58706, 5738}, +{0, 58619, 5747}, +{0, 58347, 5752}, +{0, 58253, 5750}, +{0, 58209, 5737}, +{0, 58327, 5749}, +{0, 58465, 5747}, +{0, 58677, 5773}, +{0, 58822, 5754}, +{0, 58988, 5770}, +{0, 59120, 5763}, +{0, 58836, 5753}, +{0, 58669, 5756}, +{0, 58673, 5750}, +{0, 58754, 5765}, +{0, 58889, 5752}, +{0, 59021, 5757}, +{0, 59062, 5777}, +{0, 59104, 5766}, +{0, 59146, 5760}, +{0, 58839, 5765}, +{0, 58500, 5767}, +{0, 58373, 5749}, +{0, 58279, 5756}, +{0, 58422, 5762}, +{0, 58559, 5765}, +{0, 58758, 5764}, +{0, 58937, 5768}, +{0, 59153, 5770}, +{0, 58995, 5766}, +{0, 58621, 5757}, +{0, 58507, 5756}, +{0, 58526, 5759}, +{0, 58618, 5752}, +{0, 58798, 5757}, +{0, 58994, 5757}, +{0, 59106, 5759}, +{0, 59158, 5761}, +{0, 58934, 5764}, +{0, 58364, 5763}, +{0, 58120, 5759}, +{0, 58090, 5757}, +{0, 58150, 5760}, +{0, 58238, 5758}, +{0, 58464, 5767}, +{0, 58693, 5760}, +{0, 58911, 5771}, +{0, 59013, 5762}, +{0, 58653, 5762}, +{0, 58510, 5743}, +{0, 58587, 5754}, +{0, 58661, 5758}, +{0, 58808, 5754}, +{0, 58986, 5763}, +{0, 59128, 5760}, +{0, 59136, 5765}, +{0, 59133, 5764}, +{0, 58746, 5762}, +{0, 58407, 5751}, +{0, 58295, 5754}, +{0, 58307, 5751}, +{0, 58368, 5763}, +{0, 58517, 5758}, +{0, 58731, 5752}, +{0, 58854, 5756}, +{0, 59067, 5765}, +{0, 58864, 5749}, +{0, 58655, 5752}, +{0, 58601, 5741}, +{0, 58679, 5745}, +{0, 58786, 5756}, +{0, 58916, 5763}, +{0, 58981, 5758}, +{0, 58914, 5763}, +{0, 58891, 5759}, +{0, 58888, 5764}, +{0, 58676, 5747}, +{0, 58834, 5759}, +{0, 59073, 5776}, +{0, 59332, 5767}, +{0, 59562, 5773}, +{0, 59824, 5773}, +{0, 60261, 5768}, +{0, 60683, 5770}, +{0, 61001, 5771}, +}; +static const int16_t PAH8009_mems_HRD[][3*NF_PPG_PER_CHANNEL] = +{ +{6305, -1007, 8865}, +{5777, -95, 9889}, +{6385, 1137, 8897}, +{4401, 833, 5425}, +{4465, -1647, 3153}, +{19985, 3937, 1713}, +{-2447, -3775, 8273}, +{5009, 4017, 12657}, +{6769, 1329, 6033}, +{5025, -1567, 6145}, +{6225, 1025, 5889}, +{5681, -351, 5057}, +{5905, 113, 5745}, +{5793, -31, 6369}, +{5297, 193, 5857}, +{5121, 657, 6321}, +{5121, 1041, 5937}, +{5873, 17, 6753}, +{6577, -1583, 6065}, +{5825, -63, 6385}, +{5601, 33, 4961}, +{6097, -303, 4785}, +{6001, 433, 5697}, +{6001, 929, 5553}, +{6145, 561, 5201}, +{6353, 1009, 5009}, +{6481, 1697, 5153}, +{6049, 1633, 5441}, +{6033, 1361, 5697}, +{6113, 1313, 5681}, +{6161, 1697, 5409}, +{6145, 1345, 5537}, +{6081, 1889, 5505}, +{5985, 1425, 5409}, +{5985, 1809, 5505}, +{5953, 1729, 5553}, +{5953, 1569, 5681}, +{5889, 1649, 5489}, +{6065, 1409, 5713}, +{6017, 1761, 5457}, +{6001, 1953, 5521}, +{5985, 2065, 5617}, +{5777, 1793, 5633}, +{5633, 1601, 5745}, +{5809, 1601, 5857}, +{5809, 1633, 5665}, +{5713, 1761, 5633}, +{5841, 1697, 5777}, +{5745, 1713, 5617}, +{5825, 1713, 5793}, +{5905, 1633, 5713}, +{5841, 1601, 5681}, +{5921, 1761, 5649}, +{5889, 1649, 5553}, +{5985, 1649, 5569}, +{5825, 1857, 5937}, +{5809, 1585, 5601}, +{6017, 1569, 5441}, +{5601, 1377, 5697}, +{5841, 1265, 5825}, +{6049, 1857, 6145}, +{5889, 1585, 4977}, +{6609, 1185, 5521}, +{6161, 1697, 5441}, +{6065, 1633, 5489}, +{6193, 1633, 5505}, +{6225, 1569, 5441}, +{6129, 1521, 5329}, +{6129, 1569, 5409}, +{6081, 1473, 5345}, +{5857, 1377, 5537}, +{5905, 1153, 5665}, +{6113, 1217, 5441}, +{6209, 1441, 5409}, +{6145, 1121, 5505}, +{6097, 1121, 5585}, +{6177, 1089, 5473}, +{6193, 1281, 5345}, +{6225, 1265, 5457}, +{5985, 1249, 5361}, +{6209, 1425, 5761}, +{6049, 1057, 5585}, +{5969, 1009, 5793}, +{6017, 1153, 5649}, +{6065, 1377, 5569}, +{6001, 1345, 5617}, +{6033, 1345, 5457}, +{6241, 1473, 5457}, +{6097, 1425, 5473}, +{6161, 1521, 5441}, +{6129, 1569, 5441}, +{6097, 1537, 5441}, +{6065, 1505, 5425}, +{6177, 1681, 5441}, +{6113, 1745, 5505}, +{6337, 1505, 5233}, +{6129, 1649, 5393}, +{6225, 1617, 5361}, +{6177, 1553, 5329}, +{6305, 1569, 5201}, +{6209, 1633, 5265}, +{6401, 1745, 5233}, +{6225, 1569, 5281}, +{6385, 1585, 5217}, +{6321, 1665, 5217}, +{6289, 1521, 5121}, +{6321, 1761, 5249}, +{6289, 1569, 5201}, +{6273, 1601, 5217}, +{6273, 1649, 5233}, +{6321, 1649, 5313}, +{6321, 1601, 5249}, +{6321, 1569, 5249}, +{6273, 1569, 5297}, +{6161, 1441, 5249}, +{6257, 1537, 5329}, +{6225, 1425, 5313}, +{6289, 1697, 5425}, +{6257, 1281, 5153}, +{6305, 1281, 5249}, +{6337, 1393, 5393}, +{6321, 1201, 5313}, +{6369, 1425, 5361}, +{6257, 1537, 5201}, +{6385, 1473, 5137}, +{6433, 1569, 5137}, +{6369, 1745, 4977}, +{6417, 1585, 5153}, +{6289, 1585, 5105}, +{6289, 1585, 5185}, +{6321, 1649, 5185}, +{6241, 1569, 5329}, +{6337, 1713, 5313}, +{6209, 1537, 5281}, +{6369, 1569, 5265}, +{6049, 1713, 5265}, +{6241, 1649, 5489}, +{6353, 1409, 5169}, +{6177, 1409, 5041}, +{6369, 1505, 5377}, +{6273, 1521, 5393}, +{6289, 1553, 5329}, +{6289, 1633, 5185}, +{6273, 1617, 5217}, +{6257, 1761, 5089}, +{6337, 1777, 5201}, +{6209, 1617, 5297}, +{6257, 1729, 5185}, +{6401, 1841, 5121}, +{6353, 1745, 5169}, +{6273, 1601, 5137}, +{6369, 1793, 5153}, +{6337, 1713, 5153}, +{6369, 1713, 5201}, +{6385, 1665, 5217}, +{6241, 2017, 5025}, +{6369, 1761, 5025}, +{6337, 1697, 5105}, +{6369, 1761, 5137}, +{6401, 1809, 5057}, +{6353, 1793, 5089}, +{6417, 1841, 5073}, +{6385, 1873, 5041}, +{6385, 1809, 5073}, +{6417, 1905, 5089}, +{6353, 1841, 5057}, +{6353, 1873, 5073}, +{6337, 1873, 5073}, +{6353, 1889, 5025}, +{6385, 1857, 5153}, +{6305, 1873, 5121}, +{6337, 1857, 5089}, +{6289, 1889, 4961}, +{6241, 1825, 4769}, +{6225, 1841, 4737}, +{6305, 1921, 4977}, +{6353, 2177, 4561}, +{6161, 1697, 4225}, +{6401, 3089, 6225}, +{6321, 2769, 5537}, +{6177, 2449, 5153}, +{6177, 2545, 5057}, +{6145, 2545, 5153}, +{6177, 2561, 5025}, +{6161, 2561, 5073}, +{6145, 2513, 5057}, +{6161, 2385, 5025}, +{6161, 2657, 5121}, +{6161, 2753, 4897}, +{6145, 2689, 4913}, +{6145, 2753, 4977}, +{6145, 2801, 5009}, +{6161, 2673, 5073}, +{6129, 2657, 5025}, +{6145, 2705, 5041}, +{6145, 2625, 5041}, +{6129, 2577, 5089}, +{6113, 2625, 5073}, +{6081, 2641, 5041}, +{6081, 2593, 5105}, +{6161, 2689, 5233}, +{6033, 2449, 5121}, +{6081, 2497, 5137}, +{6097, 2577, 5233}, +{6097, 2465, 5169}, +{6113, 2481, 5153}, +{6097, 2561, 5121}, +{6081, 2513, 5105}, +{6113, 2561, 5153}, +{6129, 2545, 5105}, +{6129, 2529, 5089}, +{6097, 2497, 5169}, +{6113, 2513, 5185}, +{6097, 2401, 5169}, +{6193, 2529, 5217}, +{6161, 2801, 5153}, +{6113, 2737, 5009}, +{6129, 2577, 4961}, +{6081, 2561, 5217}, +{6049, 2449, 5057}, +{6049, 2321, 5169}, +{6097, 2497, 5249}, +{6065, 2449, 5313}, +{6017, 2513, 5185}, +{6049, 2529, 5201}, +{6097, 2481, 5201}, +{6065, 2369, 5297}, +{6001, 2401, 5233}, +{6017, 2417, 5313}, +{6033, 2385, 5281}, +{5985, 2337, 5217}, +{5969, 2385, 5329}, +{6049, 2337, 5457}, +{6081, 2577, 5329}, +{5969, 2481, 5249}, +{5953, 2257, 5409}, +{5953, 2353, 5521}, +{5873, 2289, 5393}, +{5473, 3185, 5297}, +{6081, 2817, 3889}, +{6161, 3313, 5569}, +{5745, 2769, 5249}, +{6449, 2849, 4913}, +{5857, 2593, 5009}, +{5953, 2481, 5233}, +{6273, 2369, 4817}, +{6353, 2609, 4929}, +{6209, 2385, 4849}, +{6337, 2177, 5073}, +{6225, 2129, 5041}, +{6353, 2033, 5057}, +{6321, 2193, 4945}, +{6417, 2017, 5057}, +{6321, 2001, 4993}, +{6417, 2017, 4833}, +{6385, 1969, 4961}, +{6353, 1953, 4961}, +{6321, 2049, 5025}, +{6401, 2209, 4945}, +{6449, 2049, 5041}, +{6465, 2161, 4961}, +{6337, 2113, 5009}, +{6417, 2225, 4897}, +{6481, 2305, 4961}, +{6465, 2049, 4673}, +{6225, 2897, 5377}, +{6193, 2657, 5537}, +{6449, 2385, 4673}, +{6353, 2273, 4753}, +{6273, 2369, 4529}, +{6369, 3169, 6049}, +{6337, 2753, 5361}, +{6113, 2417, 5009}, +{6273, 2257, 5009}, +{6225, 2433, 4897}, +{6225, 2129, 5153}, +{6257, 2641, 5137}, +{6001, 2353, 5281}, +{6193, 2241, 4849}, +{6305, 2481, 5617}, +{6529, 2817, 5809}, +{6337, 3473, 5441}, +{6129, 1345, 3569}, +{6049, 1585, 3985}, +{6241, 1633, 4177}, +{6225, 2081, 5009}, +{6273, 1985, 4977}, +{6145, 1969, 5265}, +{6289, 1713, 4577}, +{6401, 1649, 4769}, +{6273, 1505, 4993}, +{6305, 1553, 5521}, +{6145, 1617, 5393}, +{6193, 1505, 5185}, +{6305, 1761, 5313}, +{6081, 1569, 5425}, +{6177, 1537, 5297}, +{6209, 1473, 5441}, +{6257, 1569, 5441}, +{6177, 1409, 5297}, +{6241, 1473, 5185}, +{6177, 1601, 4913}, +{6177, 1553, 5137}, +{6257, 1361, 5633}, +{6193, 1729, 5617}, +{6193, 1425, 5409}, +{6241, 1569, 5329}, +{6193, 1665, 5217}, +{6289, 1489, 5201}, +{6257, 1521, 5297}, +{6225, 1553, 5297}, +{6113, 1713, 5249}, +{6209, 1713, 5281}, +{6225, 1697, 5329}, +{6209, 1745, 5217}, +{6241, 1697, 5233}, +{6193, 1697, 5233}, +{6193, 1809, 5297}, +{6273, 1825, 5217}, +{6241, 1841, 5233}, +{6241, 1697, 5265}, +{6225, 1905, 5233}, +{6209, 1793, 5265}, +{6193, 1873, 5233}, +{6257, 1873, 5265}, +{6209, 1825, 5249}, +{6257, 1809, 5233}, +{6209, 1793, 5185}, +{6241, 1825, 5217}, +{6193, 1857, 5297}, +{6225, 1729, 5329}, +{6097, 1633, 5361}, +{6161, 1841, 5377}, +{6129, 1841, 5377}, +{6129, 1841, 5345}, +{6113, 1713, 5393}, +{6129, 1681, 5393}, +{6113, 1697, 5425}, +{6129, 1649, 5409}, +{6081, 1601, 5457}, +{6113, 1713, 5425}, +{6097, 1713, 5505}, +{6113, 1601, 5441}, +{6081, 1649, 5409}, +{6081, 1617, 5521}, +{6017, 1649, 5473}, +{6065, 1601, 5441}, +{6081, 1585, 5441}, +{6113, 1713, 5473}, +{6097, 1793, 5441}, +{6081, 1713, 5425}, +{6081, 1745, 5457}, +{6097, 1665, 5441}, +{6113, 1697, 5441}, +{6097, 1729, 5425}, +{6081, 1713, 5441}, +{6097, 1697, 5425}, +{6113, 1697, 5425}, +{6113, 1745, 5409}, +{6081, 1745, 5473}, +{6049, 1713, 5377}, +{6097, 1681, 5409}, +{6081, 1873, 5409}, +{6097, 1809, 5377}, +{6145, 1777, 5489}, +{6193, 1761, 5281}, +{6113, 1489, 5281}, +{6209, 1521, 5393}, +{6129, 1793, 5265}, +{6145, 1937, 5377}, +{6225, 1905, 5361}, +{6145, 1713, 5473}, +{6145, 1473, 5489}, +{5873, 1793, 5473}, +{5985, 1729, 5553}, +{6017, 1473, 5457}, +{6033, 1697, 5665}, +{6033, 1873, 5953}, +{6065, 1713, 5425}, +{5985, 1425, 5489}, +{5889, 1329, 5537}, +{5953, 1233, 5489}, +{6033, 1233, 5601}, +{5729, 849, 5761}, +{5681, 705, 5969}, +{5761, 833, 6161}, +{5729, 689, 6017}, +{5841, 705, 5953}, +{5713, 305, 5953}, +{5537, 481, 6001}, +{5665, 545, 6145}, +{5601, 465, 6081}, +{5601, 417, 6049}, +{5681, 449, 6081}, +{5633, 305, 6209}, +{5617, 529, 6049}, +{5633, 513, 6001}, +{5745, 481, 5969}, +{5697, 561, 5937}, +{5745, 641, 5985}, +{5921, 929, 5793}, +{5857, 737, 5681}, +{5985, 913, 5681}, +{6001, 961, 5633}, +{6097, 1473, 5393}, +{6033, 1217, 5489}, +{6145, 1233, 5649}, +{6289, 1457, 5361}, +{6273, 1441, 5249}, +{6273, 1265, 5265}, +{6145, 1665, 5377}, +{6241, 1633, 5409}, +{6161, 1617, 5377}, +{6177, 1729, 5297}, +{6177, 1665, 5409}, +{6129, 1553, 5361}, +{6161, 1569, 5345}, +{6193, 1745, 5377}, +{6273, 1361, 5393}, +{6177, 1505, 5489}, +{5905, 1073, 5553}, +{5953, 1441, 5681}, +{5873, 1249, 5777}, +{5745, 1233, 5777}, +{5921, 849, 5921}, +{5825, 913, 5873}, +{5777, 801, 5873}, +{5745, 1185, 5841}, +{5793, 1089, 5873}, +{5761, 945, 5921}, +{5793, 1041, 5841}, +{5889, 1281, 5681}, +{5793, 1153, 5777}, +{5649, 1425, 5713}, +{5809, 1553, 5809}, +{5441, 1745, 5841}, +{5537, 1841, 5729}, +{6945, 641, 5521}, +{6097, 2113, 4945}, +{5953, 2705, 5329}, +{6193, 2449, 5585}, +{5841, 1953, 5249}, +{6321, 1793, 5329}, +{6369, 1633, 5425}, +{6177, 1745, 5185}, +{6305, 1457, 4833}, +{6353, 769, 5201}, +{6529, 817, 5265}, +{6305, 641, 5473}, +{6289, 497, 5313}, +{6241, 337, 5361}, +{6321, 145, 5409}, +{6257, -63, 5441}, +{6177, 273, 5489}, +{6129, 193, 5585}, +{6241, -79, 5633}, +{6017, 65, 5665}, +{6257, 49, 5617}, +{5985, -255, 5873}, +{6049, -111, 5537}, +{6273, -15, 5585}, +{6113, 17, 5585}, +{6033, -255, 5649}, +{6017, 17, 5569}, +{6225, -287, 5553}, +{6321, -127, 5489}, +{6081, 97, 5601}, +{6193, 209, 5201}, +{6385, 241, 5217}, +{6273, 321, 5233}, +{6769, 449, 5697}, +{6433, 257, 5249}, +{6545, 689, 5089}, +{6305, 1313, 5281}, +{6177, 721, 5505}, +{6193, 1825, 5649}, +{6129, 961, 4705}, +{6641, 1121, 4961}, +{6513, 801, 4945}, +{6673, 641, 5345}, +{6241, -159, 5185}, +{6353, 657, 4977}, +{6305, 1377, 5361}, +{6433, 561, 5265}, +{6129, 1745, 5265}, +{6561, 465, 5329}, +{6417, 1089, 5505}, +{6193, 785, 5745}, +{6065, 1233, 5729}, +{5793, 1777, 5521}, +{6001, 993, 5937}, +{5905, 769, 5697}, +{6033, 1105, 5489}, +{6049, 1377, 5537}, +{5873, 1153, 5649}, +{5937, 1281, 5665}, +{6097, 2001, 5409}, +{6081, 2065, 5217}, +{6177, 1953, 5217}, +{6129, 2081, 5297}, +{6385, 1873, 5313}, +{5745, 1761, 5457}, +{6081, 2385, 5361}, +{6273, 1537, 5041}, +{6433, 1857, 4737}, +{6529, 1905, 4881}, +{6801, 1857, 4929}, +{6401, 1649, 5201}, +{6017, 1713, 4865}, +{6497, 1793, 5217}, +{5985, 1377, 4977}, +{6177, 1521, 5425}, +{6161, 1697, 5457}, +{5985, 1169, 5345}, +{6033, 1713, 5473}, +{6193, 1473, 5649}, +{5873, 1761, 5873}, +{6289, 1761, 5665}, +{5873, 1505, 5649}, +{5985, 1441, 5473}, +{6081, 1057, 5713}, +{6097, 1057, 5585}, +{6049, 1057, 5553}, +{5873, 1377, 5505}, +{6049, 1313, 5521}, +{6161, 1521, 5489}, +{6097, 1841, 5617}, +{6273, 2209, 5329}, +{6273, 2081, 5233}, +{6161, 1537, 5473}, +{6049, 2225, 4817}, +{6385, 2753, 4721}, +{6513, 2593, 4465}, +{6641, 2545, 4625}, +{6561, 2337, 4785}, +{6449, 2209, 4705}, +{6113, 1633, 4993}, +{6257, 2273, 5057}, +{6193, 1953, 5153}, +{6081, 1969, 5393}, +{5969, 1729, 5601}, +{5905, 1489, 5617}, +{6001, 1681, 5569}, +{5953, 1233, 5457}, +{5905, 1601, 5649}, +{6049, 1473, 5889}, +{5825, 1025, 6001}, +{6033, 1185, 5649}, +{6113, 1409, 5361}, +{6145, 1329, 5505}, +{6097, 1569, 5377}, +{6257, 1489, 5361}, +{6353, 1777, 5121}, +{6385, 2225, 4881}, +{6305, 2769, 5041}, +{6001, 2145, 4785}, +{6513, 1713, 5281}, +{6481, 641, 4769}, +{6657, 1297, 5137}, +{6609, 1425, 5025}, +{6529, 1185, 5201}, +{6369, 1233, 5057}, +{6465, 1441, 5041}, +{6401, 1473, 5137}, +{6417, 1473, 5025}, +{6337, 1633, 5073}, +{6305, 1521, 5313}, +{6273, 1313, 5425}, +{6129, 1089, 5601}, +{6273, 1185, 5329}, +{6225, 481, 5185}, +{6033, 193, 5153}, +{6161, 929, 5377}, +{6145, 385, 5553}, +{6065, -95, 5953}, +{5809, 33, 5969}, +{5857, 81, 5617}, +{6097, -15, 5601}, +{6001, 113, 5569}, +{6193, 465, 5633}, +{6065, 337, 5633}, +{6161, 513, 5649}, +{6257, 145, 5393}, +{6145, 497, 5505}, +{6305, 817, 5233}, +{6449, 769, 5281}, +{6385, 801, 5537}, +{6241, 1057, 5313}, +{6273, 977, 5121}, +{6529, 1137, 4897}, +{6609, 1329, 4849}, +{6801, 1649, 4897}, +{6561, 1713, 4961}, +{6545, 1537, 4817}, +{6545, 1457, 5153}, +{6401, 1553, 5057}, +{6513, 1169, 5137}, +{6513, 833, 5217}, +{6529, 1393, 4913}, +{6049, 1697, 5041}, +{5969, 2929, 5729}, +{6049, 2481, 6001}, +{5985, 2289, 5521}, +{5937, 1553, 5681}, +{5985, 1937, 5649}, +{6081, 1953, 5521}, +{6065, 1857, 5441}, +{5953, 1457, 5489}, +{5937, 1393, 5521}, +{5937, 1841, 5489}, +{6081, 1953, 5377}, +{5969, 1809, 5265}, +{6129, 2289, 5217}, +{6097, 1953, 5377}, +{6081, 2433, 5185}, +{6097, 2689, 5025}, +{6065, 2977, 5025}, +{6161, 2625, 5041}, +{6177, 2689, 5041}, +{6193, 2785, 5025}, +{5985, 2913, 4001}, +{7281, 2417, 4865}, +{6481, 3697, 5569}, +{6161, 2993, 4289}, +{6289, 2465, 4769}, +{6001, 3041, 5105}, +{6017, 2369, 5649}, +{6033, 2753, 5297}, +{5921, 2321, 5393}, +{5857, 2033, 5345}, +{5809, 1905, 5377}, +{5841, 1953, 5489}, +{5889, 2225, 5729}, +{5825, 1985, 5729}, +{6033, 1793, 5633}, +{6049, 1553, 5521}, +{5521, 1505, 5313}, +{6545, 705, 5585}, +{5553, 1905, 5713}, +{6049, 1633, 5633}, +{6369, 1073, 5121}, +{6193, 1313, 4961}, +{6273, 1873, 5201}, +{6481, 1681, 5841}, +{6113, 945, 5729}, +{6369, 1217, 4833}, +{6049, 1409, 5553}, +{6017, 1, 5745}, +{6209, 257, 5457}, +{6049, 929, 5681}, +{6001, 465, 5777}, +{5937, 257, 5921}, +{6001, 433, 5793}, +{6033, 433, 5601}, +{5937, 481, 5473}, +{6017, 529, 5585}, +{6049, 305, 5777}, +{6081, 97, 5649}, +{6065, 209, 5729}, +{5937, -15, 5649}, +{5857, 145, 5921}, +{5905, -143, 6065}, +{5681, -79, 6161}, +{5921, -239, 5649}, +{5761, -111, 5665}, +{5889, 113, 5697}, +{5841, -31, 5713}, +{5761, -399, 5809}, +{5489, -911, 5633}, +{5521, -767, 5585}, +{6433, 449, 5729}, +{6145, 33, 5793}, +{6385, 273, 5505}, +{6401, 961, 5057}, +{6385, 1505, 5185}, +{6273, 1377, 5409}, +{5985, 1841, 5201}, +{5857, 1825, 5489}, +{5889, 2209, 5777}, +{6177, 1601, 5473}, +{6113, 1969, 5601}, +{6033, 1953, 5473}, +{6193, 1857, 5601}, +{6225, 1697, 5617}, +{5985, 2353, 5601}, +{6481, 2161, 6273}, +{5713, 1585, 4849}, +{5921, 1377, 4849}, +{5825, 1009, 6209}, +{5089, 529, 5537}, +{5409, 129, 6113}, +{5761, 177, 5697}, +{6193, 289, 5249}, +{6193, 449, 5665}, +{6049, 657, 5425}, +{5905, 1329, 5153}, +{6145, 1409, 5265}, +{5329, 1137, 5857}, +{6001, 817, 5793}, +{6097, 769, 5697}, +{6513, 1393, 5297}, +{6433, 1729, 5265}, +{6321, 1537, 5169}, +{6305, 1329, 5249}, +{6097, 1185, 5265}, +{6161, 833, 5537}, +{5825, 641, 5537}, +{5889, 513, 5809}, +{6049, 401, 5969}, +{5697, 177, 6049}, +{5681, -63, 6081}, +{5601, -191, 6113}, +{5505, -863, 6289}, +{5329, -559, 6161}, +{5489, -911, 6001}, +{5441, -735, 6209}, +{5521, -959, 6225}, +{5841, -303, 5745}, +{5825, -367, 5921}, +{5825, -159, 5761}, +{6001, -47, 5681}, +{5969, 49, 5697}, +{6257, 529, 5345}, +{6241, 449, 5601}, +{5969, 769, 5617}, +{6145, 497, 5649}, +{5953, 513, 5537}, +{6097, 625, 5521}, +{6145, 993, 5313}, +{5857, 289, 5745}, +{6001, 737, 5697}, +{6065, 353, 5825}, +{5873, 641, 5905}, +{6193, 1137, 5569}, +{6145, 929, 5633}, +{6129, 1153, 5505}, +{6081, 913, 5921}, +{5873, 833, 5777}, +{5937, 193, 5809}, +{5953, 689, 5921}, +{5857, 145, 5809}, +{5873, 289, 5665}, +{5889, 241, 5633}, +{5937, 433, 5793}, +{6001, 225, 5841}, +{5921, 417, 5697}, +{6033, 1041, 5633}, +{6049, 1057, 5409}, +{5809, 1233, 5841}, +{5985, 1441, 5633}, +{6001, 1313, 5697}, +{6049, 1137, 5777}, +{6385, 1473, 5537}, +{6465, 1697, 4977}, +{6465, 1505, 4865}, +{6513, 1649, 5073}, +{6209, 1633, 4945}, +{6705, 1601, 5073}, +{6369, 1633, 5137}, +{6625, 1393, 5345}, +{6113, 1633, 4993}, +{6193, 1217, 5105}, +{6097, 1297, 5649}, +{5905, 1057, 5841}, +{5649, 897, 5937}, +{5553, 417, 6209}, +{5729, 945, 5825}, +{5921, 721, 5553}, +{5761, 593, 5297}, +{5345, 721, 5905}, +{5665, 641, 6113}, +{5697, 625, 5953}, +{5937, 705, 6209}, +{5745, 1121, 6177}, +{5953, 1105, 5329}, +{5889, 1393, 5233}, +{5745, 1217, 5937}, +{5857, 1441, 6033}, +{5889, 1585, 6065}, +{6833, 1921, 4721}, +{6801, 1969, 4417}, +{6737, 1905, 4561}, +{6657, 1921, 4785}, +{6305, 1953, 5089}, +{6065, 1937, 5281}, +{6177, 1985, 5377}, +{5985, 1905, 5553}, +{6049, 1601, 5713}, +{6001, 1313, 5713}, +{5793, 689, 5697}, +{5601, 561, 5937}, +{5505, 657, 6225}, +{5457, 433, 6449}, +{5521, 609, 6305}, +{5457, 353, 6193}, +{5361, -79, 6385}, +{5553, -223, 6017}, +{5521, -143, 6049}, +{5489, -15, 5905}, +{5505, 401, 6193}, +{5809, 689, 5793}, +{5857, 273, 5681}, +{5697, 817, 5841}, +{6177, 1137, 5441}, +{6065, 1089, 5633}, +{5969, 1313, 5745}, +{6161, 1697, 5521}, +{6241, 1761, 5329}, +{6385, 1729, 5233}, +{6353, 1617, 5137}, +{6289, 1441, 5281}, +{6145, 1601, 5425}, +{6177, 1553, 5425}, +{6065, 1393, 5553}, +{6161, 1873, 5393}, +{5889, 705, 5649}, +{5953, 881, 5777}, +{5745, 609, 5873}, +{5681, 1089, 6033}, +{5697, 721, 6033}, +{5505, 433, 6273}, +{5649, 769, 6033}, +{5809, 385, 5969}, +{5809, 305, 5665}, +{6049, 209, 5553}, +{5697, 337, 5985}, +{5809, 577, 5953}, +{5745, 721, 5921}, +{5697, 689, 5873}, +{5713, 961, 5665}, +{6049, 1105, 5649}, +{6145, 881, 5713}, +{6289, 961, 4961}, +{6465, 1425, 4689}, +{6625, 1969, 4817}, +{6241, 1425, 5265}, +{6257, 1425, 5313}, +{6001, 1793, 5377}, +{6113, 1697, 5585}, +{6097, 1905, 5393}, +{6145, 1249, 5537}, +{6177, 1601, 5489}, +{6049, 1073, 5553}, +{5889, 1521, 5681}, +{5857, 1169, 5873}, +{6001, 897, 5601}, +{6129, 1041, 5505}, +{6193, 881, 5377}, +{6289, 353, 5313}, +{5393, 1281, 6017}, +{5377, 1793, 5345}, +{5585, 1601, 6433}, +{6385, -463, 5361}, +{6449, 705, 5153}, +{6449, 577, 5425}, +{5969, 1329, 5505}, +{6529, -351, 5473}, +{6625, -79, 4689}, +{6657, 65, 4737}, +{6257, 721, 5249}, +{6129, 577, 5473}, +{6353, 161, 5441}, +{6465, 289, 5217}, +{6481, 465, 5105}, +{6465, 993, 4913}, +{6625, 673, 4865}, +{6465, 97, 5217}, +{6529, -463, 5601}, +{6513, 465, 5297}, +{6689, 17, 4721}, +{6401, -95, 4993}, +{6241, -319, 5729}, +{6193, -543, 5457}, +{6177, -495, 5361}, +{6273, -543, 5441}, +{6097, -879, 5201}, +{5393, -1551, 5457}, +{6113, -1183, 5361}, +{6225, -847, 5889}, +{6033, -879, 5809}, +{6289, -783, 5457}, +{6529, -239, 4865}, +{6545, 145, 5137}, +{6113, 593, 5249}, +{6609, 737, 5665}, +{5953, 209, 5569}, +{6241, 833, 5553}, +{6241, 769, 5489}, +{6353, 497, 5201}, +{5905, 1617, 4849}, +{6801, 865, 5553}, +{6145, -399, 5569}, +{6193, 545, 5649}, +{6113, 177, 5377}, +{6369, 481, 5409}, +{6241, 113, 5393}, +{5921, 161, 5633}, +{5729, 289, 6033}, +{5873, 449, 5969}, +{6001, 433, 6001}, +{5873, 417, 5761}, +{5985, -143, 5617}, +{6145, 209, 5489}, +{6097, 593, 5633}, +{5953, 577, 5713}, +{6017, 497, 5665}, +{6145, 769, 5665}, +{6289, 737, 5553}, +{6289, 785, 5409}, +{6337, 561, 5313}, +{6321, 881, 5121}, +{6337, 1457, 4561}, +{6273, 1313, 5057}, +{6321, 657, 4961}, +{6657, 1457, 4737}, +{6497, 1041, 4721}, +{6049, 1569, 6017}, +{5937, 945, 6017}, +{6161, 1441, 5601}, +{5985, 753, 5457}, +{6017, 737, 5537}, +{5905, 1137, 5745}, +{5761, -143, 4977}, +{5809, -127, 4097}, +{6145, 81, 5649}, +{5825, -191, 7201}, +{6017, -127, 6049}, +{6161, -383, 5633}, +{6337, 353, 5425}, +{6161, 225, 5665}, +{5937, 353, 5521}, +{6257, 465, 5137}, +{6417, 1041, 4785}, +{5873, 1937, 6305}, +{5905, 1297, 6593}, +{5713, 961, 6065}, +{5889, 1521, 5345}, +{5889, 2193, 5409}, +{5777, 1489, 6193}, +{6033, 1473, 5777}, +{5857, 1409, 5473}, +{6081, 1361, 5217}, +{6225, 1569, 4913}, +{5905, 1681, 5841}, +{5825, 1729, 5985}, +{5889, 1617, 5841}, +{6033, 1697, 5329}, +{6209, 977, 5425}, +{5857, 1521, 5921}, +{5841, 1761, 5697}, +{6097, 1665, 5553}, +{6097, 1457, 5473}, +{6033, 1393, 5473}, +{5937, 1857, 5649}, +{5905, 2001, 5649}, +{5809, 1873, 5633}, +{5825, 2017, 5761}, +{5985, 2081, 5713}, +{6049, 1825, 5185}, +{5953, 2145, 5217}, +{5937, 2305, 5489}, +{6033, 2433, 5873}, +{6177, 2161, 5441}, +{6001, 2113, 5073}, +{6177, 1889, 5185}, +{6097, 2017, 5441}, +{6033, 2033, 5537}, +{6033, 1633, 5553}, +{5921, 1521, 5761}, +{5889, 1633, 5729}, +{5873, 1825, 5553}, +{5937, 1601, 5361}, +{5937, 1745, 5569}, +{5937, 1601, 5761}, +{5809, 1329, 5649}, +{6049, 1313, 5441}, +{6001, 1569, 5441}, +{5969, 1329, 5633}, +{5921, 1521, 5697}, +{5873, 1841, 5489}, +{5665, 2161, 5233}, +{6177, 2193, 5217}, +{6113, 2321, 5521}, +{5985, 1857, 5393}, +{5841, 2753, 5217}, +{6097, 2513, 5441}, +{6049, 2497, 5297}, +{6081, 2129, 5153}, +{6065, 2433, 5201}, +{6129, 2449, 5297}, +{6033, 2113, 5361}, +{6049, 2209, 5249}, +{5953, 1921, 5425}, +{5889, 1921, 5633}, +{5745, 1617, 5745}, +{5649, 1889, 5889}, +{5649, 1809, 5777}, +{5729, 1217, 5857}, +{5633, 1521, 5953}, +{5585, 1489, 5969}, +{5713, 1425, 5793}, +{5697, 1393, 5729}, +{5889, 1905, 5713}, +{5809, 1969, 5665}, +{5777, 2065, 5569}, +{6033, 2081, 5169}, +{5905, 3217, 5393}, +{5681, 2865, 5457}, +{6033, 2977, 5345}, +{6033, 2881, 4865}, +{6017, 3121, 5041}, +{5921, 3089, 5121}, +{6017, 2689, 5217}, +{6113, 2673, 5201}, +{5937, 2913, 4961}, +{6001, 2449, 5185}, +{5921, 2401, 5377}, +{5953, 2353, 5409}, +{5777, 2577, 5521}, +{5585, 2129, 5873}, +{5553, 2081, 5889}, +{5601, 2177, 5729}, +{5729, 1825, 5697}, +{5745, 1569, 5713}, +{5761, 1345, 5889}, +{5617, 1953, 5777}, +{5649, 2065, 5729}, +{5713, 2065, 5649}, +{5633, 2209, 5537}, +{5745, 1921, 5857}, +{5809, 2849, 5745}, +{5793, 2577, 5521}, +{6017, 2689, 5041}, +{6049, 2929, 5025}, +{6001, 2369, 5409}, +{6065, 2593, 5025}, +{6065, 2289, 5345}, +{6033, 2705, 5185}, +{5953, 2673, 5249}, +{5889, 2289, 5393}, +{5921, 2417, 5521}, +{5809, 2193, 5665}, +{5889, 2161, 5521}, +{5889, 2145, 5441}, +{5969, 1873, 5505}, +{5969, 1713, 5537}, +{5649, 1713, 5777}, +{5713, 1521, 5793}, +{5793, 1489, 5857}, +{5729, 1345, 5841}, +{5841, 1681, 5857}, +{5777, 2097, 5617}, +{5729, 2193, 5537}, +{5905, 2353, 5777}, +{5697, 2273, 5697}, +{5745, 2321, 5569}, +{6129, 2945, 4241}, +{6033, 3089, 4129}, +{6657, 1537, 5345}, +{6529, 2641, 5969}, +{5809, 3153, 5137}, +{6145, 2337, 5281}, +{6385, 1553, 5025}, +{6305, 1041, 5121}, +{6177, 545, 5521}, +{5873, 609, 5777}, +{5697, 657, 6145}, +{5553, 273, 5713}, +{5217, -447, 6545}, +{5393, 273, 6129}, +{5873, 257, 5713}, +{5985, 385, 5905}, +{5841, 369, 5953}, +{5889, 529, 5905}, +{5681, 385, 5985}, +{5921, 913, 5793}, +{6033, 961, 5937}, +{5969, 801, 5649}, +{6001, 1297, 5873}, +{6017, 1409, 5937}, +{6001, 1121, 5809}, +{5953, 817, 5697}, +{6289, 1057, 5217}, +{6017, 1409, 5329}, +{6385, 929, 5297}, +{6049, -895, 5729}, +{5953, -479, 5569}, +{6529, 273, 5713}, +{6273, 17, 5185}, +{5889, -63, 4353}, +{5713, -207, 5537}, +{6257, 17, 5009}, +{5505, -527, 7665}, +{5073, -911, 6673}, +{5777, -303, 5825}, +{6065, 17, 5569}, +{5905, 401, 6081}, +{6193, 1281, 5761}, +{6049, 321, 5233}, +{5953, 1505, 5569}, +{5745, 1345, 5537}, +{6193, 769, 5937}, +{6193, 1233, 5569}, +{6129, 1457, 5457}, +{6337, 1681, 5457}, +{5777, 529, 5009}, +{5825, 2161, 5953}, +{5841, 2865, 6417}, +{6609, 2657, 5665}, +{6017, 2913, 4353}, +{6081, 3281, 4401}, +{5873, 3713, 5025}, +{5969, 1105, 5905}, +{5345, 1089, 6721}, +{5137, 977, 6129}, +{5441, 961, 6433}, +{5649, 257, 5585}, +{5905, -111, 5489}, +{6001, 1969, 6001}, +{5873, 1633, 5681}, +{6145, 1377, 5121}, +{6513, 1841, 4337}, +{6305, 3121, 5169}, +{6465, 2529, 4977}, +{6465, 2625, 4801}, +{6769, 2305, 4593}, +{6657, 1521, 4945}, +{6241, 1601, 4817}, +{6065, 1073, 5665}, +{5937, 1265, 5617}, +{6033, 1169, 5729}, +{5969, 1185, 5777}, +{5841, 929, 6049}, +{5585, 1169, 6177}, +{5809, 801, 5985}, +{5585, 337, 5953}, +{5441, -495, 6193}, +{5233, -223, 6209}, +{5329, -463, 6321}, +{5297, -351, 6113}, +{5569, -367, 6049}, +{5697, 113, 6097}, +{5889, 273, 5857}, +{6097, 849, 5569}, +{6097, 673, 5649}, +{6097, 1377, 5473}, +{6113, 993, 5521}, +{6065, 753, 5633}, +{5921, 993, 5841}, +{5825, 1137, 5921}, +{6129, 945, 5617}, +{6161, 1233, 5425}, +{6001, 1233, 5553}, +{5873, 881, 5841}, +{5825, 1297, 5825}, +{5649, 1329, 5985}, +{5649, 1761, 5937}, +{5569, 1233, 6049}, +{5489, 689, 6081}, +{5761, 945, 6017}, +{5793, 753, 5809}, +{5649, 561, 5857}, +{5761, 513, 5937}, +{5665, 817, 5953}, +{5889, 929, 5937}, +{5841, 1217, 5681}, +{5761, 977, 5761}, +{5745, 1393, 5809}, +{5825, 1217, 5809}, +{6097, 2081, 5521}, +{6097, 1681, 5457}, +{6001, 1585, 5537}, +{6177, 1793, 5345}, +{6241, 1841, 5297}, +{6257, 1601, 5329}, +{6289, 1345, 5409}, +{6017, 1121, 5505}, +{5873, 1009, 5633}, +{5857, 1025, 5665}, +{5489, 753, 6305}, +{5521, 273, 6113}, +{5633, 673, 6113}, +{5681, 769, 5985}, +{5729, 465, 6017}, +{5873, 545, 5857}, +{5777, 257, 5889}, +{5889, 833, 5857}, +{6065, 449, 5921}, +{5761, 577, 5953}, +{5809, 1105, 5729}, +{5633, 1393, 5937}, +{5889, 1601, 5649}, +{5953, 1649, 5441}, +{5985, 705, 5585}, +{5873, 1009, 5457}, +{6401, 1713, 5281}, +{6225, 2081, 5361}, +{6177, 2337, 5409}, +{6065, 2001, 5521}, +{6033, 1985, 5457}, +{5937, 1457, 5585}, +{5841, 1201, 5665}, +{5649, 1521, 5745}, +{5665, 1393, 5937}, +{5745, 1633, 5905}, +{5761, 865, 5761}, +{5953, 721, 5729}, +{5681, 545, 5857}, +{5521, 721, 6129}, +{5569, 529, 6225}, +{5617, 817, 5953}, +{5649, 1233, 5985}, +{5473, 945, 5905}, +{5825, 945, 5777}, +{5969, 1569, 5745}, +{6161, 2353, 5185}, +{6161, 2721, 4977}, +{6321, 2577, 5057}, +{6033, 2433, 5249}, +{6225, 2865, 4929}, +{6225, 2465, 5105}, +{6289, 2273, 5185}, +{6081, 2417, 5265}, +{6209, 2257, 5121}, +{6129, 2225, 5233}, +{5921, 1521, 5697}, +{5921, 1681, 5761}, +{5889, 1505, 5553}, +{5681, 1329, 6049}, +{5745, 1281, 6017}, +{5793, 1425, 5745}, +{5761, 1201, 5761}, +{5809, 961, 5825}, +{5905, 721, 5793}, +{5857, 1009, 5665}, +{5841, 593, 5889}, +{5889, 1681, 5809}, +{5921, 1377, 5665}, +{6033, 1441, 5361}, +{6017, 1601, 5425}, +{5825, 2225, 5633}, +{6241, 2321, 4865}, +{6465, 2273, 4929}, +{6257, 2529, 5057}, +{6193, 2673, 5009}, +{6225, 2625, 4833}, +{6289, 2129, 5217}, +{6097, 2209, 5297}, +{6113, 2065, 5345}, +{5905, 2353, 5393}, +{5969, 2177, 5505}, +{5857, 1697, 5633}, +{5697, 1729, 5809}, +{5633, 1793, 5841}, +{5601, 1569, 5953}, +{5665, 1681, 5969}, +{5681, 961, 6113}, +{5665, 1105, 6001}, +{5953, 1377, 5601}, +{5921, 577, 5825}, +{5713, 865, 5921}, +{6017, 1393, 5585}, +{6033, 1473, 5457}, +{6065, 1409, 5345}, +{6225, 1425, 5297}, +{6241, 1873, 5201}, +{6321, 1841, 5105}, +{5921, 2257, 4737}, +{5761, 2705, 5601}, +{5969, 2497, 5169}, +{6177, 2081, 5217}, +{6193, 2129, 5265}, +{6033, 2417, 5489}, +{5969, 1937, 5425}, +{6225, 1697, 5457}, +{6609, 977, 5185}, +{6305, -415, 5361}, +{6417, 913, 5313}, +{6209, -31, 5393}, +{6193, -511, 5569}, +{6337, -511, 5249}, +{6289, -207, 5073}, +{5729, -927, 6177}, +{5729, -991, 5985}, +{6017, -687, 5681}, +{6145, -367, 5377}, +{6273, -207, 5409}, +{6033, -575, 5633}, +{6193, -543, 5553}, +{6305, -271, 5521}, +{6273, -255, 5441}, +{6353, -335, 5681}, +{6321, 497, 5089}, +{6193, 705, 5425}, +{6369, 209, 5553}, +{6417, 337, 5265}, +{6577, 225, 5201}, +{6497, 1, 4689}, +{6497, -95, 5649}, +{6465, -735, 5345}, +{6849, 273, 5105}, +{6657, 97, 5153}, +{6385, 433, 5057}, +{6161, -63, 5681}, +{5393, 209, 4881}, +{5313, -591, 6641}, +{3681, -639, 5713}, +{5585, -2383, 7441}, +{5409, -447, 6241}, +{5313, -927, 6321}, +{5265, -399, 6369}, +{5601, -367, 6177}, +{5729, -287, 6113}, +{5809, -223, 5825}, +{5937, 561, 5457}, +{5793, 561, 5521}, +{6257, -383, 6001}, +{5793, 865, 5825}, +{6113, 881, 5857}, +{5969, 1265, 5377}, +{6017, 593, 5809}, +{5969, 593, 5745}, +{6049, 641, 5889}, +{5921, 1089, 5473}, +{5809, 609, 5569}, +{5745, 353, 5585}, +{5745, 369, 6257}, +{5713, -95, 6225}, +{5857, 385, 6129}, +{5281, 673, 5793}, +{5633, -559, 6401}, +{4961, -511, 6097}, +{5073, -783, 6145}, +{5185, -415, 6913}, +{4961, 241, 6401}, +{5281, 913, 6273}, +{5761, 657, 5569}, +{6081, 401, 5201}, +{5777, 2481, 5729}, +{6385, 753, 5537}, +{6145, 1569, 5265}, +{6465, 2049, 4929}, +{6161, 2017, 5169}, +{6417, 1953, 4961}, +{6241, 1553, 5297}, +{6097, 1617, 5617}, +{5937, 1953, 5345}, +{6193, 1649, 5425}, +{6177, 929, 5169}, +{6017, 945, 5441}, +{5985, 977, 5809}, +{5505, 609, 6385}, +{5265, 545, 6497}, +{5185, 385, 6753}, +{5665, 737, 5985}, +{5633, 225, 5617}, +{5761, 625, 5665}, +{5889, 1297, 5873}, +{6001, 1665, 5697}, +{6113, 1249, 5409}, +{6129, 1825, 4961}, +{6353, 2305, 5025}, +{6401, 2593, 5025}, +{6305, 2673, 4881}, +{6081, 2929, 4865}, +{6209, 2385, 5297}, +{6193, 2881, 5633}, +{6465, 2769, 6145}, +{5969, 4161, 6209}, +{6961, 1489, 2113}, +{6289, 2673, 5569}, +{6177, 1729, 5345}, +{6049, 1729, 5393}, +{6145, 1761, 5585}, +{6081, 785, 5649}, +{6113, 577, 5889}, +{5761, 177, 5617}, +{5329, 65, 5681}, +{5297, 1, 6305}, +{5825, -831, 5505}, +{6049, -623, 5201}, +{5649, 113, 5761}, +{5553, 321, 5713}, +{5665, 449, 6065}, +{5857, 1073, 6081}, +{6641, 673, 4961}, +{6545, 1073, 5345}, +{6177, 977, 5393}, +{6129, 1297, 5457}, +{6129, 817, 5649}, +{6081, 961, 5409}, +{5921, 1137, 5745}, +{5793, 993, 5921}, +{5873, 1073, 6001}, +{5873, 801, 5969}, +{6145, 1169, 5569}, +{6225, 1313, 5409}, +{6257, 897, 5457}, +{5617, -687, 5841}, +{5425, -191, 6225}, +{5489, -287, 6353}, +{5393, -703, 6241}, +{5569, -191, 5953}, +{5841, -751, 5617}, +{5185, -2287, 5969}, +{1905, -2751, 6785}, +{2049, -1903, 6993}, +{3505, -639, 7633}, +{4641, -1295, 7649}, +{4049, -2447, 7313}, +{4337, -1791, 7617}, +{6001, -319, 5953}, +{5857, -47, 5873}, +{5393, -863, 5153}, +{6001, -223, 5121}, +{5905, 577, 6161}, +{5825, -463, 5713}, +{5809, -15, 5633}, +{5761, -591, 5537}, +{5633, -207, 5841}, +{5649, -367, 6177}, +{6065, 225, 5569}, +{6113, 17, 5393}, +{6145, -287, 5473}, +{5713, 929, 5697}, +{4785, -319, 5921}, +{4465, -1951, 6753}, +{4705, -3103, 6465}, +{4465, -655, 7633}, +{4449, -927, 7297}, +{5009, -751, 6833}, +{5249, -1103, 5777}, +{5473, -1679, 5633}, +{5825, -543, 5953}, +{5777, 289, 6097}, +{5649, 625, 6129}, +{5985, 257, 5697}, +{6161, 385, 5313}, +{6161, 865, 5537}, +{6065, 1505, 5825}, +{6321, 257, 6177}, +{6209, 529, 5137}, +{6273, 513, 5009}, +{5969, 401, 5921}, +{5713, -95, 6321}, +{6801, 1729, 4705}, +{6241, 529, 5185}, +{6209, 257, 5729}, +{6145, 609, 5489}, +{6049, -335, 6113}, +{5921, -735, 5745}, +{6081, 657, 5921}, +{6321, -15, 5505}, +{6241, -735, 5105}, +{6097, 385, 5489}, +{6145, 1025, 5553}, +{6049, 1681, 5537}, +{5937, 353, 5729}, +{5745, 1585, 5841}, +{5841, 1825, 5857}, +{6017, 1409, 5553}, +{6769, 1313, 5329}, +{6097, 1889, 5633}, +{6225, 2129, 5313}, +{6177, 1361, 5233}, +{5777, 2433, 5313}, +{6129, 1729, 5857}, +{5825, 881, 5713}, +{5713, 625, 5713}, +{5601, 1265, 5889}, +{5665, 1105, 6145}, +{5585, 1009, 5985}, +{5681, 689, 6001}, +{5649, 1233, 6065}, +{5585, 273, 5905}, +{5425, 209, 5585}, +{6129, 225, 5537}, +{6513, 2369, 5921}, +{6737, 1025, 5681}, +{6065, 753, 5073}, +{6289, 1089, 4865}, +{6241, 1649, 5409}, +{6305, 641, 5377}, +{6209, 769, 5249}, +{6257, 1681, 5521}, +{6353, 1425, 5345}, +{6321, 1137, 5089}, +{6289, 881, 5105}, +{6737, 769, 5265}, +{6449, 1025, 5153}, +{6289, 401, 5153}, +{6449, 385, 5361}, +{6497, 481, 5217}, +{6577, 353, 5105}, +{6385, 257, 5361}, +{6289, 273, 5361}, +{6257, -143, 5441}, +{5825, -159, 6385}, +{4881, -303, 5505}, +{5425, -751, 7169}, +{5681, 273, 6961}, +{5585, 1, 5921}, +{6017, 65, 6017}, +{6145, 337, 5457}, +{6305, 1137, 5025}, +{6545, 1441, 4641}, +{5457, 305, 5025}, +{6209, -671, 6689}, +{6161, 849, 5825}, +{6081, 625, 5169}, +{5985, 65, 5457}, +{5569, 529, 6017}, +{5265, 321, 5953}, +{5441, 577, 6433}, +{5857, 289, 6017}, +{5697, 145, 5873}, +{5745, 1105, 5313}, +{6097, 1153, 5489}, +{5601, 481, 5921}, +{5409, 49, 6193}, +{4769, 241, 5921}, +{4273, 177, 6833}, +{5377, -47, 7265}, +{5521, -15, 6481}, +{5729, -703, 5889}, +{5905, -31, 5761}, +{5889, 577, 5585}, +{5905, 1297, 5137}, +{5777, 1537, 6305}, +{5441, 449, 6625}, +{5473, -319, 6465}, +{6193, 369, 5617}, +{6273, 881, 5393}, +{6321, 849, 5249}, +{6065, 737, 5329}, +{6177, 1025, 5649}, +{6113, 1617, 5617}, +{6065, 1217, 5329}, +{5489, -175, 6049}, +{5329, -303, 6193}, +{5521, -207, 6033}, +{5249, 161, 6161}, +{5169, -31, 6449}, +{4737, -207, 6241}, +{3729, -1407, 7473}, +{4369, -2463, 7729}, +{4305, -1775, 7345}, +{4353, -927, 6881}, +{4737, -1407, 6753}, +{4993, -863, 6001}, +{5409, -687, 5761}, +{6081, -367, 5905}, +{5585, 321, 5857}, +{5681, -671, 6225}, +{5569, 209, 5937}, +{5457, 49, 6321}, +{5281, -415, 6497}, +{5297, -255, 6545}, +{5425, -271, 6209}, +{5857, 417, 6225}, +{5809, 593, 5937}, +{5841, 497, 5697}, +{5809, 497, 5457}, +{5953, 481, 5601}, +{3889, 801, 5921}, +{5169, -1583, 6929}, +{3889, -1455, 7249}, +{3985, -1807, 7249}, +{3009, -2479, 7825}, +{2897, -1279, 8353}, +{2881, -1055, 7969}, +{3105, -1487, 7441}, +{3217, -1679, 7345}, +{3745, -1407, 7761}, +{6561, -1135, 2257}, +{6993, -3679, 1905}, +{5217, -1023, 6945}, +{5137, 305, 7137}, +{5857, -783, 5553}, +{5649, -1103, 6305}, +{5633, 337, 6561}, +{5745, -1407, 5617}, +{5873, -367, 5569}, +{6369, -831, 4913}, +{5521, -2015, 5217}, +{4833, -2847, 5409}, +{4097, -2559, 6817}, +{3985, -2479, 7025}, +{3185, -2911, 6673}, +{2817, -2991, 6817}, +{1153, -3359, 8033}, +{993, -2863, 8273}, +{1441, -3311, 7473}, +{1425, -3263, 7617}, +{2129, -2959, 7409}, +{3361, -2879, 6721}, +{3825, -2575, 6641}, +{4513, -2463, 5921}, +{4689, -1967, 6321}, +{4737, -2111, 6209}, +{5345, -239, 6385}, +{5633, -239, 5665}, +{4737, -1215, 5361}, +{4657, -911, 6305}, +{3633, -1695, 7025}, +{4625, -1263, 7345}, +{4593, -1823, 6865}, +{4689, -1711, 6001}, +{4641, -2159, 5793}, +{4465, -2095, 5953}, +{3905, -2191, 6785}, +{3841, -1519, 6817}, +{3457, -2031, 6833}, +{2833, -2735, 7345}, +{2641, -1535, 8193}, +{3057, -1583, 7873}, +{3249, -1871, 7537}, +{3345, -1487, 7473}, +{4321, -735, 6945}, +{4417, -1471, 6609}, +{4401, -2175, 6273}, +{5793, -1391, 5489}, +{5457, -975, 6033}, +{5537, -767, 6417}, +{5857, -591, 5985}, +{5729, -383, 6033}, +{5553, -799, 5921}, +{5553, -15, 6273}, +{5505, 369, 5761}, +{6033, -143, 5345}, +{5985, -879, 4481}, +{5857, -367, 5585}, +{5905, -399, 5985}, +{5873, 1, 5857}, +{5953, -223, 5985}, +{5825, 657, 5857}, +{5665, -207, 6193}, +{5361, -399, 6209}, +{5345, -623, 6257}, +{5121, -1263, 6273}, +{5553, -991, 6129}, +{5985, -767, 5601}, +{5841, -175, 5889}, +{6177, 449, 5729}, +{6433, 97, 5121}, +{6337, 481, 5409}, +{6641, 1649, 5057}, +{6481, 337, 5265}, +{6289, 817, 5297}, +{6673, 369, 4881}, +{6561, 513, 4961}, +{7025, 1121, 4209}, +{6129, -3407, 3809}, +{6641, -767, 8721}, +{5169, -1807, 7265}, +{2689, -2703, 6801}, +{1649, -735, 8769}, +{2625, -3599, 4865}, +{4945, -5679, 4913}, +{5457, -3967, 5233}, +{5489, -6543, 3473}, +{3105, -5199, 4049}, +{3169, -6127, 5345}, +{3521, -5727, 4833}, +{3841, -5087, 5105}, +{3889, -5663, 5169}, +{3793, -5695, 5089}, +{4161, -4959, 4625}, +{3825, -4015, 4609}, +{4529, -4527, 5665}, +{4769, -4879, 6209}, +{4529, -4191, 4817}, +{4545, -4095, 5409}, +{4657, -4111, 5233}, +{4849, -4255, 5601}, +{4913, -4431, 5585}, +{4833, -4287, 5345}, +{4897, -4879, 5793}, +{4673, -3903, 5649}, +{5521, -4511, 5537}, +{5201, -4943, 5217}, +{5601, -5439, 5953}, +{2977, -3487, 3777}, +{2609, -3775, 4929}, +{641, -1983, 6865}, +{-207, -3631, 3857}, +{-719, -543, 481}, +{13217, -4719, 12625}, +{4305, 1057, 11297}, +{6593, -655, 4145}, +{7249, 1937, 5025}, +{6513, 737, 4961}, +{6305, 1521, 4417}, +{6193, 689, 5585}, +{6289, 1057, 5121}, +{6193, 1489, 5393}, +{6273, 2081, 4977}, +{6257, 1265, 4849}, +{6433, 1201, 5041}, +{6529, 945, 5201}, +{6673, 1505, 4897}, +{6801, 881, 5233}, +{6753, 1121, 5073}, +{6561, 529, 4897}, +{6161, 145, 5441}, +{6209, 65, 5473}, +{6257, -175, 5313}, +{6225, -31, 5313}, +{6241, -623, 5569}, +{6353, -399, 5505}, +{6481, -703, 5169}, +{6545, -111, 4945}, +{6529, 353, 5057}, +{6401, 17, 5409}, +{6609, 353, 5169}, +{6545, 273, 5041}, +{6593, 593, 4945}, +{6641, 993, 4817}, +{6689, 481, 5073}, +{6689, 721, 5041}, +{6737, 625, 4929}, +{6545, 673, 4865}, +{6801, 625, 4849}, +{6833, 529, 4673}, +{6545, 241, 5073}, +{6481, 161, 5217}, +{6449, 65, 5313}, +{6369, 209, 5185}, +{6481, 209, 5153}, +{6497, 81, 5297}, +{6641, 321, 5201}, +{6689, 513, 4897}, +{6657, 753, 4881}, +{6737, 753, 5009}, +{6753, 849, 4977}, +{6513, 1025, 5025}, +{6449, 1281, 5185}, +{6385, 1137, 5249}, +{6465, 1441, 5025}, +{6385, 1265, 5009}, +{6625, 625, 5201}, +{6801, 929, 5009}, +{6625, 1009, 5057}, +{6593, 577, 4929}, +{6369, 369, 5425}, +{6273, -15, 5569}, +{6241, -111, 5441}, +{6305, 225, 5217}, +{6305, 81, 5249}, +{6193, -255, 5473}, +{6513, -399, 5265}, +{6145, -351, 5345}, +{6353, 225, 5409}, +{6417, 257, 5281}, +{6561, 241, 5169}, +{6369, 353, 5185}, +{6433, 481, 5345}, +{6513, 801, 5009}, +{6513, 721, 5105}, +{6449, 641, 5201}, +{6513, 801, 5025}, +{6673, 1041, 4865}, +{6737, 225, 5089}, +{6497, 33, 5089}, +{6497, 417, 5281}, +{6337, 113, 5249}, +{6385, -15, 5329}, +{6353, 33, 5105}, +{6321, -191, 5281}, +{6225, -511, 5537}, +{6401, -287, 5281}, +{5953, 177, 5425}, +{7201, 273, 4849}, +{6305, -447, 5473}, +{6545, 817, 5553}, +{6113, 1009, 5297}, +{6705, 833, 5329}, +{6561, 1761, 4881}, +{6657, 1793, 4913}, +{6417, 1281, 4993}, +{6641, 1281, 4945}, +{6929, 1409, 4785}, +{6817, 1457, 4673}, +{6561, 1649, 4577}, +{6465, 865, 5473}, +{6161, 1329, 5425}, +{6081, 1153, 5793}, +{6241, 833, 6241}, +{5697, 1329, 6065}, +{5745, 2593, 5169}, +{6353, 1969, 4721}, +{6289, 1409, 4929}, +{5969, 1841, 4817}, +{6385, 2433, 4913}, +{6305, 1857, 5505}, +{6305, 1793, 5217}, +{6401, 2257, 4705}, +{6449, 2321, 5089}, +{6321, 2273, 5249}, +{6561, 2209, 5249}, +{6401, 2161, 5729}, +{6161, 1601, 4945}, +{6273, 1921, 4641}, +{6257, 1585, 4241}, +{6097, 1409, 5217}, +{5953, 1425, 4993}, +{5905, 1505, 5889}, +{5905, 1697, 6305}, +{5745, 1761, 5745}, +{6273, 1329, 5297}, +{6529, 945, 5105}, +{5985, 1921, 5313}, +{6049, 2065, 5553}, +{6001, 1697, 5905}, +{6033, 1457, 5569}, +{6193, 1697, 5377}, +{6305, 2001, 5137}, +{6065, 1617, 5617}, +{6113, 1921, 5441}, +{6225, 1665, 5361}, +{6177, 1649, 5281}, +{6001, 1841, 5409}, +{6225, 1905, 5409}, +{6257, 1521, 5553}, +{6257, 1121, 5249}, +{6193, 1041, 5441}, +{6065, 1649, 5585}, +{6065, 1777, 5313}, +{6225, 1441, 5217}, +{6257, 1489, 5329}, +{6225, 1489, 5361}, +{6081, 2209, 5265}, +{6161, 2033, 5265}, +{6385, 2017, 5265}, +{6385, 1937, 4977}, +{6497, 2305, 4929}, +{6305, 1921, 5249}, +{6273, 1953, 5137}, +{6305, 1857, 5185}, +{6241, 1985, 5073}, +{6273, 1857, 5217}, +{6161, 1521, 5361}, +{5921, 1857, 5617}, +{6001, 1809, 5553}, +{6065, 1457, 5361}, +{6145, 1681, 5281}, +{5969, 1185, 5553}, +{5985, 1297, 5825}, +{6049, 1633, 5457}, +{6225, 1681, 5169}, +{6097, 1521, 5313}, +{5937, 1985, 5377}, +{5985, 2081, 5777}, +{6065, 1841, 5457}, +{6161, 2193, 5249}, +{6209, 2321, 5137}, +{6257, 2337, 5009}, +{6129, 2033, 5249}, +{6337, 2433, 5313}, +{6289, 2577, 5249}, +{6289, 2033, 5073}, +{6257, 1649, 5089}, +{5921, 2385, 5457}, +{5793, 1633, 5953}, +{6129, 1393, 5393}, +{6273, 1585, 5425}, +{5873, 1969, 5617}, +{6017, 1569, 5489}, +{6161, 1825, 5441}, +{6033, 1537, 5585}, +{5969, 1857, 5441}, +{5761, 2177, 5617}, +{6033, 2113, 5521}, +{5985, 2017, 5281}, +{6193, 2257, 5185}, +{6225, 2401, 5217}, +{6065, 2033, 5457}, +{6129, 2001, 5441}, +{6305, 2497, 5121}, +{6241, 2305, 5057}, +{6209, 1441, 5153}, +{5905, 1889, 5505}, +{5729, 1697, 5889}, +{6065, 1585, 5505}, +{5905, 1617, 5633}, +{5937, 1937, 5617}, +{5905, 1889, 5569}, +{6129, 1569, 5505}, +{6193, 1361, 5345}, +{6193, 1873, 5249}, +{6145, 2129, 5137}, +{6337, 2129, 5249}, +{6065, 1761, 5633}, +{6081, 2081, 5265}, +{5921, 2113, 5441}, +{5793, 2305, 5585}, +{6081, 2113, 5265}, +{6369, 2673, 6081}, +{6081, 2449, 4961}, +{6129, 1313, 5297}, +{5761, 1441, 5665}, +{6465, 1265, 5681}, +{6001, 625, 5377}, +{6097, 1089, 5537}, +{6065, 945, 5441}, +{6289, 129, 5361}, +{6481, 257, 5553}, +{6273, 577, 5217}, +{6289, 1505, 5281}, +{6273, 801, 5489}, +{6049, 977, 5553}, +{6161, 1297, 5409}, +{6449, 1553, 5201}, +{6353, 1393, 5425}, +{6433, 1521, 5313}, +{6385, 849, 5137}, +{6641, 1537, 4961}, +{6481, 993, 5073}, +{6289, 1009, 5249}, +{6097, 945, 5521}, +{6273, 545, 5329}, +{6033, 641, 5393}, +{6001, 801, 5697}, +{5809, 449, 6017}, +{6385, 465, 4849}, +{6513, 1041, 4737}, +{6625, 2129, 4785}, +{6721, 1473, 4881}, +{6625, 1265, 4833}, +{6545, 1873, 4753}, +{6801, 2145, 4593}, +{6625, 1697, 4929}, +{6449, 1489, 4801}, +{6481, 1393, 5329}, +{6673, 1265, 4961}, +{6641, 993, 4961}, +{6417, 1505, 4993}, +{6081, 785, 5393}, +{6017, 977, 5617}, +{6033, 769, 5633}, +{6401, 1057, 5409}, +{6257, 705, 5489}, +{6369, 689, 5361}, +{6385, 993, 5201}, +{6353, 1825, 4817}, +{6385, 1921, 4945}, +{6433, 1585, 5201}, +{6449, 1809, 4721}, +{6705, 2065, 4641}, +{6593, 2289, 4881}, +{6385, 1985, 4833}, +{6369, 1777, 5057}, +{6449, 1489, 5185}, +{6337, 1889, 5089}, +{6321, 1281, 5521}, +{5713, 1345, 5745}, +{6225, 1105, 5649}, +{6097, 1361, 5281}, +{6001, 1441, 5601}, +{5985, 2081, 5537}, +{6129, 1505, 5377}, +{5905, 1937, 5201}, +{5873, 993, 5633}, +{5905, 2161, 5457}, +{6417, 2305, 5169}, +{6529, 2177, 4465}, +{6641, 2641, 4161}, +{6353, 2673, 4897}, +{6305, 2849, 4929}, +{6401, 2593, 4929}, +{6353, 2193, 5153}, +{6513, 1521, 5489}, +{6353, 2049, 5313}, +{6129, 2161, 4833}, +{6001, 1425, 5201}, +{6273, 1201, 5185}, +{6289, 1361, 5345}, +{5873, 1233, 5681}, +{5889, 1153, 5873}, +{5857, 1361, 5665}, +{6881, 1873, 4801}, +{6593, 1825, 4993}, +{6273, 1585, 5105}, +{6497, 1713, 5137}, +{6273, 2161, 4945}, +{6513, 2001, 4961}, +{6369, 2049, 5057}, +{6257, 1985, 5153}, +{6289, 2017, 5137}, +{6417, 2177, 4993}, +{6369, 1489, 5153}, +{6257, 1457, 5265}, +{6193, 1681, 5233}, +{6145, 1649, 5457}, +{6001, 1585, 5393}, +{6129, 993, 5457}, +{6017, 1601, 5329}, +{5953, 1889, 5489}, +{6305, 1201, 5377}, +{6561, 1153, 5105}, +{6481, 1921, 4993}, +{6017, 2081, 5345}, +{6001, 1521, 5937}, +{5649, 2017, 6561}, +{5633, 2145, 5969}, +{6129, 2401, 4961}, +{6561, 1745, 4721}, +{5985, 1825, 5681}, +{6113, 2289, 5521}, +{6385, 1873, 5361}, +{6177, 1809, 5249}, +{6081, 1889, 5281}, +{6081, 1617, 5345}, +{6129, 1377, 5569}, +{6129, 1217, 5441}, +{5985, 1265, 5489}, +{6065, 1793, 5489}, +{6273, 1329, 5409}, +{6465, 1521, 5249}, +{6337, 1601, 5169}, +{6225, 1745, 5121}, +{6177, 1665, 5553}, +{5889, 2065, 5569}, +{6081, 1921, 5409}, +{6193, 2241, 5025}, +{6241, 2097, 5185}, +{5937, 2257, 5361}, +{6369, 1601, 5409}, +{6129, 2017, 5041}, +{6417, 1329, 5169}, +{5969, 1233, 5393}, +{5985, 1617, 6049}, +{6273, 1345, 5265}, +{6369, 1137, 5105}, +{5969, 1553, 5489}, +{6257, 1265, 5553}, +{5985, 1249, 5905}, +{6065, 1697, 5185}, +{6305, 2033, 4897}, +{6481, 1825, 5121}, +{6321, 1697, 5377}, +{6353, 1713, 5041}, +{6065, 2593, 5137}, +{6241, 1985, 5425}, +{6481, 2529, 4721}, +{6577, 1937, 4881}, +{6465, 1569, 5153}, +{6273, 1729, 5329}, +{6081, 2033, 5281}, +{6305, 1681, 5281}, +{6161, 1377, 5073}, +{5937, 1585, 5169}, +{5825, 2369, 6225}, +{6225, 1473, 5169}, +{6433, 1889, 4833}, +{6353, 1745, 4849}, +{6321, 2321, 4737}, +{6129, 2449, 5153}, +{6257, 2177, 4929}, +{6241, 2417, 4769}, +{6273, 2417, 5249}, +{6305, 2257, 5313}, +{6353, 1921, 5009}, +{6225, 2241, 5137}, +{6145, 1969, 5265}, +{6161, 2129, 5105}, +{6369, 2001, 5137}, +{6337, 1681, 5009}, +{6145, 1905, 5169}, +{6177, 2209, 5249}, +{6129, 1697, 5489}, +{6241, 1921, 5009}, +{6545, 1793, 4769}, +{6321, 2241, 5313}, +{6161, 2081, 5505}, +{6209, 2241, 5153}, +{6289, 2209, 4865}, +{6209, 2545, 5041}, +{6289, 2113, 5329}, +{6257, 2305, 5185}, +{6465, 2225, 5041}, +{6273, 1873, 5137}, +{6145, 1681, 5185}, +{6081, 1937, 5537}, +{6113, 1697, 5377}, +{6097, 1521, 5249}, +{6097, 1713, 5345}, +{5953, 1889, 5537}, +{6337, 1489, 5329}, +{6049, 1601, 5457}, +{6289, 1761, 5265}, +{6193, 2081, 5089}, +{6289, 2177, 5041}, +{6177, 2001, 5121}, +{6289, 1953, 5057}, +{6257, 2241, 5073}, +{6225, 2225, 5137}, +{6161, 2129, 5233}, +{6353, 1857, 4993}, +{6257, 1745, 5057}, +{6705, 1265, 6097}, +{5425, 2721, 5409}, +{6577, 1441, 4993}, +{6033, 1745, 5329}, +{6129, 1905, 5585}, +{5969, 1473, 5649}, +{6177, 1473, 5633}, +{6241, 865, 5201}, +{6321, 1121, 5153}, +{6609, 1345, 4865}, +{6353, 1057, 5297}, +{6305, 785, 5457}, +{6401, 1169, 5281}, +{6465, 1281, 4961}, +{6529, 1169, 4737}, +{6769, 1729, 4593}, +{7169, 1121, 4865}, +{6721, 1217, 4737}, +{6737, 897, 4865}, +{6497, 417, 5233}, +{6529, 609, 5025}, +{6625, 289, 5009}, +{6513, 369, 4977}, +{6129, 209, 5217}, +{6273, 177, 5377}, +{6481, 49, 5185}, +{6401, 353, 4993}, +{6833, 1057, 4833}, +{6593, 1953, 4625}, +{6289, 801, 4849}, +{6737, 897, 5473}, +{6257, 1665, 4833}, +{6577, 1921, 4881}, +{6465, 913, 5457}, +{6737, 689, 5121}, +{6513, 897, 4945}, +{6305, 1489, 5121}, +{6241, 1393, 5585}, +{6241, 513, 5569}, +{6241, 801, 5377}, +{6241, 1393, 5553}, +{6097, 977, 5553}, +{6177, 449, 5585}, +{6385, 1089, 5329}, +{6449, 1793, 4705}, +{6369, 2257, 4945}, +{6849, 1457, 5489}, +{6465, 1697, 4689}, +{6801, 2001, 4769}, +{6529, 2113, 4849}, +{6593, 1713, 4913}, +{6385, 1265, 5105}, +{6481, 1329, 5585}, +{5905, 1409, 5361}, +{6321, 1633, 5313}, +{6209, 689, 5473}, +{6113, 401, 5713}, +{6049, 1265, 5473}, +{5969, 1409, 5553}, +{6033, 1601, 5633}, +{6289, 1409, 5105}, +{6417, 1569, 4865}, +{6385, 1793, 5073}, +{6225, 2177, 5185}, +{6257, 1665, 5281}, +{6529, 1921, 4801}, +{6369, 2241, 5009}, +{6449, 1953, 5249}, +{6321, 2273, 5009}, +{6305, 2257, 4945}, +{6321, 1585, 5201}, +{6273, 1393, 5153}, +{6097, 1649, 5361}, +{6049, 1793, 5489}, +{6161, 1057, 5489}, +{6033, 1057, 5569}, +{5905, 1313, 5745}, +{6145, 1281, 5553}, +{6257, 1073, 5329}, +{6257, 2017, 5169}, +{6081, 2097, 5393}, +{6129, 1665, 5729}, +{6145, 1665, 5537}, +{6241, 2177, 5009}, +{6305, 2129, 5025}, +{6097, 2273, 5281}, +{6129, 2609, 5249}, +{6513, 1521, 5137}, +{6433, 1937, 4881}, +{6305, 1297, 5169}, +{6097, 1473, 5329}, +{5985, 1473, 5809}, +{6113, 1553, 5185}, +{6257, 1265, 5041}, +{6033, 1713, 5345}, +{6065, 1569, 5553}, +{6433, 1345, 5217}, +{6209, 2161, 4993}, +{6257, 2657, 4945}, +{6129, 2609, 5153}, +{5969, 2625, 5329}, +{6033, 2529, 4961}, +{6081, 3169, 4945}, +{6369, 2657, 4961}, +{6465, 2497, 4833}, +{6289, 1665, 5153}, +{6081, 1473, 5329}, +{5905, 2081, 5425}, +{5857, 1889, 5729}, +{6033, 1825, 5537}, +{6161, 1729, 5233}, +{6065, 1745, 5617}, +{6049, 1553, 5809}, +{6273, 2017, 5009}, +{6401, 1585, 5041}, +{6129, 1969, 5105}, +{6081, 2161, 5729}, +{6209, 2385, 5185}, +{6353, 1857, 4993}, +{6241, 2225, 4881}, +{6065, 2033, 5425}, +{6097, 2401, 5489}, +{6193, 1937, 5265}, +{6193, 1185, 5281}, +{5953, 2017, 5233}, +{6065, 1633, 5537}, +{6065, 1873, 5473}, +{6081, 1569, 5473}, +{6177, 1649, 5473}, +{6177, 1569, 5457}, +{6209, 1265, 5457}, +{6225, 1201, 5345}, +{6193, 1921, 5041}, +{6273, 2161, 5601}, +{6353, 1857, 5297}, +{6433, 1425, 4993}, +{6321, 1873, 4849}, +{6161, 2657, 5201}, +{6273, 2033, 5505}, +{6241, 1825, 5569}, +{6193, 913, 5025}, +{6097, 673, 4977}, +{6545, 1761, 5729}, +{6065, -111, 5601}, +{5969, 881, 5473}, +{6161, 1409, 5121}, +{5889, 737, 5585}, +{6097, 1713, 5057}, +{6561, 1377, 4449}, +{6673, 1697, 5313}, +{6433, 2689, 5345}, +{6401, 2049, 4737}, +{6081, 1777, 5153}, +{5969, 1793, 5969}, +{6081, 1553, 5745}, +{6081, 2049, 5201}, +{6257, 1313, 5201}, +{6433, 1297, 4801}, +{6337, 1009, 5249}, +{6081, 1121, 5601}, +{5713, 289, 6017}, +{5793, 417, 6113}, +{5729, 737, 6209}, +{6385, 913, 5345}, +{6049, 1121, 5457}, +{6177, 1553, 5153}, +{6321, 1713, 5217}, +{6113, 1921, 5665}, +{6177, 1489, 5185}, +{6225, 1825, 4993}, +{6241, 2097, 5265}, +{6369, 2241, 5201}, +{6369, 2289, 5009}, +{6385, 1761, 5409}, +{6289, 2049, 4977}, +{6129, 1553, 4657}, +{5905, 609, 5697}, +{5713, 785, 5905}, +{6193, 1073, 5553}, +{5761, 1233, 5873}, +{6129, 737, 5697}, +{6321, 1297, 5089}, +{6561, 1297, 4865}, +{6337, 1825, 5649}, +{6161, 1793, 5489}, +{6177, 1585, 5217}, +{6113, 1729, 5217}, +{6353, 2465, 5041}, +{6353, 2513, 4929}, +{6193, 1729, 5345}, +{6161, 1633, 5217}, +{6097, 1473, 5345}, +{6081, 2129, 5377}, +{6145, 2001, 5281}, +{5825, 1473, 5457}, +{6241, 1393, 5265}, +{6241, 1937, 5073}, +{6225, 1425, 5585}, +{6273, 1873, 5281}, +{6369, 1761, 5025}, +{6289, 1793, 5281}, +{5937, 1809, 5537}, +{5905, 2433, 5617}, +{6209, 2001, 5297}, +{6097, 1953, 5425}, +{6017, 2305, 5441}, +{6257, 2385, 5297}, +{5921, 1713, 5505}, +{6081, 1937, 5505}, +{6001, 2193, 5457}, +{5745, 2177, 5777}, +{5505, 993, 5393}, +{5089, 2737, 6161}, +{6737, 1953, 5041}, +{6753, 465, 5457}, +{6209, 961, 4657}, +{6849, 1057, 4817}, +{6641, 2289, 4801}, +{6593, 1617, 4785}, +{6401, 673, 5585}, +{6641, 1841, 4769}, +{6593, 1585, 4625}, +{6625, 1249, 4929}, +{6561, 1329, 5169}, +{6609, 1233, 4609}, +{6609, 1393, 4785}, +{6657, 833, 4913}, +{6241, 721, 5505}, +{6561, 593, 5473}, +{6561, 625, 4961}, +{6241, 897, 5313}, +{6481, 513, 5537}, +{6353, 369, 5313}, +{6257, 497, 5153}, +{6529, 1297, 4849}, +{6673, 1153, 5041}, +{6465, 801, 5393}, +{6609, 1057, 4961}, +{6641, 1473, 4977}, +{6241, 2113, 4657}, +{6257, 1873, 4977}, +{6689, 1121, 5185}, +{6673, 1249, 4769}, +{6641, 1393, 4849}, +{6497, 849, 5137}, +{6401, 977, 5505}, +{6289, 1249, 5457}, +{6305, 1185, 5249}, +{6081, 1633, 5457}, +{6161, 1361, 5569}, +{6353, 1633, 5009}, +{6545, 1601, 4961}, +{6337, 2081, 4865}, +{6401, 1601, 5169}, +{6385, 1569, 5185}, +{6577, 2737, 4769}, +{6321, 2001, 5009}, +{6321, 2529, 4897}, +{6337, 2161, 5121}, +{6305, 1937, 5233}, +{6193, 1409, 5393}, +{5665, 1777, 5585}, +{5889, 1457, 5857}, +{6097, 1505, 5489}, +{6065, 1585, 5425}, +{5953, 1697, 5473}, +{5921, 1361, 5777}, +{6049, 1569, 5377}, +{6369, 2049, 4929}, +{6561, 1985, 4977}, +{6001, 2481, 5185}, +{6145, 2065, 5217}, +{6273, 2161, 4881}, +{6177, 2305, 5137}, +{6177, 2465, 5409}, +{6193, 2433, 5345}, +{6337, 1985, 5057}, +{6065, 1745, 5265}, +{5873, 1665, 5649}, +{5649, 2049, 5905}, +{6209, 1761, 5233}, +{6145, 1297, 5249}, +{5921, 1601, 5617}, +{6081, 1873, 5729}, +{6257, 1825, 5137}, +{6385, 1857, 4801}, +{6033, 2545, 5537}, +{6257, 2465, 5377}, +{6289, 2033, 5137}, +{6465, 1905, 4833}, +{6593, 2353, 4737}, +{6289, 2289, 4961}, +{6353, 2273, 4785}, +{6417, 1537, 5137}, +{6257, 1617, 5137}, +{6209, 1345, 5393}, +{6001, 1697, 5249}, +{6241, 1505, 5377}, +{6001, 1281, 5425}, +{6017, 1137, 5537}, +{5793, 1377, 5921}, +{5777, 1185, 6001}, +{6257, 1409, 5169}, +{6273, 1793, 5201}, +{5889, 1873, 5521}, +{5809, 2161, 5425}, +{5921, 2065, 5409}, +{6097, 1841, 4993}, +{6305, 1761, 5473}, +{6209, 1857, 5649}, +{6449, 1393, 5217}, +{6209, 1121, 5361}, +{6273, 1041, 5361}, +{6065, 1633, 5345}, +{6321, 1297, 5777}, +{6353, 705, 5521}, +{6081, 865, 5297}, +{6017, 1009, 5649}, +{6081, 1025, 5569}, +{6289, 545, 5537}, +{6209, 1105, 5153}, +{6449, 1217, 5233}, +{6273, 1521, 5233}, +{6465, 1105, 5233}, +{6497, 1137, 4945}, +{6401, 1457, 5041}, +{6529, 1713, 5329}, +{6353, 1137, 5409}, +{6561, 1553, 5041}, +{6481, 1377, 5009}, +{6481, 1297, 5073}, +{6449, 721, 5345}, +{6305, 881, 5393}, +{6065, 369, 5649}, +{5761, 529, 5825}, +{5777, 721, 6129}, +{5585, 1217, 6081}, +{6449, 961, 5361}, +{6337, 993, 5137}, +{6305, 1329, 5201}, +{6209, 2113, 5057}, +{6353, 1793, 5361}, +{6721, 1297, 5393}, +{6497, 1841, 4817}, +{6177, 2193, 5073}, +{6225, 2017, 5377}, +{6145, 2049, 5473}, +{6497, 1505, 5105}, +{6001, 2225, 4817}, +{6273, 1649, 5217}, +{5969, 1921, 5569}, +{6161, 1521, 5457}, +{6193, 1249, 5393}, +{6033, 1169, 5649}, +{5921, 1537, 5665}, +{6129, 1409, 5585}, +{6113, 1633, 5297}, +{6273, 1457, 5121}, +{6289, 2049, 5281}, +{6145, 1969, 5569}, +{6161, 1761, 5249}, +{6273, 1761, 5009}, +{6465, 2273, 5025}, +{6433, 2081, 4961}, +{6449, 1793, 5153}, +{6449, 1905, 5201}, +{6481, 1905, 5009}, +{6385, 1761, 4817}, +{6401, 1473, 4977}, +{6081, 1713, 5217}, +{6113, 1505, 5217}, +{6145, 1489, 5201}, +{6129, 1457, 5425}, +{6113, 1761, 5585}, +{6321, 1521, 5169}, +{6561, 1537, 5025}, +{6417, 1777, 4945}, +{6193, 2289, 5153}, +{6273, 1761, 5345}, +{6001, 2017, 5185}, +{6465, 2305, 4977}, +{6321, 2401, 4865}, +{6433, 1777, 5185}, +{6353, 1633, 5281}, +{6497, 2289, 5425}, +{6337, 1473, 5217}, +{6337, 1649, 5041}, +{6161, 2097, 5441}, +{6017, 1905, 5425}, +{6209, 1569, 5249}, +{6193, 1425, 5217}, +{5937, 1713, 5313}, +{5889, 1953, 5777}, +{6113, 1457, 5985}, +{6433, 1697, 5137}, +{6337, 2241, 5137}, +{6097, 2289, 5089}, +{6161, 1633, 5521}, +{6257, 1889, 5185}, +{6353, 2161, 4929}, +{6305, 1969, 5249}, +{6305, 2033, 5281}, +{6353, 2225, 5137}, +{6401, 1841, 5041}, +{6401, 1569, 5169}, +{6097, 1889, 5377}, +{6001, 1697, 5361}, +{6033, 1713, 5217}, +{6113, 1425, 5505}, +{6017, 1649, 5649}, +{6177, 1441, 5409}, +{6481, 1425, 5153}, +{6385, 1761, 4961}, +{6081, 1953, 5217}, +{5777, 2097, 5553}, +{6609, 961, 5761}, +{6353, 2017, 4769}, +{6449, 2225, 5057}, +{6385, 1505, 5537}, +{6081, 1969, 5281}, +{6161, 497, 5553}, +{6449, 1121, 5329}, +{6177, 897, 5313}, +{6129, 753, 4929}, +{6273, -79, 5425}, +{6129, 305, 5505}, +{6033, -127, 5633}, +{6049, -223, 5777}, +{6289, 273, 5617}, +{6305, 113, 5377}, +{6433, 657, 5121}, +{6353, 209, 5361}, +{6209, 65, 5793}, +{6241, 593, 5345}, +{6561, 753, 5153}, +{6433, 673, 5233}, +{6705, 737, 5329}, +{6465, -335, 5345}, +{6161, 257, 4945}, +{6369, 145, 5073}, +{6225, 337, 5793}, +{5969, -463, 5697}, +{6065, 49, 5505}, +{6657, -847, 6177}, +{5777, 497, 5233}, +{6401, 545, 5649}, +{6449, 1057, 5137}, +{6561, 993, 5073}, +{6481, 1537, 4817}, +{6881, 1137, 4993}, +{6321, 1537, 5121}, +{6433, 1729, 4929}, +{6561, 1297, 5457}, +{6449, 1217, 5265}, +{6177, 1921, 5121}, +{6305, 1633, 5201}, +{6017, 1217, 5185}, +{6353, 785, 5441}, +{6321, 737, 5489}, +{6129, 977, 5201}, +{6193, 1329, 5137}, +{6257, 801, 5825}, +{6177, 1169, 5377}, +{6801, 1361, 4753}, +{6769, 1777, 4657}, +{6257, 2305, 4625}, +{6417, 1889, 4545}, +{6641, 1937, 4865}, +{6545, 2193, 5105}, +{6433, 2065, 5185}, +{6769, 1937, 5105}, +{6577, 1761, 5393}, +{6241, 2337, 5105}, +{6257, 1825, 5201}, +{6017, 1681, 5153}, +{5921, 1009, 5425}, +{5985, 1121, 5457}, +{5825, 1185, 5489}, +{6113, 1105, 5777}, +{6193, 1457, 5537}, +{6337, 1697, 4625}, +{6321, 1985, 4721}, +{6657, 2465, 5585}, +{6433, 2241, 4833}, +{6561, 2577, 4401}, +{6481, 2577, 4545}, +{6289, 2673, 4897}, +{6401, 2193, 5169}, +{6385, 2257, 5169}, +{6145, 2241, 4881}, +{5905, 1889, 5409}, +{5905, 1329, 5601}, +{6257, 1537, 5345}, +{6081, 1281, 5217}, +{6065, 1361, 5265}, +{5841, 1345, 5489}, +{5681, 1409, 5761}, +{6353, 1601, 5121}, +{6449, 1761, 5265}, +{6353, 1985, 5233}, +{6273, 2129, 5297}, +{6273, 1985, 5233}, +{6161, 1969, 4961}, +{6129, 2209, 5201}, +{6129, 2161, 5249}, +{6097, 2241, 5233}, +{6129, 2465, 5217}, +{6193, 1905, 5361}, +{6097, 1697, 5249}, +{6017, 1585, 5521}, +{5697, 1697, 5761}, +{5729, 1793, 5969}, +{5761, 1729, 5521}, +{5857, 1521, 6097}, +{5873, 2017, 6033}, +{5985, 1809, 5537}, +{6081, 1985, 5313}, +{6049, 2241, 5617}, +{5937, 3393, 6065}, +{6241, 3681, 4721}, +{6481, 3569, 4673}, +{6577, 3521, 4433}, +{6145, 2881, 3889}, +{6257, 2817, 5201}, +{6337, 2769, 5777}, +{6289, 2577, 5777}, +{6177, 1985, 5793}, +{5969, 2529, 4321}, +{5921, 1649, 4865}, +{6033, 1825, 5089}, +{6033, 1537, 5681}, +{6161, 929, 5841}, +{6001, 1041, 4945}, +{6385, 1201, 5153}, +{5889, 1441, 5393}, +{6113, 1633, 5297}, +{6129, 1457, 5313}, +{6001, 2145, 5537}, +{6161, 1809, 6065}, +{6161, 1745, 5105}, +{6481, 1969, 5073}, +{6481, 2113, 5073}, +{6209, 1953, 5393}, +{6113, 1889, 5601}, +{6273, 2033, 5073}, +{6177, 1681, 5201}, +{6033, 1649, 5489}, +{6001, 2145, 5297}, +{5809, 1505, 5329}, +{5713, 1249, 5873}, +{5921, 1249, 5905}, +{5745, 1057, 6049}, +{5873, 1377, 5729}, +{6289, 1089, 5265}, +{5953, 1713, 5377}, +{5793, 1425, 5953}, +{5985, 1169, 5681}, +{6049, 1185, 5489}, +{6305, 1713, 4945}, +{6225, 1905, 5681}, +{6161, 1457, 5665}, +{6177, 1233, 5409}, +{6369, 1153, 5169}, +{6097, 1345, 5345}, +{6017, 1073, 5921}, +{5841, 1201, 5729}, +{6081, 1105, 5377}, +{5969, 1217, 5729}, +{5809, 1185, 5921}, +{5857, 929, 5697}, +{6065, 2097, 5249}, +{6033, 2033, 5281}, +{6001, 2449, 5441}, +{6193, 1681, 5441}, +{6177, 1937, 5201}, +{6049, 1969, 5393}, +{6033, 1713, 5729}, +{6001, 2209, 5361}, +{6161, 1649, 5345}, +{6097, 1361, 5505}, +{5729, 1361, 5745}, +{5793, 1857, 5777}, +{6033, 1217, 5745}, +{5889, 1233, 5553}, +{5969, 1169, 5553}, +{6017, 1185, 5617}, +{5985, 1265, 5681}, +{6001, 1233, 5569}, +{6033, 1137, 5473}, +{5985, 2033, 5313}, +{5969, 1537, 5569}, +{6145, 1473, 5233}, +{6209, 1713, 5201}, +{6033, 1985, 5537}, +{6097, 1777, 5649}, +{6209, 1489, 5457}, +{6033, 1217, 5489}, +{6065, 1569, 5505}, +{6081, 1713, 5457}, +{6209, 1425, 5441}, +{6209, 945, 5393}, +{6145, 1169, 5489}, +{5937, 1569, 5569}, +{6145, 1441, 5569}, +{6225, 1569, 5265}, +{6353, 1441, 5025}, +{6209, 1937, 5521}, +{6177, 1873, 5569}, +{6145, 1953, 5137}, +{6337, 2145, 4897}, +{6337, 2081, 5137}, +{6225, 1857, 5345}, +{6321, 2017, 5281}, +{6209, 1633, 5249}, +{6113, 1745, 5377}, +{6177, 1809, 5297}, +{5905, 1169, 5617}, +{5825, 1505, 5665}, +{6001, 1601, 5617}, +{6033, 1969, 5505}, +{6113, 1153, 5585}, +{6257, 1793, 5041}, +{6225, 1617, 5137}, +{5937, 2689, 5121}, +{5521, 1345, 6049}, +{6609, 1329, 5889}, +{6577, 1729, 5457}, +{5617, 2225, 5537}, +{6753, 1521, 5489}, +{6433, 1073, 5569}, +{6497, 1617, 4961}, +{6097, 1329, 4785}, +{6049, 481, 5857}, +{6017, -79, 5521}, +{6161, 689, 5313}, +{6401, 81, 5393}, +{6241, 65, 5617}, +{6417, 353, 5441}, +{6321, 305, 5169}, +{6433, 577, 5057}, +{6241, 593, 5361}, +{6225, 465, 5569}, +{6241, 497, 5377}, +{6129, 497, 5553}, +{6177, 241, 5617}, +{6353, 1185, 5489}, +{6545, 209, 5537}, +{6289, -255, 5313}, +{6241, -191, 5409}, +{5889, -79, 6145}, +{6385, -143, 5441}, +{6273, 161, 5441}, +{6209, 257, 5393}, +{5873, -271, 6049}, +{6353, -367, 5585}, +{6385, 33, 5633}, +{6513, 1329, 4961}, +{6465, 1105, 4993}, +{6545, 993, 5105}, +{6369, 737, 5233}, +{6513, 1889, 5233}, +{6209, 1505, 5297}, +{6529, 817, 5377}, +{6625, 1009, 5441}, +{6433, 1105, 4881}, +{6273, 1569, 4689}, +{6817, 1761, 5137}, +{5905, 849, 5489}, +{6241, 1505, 5233}, +{6081, 1921, 5345}, +{6257, 1089, 5857}, +{5969, 401, 5617}, +{5921, 1249, 5361}, +{6209, 2145, 5041}, +{6337, 1825, 5521}, +{6177, 1489, 5665}, +{6113, 1425, 5313}, +{6289, 2289, 4817}, +{6177, 1233, 5521}, +{6081, 1921, 5425}, +{6417, 913, 5665}, +{6145, 1073, 5345}, +{6049, 1313, 5329}, +{5697, 1089, 6209}, +{5777, 1073, 5969}, +{5825, 849, 5697}, +{5985, 1345, 5649}, +{5729, 1505, 5729}, +{5905, 1185, 5841}, +{5937, 1185, 5585}, +{5809, 1297, 5505}, +{5681, 1761, 5745}, +{5969, 1569, 5777}, +{5937, 1393, 5649}, +{6225, 1729, 5281}, +{6241, 1697, 5281}, +{5953, 1505, 5633}, +{6049, 1905, 5585}, +{6273, 1409, 5345}, +{6257, 1073, 5473}, +{5905, 609, 5505}, +{5729, 497, 5665}, +{5665, 561, 6145}, +{5713, 257, 5793}, +{5409, 113, 6145}, +{5345, 913, 6401}, +{5825, 753, 5921}, +{6225, 961, 5585}, +{6241, 481, 5361}, +{5569, 593, 6065}, +{6049, 225, 6273}, +{5713, 673, 6321}, +{5825, 721, 5793}, +{5969, 977, 5441}, +{5889, 881, 5841}, +{5857, 849, 6017}, +{5985, 497, 5809}, +{5729, 865, 5873}, +{5841, 1089, 5745}, +{5649, 657, 6241}, +{5617, 401, 6081}, +{5569, 497, 6033}, +{5617, 481, 5905}, +{5537, 513, 6337}, +{5745, 449, 5969}, +{5873, 641, 5713}, +{6001, 785, 5473}, +{6001, 1265, 5601}, +{5969, 1041, 5809}, +{5969, 753, 5601}, +{5921, 1297, 5505}, +{5841, 1441, 5713}, +{5937, 1409, 5905}, +{5873, 1297, 5857}, +{6065, 1361, 5537}, +{6081, 1041, 5473}, +{5777, 1121, 5825}, +{5809, 865, 6161}, +{5681, 865, 5953}, +{5761, 529, 5873}, +{5681, 1041, 6337}, +{5665, 705, 6241}, +{5745, 657, 5969}, +{6001, 929, 5457}, +{6001, 1153, 5457}, +{6033, 1521, 5569}, +{5985, 817, 5713}, +{6017, 1329, 5377}, +{6161, 1809, 5361}, +{6049, 1633, 5569}, +{6001, 1345, 5601}, +{5953, 1313, 5633}, +{6049, 1473, 5569}, +{6001, 1105, 5569}, +{5617, 833, 5793}, +{5889, 961, 5905}, +{5953, 881, 5633}, +{5889, 673, 5617}, +{5793, 753, 5809}, +{5809, 1073, 5969}, +{6177, 1137, 5425}, +{6209, 1009, 5361}, +{6049, 1025, 5473}, +{6081, 1297, 5617}, +{5889, 977, 5809}, +{6033, 1281, 5505}, +{5953, 1505, 5489}, +{6097, 1793, 5793}, +{6001, 1457, 5825}, +{6049, 1521, 5537}, +{5985, 1281, 5473}, +{5745, 1009, 5841}, +{5521, 945, 6417}, +{6049, 1441, 5633}, +{5921, 1185, 5425}, +{5809, 1265, 5633}, +{5633, 1329, 6337}, +{5697, 1265, 5985}, +{6097, 1105, 5537}, +{6081, 1441, 5233}, +{5921, 2161, 5425}, +{6049, 1537, 5857}, +{6033, 1521, 5601}, +{6113, 1537, 5217}, +{6097, 1985, 5233}, +{6049, 1809, 5585}, +{6257, 1425, 5425}, +{6033, 1377, 5377}, +{6225, 1553, 5297}, +{5921, 1057, 5649}, +{5681, 1393, 6097}, +{5825, 913, 5713}, +{5985, 1025, 5489}, +{5761, 625, 5889}, +{5617, 849, 6305}, +{5857, 593, 6161}, +{5937, 977, 5457}, +{5985, 1489, 5393}, +{6065, 1425, 5553}, +{5937, 1217, 5985}, +{5969, 977, 5665}, +{6081, 1665, 5329}, +{6113, 1537, 5489}, +{5841, 1537, 5921}, +{6129, 1537, 5617}, +{5985, 657, 5681}, +{5825, 657, 5745}, +{5665, 1089, 5857}, +{5889, 1137, 6001}, +{5713, 657, 6033}, +{5793, 929, 5809}, +{5681, 769, 5921}, +{5697, 1025, 6273}, +{5809, 1601, 5665}, +{6129, 913, 5457}, +{5921, 657, 5489}, +{5713, 1921, 5585}, +{5825, 1489, 5889}, +{5825, 1249, 5585}, +{5841, 1361, 5521}, +{5921, 1521, 5921}, +{5825, 1905, 5825}, +{5953, 769, 5713}, +{6049, 1217, 5489}, +{5857, 881, 5553}, +{5921, 1393, 5713}, +{5793, 1153, 6049}, +{5905, 881, 5601}, +{5825, 737, 5761}, +{5681, 1105, 6065}, +{5649, 833, 6273}, +{5729, 961, 6033}, +{5953, 753, 5521}, +{5985, 1057, 5553}, +{5729, 2177, 5569}, +{6305, 433, 6561}, +{6273, 1345, 5137}, +{6257, 1361, 5345}, +{5905, 1249, 5505}, +{6209, 1009, 5393}, +{6033, 1361, 5265}, +{6401, 369, 5697}, +{6769, 1217, 4529}, +{6801, 1089, 4561}, +{6433, 865, 4481}, +{6449, 369, 5265}, +{6257, 81, 5457}, +{6321, 497, 5377}, +{6305, 81, 5521}, +{6545, 177, 5153}, +{6577, 97, 5025}, +{6609, 513, 4817}, +{6721, 865, 4929}, +{6609, 705, 5121}, +{6353, 241, 5345}, +{6241, 465, 5345}, +{6369, 1217, 5249}, +{6321, 945, 5265}, +{6593, 497, 5281}, +{6529, 737, 5089}, +{6897, 369, 5201}, +{6417, 1121, 4561}, +{6833, 161, 4833}, +{6337, -79, 5425}, +{6545, 49, 5137}, +{6369, 305, 5137}, +{6369, 1, 5681}, +{5857, 897, 5345}, +{6225, 657, 5809}, +{6385, 1041, 5233}, +{6689, 1137, 5281}, +{6497, 1569, 4881}, +{6337, 2225, 4497}, +{6081, 1377, 5089}, +{6609, 1633, 4721}, +{6465, 2017, 4641}, +{6593, 2065, 5073}, +{6481, 1313, 5217}, +{6465, 1265, 5585}, +{6465, 1505, 5313}, +{6353, 1905, 5489}, +{6385, 1729, 5777}, +{6257, 2145, 5921}, +{5409, 1489, 4737}, +{5121, -463, 6465}, +{5505, 801, 6209}, +{5265, 1137, 6385}, +{5729, 577, 5969}, +{5873, 321, 5777}, +{5761, 1553, 5569}, +{5857, 1697, 5793}, +{5889, 1073, 6385}, +{5841, 1409, 5969}, +{6049, 1249, 5441}, +{6209, 929, 5201}, +{6017, 545, 5729}, +{6001, 1441, 5937}, +{6209, 1073, 5681}, +{6161, 1153, 5585}, +{5889, 881, 5489}, +{5729, 833, 5825}, +{5777, 673, 6193}, +{5585, 817, 5953}, +{5425, 369, 6193}, +{5585, 481, 6193}, +{5793, 737, 5969}, +{6209, 1105, 5345}, +{6209, 1185, 5249}, +{6113, 1745, 5457}, +{5873, 1889, 5889}, +{5825, 1313, 5985}, +{5777, 1329, 5729}, +{5841, 1425, 5617}, +{5777, 2225, 5713}, +{5905, 2385, 5793}, +{5937, 1345, 5777}, +{5729, 1409, 5681}, +{5745, 1233, 5761}, +{5537, 1441, 5921}, +{5473, 1537, 6017}, +{5553, 929, 5921}, +{5585, 849, 6017}, +{5585, 1057, 6017}, +{5473, 673, 6401}, +{5537, 881, 5985}, +{6145, 1121, 5569}, +{5953, 1793, 5521}, +{6001, 1537, 5809}, +{5889, 1457, 5777}, +{6017, 1377, 5617}, +{5905, 1905, 5489}, +{5953, 1793, 5601}, +{6049, 1489, 5569}, +{5969, 1569, 5809}, +{5905, 1137, 5633}, +{5713, 1313, 5809}, +{5569, 1649, 6081}, +{5793, 929, 5985}, +{5681, 769, 5857}, +{5681, 961, 5793}, +{5729, 1345, 6001}, +{5617, 561, 6225}, +{5601, 849, 6049}, +{5921, 1233, 5569}, +{5857, 1649, 5569}, +{6017, 1713, 5601}, +{5889, 769, 5889}, +{5777, 1121, 5729}, +{5937, 1761, 5553}, +{5889, 1473, 5633}, +{5857, 1361, 5985}, +{6033, 1617, 5713}, +{6257, 1601, 5521}, +{6225, 1185, 5249}, +{6161, 1105, 5153}, +{6017, 849, 5297}, +{5633, 1169, 5937}, +{6113, 1393, 5473}, +{6257, 401, 5441}, +{5937, 657, 5697}, +{5985, 993, 5777}, +{5969, 1441, 5601}, +{6241, 1073, 5473}, +{5857, 1729, 5489}, +{6017, 1633, 5649}, +{6065, 1681, 5681}, +{6113, 1457, 5281}, +{6193, 1745, 5153}, +{6209, 1825, 5409}, +{6113, 1729, 5585}, +{5937, 1697, 5665}, +{6033, 1105, 5841}, +{6033, 2001, 5537}, +{6145, 1665, 5249}, +{6209, 865, 5297}, +{6017, 1377, 5601}, +{5793, 769, 5889}, +{5697, 1025, 5889}, +{5601, 897, 6081}, +{5617, 1249, 6049}, +{6097, 833, 5697}, +{6193, 1105, 5409}, +{6001, 1313, 5553}, +{6033, 1617, 5521}, +{5985, 1745, 5617}, +{6001, 1409, 5761}, +{6033, 1537, 5441}, +{6129, 1729, 5313}, +{6017, 1665, 5313}, +{5905, 1617, 5953}, +{5825, 1457, 5937}, +{6097, 1585, 5553}, +{5969, 1153, 5665}, +{5857, 1441, 5633}, +{5889, 1169, 5761}, +{5889, 1217, 5873}, +{5889, 881, 5793}, +{5633, 1089, 5985}, +{5649, 961, 6033}, +{5617, 993, 6049}, +{5681, 849, 6065}, +{5745, 1057, 5937}, +{5921, 1185, 5745}, +{5825, 945, 5729}, +{5841, 1249, 5665}, +{5889, 1441, 5681}, +{5905, 1329, 5809}, +{5857, 1249, 5697}, +{5937, 1489, 5665}, +{5809, 1681, 5937}, +{5889, 1873, 5665}, +{5921, 1505, 5697}, +{6065, 1489, 5361}, +{6049, 1265, 5409}, +{6017, 1489, 5489}, +{5937, 1201, 5617}, +{5745, 1265, 5937}, +{5777, 1281, 5873}, +{5937, 1265, 5649}, +{5745, 945, 5969}, +{5777, 929, 5905}, +{5761, 945, 5905}, +{5777, 961, 5793}, +{5921, 561, 5777}, +{5857, 865, 5761}, +{5969, 1201, 5569}, +{5681, 1633, 5777}, +{5681, 1089, 6129}, +{5537, 1377, 6001}, +{5825, 1617, 5777}, +{5697, 1601, 5841}, +{5745, 1441, 5953}, +{5729, 1313, 5985}, +{5921, 1377, 5681}, +{5841, 1521, 5729}, +{5793, 929, 5969}, +{5585, 1601, 5937}, +{5761, 1281, 5921}, +{5697, 945, 5873}, +{5697, 881, 5921}, +{5713, 1073, 5841}, +{5585, 993, 5841}, +{5489, 961, 5985}, +{5889, 785, 6321}, +{5745, 1057, 6145}, +{6529, 1441, 5249}, +{6321, 561, 4401}, +{6497, 913, 5089}, +{6161, 513, 5553}, +{6449, 353, 5233}, +{6401, 417, 5121}, +{6273, 561, 5217}, +{6577, 273, 5249}, +{6465, -335, 5025}, +{6417, 97, 5041}, +{6497, -319, 5185}, +{6209, -559, 5345}, +{6001, -719, 5697}, +{5937, -1039, 6241}, +{5905, -895, 5745}, +{5985, -687, 5425}, +{5985, -1103, 5601}, +{6193, -911, 5393}, +{6257, -943, 5313}, +{6433, -351, 5233}, +{6129, 65, 4865}, +{6369, 49, 5937}, +{6305, -543, 5537}, +{6577, -383, 5345}, +{6785, 737, 5185}, +{6673, 289, 4593}, +{5969, 1313, 4817}, +{7969, 145, 4897}, +{6497, 1393, 5057}, +{6593, -591, 5169}, +{5921, -159, 5201}, +{6113, -367, 5761}, +{6129, 33, 5649}, +{6577, -447, 5361}, +{6177, 769, 5073}, +{6241, 209, 5761}, +{6209, -79, 6321}, +{6305, 209, 5713}, +{6577, 881, 4945}, +{6497, 1489, 4785}, +{6321, 657, 5313}, +{6241, 625, 5601}, +{6529, 929, 5377}, +{6449, 1489, 4977}, +{6193, 1585, 4961}, +{6273, 625, 5825}, +{6257, 1457, 5345}, +{6529, 785, 5249}, +{6289, 913, 4929}, +{6081, 385, 4897}, +{5809, -223, 6113}, +{5889, -271, 6049}, +{5761, -463, 5905}, +{5905, 33, 5793}, +{5921, 17, 5729}, +{5873, -111, 6049}, +{6081, -175, 5777}, +{6065, 65, 5697}, +{6193, 769, 5169}, +{6305, 865, 5121}, +{6337, 337, 5505}, +{6177, 417, 5697}, +{6241, 881, 5297}, +{6065, 1009, 5297}, +{6017, 545, 5745}, +{6193, 257, 5649}, +{6433, 641, 5361}, +{6401, 705, 5265}, +{6161, -399, 5473}, +{6033, 289, 5745}, +{6113, 257, 5553}, +{6161, -175, 5601}, +{6193, -335, 5569}, +{6113, 81, 5361}, +{6113, 465, 5393}, +{6001, 641, 5313}, +{6161, 2049, 6881}, +{6257, 1105, 5473}, +{6129, 1761, 5313}, +{6353, 2529, 5249}, +{6353, 2737, 5377}, +{6545, 2257, 4897}, +{6497, 2497, 5281}, +{6353, 2977, 4929}, +{6353, 2129, 3681}, +{6449, 2593, 4081}, +{6001, 1505, 5937}, +{6353, 1425, 5169}, +{6049, 1665, 5457}, +{5953, 1409, 5489}, +{6017, 977, 5617}, +{5617, 753, 5793}, +{5761, 897, 5713}, +{5825, 577, 5841}, +{5937, 753, 5649}, +{5793, 353, 5425}, +{6001, 225, 6049}, +{6353, 417, 5169}, +{6353, 577, 5521}, +{5921, 913, 5377}, +{6017, 1153, 5025}, +{6193, 1537, 6129}, +{5937, 1393, 5921}, +{5969, 1265, 5553}, +{6081, 1505, 5505}, +{6097, 1729, 5329}, +{6129, 1921, 5729}, +{5937, 1617, 5521}, +{6113, 1665, 5297}, +{6241, 1505, 5297}, +{6273, 1857, 5249}, +{5921, 1185, 5729}, +{5889, 1073, 5905}, +{6145, 1025, 5569}, +{6049, 961, 5457}, +{5889, 1089, 5665}, +{5745, 1057, 5921}, +{5889, 289, 5969}, +{6049, 929, 5585}, +{6129, 1105, 5425}, +{6049, 977, 5569}, +{5873, 1361, 5697}, +{6161, 1393, 5569}, +{6033, 1457, 5473}, +{6241, 1649, 5233}, +{6209, 2001, 5185}, +{6161, 1681, 5345}, +{6097, 1697, 5473}, +{6161, 1777, 5297}, +{6273, 1681, 5297}, +{6225, 1793, 5313}, +{6017, 1553, 5441}, +{5921, 1201, 5745}, +{5889, 1425, 5697}, +{6033, 1073, 5633}, +{5905, 1089, 5489}, +{5921, 897, 5681}, +{5745, 977, 6049}, +{5937, 1265, 5681}, +{6097, 865, 5473}, +{6081, 1217, 5441}, +{5873, 1281, 5713}, +{5889, 1697, 5729}, +{6129, 1585, 5553}, +{6097, 1489, 5425}, +{6097, 1457, 5409}, +{6049, 1633, 5473}, +{6033, 1697, 5569}, +{6129, 1505, 5441}, +{6129, 1537, 5473}, +{6177, 1761, 5345}, +{6193, 1585, 5361}, +{6145, 1393, 5441}, +{5841, 1473, 5697}, +{6065, 1233, 5585}, +{6129, 1073, 5425}, +{6001, 1073, 5553}, +{5969, 1185, 5649}, +{6049, 1089, 5697}, +{6129, 817, 5569}, +{6033, 1201, 5409}, +{6049, 993, 5553}, +{5969, 1361, 5553}, +{6017, 1313, 5633}, +{6225, 1409, 5313}, +{6209, 1217, 5297}, +{6193, 1457, 5329}, +{6193, 1633, 5345}, +{6033, 1505, 5665}, +{6129, 1537, 5441}, +{6145, 1553, 5409}, +{6161, 1473, 5457}, +{6161, 1281, 5553}, +{5969, 1361, 5617}, +{5985, 1281, 5617}, +{6033, 1249, 5553}, +{6001, 1041, 5585}, +{5969, 1137, 5681}, +{5889, 1089, 5825}, +{5921, 1185, 5761}, +{6113, 993, 5649}, +{6129, 1153, 5441}, +{6049, 1121, 5601}, +{6017, 1137, 5601}, +{6081, 1265, 5457}, +{6081, 1265, 5521}, +{6081, 1233, 5601}, +{5937, 1425, 5633}, +{6049, 1361, 5601}, +{6017, 1345, 5665}, +{5969, 1265, 5665}, +{6113, 1697, 5473}, +{6177, 1617, 5425}, +{6129, 1025, 5521}, +{5921, 1121, 5713}, +{5841, 1089, 5825}, +{6033, 1185, 5649}, +{5985, 1105, 5601}, +{5905, 1089, 5729}, +{5857, 737, 5873}, +{5857, 897, 5921}, +{5809, 849, 5809}, +{6129, 1073, 5505}, +{6001, 673, 5569}, +{6113, 1073, 5569}, +{6097, 1281, 5569}, +{6097, 1441, 5457}, +{6113, 1233, 5329}, +{5409, 1953, 5489}, +{6065, 1281, 5969}, +{5905, 1969, 5569}, +{6449, 1313, 4977}, +{6529, 1329, 4401}, +{6657, 945, 5041}, +{6273, 1121, 5473}, +{6369, 417, 5169}, +{6321, 385, 5345}, +{6289, 705, 5185}, +{6433, 417, 5329}, +{6161, 225, 5505}, +{6257, 417, 5121}, +{6657, 177, 4881}, +{6337, 241, 5393}, +{6369, 657, 5457}, +{6609, 849, 5089}, +{6577, 433, 5169}, +{6465, 913, 5169}, +{6641, 865, 4849}, +{6545, 1201, 4897}, +{6401, 945, 5265}, +{6449, 801, 5233}, +{6689, 929, 5025}, +{6625, 1041, 4945}, +{6577, 897, 4929}, +{6385, 417, 5201}, +{6289, 289, 5601}, +{6145, 241, 5521}, +{6193, 609, 5361}, +{6209, 353, 5537}, +{6385, 401, 5585}, +{6673, 609, 5265}, +{6273, 465, 5217}, +{6545, 513, 5105}, +{6369, 1185, 4977}, +{6465, 913, 5121}, +{6433, 753, 5249}, +{6305, 1137, 5265}, +{6321, 1313, 5249}, +{6289, 1313, 5441}, +{6321, 1057, 5393}, +{6257, 993, 5345}, +{6321, 1217, 5169}, +{6401, 817, 5201}, +{6465, 577, 5313}, +{6257, 481, 5537}, +{6401, 769, 5441}, +{6305, 513, 5249}, +{6001, 929, 5441}, +{5969, 849, 5825}, +{5953, 785, 6177}, +{6097, 609, 5777}, +{6097, 1281, 5425}, +{6081, 1489, 5617}, +{6145, 1345, 5553}, +{6289, 1185, 5073}, +{6225, 1313, 5169}, +{6433, 1409, 4961}, +{6113, 1521, 5537}, +{6225, 1265, 5681}, +{6161, 705, 5665}, +{6353, 1041, 5585}, +{5953, 1377, 5521}, +{6097, 1265, 5473}, +{6081, 1265, 5489}, +{5681, 881, 6193}, +{5857, 1521, 5953}, +{6209, 1457, 4977}, +{5969, 1537, 5617}, +{5889, 1313, 5793}, +{6049, 1553, 5937}, +{6065, 1425, 5745}, +{6001, 1681, 5521}, +{5537, 1937, 5777}, +{5889, 1937, 6273}, +{6289, 1329, 5489}, +{6257, 1201, 5057}, +{6241, 1425, 4721}, +{6209, 1937, 4929}, +{6049, 913, 5601}, +{5969, 1201, 5905}, +{6097, 1313, 5681}, +{6097, 1201, 5681}, +{5937, 1169, 5825}, +{5857, 1281, 5857}, +{6097, 1073, 5601}, +{6001, 1009, 5521}, +{5985, 1137, 5713}, +{6033, 1137, 5601}, +{5857, 1217, 5665}, +{5905, 1009, 5889}, +{5969, 1265, 5745}, +{5985, 1313, 5553}, +{6209, 1649, 5313}, +{6049, 1377, 5633}, +{6305, 1505, 5313}, +{6385, 1457, 5105}, +{6289, 1601, 5089}, +{6353, 1729, 5265}, +{6225, 1713, 5457}, +{6289, 1505, 5425}, +{6289, 1617, 5313}, +{6273, 1665, 5233}, +{6081, 1409, 5441}, +{6145, 1553, 5361}, +{5985, 977, 5665}, +{5953, 1169, 5809}, +{5825, 865, 5889}, +{5905, 1073, 5921}, +{5809, 945, 5921}, +{5777, 673, 5857}, +{5873, 897, 5745}, +{5921, 545, 5745}, +{5953, 865, 5761}, +{5985, 1041, 5713}, +{5921, 1025, 5873}, +{5969, 1025, 5745}, +{5969, 849, 5633}, +{5953, 1105, 5569}, +{5969, 1457, 5665}, +{5985, 1393, 5633}, +{6033, 1137, 5713}, +{6097, 961, 5697}, +{6209, 1025, 5329}, +{6113, 641, 5553}, +{6049, 1089, 5649}, +{6001, 753, 5729}, +{5953, 817, 5729}, +{5969, 721, 5777}, +{5825, 1073, 5809}, +{5841, 897, 5905}, +{5873, 1009, 5809}, +{6001, 801, 5713}, +{5937, 865, 5713}, +{5969, 1185, 5633}, +{5921, 1281, 5665}, +{5969, 1521, 5601}, +{6033, 1457, 5681}, +{6001, 1473, 5537}, +{6033, 1569, 5441}, +{5969, 1617, 5537}, +{5969, 1809, 5681}, +{6017, 1585, 5665}, +{6177, 1729, 5409}, +{6145, 1649, 5281}, +{6017, 1841, 5473}, +{5857, 1585, 5569}, +{5761, 1297, 5809}, +{5905, 1585, 5761}, +{5969, 1201, 5729}, +{5825, 1409, 5601}, +{5681, 1313, 5953}, +{5729, 1473, 6097}, +{5857, 1025, 5969}, +{5953, 1185, 5585}, +{5969, 1377, 5537}, +{5985, 1633, 5633}, +{5921, 1457, 5745}, +{5889, 1601, 5729}, +{5873, 1409, 5617}, +{5905, 1777, 5649}, +{5777, 1969, 5681}, +{5905, 1889, 5649}, +{6017, 1873, 5553}, +{5985, 1761, 5617}, +{6033, 1553, 5537}, +{5937, 1521, 5569}, +{5841, 1313, 5681}, +{5841, 1585, 5729}, +{5921, 1265, 5761}, +{5937, 1569, 5329}, +{5953, 1025, 5809}, +{5873, 1553, 5905}, +{5921, 945, 5953}, +{5841, 1249, 5713}, +{5729, 1889, 5521}, +{5857, 2337, 5569}, +{6193, 2129, 5393}, +{5825, 2497, 5473}, +{6113, 1985, 5361}, +{5921, 2097, 5473}, +{5953, 2209, 5537}, +{6193, 1953, 5361}, +{6065, 2113, 5377}, +{6001, 1953, 5441}, +{5905, 1857, 5553}, +{5793, 1873, 5665}, +{5761, 1345, 5729}, +{5777, 865, 5473}, +{5729, 1073, 5649}, +{5553, 1569, 6065}, +{5665, 1169, 6177}, +{5873, 1473, 5425}, +{5985, 1729, 5169}, +{6033, 1809, 5281}, +{5617, 1745, 6097}, +{5793, 1841, 5441}, +{5777, 2081, 5185}, +{5793, 1905, 5809}, +{5457, 1841, 5905}, +{5617, 1569, 6129}, +{5809, 1633, 5921}, +{5889, 1889, 5729}, +{5873, 1553, 5537}, +{5793, 1217, 5457}, +{5713, 1265, 6241}, +{5777, 1201, 5857}, +{5745, 1153, 5761}, +{5841, 1041, 5873}, +{6049, 1025, 5665}, +{6257, 945, 5665}, +{6065, 849, 5281}, +{6321, 1089, 5185}, +{6369, 1505, 5169}, +{6401, 977, 5425}, +{6097, 913, 5681}, +{6289, 1105, 5345}, +{6449, 1441, 5201}, +{6305, 1137, 5121}, +{6465, 1329, 5073}, +{6369, 897, 5393}, +{6497, 1073, 5249}, +{6433, 1121, 4929}, +{6241, 1121, 5281}, +{6193, 641, 5569}, +{6177, 433, 5553}, +{6113, 513, 5393}, +{6161, 705, 5457}, +{6273, 289, 5649}, +{6193, 337, 5665}, +{6401, 577, 5329}, +{6561, 385, 5217}, +{6305, 1121, 4929}, +{6065, 2193, 5425}, +{6769, -47, 5345}, +{6449, 1889, 5041}, +{6417, 1409, 5345}, +{6177, 1521, 5281}, +{6001, 1873, 5393}, +{6417, 1249, 5057}, +{6225, 945, 4929}, +{6241, 1041, 4945}, +{5969, 1601, 5329}, +{5665, 1889, 6081}, +{5649, 2417, 6609}, +{5745, 1361, 5585}, +{5985, 1441, 5473}, +{5953, 2289, 5537}, +{5985, 1393, 5377}, +{5921, 2081, 5441}, +{5905, 2241, 5601}, +{5985, 1921, 5489}, +{6097, 1969, 5249}, +{6081, 2161, 5169}, +{6097, 2065, 5329}, +{6097, 2241, 5585}, +{6097, 2241, 5393}, +{6065, 1809, 5409}, +{5969, 1633, 5377}, +{5937, 1745, 5537}, +{5953, 1985, 5601}, +{5921, 1793, 5553}, +{5889, 1729, 5569}, +{5793, 1809, 5937}, +{5841, 1793, 5873}, +{6129, 1665, 5505}, +{6241, 1361, 5361}, +{6049, 2081, 5105}, +{5937, 2273, 5249}, +{6033, 2161, 5633}, +{5921, 2017, 5905}, +{5889, 2033, 5713}, +{6001, 2097, 5217}, +{5825, 2337, 5553}, +{5953, 2129, 5633}, +{6017, 2065, 5409}, +{6017, 1777, 5457}, +{6065, 2273, 5297}, +{5889, 1873, 5537}, +{5809, 1825, 5713}, +{5745, 1425, 5841}, +{5777, 1777, 5745}, +{5889, 1265, 5585}, +{5809, 1681, 5777}, +{5873, 1553, 5777}, +{6033, 1505, 5665}, +{6065, 1393, 5489}, +{5953, 2017, 5329}, +{6129, 1553, 5553}, +{6065, 1185, 5521}, +{6049, 1297, 5489}, +{6017, 1585, 5377}, +{6033, 1889, 5329}, +{5953, 1921, 5537}, +{6113, 1681, 5473}, +{6177, 1825, 5297}, +{6113, 1697, 5329}, +{5985, 1505, 5425}, +{5937, 1457, 5649}, +{5857, 1425, 5921}, +{5825, 1185, 5681}, +{5809, 1377, 5745}, +{5713, 1393, 5873}, +{5745, 1217, 6049}, +{5825, 1281, 5777}, +{5937, 1169, 5649}, +{5905, 1185, 5585}, +{5873, 1345, 5665}, +{5857, 1377, 5713}, +{5873, 1633, 5873}, +{5889, 1473, 5745}, +{5841, 1249, 5601}, +{5873, 1729, 5617}, +{5793, 1761, 5633}, +{5777, 1441, 5969}, +{5873, 1681, 5713}, +{5985, 1665, 5505}, +{5969, 1601, 5617}, +{5873, 1537, 5617}, +{5857, 1297, 5841}, +{5761, 1313, 5969}, +{6017, 1377, 5409}, +{5953, 1265, 5473}, +{5889, 1329, 5537}, +{5873, 1265, 5809}, +{5953, 1169, 5697}, +{6049, 1249, 5489}, +{6113, 1361, 5441}, +{6065, 1601, 5441}, +{5873, 1585, 5553}, +{5809, 1617, 5761}, +{5841, 1857, 5665}, +{5873, 1793, 5489}, +{5969, 1809, 5505}, +{5857, 1873, 5633}, +{5969, 2225, 5409}, +{6017, 1617, 5537}, +{6049, 1697, 5521}, +{5953, 1505, 5553}, +{5905, 1761, 5489}, +{6001, 1601, 5825}, +{5905, 1393, 5553}, +{5921, 1441, 5505}, +{5777, 1265, 5633}, +{5681, 1681, 5889}, +{5985, 1521, 5617}, +{6065, 1169, 5441}, +{5969, 1425, 5473}, +{5841, 1521, 5649}, +{5777, 1857, 5809}, +{5793, 1745, 5953}, +{5825, 1745, 5553}, +{5841, 1841, 5553}, +{5889, 2017, 5569}, +{5793, 1873, 5681}, +{5937, 1889, 5729}, +{5921, 1985, 5505}, +{6017, 1921, 5441}, +{5905, 1649, 5681}, +{5905, 1585, 5697}, +{5937, 1761, 5569}, +{6097, 1409, 5265}, +{6017, 1377, 5441}, +{5905, 1377, 5649}, +{5793, 1665, 5921}, +{6001, 1521, 5649}, +{6065, 1473, 5361}, +{6033, 1313, 5521}, +{5873, 1777, 5697}, +{5841, 1649, 5857}, +{5761, 1569, 6001}, +{5841, 1793, 5409}, +{5777, 1729, 5537}, +{5809, 1713, 5713}, +{5713, 1905, 5777}, +{5761, 1681, 5969}, +{5889, 1937, 5569}, +{5857, 1713, 5553}, +{5777, 1521, 5761}, +{5745, 1457, 5857}, +{5745, 1777, 5745}, +{5825, 1393, 5777}, +{5825, 1377, 5777}, +{5825, 1345, 5761}, +{5745, 1681, 5841}, +{5697, 1361, 5841}, +{5761, 1377, 5905}, +{5937, 1409, 5633}, +{5873, 1617, 5601}, +{5745, 1857, 5521}, +{5793, 1793, 5601}, +{5793, 1969, 5889}, +{5857, 2049, 5489}, +{5889, 2161, 5377}, +{5873, 2385, 5409}, +{5873, 2193, 5585}, +{5793, 2001, 5681}, +{5985, 2401, 5297}, +{6001, 2289, 5377}, +{5873, 2289, 5409}, +{5857, 1729, 5617}, +{5825, 2017, 5601}, +{5889, 1761, 5569}, +{5841, 1713, 5521}, +{5793, 1601, 5601}, +{5825, 1873, 5793}, +{5841, 1521, 5857}, +{5921, 1441, 5633}, +{5905, 1793, 5601}, +{5809, 1745, 5713}, +{5809, 1793, 5713}, +{5905, 1761, 5745}, +{5921, 1745, 5473}, +{5713, 1745, 5425}, +{5793, 2129, 5585}, +{6689, 897, 6161}, +{6065, 2913, 5681}, +{6097, 1521, 5537}, +{6097, 1761, 5457}, +{6273, 1153, 5441}, +{6273, 1521, 5361}, +{6257, 1889, 5137}, +{6033, 1329, 5009}, +{6033, 209, 5729}, +{6113, 177, 5713}, +{5953, 609, 5761}, +{6129, 481, 5713}, +{5937, 481, 5665}, +{6129, 449, 5409}, +{6177, 369, 5457}, +{6177, 609, 5489}, +{6225, 305, 5569}, +{6097, 401, 5537}, +{6145, 305, 5649}, +{6081, 625, 5457}, +{6113, 705, 5457}, +{6081, 561, 5473}, +{6273, 609, 5633}, +{6433, 481, 5281}, +{6385, 529, 5217}, +{5873, 593, 5569}, +{6657, -1983, 5969}, +{5873, 1185, 5345}, +{6289, -607, 5681}, +{5489, 1441, 5313}, +{6033, -63, 5921}, +{6081, 1009, 5745}, +{5889, 1041, 6129}, +{6241, 817, 5345}, +{6145, 689, 5313}, +{6209, 1121, 5377}, +{6321, 1121, 5665}, +{6321, 1505, 5297}, +{6321, 1537, 5185}, +{6161, 2001, 4721}, +{6513, 2097, 5041}, +{6513, 1777, 5313}, +{6289, 1793, 5361}, +{5921, 2241, 4977}, +{6369, 2865, 4865}, +{5953, 3041, 5185}, +{6273, 3457, 4753}, +{6097, 3841, 4641}, +{6241, 3521, 4577}, +{6145, 2705, 4753}, +{6113, 2305, 4481}, +{5729, 2353, 4609}, +{5777, 3169, 7057}, +{6065, 2049, 4977}, +{6049, 1953, 5073}, +{5857, 2673, 5393}, +{5873, 2625, 5633}, +{5953, 2289, 5633}, +{5761, 2657, 5377}, +{5841, 2577, 5217}, +{5841, 2529, 5377}, +{5857, 2433, 5585}, +{5857, 2849, 5585}, +{5937, 2385, 5329}, +{5905, 2449, 5201}, +{6001, 2337, 5329}, +{5841, 2273, 5473}, +{5793, 2273, 5505}, +{5761, 2209, 5649}, +{5809, 2209, 5633}, +{5745, 2033, 5649}, +{5745, 2177, 5745}, +{5633, 2177, 5793}, +{5921, 2049, 5569}, +{5937, 1681, 5489}, +{5873, 1905, 5553}, +{5761, 2401, 5553}, +{5697, 2545, 5633}, +{5697, 2481, 5665}, +{5809, 2305, 5697}, +{5873, 2417, 5313}, +{5809, 2593, 5377}, +{5745, 2449, 5553}, +{5793, 2465, 5713}, +{5905, 2689, 5313}, +{5969, 2065, 5457}, +{5841, 2081, 5489}, +{5761, 1921, 5569}, +{5713, 2289, 5569}, +{5665, 2401, 5825}, +{5745, 1857, 5585}, +{5857, 1713, 5521}, +{5761, 1969, 5601}, +{5857, 2065, 5761}, +{5761, 1969, 5713}, +{6033, 1361, 5521}, +{5873, 2209, 5505}, +{5761, 2289, 5345}, +{5713, 2497, 5249}, +{5905, 2801, 5649}, +{6001, 2529, 5057}, +{6001, 2625, 5041}, +{6033, 2817, 5185}, +{5873, 2913, 5297}, +{5857, 2561, 5505}, +{5825, 2337, 5585}, +{5857, 2065, 5361}, +{5905, 2193, 5377}, +{5873, 1985, 5665}, +{5793, 1969, 5585}, +{5905, 1889, 5617}, +{5729, 1905, 5745}, +{5857, 1633, 5697}, +{5777, 1889, 5681}, +{5969, 2129, 5441}, +{6113, 1617, 5617}, +{6065, 1649, 5569}, +{5809, 2161, 5377}, +{5889, 2369, 5441}, +{5905, 1825, 5745}, +{6001, 2529, 5377}, +{6033, 2321, 5089}, +{6065, 2129, 5313}, +{5985, 2209, 5441}, +{6001, 2273, 5553}, +{6033, 1889, 5601}, +{5937, 1617, 5361}, +{5905, 1841, 5409}, +{5953, 1777, 5601}, +{6001, 1793, 5761}, +{5873, 1457, 5633}, +{5857, 1857, 5457}, +{5905, 1393, 5761}, +{5889, 1345, 5697}, +{5985, 1313, 5489}, +{6017, 1521, 5409}, +{5889, 2577, 5217}, +{5937, 2673, 5457}, +{5921, 2913, 5393}, +{5889, 2737, 5265}, +{6001, 2433, 5025}, +{6017, 2625, 5121}, +{5953, 2721, 5265}, +{6033, 2881, 5297}, +{6049, 2593, 5217}, +{6065, 2529, 5217}, +{5985, 2513, 5121}, +{5825, 2593, 5489}, +{5889, 2289, 5633}, +{5873, 2081, 5505}, +{5761, 1985, 5553}, +{5841, 2129, 5553}, +{5857, 2209, 5729}, +{5969, 1953, 5281}, +{5953, 2129, 5265}, +{5985, 2177, 5441}, +{5937, 2497, 5473}, +{6017, 2337, 5265}, +{6001, 2289, 5137}, +{5889, 2625, 5281}, +{5889, 2561, 5441}, +{5921, 2369, 5585}, +{6177, 2465, 5201}, +{5953, 2497, 5249}, +{5953, 2273, 5345}, +{6001, 2193, 5393}, +{5793, 2113, 5521}, +{5873, 1921, 5697}, +{5777, 1729, 5697}, +{5793, 2113, 5745}, +{5921, 1777, 5841}, +{5873, 2033, 5665}, +{5985, 1793, 5521}, +{5953, 1745, 5553}, +{5889, 2273, 5377}, +{5889, 2465, 5457}, +{6049, 2225, 5521}, +{5889, 2033, 5473}, +{5873, 2273, 5393}, +{5857, 2577, 5585}, +{5953, 2433, 5697}, +{6017, 2417, 5425}, +{6033, 2289, 5169}, +{5921, 2065, 5329}, +{5889, 1953, 5729}, +{5857, 2113, 5617}, +{6033, 1793, 5345}, +{5921, 2097, 5201}, +{5873, 1681, 5729}, +{5825, 2113, 5697}, +{5953, 1921, 5489}, +{5985, 1761, 5425}, +{6081, 1665, 5393}, +{6001, 2289, 5569}, +{6049, 2401, 5537}, +{6017, 2273, 5457}, +{5921, 1809, 5297}, +{5937, 2225, 5329}, +{5985, 2433, 5585}, +{5953, 2049, 5425}, +{6033, 2193, 5297}, +{5969, 2113, 5393}, +{5857, 1809, 5505}, +{5921, 1969, 5537}, +{5937, 2353, 5265}, +{5985, 2033, 5393}, +{5841, 2257, 5409}, +{5777, 2049, 5649}, +{5809, 1873, 5857}, +{5921, 1793, 5393}, +{5713, 2785, 5745}, +{6017, 1777, 5649}, +{5857, 2785, 5313}, +{6065, 2049, 5937}, +{6033, 2113, 5281}, +{6001, 1985, 5153}, +{5905, 2417, 5505}, +{5713, 2305, 5713}, +{5905, 2641, 5921}, +{6497, 1777, 4417}, +{6497, 673, 4625}, +{6721, 1057, 4785}, +}; +static const uint32_t duration_HRD[] = +{ +41, +39, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +40, +40, +80, +40, +40, +}; +static const uint32_t frame_HRD[] = +{ +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +151, +152, +153, +154, +155, +156, +157, +158, +159, +160, +161, +162, +163, +164, +165, +166, +167, +168, +169, +170, +171, +172, +173, +174, +175, +176, +177, +178, +179, +180, +181, +182, +183, +184, +185, +186, +187, +188, +189, +190, +191, +192, +193, +194, +195, +196, +197, +198, +199, +200, +201, +202, +203, +204, +205, +206, +207, +208, +209, +210, +211, +212, +213, +214, +215, +216, +217, +218, +219, +220, +221, +222, +223, +224, +225, +226, +227, +228, +229, +230, +231, +232, +233, +234, +235, +236, +237, +238, +239, +240, +241, +242, +243, +244, +245, +246, +247, +248, +249, +250, +251, +252, +253, +254, +255, +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +60, +61, +62, +63, +64, +65, +66, +67, +68, +69, +70, +71, +72, +73, +74, +75, +76, +77, +78, +79, +80, +81, +82, +83, +84, +85, +86, +87, +88, +89, +90, +91, +92, +93, +94, +95, +96, +97, +98, +99, +100, +101, +102, +103, +104, +105, +106, +107, +108, +109, +110, +111, +112, +113, +114, +115, +116, +117, +118, +119, +120, +121, +122, +123, +124, +125, +126, +127, +128, +129, +130, +131, +132, +133, +134, +135, +136, +137, +138, +139, +140, +141, +142, +143, +144, +145, +146, +147, +148, +149, +150, +}; + +static const uint8_t touch_HRD[] = +{ +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +}; + +static const int32_t Expo_time[][NF_PPG_PER_CHANNEL*NF_PPG_CHANNEL] = +{ +{0, 256, 40}, +{0, 240, 40}, +{0, 224, 40}, +{0, 208, 40}, +{0, 208, 40}, +{0, 192, 40}, +{0, 184, 40}, +{0, 176, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +{0, 168, 40}, +}; + + + + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pxialg.h b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pxialg.h new file mode 100644 index 000000000..ac2b98c25 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pxialg.h @@ -0,0 +1,698 @@ +#ifndef PXIALG_H__ +#define PXIALG_H__ +#include "stdint.h" +#include "pxivar.h" + +#define FW 1 + +#define FW_DEBUG 0 +#if ( FW == 0 ) +#undef FW_DEBUG +#define FW_DEBUG 0 +#endif + +//#define STRIIV + +#if FW == 1 +#define PXIALG_API +#else +#ifdef PXIALG_EXPORTS +#define PXIALG_API __declspec(dllexport) +#else +#define PXIALG_API __declspec(dllimport) +#endif +#endif +/* +typedef struct { + uint8_t frame_count; + uint32_t time; + uint8_t touch_flag; + uint32_t nf_ppg_channel; + uint32_t nf_ppg_per_channel; + int32_t *ppg_data; + uint32_t nf_mems; + int16_t *mems_data; +} pah8series_data_t; + +typedef enum { + FLAG_DATA_READY = 0, + FLAG_DATA_NOT_READY, + FLAG_DATA_LOSS, + FLAG_NO_TOUCH, + FLAG_DATA_ERROR, + FLAG_POOR_SIGNAL, + FLAG_FIFO_ERROR, + FLAG_TIMMING_ERROR, + FLAG_MEMS_ERROR, + FLAG_HR_UPDATE = 16, + FLAG_SG_UPDATE, +} PXI_STATUS_FLAG; + +typedef enum { + _quick_report_rms_gs_th = 0, + _hr_speed_mode, + _support_cal_motion_idx_enhancement_enh, + _rsv1, + _set_switch_mems_fft_max_energy_th, + _set_switch_mems_large_energy_num_th, + _set_switch_mn_fft_energy_lo_thr, + _set_switch_mn_fft_energy_hi_thr, + + _ppg_large_energy_num_th, + _max_hr_idx_th, + _min_hr_idx_th, + _ppg_fft_total_peak_num_th, + _mems_large_energy_num_th, + _mems_fft_max_energy_th, + _support_signal_grade_motion_detection_enh, + _support_signal_grade_check_signal_lelvel_enh, + _support_signal_grade_large_energy_num_enh, + _rsv2, + _rsv3, + _set_reg_shake_count_th0, +} PXI_PARAM_SET; + +typedef enum { + _rms_gs = 0, + _signal_level, + _cal_motion_idx, + _is_prediction_hr, + _get_switch_mems_fft_max_energy_th, + _get_switch_mems_large_energy_num_th, + _get_switch_mn_fft_energy_lo_thr, + _get_switch_mn_fft_energy_hi_thr, + + _hr_sample_count, + _ppg_large_energy_num, + _signal_grade_motion_frm, + _ppg_fft_max_energy_idx, + _ppg_fft_total_peak_num, + _mems_large_energy_num, + _mems_fft_max_energy, + _grade, + _signal_grade_hr_to_low_frm, + _flag_signal_grade_ready_go, + _motion_flag, + _get_reg_shake_count_th0, +} PXI_PARAM_GET; + +typedef enum { + MemsLargeEnergyNumTh = 0, + MemsFftMaxEnergyTh, + QuickReportRmsGsTh, + SupportSigGradeMotionDetection, + PpgLargeEnergyNumTh, + SupportSigGradeLargeEnergyNumEnh, + SupportSigGradeLargeEnergyNumTh, + SigGradeThr, + SupportSigGradeCheckSigLevel, + FlagCheckNotStableFirstHR, + MaxHrDefinition, + MinHrDefinition, +} PXI_PARAM2; +*/ + +#if FW == 1 +/** + * @brief When HRD and MEMS data are ready, call this function to do the algorithm processing + * + * @param[in] HRD_Data Pointer to the buffer where HRD data (13 Bytes) is stored. + * @param[in] MEMS_Data Pointer to the buffer where MEMS data (3*sizeof(float) Bytes) is stored. + * + * @return Return one of the PXI_STATUS_FLAG types. + */ +PXIALG_API int32_t PxiAlg_ProcessByTime(unsigned char *HRD_Data, float *MEMS_Data, float time); +PXIALG_API int32_t PxiAlg_Process(unsigned char *HRD_Data, float *MEMS_Data); + +/** + * @brief Call this function to get Heart Rate + * + * @param[out] hr Pointer to a float variable where heart rate is stored + * + * @return None + */ +PXIALG_API void PxiAlg_HrGet(float *hr); + + +PXIALG_API void PxiAlg_FlagInitialSignalNoiseGet(uint8_t *flag); +/** + * @brief Call this function to feed Algorithm raw data(19 Bytes), and get Signal Grade and Heart Rate + * + * @param[in] pixart_19_byte_data Pointer to a arrag where raw data is stored + * Format: 13 bytes PPG + G-sensor X_L[13] + X_H[14] + Y_L[15] + Y_H[16] + Z_L[17] + Z_H[18] + * @param[out] grade Pointer to a float variable where signal grade is stored. + * @param[out] heart_rate Pointer to a float variable where heart rate is stored + * + * @return status bit field, combinatoin of the list below + * 1 << FLAG_DATA_READY, + * 1 << FLAG_DATA_NOT_READY, + * 1 << FLAG_DATA_LOSS, + * 1 << FLAG_NO_TOUCH, + * 1 << FLAG_DATA_ERROR, + * 1 << FLAG_POOR_SIGNAL, + * 1 << FLAG_FIFO_ERROR, + * 1 << FLAG_TIMMING_ERROR, + * 1 << FLAG_MEMS_ERROR, + * 1 << FLAG_HR_UPDATE, + * 1 << FLAG_SG_UPDATE, + */ +PXIALG_API uint32_t PxiAlg_HRM(uint8_t *pixart_19_byte_data, float *grade, float * heart_rate); +#else +/** + * @brief When HRD, MEMS, and ECG data are ready, call this function to do the algorithm processing + * + * @param[in] HRD_Data Pointer to the buffer where HRD data (13 Bytes) is stored. + * @param[in] MEMS_Data Pointer to the buffer where MEMS data (12 Bytes) is stored. + * @param[in] ECG_Data Pointer to the buffer where ECG data (4 Bytes) is stored. + * + * @return Return one of the PXI_STATUS_FLAG types. + */ +PXIALG_API int32_t PxiAlg_Process(unsigned char *HRD_Data, float *MEMS_Data, float ECG_Data); + +/** + * @brief When HRD, MEMS, ECG data, and time interval are ready, call this function to do the algorithm processing + * + * @param[in] HRD_Data Pointer to the buffer where HRD data (13 Bytes) is stored. + * @param[in] MEMS_Data Pointer to the buffer where MEMS data (12 Bytes) is stored. + * @param[in] ECG_Data Pointer to the buffer where ECG data (4 Bytes) is stored. + * @param[in] time Time interval. + * + * @return Return one of the PXI_STATUS_FLAG types. + */ +PXIALG_API int32_t PxiAlg_ProcessByTime(unsigned char *HRD_Data, float *MEMS_Data, float ECG_Data, float time); + +/** + * @brief Call this function to get Heart Rate + * + * @param[out] hr Pointer to a float variable where heart rate is stored + * + * @return None + */ +PXIALG_API void PxiAlg_HrGet(float *hr); + +PXIALG_API void PxiAlg_FlagInitialSignalNoiseGet(uint8_t *flag); + +/** + * @brief Call this function to get output + * + * @param[out] output Pointer to a SHr_motion_plot variable where output information is stored + * + * @return None + */ +PXIALG_API int32_t PxiAlg_OutputGet(void *output); + +/** + * @brief Call this function to get a specific parameter + * + * @param[out] param Pointer to the start address of the variable of parameter list + * @param[in] offset Offset of the parameter variable + * @param[in] size Type size of the parameter + * + * @return None + */ +PXIALG_API void PxiAlg_ParamGet(uint8_t *param, int32_t offset, int32_t size); + +/** + * @brief Call this function to set a specific parameter + * + * @param[in] offset Offset of the parameter variable + * @param[in] size Type size of the parameter + * @param[in] param Pointer to the start address of the variable of parameter list + * + * @return None + */ +PXIALG_API void PxiAlg_ParamSet(int32_t offset, int32_t size, uint8_t *param); +#endif + +/** +* @brief When HRD, MEMS, and Expo data are ready, call this function to do the algorithm processing +* +* @param[in] HRD_Data Pointer to the buffer where HRD data (13 Bytes) is stored. +* @param[in] MEMS_Data Pointer to the buffer where MEMS data (12 Bytes) is stored. +* @param[in] expo Exposure Time. +* +* @return Return one of the PXI_STATUS_FLAG types. +*/ +PXIALG_API int32_t PxiAlg_Process_Expo(unsigned char *HRD_Data, float *MEMS_Data, int expo); + +/** + * @brief Call this function to determine the version of the algorithm + * + * + * @return Version of the algorithm + */ +PXIALG_API int32_t PxiAlg_Version(void); + +/** + * @brief Call this funtion to get Ready_Flag + * + * @return Return Ready_Flag + */ +PXIALG_API unsigned char PxiAlg_GetReadyFlag(void); + +/** + * @brief Call this funtion to get Motion_Flag + * + * @return Return Motion_Flag + */ +PXIALG_API unsigned char PxiAlg_GetMotionFlag(void); + + +/** +* @brief Call this function to get force flag +* +* @return force_flag +*/ +PXIALG_API unsigned char PxiAlg_GetForceFlag(void); + +/** + * @brief Call this funtion to get Timeout_Flag + * + * @return Return Timeout_Flag + */ +PXIALG_API unsigned char PxiAlg_GetTimeoutFlag(void); + +/** + * @brief Call this function to set PPG buffer pointer and size + * + * @param[in] ppg_buffer Pointer to a float buffer where the PPG data would be stored + * @param[in] size PPG buffer size + * + * @return None + */ +PXIALG_API void PxiAlg_SetPPGBuffer(float *ppg_buffer, int32_t size); + +/** + * @brief Call this function to set algorithm parameters + * + * @param[in] hr_param Pointer to a "HR_Param" sturcture where the parameters are stored. + * + * @return None + */ +PXIALG_API void PxiAlg_SetParam(void *hr_param); + +/** + * @brief Call this function to set data + * + * @param[in] data Pointer to an algorithm-dependent data + * + * @return None + */ +PXIALG_API void PxiAlg_SetData(void *data); + + +/** + * @brief Call this function to notify algorithm the Output Data Rate of PPG Sensor + * + * @param[in] odr The Output Data Rate of PPG Sensor. Only 10,20,40,160 and 200 ODR are supported. + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetODR(int32_t odr); + +/** + * @brief Call this function to notify algorithm the Timeout Length of PPG Sensor + * + * @param[in] t The Timeout Length of PPG Sensor. Unit: second. + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetTimeoutLength(int32_t t); + +/** + * @brief Call this function to notify algorithm the Quality Threshold of PPG Sensor + * + * @param[in] th The Quality Threshold of PPG Sensor. Range: 0.0 ~ 1.0 + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetQualityThreshold(float th); + +/** +* @brief Call this function to notify algorithm the HR smooth weight of PPG Sensor +* +* @param[in] w The weight. Range: 0.0 ~ 1.0 +* +* @return 1 for success. 0 for failure. +*/ +PXIALG_API uint8_t PxiAlg_SetHRSmoothWeight(float w); + +/** +* @brief Call this function to notify algorithm the length of process window of PPG Sensor +* +* @param[in] t The normal time window. +* @param[in] t_fast The fast time window. +* +* @return 1 for success. 0 for failure. +*/ +PXIALG_API uint8_t PxiAlg_SetProcWindow(float t, float t_fast); + +/** + * @brief Call this function to notify algorithm the number of PPG sample to skip + * + * @param[in] num The number + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetSkipSampleNum(int num); + + +/** + * @brief Call this function to notify algorithm the MEMS Scale of Motion Sensor + * + * @param[in] scale The MEMS Scale of Motion Sensor. 0: +-2G, 1: +-4G, 2: +-8G, and 3: +-16G + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetMemsScale(int scale); +PXIALG_API uint8_t PxiAlg_SetMemsScaleBase(int scale, int th); + + + + + +/** + * @brief Call this function to notify algorithm the time length to force hr to update + * + * @param[in] t The time length + * @param[in] ub The upper bound + * @param[in] lb The lower bound + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetForceOutput(int t, int ub, int lb); + + + +/** + * @brief Call this function to notify algorithm force hr to output + * + * @param[in] t The time length + * @param[in] ub The upper bound + * @param[in] lb The lower bound + * @param[in] link_flag To link with normal output + * @param[in] w Smoothing weight between force and normal + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetForceOutputLink(int t, int ub, int lb, int link_flag, float w); + + +/** + * @brief Call this function to notify algorithm normal hr to output + * + * @param[in] ub The upper bound + * @param[in] lb The lower bound + * @param[in] static_flag First normal output at static + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetNormalOutput(int ub, int lb, int static_flag); + + +/** + * @brief Call this function to notify algorithm the time to force hr to output + * + * @param[in] t The duration + * @param[in] bpm The amplitude + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetForceRipple(int t, int bpm); + + +/** + * @brief Call this function to notify algorithm the time to force hr to output + * + * @param[in] ch The ppg channel selection + * @param[in] flag The resample flag + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetPackage(int ch, int flag); + + +/** + * @brief Call this function to notify algorithm the time length to force hr to update + * + * @param[in] t The time length + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetForceUpdateTimeLength(int t); +/** + * @brief Call this function to notify algorithm the time to force hr to output + * + * @param[in] t The time length + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetForceOutputTime(int t); +/** + * @brief Call this function to notify algorithm the bound of hr + * + * @param[in] ub The upper bound + * @param[in] lb The lower bound + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetFullHRBound(int ub, int lb); +/** + * @brief Call this function to notify algorithm the bound of first hr + * + * @param[in] ub The upper bound + * @param[in] lb The lower bound + * @param[in] t The time length to keep this bound + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetFirstHRBound(int ub, int lb, int t); + + + +/** + * @brief Call this function to notify algorithm the MEMS Energy Threshold of Motion Sensor + * + * @param[in] lower The MEMS energy lower threshold + * @param[in] upper The MEMS energy upper threshold + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetMemsEnergyThrd(int lower, int upper); + +/** + * @brief Call this function to set PPG Signal Grade Threshold + * + * @param[in] threshold The PPG Signal Grade Threshold. Its value ranges from 0 to 100. + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetSigGradeThrd(float thrd); + +/** + * @brief Call this function to set parameters of PPG Signal Grade + * + * @param[in] frm_thrd The PPG Signal Grade Frame Threshold. + * @param[in] rep_count The PPG Signal Grade Repetitive Counter. + * + * @return 1 for success. 0 for failure. + */ +PXIALG_API uint8_t PxiAlg_SetSigGradeParam(int16_t frm_thrd, int16_t rep_count); + +/** + * @brief Call this function to enable or disable fast output mode + * + * @param[in] en The flag of fast output mode. + */ + +PXIALG_API void PxiAlg_EnableFastOutput(uint8_t en); + +/** + * @brief Call this function to enable or disable motion mode + * + * @param[in] en The flag of motion mode. + */ +PXIALG_API void PxiAlg_EnableMotionMode(uint8_t en); + +/** + * @brief Call this function to enable or disable auto mode + * + * @param[in] en The flag of auto mode. + */ +PXIALG_API void PxiAlg_EnableAutoMode(uint8_t en); + +/** + * @brief Call this function to enable or disable tracking mode after fast output + * + * @param[in] en The flag of tracking mode. + */ +PXIALG_API void PxiAlg_EnableTrackingAfterFastOut(uint8_t en); + +/** + * @brief Call this function to enable or disable mems0 signal grade mode + * + * @param[in] en 1 : enable. 0 : disable. + */ +PXIALG_API void PxiAlg_EnableMEMS0SigGrade(uint8_t en); + +//PXIALG_API void PxiAlg_EnableMEMS0SigGrade(uint8_t en, uint8_t idx); +//// idx = 0: PxiAlg_EnableFastOutput(uint8_t en); +//// idx = 1: PxiAlg_EnableMotionMode(uint8_t en); +//// idx = 2: PxiAlg_EnableAutoMode(uint8_t en); +//// idx = 3: PxiAlg_EnableTrackingAfterFastOut(uint8_t en); + +/** + * @brief Call this function to get PPG Signal Grade + * + * @param[out] grade Pointer to a float variable where signal grade is stored. + * + * @return Return 1 when Signal Grade is ready. Otherwise, return 0. + */ +PXIALG_API uint8_t PxiAlg_GetSigGrade(float *grade); + +/** + * @brief Call this function to get the alarm flag of fast output + * + * @param[out] flag The alarm flag of fast output + * + * @return Return 1 when the flag is set. Otherwise, return 0. + */ +PXIALG_API uint8_t PxiAlg_GetFastOutAlarmFlag(void); + +/** + * @brief Call this function to get the alarm flag of signal bad + * + * @param[out] flag The alarm flag of fast output + * + * @return Return 1 when the flag is set. Otherwise, return 0. + */ +PXIALG_API uint8_t PxiAlg_GetSignalBadAlarm(void); + +/** + * @brief Call this function to open algorithm + */ +#if FW == 1 +PXIALG_API uint8_t PxiAlg_Open_Mem(void *mem); +#else +PXIALG_API void PxiAlg_Open(void); +#endif + +/** + * @brief Call this function to close algorithm + */ +PXIALG_API void PxiAlg_Close(void); + +/** + * @brief Call this function to initialize 200Hz low-pass filter + */ +PXIALG_API void PxiAlg_LPF200Hz_Init(void); + +/** + * @brief Call this function to process 200Hz low-pass filter + */ +PXIALG_API float PxiAlg_LPF200Hz_Process(float data); + +/** + * @brief Call this function to get PPG Signal Level + * + * @param[out] grade Pointer to a float variable where signal level is stored. + * + * @return Return 1 when Signal Level is ready. Otherwise, return 0. + */ +#ifndef REDUCE_MORE_CODE_SIZE +PXIALG_API uint8_t PxiAlg_Get_Signal_Level(float *level); +#endif +/** + * @brief Call this function to enable/disable Check_Not_Stable_First_HR + * + * @param[in] 1 : enable, 0: disable + */ +PXIALG_API void PxiAlg_Check_Not_Stable_First_HR(uint8_t check); + +/** + * @brief Call this function to set Signal_Grade_Large_Energy_Num_Th_Lo + * + * @param[in] Threshold. + * + */ +PXIALG_API void PxiAlg_Set_Signal_Grade_Large_Energy_Num_Th_Lo(uint8_t th) ; + +/** + * @brief Call this function to Set SportMode + * + * @@param[in] en 0: disable 1: enable + * + * @return Return 1 when Set Signal Grade Large Energy Num Threshold is ready. Otherwise, return 0. + */ +PXIALG_API void PxiAlg_SetSportMode(uint8_t en); + +/** + * @brief Call this function to Set Signal Grade Large Energy Num Threshold + * + * @@param[in] th => threshold + * + * @return Return 1 when Set Signal Grade Large Energy Num Threshold is ready. Otherwise, return 0. + */ +PXIALG_API uint8_t PxiAlg_Set_Signal_Grade_Large_Energy_Num_Th(uint8_t th); + + +/** + * @brief Call this function to Set Algorithm Parameters + * + * @@param[in] index - index of parameters, param - parameter value + * + * @return Return 1 when Set algorithm parameter suceeessfully. Otherwise, return 0. + */ +PXIALG_API uint8_t PxiAlg_Set_Parameter(uint32_t index, float param); + +/** + * @brief Call this function to Get Algorithm Parameters + * + * @@param[in] index - index of parameters, *param - pointer to parameter value + * + * @return Return 1 when Set algorithm parameter suceeessfully. Otherwise, return 0. + */ +PXIALG_API uint8_t PxiAlg_Get_Parameter(uint32_t index, float *param); + +/** +* @brief Call this function to Set Algorithm Parameters (2nd Version) +* +* @@param[in] index - index of parameters, param - parameter value +* +* @return Return 1 when Set algorithm parameter suceeessfully. Otherwise, return 0. +*/ +PXIALG_API uint8_t PxiAlg_Set_Parameter2(uint32_t index, float param); + +/** +* @brief Call this function to Get Algorithm Parameters (2nd Version) +* +* @@param[in] index - index of parameters, *param - pointer to parameter value +* +* @return Return 1 when Set algorithm parameter suceeessfully. Otherwise, return 0. +*/ +PXIALG_API uint8_t PxiAlg_Get_Parameter2(uint32_t index, float *param); + + + +PXIALG_API uint8_t PxiAlg_Set_Cal_Flag_HR_Trust_Energy_Ratio(float fValue); +PXIALG_API uint8_t PxiAlg_Set_Cal_Flag_HR_Trust_Large_Energy_Num_Th(uint16_t fValue); +PXIALG_API uint8_t PxiAlg_Get_Cal_Flag_HR_Trust_Energy_Ratio(float *fValue); +PXIALG_API uint8_t PxiAlg_Get_Cal_Flag_HR_Trust_Large_Energy_Num_Th(uint16_t *fValue); + +PXIALG_API uint8_t PxiAlg_Get_Flag_HR_Trust(uint8_t *flag); + +#if (ANDROID_JNI==1) +PXIALG_API uint8_t PxiAlg_Get_ParameterName(uint32_t index, const char **param); +#endif + +PXIALG_API uint8_t PxiAlg_DecodeProcess(uint32_t data, int touch_flag, float time_in); +PXIALG_API uint8_t PxiAlg_Entrance_0(pah8series_data_t *pah8series_data); +PXIALG_API uint8_t PxiAlg_Entrance(pah8series_data_t *pah8series_data); +PXIALG_API uint8_t PxiAlg_EntranceD(pah8series_data_t *pah8series_data); +PXIALG_API uint32_t PxiAlg_Query_Mem_Size(); +PXIALG_API uint8_t PxiAlg_GetHrUpdateFlag(); + +PXIALG_API void PxiAlg_SetData_Seg(pah8series_data_t *pah8series_data); +PXIALG_API uint8_t PxiAlg_Process_Seg(uint8_t *is_finished); +PXIALG_API uint8_t PxiAlg_ProcessD_Seg(uint8_t *is_finished); +#endif /* PXIALG_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pxivar.h b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pxivar.h new file mode 100644 index 000000000..0f1dd761b --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/pxivar.h @@ -0,0 +1,96 @@ +#ifndef PXIVAR_H__ +#define PXIVAR_H__ + +#include "stdint.h" + +#ifndef pah8series_data_t +typedef struct { + uint8_t frame_count; + uint32_t time; + uint8_t touch_flag; + uint32_t nf_ppg_channel; + uint32_t nf_ppg_per_channel; + int32_t *ppg_data; + uint32_t nf_mems; + int16_t *mems_data; +} pah8series_data_t; +#endif + +typedef enum { + FLAG_DATA_READY = 0, + FLAG_DATA_NOT_READY, + FLAG_DATA_LOSS, + FLAG_NO_TOUCH, + FLAG_DATA_ERROR, + FLAG_POOR_SIGNAL, + FLAG_FIFO_ERROR, + FLAG_TIMMING_ERROR, + FLAG_MEMS_ERROR, + FLAG_HR_UPDATE = 16, + FLAG_SG_UPDATE, +} PXI_STATUS_FLAG; + +typedef enum { + _quick_report_rms_gs_th = 0, + _hr_speed_mode, + _support_cal_motion_idx_enhancement_enh, + _rsv1, + _set_switch_mems_fft_max_energy_th, + _set_switch_mems_large_energy_num_th, + _set_switch_mn_fft_energy_lo_thr, + _set_switch_mn_fft_energy_hi_thr, + + _ppg_large_energy_num_th, + _max_hr_idx_th, + _min_hr_idx_th, + _ppg_fft_total_peak_num_th, + _mems_large_energy_num_th, + _mems_fft_max_energy_th, + _support_signal_grade_motion_detection_enh, + _support_signal_grade_check_signal_lelvel_enh, + _support_signal_grade_large_energy_num_enh, + _rsv2, + _rsv3, + _set_reg_shake_count_th0, +} PXI_PARAM_SET; + +typedef enum { + _rms_gs = 0, + _signal_level, + _cal_motion_idx, + _is_prediction_hr, + _get_switch_mems_fft_max_energy_th, + _get_switch_mems_large_energy_num_th, + _get_switch_mn_fft_energy_lo_thr, + _get_switch_mn_fft_energy_hi_thr, + + _hr_sample_count, + _ppg_large_energy_num, + _signal_grade_motion_frm, + _ppg_fft_max_energy_idx, + _ppg_fft_total_peak_num, + _mems_large_energy_num, + _mems_fft_max_energy, + _grade, + _signal_grade_hr_to_low_frm, + _flag_signal_grade_ready_go, + _motion_flag, + _get_reg_shake_count_th0, +} PXI_PARAM_GET; + +typedef enum { + MemsLargeEnergyNumTh = 0, + MemsFftMaxEnergyTh, + QuickReportRmsGsTh, + SupportSigGradeMotionDetection, + PpgLargeEnergyNumTh, + SupportSigGradeLargeEnergyNumEnh, + SupportSigGradeLargeEnergyNumTh, + SigGradeThr, + SupportSigGradeCheckSigLevel, + FlagCheckNotStableFirstHR, + MaxHrDefinition, + MinHrDefinition, +} PXI_PARAM2; + +#endif /* PXIVAR_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/test_library_HRD.c b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/test_library_HRD.c new file mode 100644 index 000000000..708570159 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_hr/V303009/test_library_HRD.c @@ -0,0 +1,112 @@ + +#include "pah8009_testpattern_HRD.h" +// platform +#include +#include "pah800x_main.h" +#include "pah800x_bsp.h" +#include +//#include "nrf_delay.h" +#define array_szie(arr) (sizeof(arr) / sizeof(arr[0])) + + + + +void test_library_HRD(void) +{ + int i = 0; + void *hr_pBuffer = NULL; + static ppg_mems_data_t ppg_mems_data_alg; + + sRaw_Data_13Bytes hr_data; + + + // static Hr-V301009 + + PxiAlg_Close(); + int32_t version = PxiAlg_Version(); + DEBUG_PRINT("HR_Version = %d \r\n", version); + + + uint32_t Query_Mem_Size = PxiAlg_Query_Mem_Size(); + DEBUG_PRINT("HR_Mem_Size = %d \r\n", Query_Mem_Size); + + hr_pBuffer = malloc(Query_Mem_Size); + + + if(!PxiAlg_Open_Mem(hr_pBuffer)) + DEBUG_PRINT("PxiAlg_Open_Mem fail \n"); + + + PxiAlg_SetQualityThreshold(0.35f); + PxiAlg_SetHRSmoothWeight(0.9f); + PxiAlg_SetProcWindow(5.0f, 5.0f); + PxiAlg_SetTimeoutLength(30.0f); + PxiAlg_SetMemsScale(1); //MEMS 2/4/8/16G : 0/1/2/3 + PxiAlg_SetSkipSampleNum(10); + PxiAlg_SetMemsScaleBase(1, 0); //MEMS 2/4/8/16G : 0/1/2/3 + PxiAlg_SetForceOutputLink(0, 150, 40, 1, 0.9f); + PxiAlg_SetNormalOutput(200, 40, 0); + PxiAlg_SetForceRipple(3, 1); + //PxiAlg_SetForceOutput(30, 120, 45); + //PxiAlg_SetForceOutputTime(10); + PxiAlg_SetPackage(0, 1); + + + +//-----------------------------------------------// + + LOG_PRINT("ARRAY_SIZE = %d\n",array_szie(PAH8009_rawdata_HRD)); +//****************************************************************** + + float hr = 0.0f; + float hr_grader = 0.0f; + +//******************************************************************* + + //nrf_delay_ms(50); + + + for( i = 0 ; i 0 ? 0x80 : 0x00; + //LOG_PRINT("touch = %d ", hr_data.touch); + hr_data.rsv2 = 0; + + int exposure_time = Expo_time[i][1]; + //LOG_PRINT("exposure_time = %d \n",exposure_time); + + ppg_mems_data_alg.MEMS_Data[0]=PAH8009_mems_HRD[i][0]; + ppg_mems_data_alg.MEMS_Data[1]=PAH8009_mems_HRD[i][1]; + ppg_mems_data_alg.MEMS_Data[2]=PAH8009_mems_HRD[i][2]; + + int32_t ret = PxiAlg_Process_Expo((uint8_t*)&hr_data, ppg_mems_data_alg.MEMS_Data, exposure_time); + + //LOG_PRINT("ret_HR %d \n",ret); + + if(PxiAlg_GetHrUpdateFlag()) + { + PxiAlg_HrGet(&hr); + PxiAlg_GetSigGrade(&hr_grader); + } + + LOG_PRINT("ret %d , hr %f , hr_grade %f \n", ret, hr, hr_grader); + + } + + PxiAlg_Close(); + + return; +} diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/libv703_0_1.a b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/libv703_0_1.a new file mode 100644 index 000000000..0cb0d3ba7 Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/libv703_0_1.a differ diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/pah8009_testpattern_SPO2.h b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/pah8009_testpattern_SPO2.h new file mode 100644 index 000000000..d8d9d4950 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/pah8009_testpattern_SPO2.h @@ -0,0 +1,257 @@ +#ifndef _PAH8009_TESTPATTERN_ +#define _PAH8009_TESTPATTERN_ + +#include +#define NF_PPG_CHANNEL 2 +#define NF_PPG_PER_CHANNEL 81 +static const int32_t PAH8009_rawdata_SPO2[][NF_PPG_PER_CHANNEL*NF_PPG_CHANNEL] = +{ +{1,44,1413227,1375343,1847643,1787527,1849059,1795619,1850643,1799035,1853773,1804053,1855985,1807487,1857211,1810045,1858155,1811489,1857549,1810013,1856203,1807653,1855885,1807985,1856225,1808433,1856443,1808915,1856873,1809501,1856415,1809469,1856153,1808027,1854979,1805393,1853881,1804191,1853475,1803313,1853703,1803495,1853817,1804027,1852163,1801415}, +{1,50,1849833,1797659,1848117,1794425,1846501,1792429,1846933,1794465,1848347,1797081,1847485,1795507,1845053,1791709,1845377,1792531,1845089,1792009,1844055,1790507,1844639,1792275,1845127,1792257,1844247,1791883,1845803,1795625,1848153,1799679,1848469,1799821,1847757,1799101,1847791,1798791,1847717,1799383,1847285,1799295,1846165,1798421,1846711,1799119,1846979,1800181,1847917,1802373,1850389,1806013}, +{1,54,1851247,1807949,1852643,1810447,1854655,1814097,1856243,1816695,1856223,1816223,1855313,1814589,1854833,1813203,1854871,1813909,1855589,1815461,1855909,1816625,1856441,1816653,1856433,1816745,1856403,1816085,1854765,1813617,1853649,1811729,1853635,1812979,1854253,1814335,1854801,1814861,1855735,1817119,1856677,1818893,1856001,1817823,1855067,1815591,1854373,1814907,1853907,1813719,1852421,1811229,1851319,1809519,1850537,1808687}, +{1,54,1850007,1808285,1850491,1808867,1851353,1810153,1850677,1808535,1849503,1806183,1847779,1803439,1845305,1798249,1842229,1794125,1841311,1792951,1840299,1790817,1839801,1790775,1839609,1791541,1840653,1792959,1840111,1792037,1838781,1789819,1838071,1788025,1837549,1786829,1837177,1786199,1834709,1782813,1835469,1783903,1837155,1788265,1838507,1791097,1839841,1792945,1841147,1795599,1842109,1797251,1842343,1798043,1843101,1799101}, +{1,52,1843105,1799891,1843259,1800647,1843283,1801331,1842971,1800695,1843171,1800911,1843061,1801429,1843091,1801291,1843385,1801803,1843243,1802025,1843955,1803115,1845053,1804645,1844847,1804419,1844275,1802959,1844563,1803241,1844051,1802191,1844389,1802653,1844789,1803795,1845123,1804267,1845465,1804429,1845769,1804835,1845421,1804775,1844911,1804409,1844629,1804201,1844617,1804613,1845049,1804889,1845049,1805099}, +{1,54,1845203,1805421,1844861,1805319,1845265,1805971,1845519,1806249,1845809,1806711,1845999,1807367,1846361,1807837,1846561,1808147,1847089,1809035,1847853,1810107,1848437,1811271,1848687,1811447,1848663,1811475,1848819,1811293,1848815,1811405,1847765,1810337,1847277,1809779,1847415,1809381,1846875,1808739,1846289,1808049,1846243,1807663,1846263,1807911,1845817,1807357,1845631,1807343,1845983,1807737,1846023,1807371,1845827,1807367}, +{1,52,1846061,1807943,1845723,1807769,1845883,1807671,1845831,1807777,1845765,1807449,1845733,1807487,1845631,1807823,1845133,1806927,1844505,1806271,1844083,1805967,1843839,1805569,1843705,1805473,1844097,1806027,1844243,1806141,1844395,1806617,1844113,1806423,1844341,1806709,1844363,1807205,1844527,1807439,1844603,1807187,1844567,1807015,1844563,1806931,1844247,1806691,1844457,1806229,1844533,1806451,1844537,1806307}, +{1,52,1844555,1806299,1843955,1806475,1843797,1805597,1843233,1805593,1843451,1805647,1843265,1805505,1843037,1805499,1843121,1805159,1843229,1805383,1843029,1804627,1843313,1805051,1843019,1805145,1843261,1804877,1842989,1804949,1842807,1804521,1843091,1805135,1843381,1805241,1843323,1805171,1843523,1805439,1843737,1805711,1843861,1806105,1843411,1806039,1842957,1805241,1842411,1804437,1842521,1804595,1842225,1804201}, +{1,54,1842265,1804225,1842225,1804141,1842091,1803731,1842001,1803837,1842331,1804307,1842349,1804483,1842811,1805057,1842709,1804691,1842997,1805397,1843061,1805025,1843003,1805237,1843179,1805291,1843309,1804907,1843287,1805309,1843237,1805263,1843353,1805513,1843121,1805413,1842015,1803891,1841531,1803513,1841903,1804169,1841713,1803343,1841855,1803643,1841597,1803495,1841721,1803983,1841979,1804191,1841961,1804663,1842237,1805463}, +{1,52,1842841,1805611,1843219,1805829,1843215,1806035,1843643,1806543,1843665,1807081,1844097,1807349,1844393,1807677,1844555,1808157,1844457,1808143,1845213,1809151,1844893,1808913,1844453,1808725,1844261,1808397,1844083,1808377,1844029,1807939,1843945,1807671,1843379,1807363,1843327,1806831,1843163,1806443,1842717,1806451,1842935,1806207,1842847,1806623,1843341,1806843,1843117,1806631,1842887,1806461,1843239,1806761}, +{1,52,1843491,1806813,1843455,1807039,1843207,1806913,1843179,1806881,1843535,1806961,1842847,1806401,1842167,1805047,1842027,1804743,1841633,1804475,1841295,1803827,1841263,1803435,1840961,1803563,1840957,1803337,1841055,1803563,1840755,1803551,1841335,1804649,1842085,1805085,1842247,1805269,1842033,1805263,1842063,1805325,1842263,1805527,1842563,1805681,1843101,1806203,1843291,1806545,1844207,1808087,1844433,1808143}, +{1,54,1844493,1808715,1843847,1808245,1844033,1809131,1844385,1809343,1844457,1808979,1844433,1808869,1844073,1808139,1843385,1807065,1843145,1806497,1843803,1807307,1843051,1806933,1844003,1809509,1845831,1812717,1847551,1816579,1851097,1823331,1860321,1839875,1866743,1849125,1865911,1843927,1860507,1835367,1859875,1834775,1858871,1833191,1857559,1830255,1854361,1824619,1852367,1821855,1851795,1820705,1850731,1818609,1850629,1818733}, +{1,52,1852007,1822665,1852347,1822961,1851195,1820025,1850279,1817891,1848753,1815595,1847853,1814407,1847935,1814333,1848401,1816057,1848725,1816107,1848753,1815591,1848549,1815471,1848717,1815887,1849229,1816815,1848961,1816479,1848807,1815707,1847681,1814379,1846801,1812689,1846111,1810819,1843763,1806849,1840543,1801615,1839751,1801757,1840755,1802973,1841277,1804533,1840179,1802529,1840005,1801457,1840333,1802113}, +{1,52,1839583,1800437,1838631,1799091,1838427,1799267,1839369,1800713,1839779,1801687,1840619,1804035,1841259,1804479,1841405,1804525,1841135,1804127,1841249,1804447,1840529,1804373,1840391,1804179,1839897,1803301,1839635,1802829,1839387,1802491,1839369,1802159,1839377,1802149,1839271,1801763,1839453,1802063,1839409,1802091,1839343,1802141,1839449,1802299,1839911,1802955,1840165,1803041,1840579,1803235,1840957,1803901}, +{1,54,1840957,1804053,1841015,1804355,1841415,1804557,1841627,1805273,1841847,1805861,1841179,1805361,1841343,1805159,1841357,1805579,1841353,1805249,1841153,1805343,1841231,1805547,1841491,1805587,1841633,1806263,1841685,1806429,1841651,1806705,1842211,1807541,1842779,1807939,1843069,1808897,1843483,1809417,1843837,1809717,1844225,1810343,1844371,1811299,1844701,1811483,1845013,1811833,1845563,1812531,1845239,1812135,1844749,1811935}, +{1,52,1844875,1812555,1844835,1812143,1844691,1811903,1844741,1811959,1844491,1811669,1844505,1811673,1844443,1811543,1844435,1811445,1844101,1811371,1844163,1811027,1844233,1811177,1843949,1811133,1844233,1811133,1844221,1811021,1844069,1810507,1844051,1810775,1844061,1810745,1844051,1810749,1843349,1810309,1842981,1809331,1842705,1809183,1842441,1808973,1842451,1808739,1842345,1808835,1842219,1808761,1842411,1808559}, +{1,54,1842157,1808645,1842139,1808919,1842389,1808895,1842463,1808749,1842335,1808767,1842407,1808839,1842527,1808295,1842543,1808405,1842563,1808735,1842229,1808049,1842567,1808585,1842535,1808383,1842411,1808495,1841747,1807763,1841427,1807067,1841277,1807089,1841295,1807213,1840813,1806619,1840951,1806783,1841151,1807095,1841019,1806927,1841053,1807181,1840885,1807043,1841227,1806959,1841073,1807035,1841063,1807181,1841215,1807417}, +{1,52,1841459,1807145,1841449,1807199,1841393,1807067,1841415,1806979,1841509,1807187,1841507,1807269,1841729,1807481,1840863,1806965,1840663,1806083,1840347,1805851,1840275,1805935,1840177,1805587,1839961,1805841,1840045,1805471,1839875,1805569,1840161,1805727,1840281,1805785,1840409,1805607,1840463,1806087,1840779,1806397,1840677,1806737,1841009,1806767,1841183,1807029,1841241,1807131,1841197,1807195,1841343,1807293}, +{1,52,1841673,1807403,1841477,1807223,1841063,1806543,1840397,1806369,1840027,1805805,1839885,1805675,1839769,1805283,1839823,1804973,1839867,1805033,1839169,1804963,1839217,1805009,1839599,1804875,1839439,1805443,1839685,1805367,1839583,1804599,1839377,1804201,1839027,1803559,1838803,1803089,1838555,1802459,1837971,1801073,1837439,1800159,1837599,1801079,1837897,1801331,1836701,1799857,1836455,1800321,1837069,1801853}, +{1,54,1837643,1802797,1837269,1801951,1836379,1801137,1836025,1799811,1835379,1799317,1835171,1798263,1834655,1798043,1834249,1797073,1833925,1796527,1833769,1796001,1833431,1795583,1833475,1795783,1833499,1795867,1832885,1794835,1832697,1794735,1832605,1794313,1832151,1793511,1832045,1793463,1831047,1792143,1830137,1791131,1829695,1790225,1829007,1789429,1829437,1789379,1828881,1789107,1828783,1789009,1829103,1789001,1828851,1789125}, +{1,52,1829207,1789139,1829051,1789453,1829331,1789623,1829469,1789449,1829407,1788433,1828309,1786533,1827885,1785401,1826885,1783253,1826359,1782583,1826343,1783151,1825813,1781565,1824831,1780531,1824051,1779917,1823559,1779967,1823461,1779837,1824221,1781705,1824447,1781357,1823893,1781117,1823901,1780941,1823883,1781123,1824131,1780957,1823839,1781045,1823811,1780333,1823719,1780059,1823785,1780587,1824243,1781293}, +{1,52,1824133,1781279,1824061,1781059,1823835,1780387,1823857,1779837,1823781,1780479,1823985,1780725,1823713,1780581,1822647,1779399,1822121,1779229,1822219,1779113,1821779,1778493,1822043,1779141,1822127,1779127,1822081,1779237,1822189,1779195,1822481,1779691,1822655,1779935,1823117,1780235,1823349,1780897,1823763,1780883,1823977,1781445,1823793,1780467,1823777,1780327,1823715,1780481,1823367,1779621,1823461,1779755}, +{1,52,1823465,1779557,1823283,1779347,1822891,1778737,1822153,1778157,1821487,1777481,1821353,1777227,1821121,1777199,1820645,1776801,1820579,1775975,1820005,1775847,1820139,1775845,1819555,1774539,1818991,1774099,1819245,1774247,1818719,1773383,1818675,1773563,1818791,1774507,1819827,1776039,1819635,1775619,1819863,1775813,1819399,1774935,1819159,1774599,1818537,1773767,1818973,1773683,1817563,1772195,1816719,1771193}, +{1,54,1816439,1770893,1816497,1770653,1816021,1770379,1815945,1769969,1816019,1769913,1815701,1769797,1815695,1769489,1815829,1769099,1814869,1769189,1815429,1769169,1815005,1768841,1815127,1768777,1814807,1768449,1815069,1768503,1814833,1768411,1814667,1768117,1814673,1767747,1814187,1767043,1814171,1766827,1813321,1765607,1812461,1764623,1811547,1763381,1811347,1762825,1811605,1763061,1811461,1763159,1811267,1763141,1811417,1763043}, +{1,52,1811207,1763505,1811399,1763381,1811279,1762695,1811127,1762769,1810949,1762285,1810439,1761947,1810625,1762151,1810679,1761753,1810119,1760941,1810021,1760303,1809585,1760031,1809807,1759923,1809531,1760353,1810315,1761195,1809123,1759887,1809127,1759245,1808331,1757739,1807961,1757407,1807691,1756865,1807641,1756431,1806881,1754813,1805857,1753145,1805035,1752749,1805217,1752675,1804987,1752327,1804667,1752295}, +{1,52,1804585,1751465,1803327,1749265,1803413,1749487,1803309,1749749,1803243,1749473,1803393,1750037,1803025,1749159,1802261,1747897,1801561,1747231,1800863,1746159,1799649,1745263,1799405,1744755,1798743,1743721,1798005,1742265,1798061,1742259,1797767,1741831,1796901,1740061,1796891,1740181,1796599,1739815,1798083,1743175,1799139,1743641,1798311,1742347,1797813,1740889,1797559,1740953,1799387,1743481,1798947,1742593}, +{1,54,1799303,1742917,1799445,1742663,1799517,1743083,1799889,1743079,1799733,1743379,1799933,1743517,1799961,1743591,1800597,1744391,1801647,1745711,1802941,1747685,1803389,1748443,1804265,1749357,1804725,1750605,1805401,1751169,1806089,1752397,1806809,1754191,1807241,1754333,1807415,1755207,1808975,1757327,1809331,1757363,1809041,1757489,1809379,1758127,1809705,1759277,1809865,1759227,1808869,1757333,1808459,1757331,1808091,1756473}, +{1,52,1807045,1755147,1807231,1755243,1806873,1755451,1806761,1754827,1806757,1754295,1806217,1753817,1806027,1753769,1806401,1754069,1806711,1754661,1806859,1755233,1806933,1755225,1807365,1755345,1807071,1755757,1807251,1755761,1807623,1756141,1807495,1756057,1807387,1755677,1807371,1755835,1807757,1756141,1807543,1755461,1806361,1754421,1805533,1753405,1805511,1753201,1805605,1753187,1805401,1752729,1805263,1752781}, +{1,52,1805613,1752315,1805137,1752665,1805399,1752813,1805449,1753159,1805729,1753197,1806223,1753723,1806507,1754129,1806973,1754699,1807193,1755253,1807833,1755965,1808139,1756455,1808989,1757391,1809501,1758191,1809683,1758837,1810497,1759453,1810839,1760163,1810781,1760455,1810839,1760599,1811329,1761517,1812057,1762755,1811983,1762155,1812405,1762877,1812733,1763441,1813155,1764143,1812799,1763593,1812693,1763099}, +{1,54,1812481,1762807,1812405,1762063,1812249,1761607,1812057,1761435,1812155,1761647,1811813,1761203,1811925,1761757,1811969,1761647,1811403,1761043,1811723,1761365,1810887,1760215,1810353,1759897,1809919,1759359,1809891,1759121,1809359,1758787,1809403,1758791,1808939,1757795,1808829,1757503,1808451,1756935,1808371,1756989,1808229,1756681,1807947,1755785,1807993,1756061,1807975,1755867,1807775,1755789,1807797,1755511,1807659,1754985}, +{1,52,1807571,1755303,1808317,1755933,1807913,1755669,1807827,1755669,1807589,1755723,1807089,1755683,1807089,1755355,1806965,1755235,1806689,1754925,1806067,1754607,1806019,1754393,1805933,1754103,1805657,1753807,1805565,1753949,1805707,1753847,1805747,1754023,1805729,1753903,1805827,1754413,1805801,1754563,1805921,1754255,1805897,1754011,1805921,1754429,1805871,1754121,1805919,1754323,1805671,1754277,1805263,1754413}, +{1,52,1805209,1754227,1805897,1755557,1806035,1755549,1806173,1755697,1806917,1756611,1806969,1757139,1806929,1757599,1807535,1758705,1807847,1759115,1807765,1758737,1807761,1759143,1808165,1759313,1807975,1758823,1807067,1757647,1807303,1758459,1807947,1759133,1807415,1758703,1807023,1758117,1805867,1757439,1805501,1756357,1805079,1756339,1804715,1755955,1804569,1756201,1804279,1755947,1804421,1756037,1804527,1756601}, +{1,52,1804421,1756603,1804003,1756661,1804229,1756589,1804137,1756763,1804239,1756745,1804127,1756897,1803851,1756615,1803973,1756601,1804061,1756971,1803985,1757065,1803905,1757175,1803039,1756335,1802317,1755469,1802149,1755613,1801841,1755233,1801673,1754699,1801405,1755127,1801317,1755405,1801865,1755553,1801775,1755783,1802007,1756199,1802047,1756413,1802665,1757401,1802757,1758035,1802861,1758265,1803333,1758617}, +{1,54,1803509,1759013,1803501,1758825,1803795,1759225,1803461,1759059,1802741,1758075,1801625,1757051,1801379,1756855,1801095,1756713,1801011,1756625,1800729,1756575,1800587,1757069,1800615,1757869,1800587,1757725,1801113,1758269,1801113,1758713,1800655,1757585,1799911,1756633,1799735,1756663,1800747,1757825,1800325,1756675,1799329,1755123,1799205,1755179,1799257,1755341,1798751,1755963,1798707,1756185,1798551,1755997,1797879,1755225}, +{1,52,1797367,1754219,1796909,1753631,1796335,1752809,1796371,1753193,1796439,1752919,1795339,1751653,1795025,1751049,1794957,1751515,1795433,1752569,1795659,1753511,1795905,1753413,1796083,1754171,1795839,1753729,1795621,1753535,1795993,1754393,1795527,1754129,1795243,1754023,1794505,1753095,1794037,1752227,1793841,1752365,1794041,1752597,1794273,1753441,1794505,1753691,1794229,1753579,1794331,1753715,1794029,1753835}, +{1,52,1794295,1753793,1793707,1753123,1793787,1753483,1793619,1753311,1793601,1753293,1793553,1753311,1794067,1753995,1794167,1754753,1794223,1754135,1794091,1754389,1793681,1753663,1792693,1752901,1792507,1753105,1792355,1753073,1792199,1753371,1792045,1752957,1792649,1753473,1792303,1753857,1792405,1753733,1792671,1753691,1792351,1753631,1793255,1754989,1794139,1756167,1794665,1757393,1795615,1759015,1797051,1760923}, +{1,54,1797991,1762359,1798559,1763421,1799031,1764405,1799703,1764909,1799057,1764355,1798547,1763805,1798737,1763389,1798591,1763057,1798417,1762189,1797965,1761883,1797911,1762243,1798551,1762849,1797751,1761471,1797311,1760659,1797417,1760673,1797075,1760535,1797289,1760857,1797417,1760483,1797421,1760539,1797065,1760297,1797083,1760017,1796897,1760843,1797111,1760641,1796375,1759817,1796065,1759407,1795299,1758599,1794891,1757997}, +{1,52,1795229,1758153,1794979,1758241,1794927,1758215,1794753,1758163,1794531,1757951,1794695,1758301,1794971,1758681,1794939,1758113,1794869,1757941,1794863,1758579,1794913,1758357,1795135,1758257,1795121,1758229,1795145,1758331,1795241,1758783,1795439,1758945,1795717,1758843,1795145,1758755,1794829,1758243,1794325,1757997,1794269,1757651,1793837,1757147,1793867,1756763,1793707,1756767,1793947,1756901,1793907,1757069}, +{1,52,1793863,1757511,1794237,1757447,1794113,1757077,1794527,1757489,1794525,1757479,1794553,1757143,1794273,1757065,1794167,1756233,1794219,1755963,1793971,1756111,1794189,1755799,1794015,1755489,1793939,1755603,1793237,1755003,1793173,1755039,1793027,1755271,1793255,1755335,1793263,1755113,1793111,1755211,1793295,1754985,1792939,1754713,1793013,1754815,1793161,1754861,1793095,1754365,1792969,1754167,1793191,1754639}, +{1,54,1793451,1754383,1793197,1754107,1793031,1753455,1793121,1753197,1792693,1752887,1792279,1751911,1792253,1752093,1792703,1752489,1792099,1752093,1791591,1751783,1791697,1752701,1792059,1752601,1792155,1752739,1792431,1752761,1792067,1752901,1792537,1753275,1792721,1753297,1792775,1753497,1793449,1753821,1793771,1754181,1794665,1754975,1795037,1755147,1795439,1756265,1796243,1757069,1796545,1757719,1797129,1757675,1797421,1757989}, +{1,52,1797827,1758691,1797973,1759365,1797889,1759835,1797707,1759929,1798089,1760553,1797719,1759745,1797963,1760145,1798387,1760733,1797475,1759877,1797719,1760201,1797945,1760113,1797449,1759531,1797545,1758953,1797247,1759083,1797243,1759055,1797479,1758935,1797465,1759611,1797809,1759615,1797825,1760007,1798013,1760127,1798061,1760455,1798125,1760327,1798311,1760599,1798243,1760345,1797265,1759101,1797247,1759037}, +{1,58,1797381,1759389,1797111,1758861,1797007,1758981,1796897,1758719,1796803,1758561,1796629,1758353,1796679,1758385,1796871,1758779,1796733,1758215,1796683,1758241,1796821,1758251,1796949,1758399,1797217,1757969,1797221,1758569,1797319,1758283,1797675,1758897,1797475,1758991,1797933,1759147,1797947,1759319,1797337,1758603,1797155,1758227,1797247,1758575,1797071,1758301,1796851,1758195,1797163,1758279,1796999,1758539,1797443,1758195,1797407,1758985,1797523,1759019}, +{1,54,1797665,1758957,1798177,1759151,1798279,1759715,1798257,1759849,1798347,1759957,1798085,1759513,1798725,1760179,1798381,1759415,1798631,1758657,1798133,1757821,1797741,1757073,1797115,1756099,1796243,1756261,1796673,1756537,1796193,1756149,1795713,1755589,1796811,1757377,1797029,1757761,1796433,1757651,1796611,1758049,1796941,1758911,1797003,1759107,1797399,1759213,1797483,1759619,1797973,1760635,1798445,1760547,1798707,1761071}, +{1,52,1799277,1761591,1799209,1762007,1799747,1762487,1800085,1763007,1800473,1763689,1800161,1763315,1799281,1762309,1799427,1762225,1799285,1762189,1798857,1761577,1798671,1760497,1798751,1760641,1798501,1760441,1798503,1759999,1798485,1759943,1798421,1760427,1798507,1759929,1798729,1760695,1798759,1760803,1799001,1760787,1798863,1760853,1799271,1761001,1799417,1761055,1799539,1761569,1799453,1761439,1799939,1761785}, +{1,52,1799521,1761459,1799089,1760973,1799063,1760833,1799165,1761269,1799197,1761375,1799115,1761385,1799119,1761357,1799431,1762063,1799201,1761749,1799539,1762119,1799779,1762307,1800183,1762571,1799943,1762585,1800245,1762687,1800507,1762937,1800815,1762705,1800153,1761703,1799965,1761459,1799775,1761463,1800245,1761255,1799463,1760381,1798795,1759877,1798223,1759481,1798399,1759619,1797981,1758723,1797529,1758127}, +{1,54,1797773,1758939,1797609,1759523,1797559,1758847,1797547,1759313,1797853,1759703,1797737,1759285,1797625,1759403,1797621,1759287,1797315,1758769,1797235,1758349,1797071,1758349,1797053,1757913,1797129,1758529,1797079,1758487,1796995,1757601,1796661,1758003,1795985,1757139,1795833,1756439,1795385,1756513,1795277,1756237,1794699,1755395,1794647,1754749,1794263,1754773,1794245,1754819,1794165,1754841,1794481,1755679,1794903,1755807}, +{1,52,1794625,1755947,1795273,1756347,1795101,1756915,1795403,1756917,1795127,1756865,1795403,1757271,1795659,1757553,1795611,1757319,1795523,1757197,1794793,1756527,1794047,1755617,1793775,1755553,1793823,1755307,1793357,1755129,1793289,1754855,1793255,1754727,1793405,1755159,1793295,1755351,1793335,1755091,1793449,1755155,1793713,1755899,1794673,1757867,1795135,1757937,1795539,1758279,1795975,1759213,1796069,1759687}, +{1,52,1796651,1759951,1796531,1759435,1796831,1759809,1796203,1759315,1796145,1759375,1795647,1758913,1796029,1759623,1796669,1760941,1796847,1761305,1796799,1761905,1797447,1762993,1797381,1763315,1797489,1763569,1798253,1764323,1798027,1764683,1798155,1764631,1798285,1765205,1798461,1764483,1798137,1764147,1798227,1764217,1798097,1763989,1799093,1766027,1799693,1766979,1799867,1767313,1799303,1765971,1798503,1765287}, +{1,54,1798307,1764545,1797951,1762859,1796985,1760899,1796723,1759923,1795953,1758823,1795443,1758565,1795571,1757899,1795531,1758375,1795553,1758657,1795931,1758991,1795749,1759015,1795917,1759203,1796105,1759485,1796149,1759805,1796439,1760077,1796647,1760847,1795843,1760169,1795723,1759507,1795759,1759849,1795887,1759327,1795799,1759411,1795665,1759475,1795647,1759827,1795957,1759475,1795777,1759623,1796025,1759873,1796037,1759975}, +{1,52,1796411,1760465,1796949,1761305,1797151,1761693,1797209,1761859,1797519,1762475,1798107,1763275,1798577,1764179,1798555,1763559,1797825,1762927,1797563,1762803,1797861,1763227,1797271,1762681,1797409,1762409,1797541,1762711,1797527,1762651,1797239,1762659,1797439,1762603,1797333,1762863,1797541,1762637,1797289,1762525,1797537,1762531,1797351,1762169,1797573,1761901,1797083,1761043,1797367,1761623,1797621,1761873}, +{1,52,1797069,1761279,1796973,1761463,1796817,1761251,1796341,1760013,1796203,1760165,1796109,1760417,1796381,1760849,1796693,1761665,1796749,1762427,1797123,1762151,1797207,1762723,1797189,1762507,1797507,1762963,1797247,1762963,1797439,1762715,1797345,1762151,1797163,1762137,1797283,1762127,1797269,1761891,1797275,1762087,1797221,1762317,1797551,1762243,1797199,1762437,1796967,1762469,1796577,1761907,1796891,1762031}, +{1,52,1796879,1762087,1796475,1761633,1796335,1761369,1796221,1761323,1796229,1760927,1796153,1761189,1796033,1761195,1796261,1761369,1796469,1761509,1796653,1761787,1796653,1762295,1796705,1762353,1797003,1762373,1797435,1762933,1796999,1762913,1797213,1762739,1797319,1762451,1797275,1762415,1797029,1762161,1796643,1761667,1796665,1761683,1796581,1761725,1796493,1761791,1796331,1761933,1796933,1762189,1796705,1761861}, +{1,54,1796393,1761875,1796577,1762031,1796785,1762059,1796927,1762581,1797395,1762817,1797349,1763037,1797311,1762709,1797705,1763311,1797773,1763181,1798243,1763395,1798337,1764331,1798319,1764243,1798777,1764225,1798547,1764299,1797991,1764139,1797627,1763685,1797763,1763559,1797817,1763385,1797261,1763007,1797181,1762803,1797279,1762903,1797123,1762785,1796995,1762405,1796875,1761985,1796715,1762127,1796755,1762299,1796795,1762247}, +{1,52,1796705,1761915,1796639,1761781,1796781,1762017,1796567,1761625,1796635,1761759,1796767,1761637,1796937,1761569,1796915,1761163,1796447,1761505,1795793,1760875,1795665,1760205,1795341,1759965,1795361,1759703,1795201,1759231,1795069,1759093,1794975,1758815,1794749,1758741,1794819,1758807,1794557,1758145,1794405,1758375,1794743,1758325,1794645,1757997,1794807,1758123,1794579,1758205,1794727,1758081,1794757,1757881}, +{1,52,1794385,1757605,1794561,1757691,1794659,1757157,1794645,1757035,1794735,1757133,1794549,1757525,1794019,1756869,1793285,1755965,1793183,1756265,1793175,1756043,1792965,1755397,1793139,1755405,1792573,1755299,1792889,1755007,1792437,1754819,1792645,1754827,1792471,1754855,1792623,1754449,1792529,1754653,1792695,1754523,1792885,1754707,1792867,1754815,1792827,1754847,1793089,1755175,1793173,1754949,1793333,1755165}, +{1,54,1793223,1754919,1793253,1755275,1793161,1754949,1793089,1754847,1792231,1754005,1792143,1753613,1791987,1753709,1791881,1753131,1791841,1753123,1791729,1753063,1791609,1753251,1791681,1752855,1791387,1752771,1791439,1752961,1791569,1752805,1791639,1752447,1791547,1752809,1792019,1752869,1791845,1753193,1792187,1753505,1792449,1753787,1792877,1754295,1792853,1754417,1793015,1754361,1793085,1754431,1793117,1754845,1793055,1754759}, +{1,52,1792707,1754499,1792507,1754283,1792915,1754739,1792681,1754707,1792783,1754495,1792445,1754611,1792783,1754883,1792657,1754647,1792635,1754231,1792965,1754795,1793209,1755035,1793481,1755817,1793771,1756199,1794081,1756745,1794263,1756981,1794367,1757439,1795033,1757721,1795113,1758629,1795901,1759047,1795817,1759439,1796159,1760469,1797013,1761309,1797127,1761781,1796853,1762017,1796891,1761851,1796785,1762085}, +{1,52,1796719,1761901,1797007,1762303,1797167,1762295,1796429,1761611,1796465,1761439,1796491,1761473,1796509,1761593,1796275,1761301,1796283,1761033,1796399,1761139,1795989,1760871,1796039,1760751,1796101,1761115,1796265,1761037,1796175,1761319,1796453,1761213,1796417,1761319,1796083,1761287,1795105,1759139,1794157,1757065,1793851,1756269,1793677,1756107,1793037,1754947,1792279,1754457,1792489,1755755,1792743,1756163}, +{1,54,1792657,1756201,1792783,1756523,1793001,1757021,1793215,1757845,1793271,1757961,1792601,1756879,1793499,1758159,1793027,1757799,1792929,1757563,1793259,1758237,1793343,1758329,1793467,1758671,1793659,1758523,1793223,1758423,1792769,1757645,1792245,1757271,1792151,1757807,1791901,1757467,1791333,1756099,1791435,1756375,1791097,1755941,1790999,1755859,1790493,1755525,1790839,1755977,1790609,1755849,1791075,1756593,1791239,1756499}, +}; +static const int16_t PAH8009_mems_SPO2[][3*NF_PPG_PER_CHANNEL] = +{ +{80, 155,370,2007,136,383,2012,170,393,2021,170,381,2016,150,376,2012,155,376,2010,163,383,2016,163,377,2015,156,367,2029,153,373,2014,161,402,1999,168,390,2012,151,385,2015,159,386,2015,167,390,2013,162,394,2014,161,391,2014,163,395,2014,166,394,2010,158,398,2010,159,396,2007,164,396,2007,162,397,2010,157,397,2008,160,403,2009,162,402,2008,162,400,2009,162,395,2009,161,396,2009,161,397,2013,161,394,2014,162,388,2011,159,386,2011,160,392,2012,159,391,2016,161,385,2015,162,386,2012,158,389,2016,161,392,2014,161,391,2011,159,394,2015,163,394,2011,161,393,2011,160,399,2010,162,402,2010,163,412,2014,159,428,1982,162,439,1993,173,352,2029,139,371,2020,162,419,2015,188,416,2011,164,412,2012,152,401,2004,165,402,1999,164,420,2002,157,443,1997,165,430,2007,166,388,2023,154,366,2016,156,396,2002,171,407,2010,162,408,2015,158,391,2010,161,386,2008,163,388,2012,163,363,2044,159,345,2022,151,404,2012,164,426,1988,169,409,2005,156,392,2018,158,382,2016,161,387,2013,157,408,2002,157,413,2008,162,400,2016,158,393,2012,158,392,2009,161,392,2010}, +{52, 162,411,2012,164,406,2008,164,407,2005,161,413,2006,165,412,2005,164,417,2005,169,407,2000,165,403,2010,160,409,2011,166,409,2008,161,412,2010,159,421,2016,165,417,2012,162,409,2008,166,391,2001,163,400,2005,164,411,2004,159,426,2013,160,420,2017,167,408,2004,170,402,2000,163,406,2003,161,410,2010,165,415,2010,161,415,2013,162,409,2010,165,395,2003,163,392,2003,168,398,2004,154,409,2017,157,409,2017,166,402,2016,161,400,2013,160,387,2006,157,391,2010,161,396,2012,164,395,2011,159,392,2012,159,392,2009,159,396,2013,160,399,2012,158,392,2009,159,391,2010,163,386,2007,161,384,2006,155,393,2014,165,387,2014,158,384,2015,162,342,2044,152,371,2009,164,419,1993,168,420,2003}, +{53, 158,390,2012,150,377,2025,160,377,2018,166,391,2011,164,403,2010,157,403,2009,157,398,2009,156,406,2013,161,402,2008,156,393,2012,152,393,2011,161,393,2012,164,393,2011,157,387,2010,160,397,2012,167,394,2010,151,396,2014,159,394,2013,161,395,2017,163,395,2011,159,390,2010,159,394,2013,164,393,2009,158,392,2013,159,393,2006,157,398,2012,163,404,2014,165,396,2013,165,388,2007,167,396,2004,161,400,2011,161,405,2015,167,399,2000,152,402,2041,180,407,2000,145,369,2002,159,417,2022,181,384,2001,143,413,2025,169,393,2004,159,412,2020,167,399,2006,160,399,2009,165,396,2003,161,410,2010,169,413,2006,168,412,2008,158,418,1996,163,441,1985,179,390,2022,155,380,2030,163,399,2005,175,415,2011}, +{52, 169,408,2005,161,400,2006,162,403,2009,171,408,2008,165,413,2009,166,417,2015,169,418,2012,172,406,2005,160,429,1989,167,441,1995,177,411,2006,158,409,2022,158,408,2010,173,400,2006,174,388,2003,161,392,2019,164,408,2011,166,419,2012,167,411,1997,161,417,2006,166,420,2009,163,395,2011,156,399,2000,165,410,2006,170,424,2015,166,420,2016,167,418,2011,167,417,2010,168,415,2006,163,423,1996,164,446,1991,175,396,2016,162,398,2019,161,429,2006,164,459,1984,170,422,2004,165,370,2017,157,368,2018,164,398,2000,167,404,2007,167,406,2008,159,402,2014,152,397,2013,159,388,2022,159,372,2026,151,408,2003,165,411,2000,159,399,2012,154,386,2010,153,393,2017,158,378,2014,157,383,2018}, +{52, 155,398,2007,160,397,2012,152,392,2014,159,379,2016,155,393,2018,153,407,2007,161,402,2010,153,391,2014,150,388,2011,154,391,2012,159,391,2010,154,394,2013,157,393,2011,154,390,2013,155,390,2013,155,391,2014,153,393,2015,156,381,2014,163,367,2031,147,382,2011,153,421,2002,169,415,2006,149,400,2016,154,399,2015,159,395,2008,152,392,2008,149,399,2009,161,404,2012,162,402,2012,158,395,2008,155,398,2008,157,403,2012,158,405,2011,156,401,2011,158,405,2009,158,401,2012,158,402,2011,159,399,2008,156,401,2011,158,402,2009,154,403,2009,155,402,2011,158,400,2010,158,402,2009,160,400,2010,154,399,2011,153,399,2009,156,400,2011,157,402,2013,153,399,2012,155,399,2011,158,399,2012}, +{53, 157,401,2011,157,398,2012,155,398,2011,154,396,2009,154,402,2011,159,400,2012,156,399,2012,159,398,2011,157,394,2008,155,399,2012,158,399,2011,155,398,2014,156,397,2011,156,398,2014,157,394,2009,155,395,2011,156,395,2012,156,393,2008,155,395,2014,157,398,2012,155,396,2013,154,397,2012,159,399,2014,158,392,2009,154,394,2011,157,395,2010,156,397,2015,158,400,2013,157,398,2012,156,397,2011,158,397,2009,160,395,2010,156,399,2011,158,402,2011,158,404,2012,157,401,2011,156,402,2012,157,404,2008,159,404,2010,158,403,2011,157,402,2012,157,404,2009,158,406,2010,160,405,2012,156,403,2011,156,401,2010,159,403,2008,159,404,2010,159,408,2010,158,408,2012,159,405,2010,157,397,2006,160,406,2012}, +{52, 160,407,2009,154,407,2013,160,403,2009,160,402,2008,159,405,2012,157,403,2010,156,404,2010,158,405,2010,157,407,2011,159,405,2009,158,402,2010,159,405,2010,160,406,2009,158,406,2012,156,408,2011,157,405,2008,159,405,2010,162,406,2007,156,404,2009,157,405,2008,159,405,2010,160,408,2010,157,405,2010,156,405,2008,161,402,2007,156,407,2014,159,405,2006,154,405,2013,158,410,2012,159,403,2009,156,405,2009,161,403,2006,157,405,2011,154,407,2012,157,404,2011,155,404,2013,158,402,2008,158,402,2013,157,403,2011,158,402,2009,157,402,2010,157,405,2011,157,406,2009,155,406,2011,156,406,2009,155,405,2011,159,404,2008,157,404,2007,157,407,2011,159,406,2008,156,407,2012,161,405,2007}, +{52, 157,406,2009,156,406,2011,159,408,2011,160,407,2007,158,408,2009,160,404,2011,158,405,2008,157,404,2008,158,407,2014,157,405,2011,156,408,2010,157,405,2007,158,407,2011,159,407,2009,156,405,2010,154,404,2007,158,407,2008,158,408,2009,158,405,2009,157,405,2007,158,405,2010,158,407,2007,159,407,2010,158,405,2009,155,406,2007,158,406,2008,157,409,2011,160,407,2006,156,406,2009,160,404,2005,154,405,2011,160,411,2012,157,407,2010,155,406,2011,158,402,2010,156,404,2006,161,408,2012,159,407,2006,154,406,2011,158,407,2011,159,405,2011,158,405,2010,156,404,2008,156,406,2010,157,408,2010,160,405,2009,153,403,2007,157,405,2008,157,408,2008,159,410,2011,159,405,2007,156,406,2007}, +{53, 157,405,2014,159,407,2006,156,411,2013,160,405,2004,159,407,2009,160,405,2006,153,406,2012,158,405,2005,156,409,2013,158,406,2007,157,404,2010,158,405,2009,159,408,2011,158,404,2010,156,402,2009,158,404,2010,158,406,2009,157,407,2012,157,405,2012,159,403,2008,159,404,2010,158,404,2010,157,407,2008,157,406,2012,157,405,2009,158,403,2009,157,407,2010,159,406,2011,159,406,2011,158,403,2008,157,406,2013,157,407,2011,155,409,2012,158,406,2008,156,406,2011,162,404,2006,159,403,2008,158,407,2010,158,408,2013,159,405,2011,155,408,2012,158,407,2010,157,407,2007,157,408,2010,158,405,2010,157,405,2008,159,407,2011,159,407,2012,156,405,2010,156,405,2008,157,406,2011,157,404,2009,156,405,2012}, +{52, 159,405,2010,159,400,2010,158,399,2009,155,404,2011,156,406,2013,155,405,2009,155,402,2012,160,401,2012,156,398,2009,158,402,2011,160,403,2009,157,403,2009,154,398,2013,154,405,2011,157,402,2009,155,402,2014,159,400,2010,155,397,2010,158,401,2011,158,404,2013,155,405,2012,156,400,2009,153,400,2011,158,399,2008,159,401,2012,155,400,2010,156,399,2008,159,404,2010,156,402,2012,153,399,2010,154,400,2010,158,402,2010,158,403,2011,160,401,2009,156,402,2014,157,404,2007,152,401,2012,157,403,2008,159,402,2011,158,405,2009,158,401,2010,158,403,2010,155,401,2008,156,404,2012,156,407,2012,156,405,2011,156,402,2010,158,402,2011,159,403,2009,155,400,2011,154,404,2012,159,405,2010}, +{52, 157,404,2012,157,404,2010,156,401,2009,155,402,2011,157,406,2012,161,403,2012,156,402,2012,156,402,2009,158,405,2013,157,404,2011,155,405,2012,157,403,2008,157,404,2011,159,404,2009,157,403,2008,157,405,2008,157,406,2012,156,405,2010,155,404,2009,156,403,2009,158,407,2008,157,406,2010,157,409,2010,158,403,2010,157,403,2008,157,403,2009,157,407,2012,160,402,2009,158,402,2010,158,400,2009,155,403,2008,156,405,2012,158,406,2011,159,403,2010,156,399,2012,157,400,2013,158,404,2007,156,403,2013,158,405,2011,155,399,2008,157,403,2013,160,403,2008,159,401,2014,160,403,2011,157,401,2011,161,405,2011,155,394,2007,151,401,2009,160,404,2010,158,404,2014,159,397,2008,158,400,2008}, +{53, 157,404,2011,157,401,2012,158,396,2010,156,397,2009,155,401,2010,158,404,2012,160,400,2012,158,397,2008,158,400,2010,156,404,2013,160,405,2009,156,401,2009,156,404,2011,158,401,2006,157,404,2007,161,405,2009,160,403,2008,159,408,2013,167,414,2010,168,405,2007,155,396,2006,154,394,2007,161,400,2008,163,399,2008,162,390,2008,155,392,2014,147,396,2024,159,365,2019,177,274,2086,159,354,2003,160,433,1978,145,472,1978,124,461,2001,145,446,2029,156,437,1987,152,444,1982,164,351,2016,134,333,2034,144,399,2014,177,420,2013,152,416,2013,143,414,2012,156,426,2011,159,453,1983,159,411,2010,146,366,2029,143,385,2013,162,417,2007,160,417,2005,151,410,1998,149,413,2024,171,416,2002,149,391,1996}, +{52, 147,423,2013,163,416,2007,143,434,2023,154,418,2010,152,423,2013,157,415,2004,157,415,1997,147,449,1979,160,416,2015,154,384,2029,144,410,2005,157,416,2006,157,414,2004,150,412,2007,157,416,2005,154,420,2007,152,421,2012,157,417,2010,156,413,2007,156,415,2007,156,413,2007,155,417,2010,156,409,2004,150,412,2010,154,417,2006,152,414,2012,154,417,2010,157,409,2006,156,411,2008,153,414,2011,154,418,2011,156,417,2009,156,420,2009,160,421,2007,148,433,2012,150,456,1968,156,466,1996,161,381,2024,147,358,2034,147,396,1999,165,401,2002,165,429,2017,167,409,2010,147,409,2014,158,413,2006,159,423,2016,160,415,2016,159,407,2010,161,402,2000,157,410,2007,162,420,2010,162,425,2008}, +{52, 162,427,2011,164,419,2006,153,423,1989,158,425,1990,170,379,2026,150,415,2006,165,422,2011,162,414,2010,156,409,2007,162,404,2006,162,412,2009,158,410,2011,155,409,2012,158,408,2011,162,405,2011,156,399,2007,155,401,2010,159,401,2009,160,402,2007,156,402,2012,157,402,2011,157,402,2011,159,405,2011,159,402,2011,158,404,2010,159,400,2010,157,404,2009,158,399,2009,159,403,2011,159,399,2007,154,404,2012,158,407,2011,160,405,2009,158,402,2010,157,404,2012,159,402,2008,162,406,2010,159,405,2010,158,405,2009,157,405,2011,157,404,2010,157,403,2012,160,404,2010,158,405,2011,157,407,2009,158,404,2012,158,404,2010,156,402,2009,156,406,2008,157,404,2010,160,403,2009,159,401,2009}, +{52, 158,403,2010,155,405,2012,159,400,2008,157,404,2012,157,402,2010,152,401,2012,158,403,2009,158,402,2011,156,403,2011,159,402,2011,157,402,2011,155,399,2009,156,401,2010,153,402,2012,155,403,2011,157,403,2009,155,401,2011,157,402,2010,156,398,2010,155,402,2011,156,403,2010,154,404,2014,155,400,2008,155,403,2011,157,401,2010,157,401,2012,156,398,2013,156,396,2009,155,400,2010,156,405,2011,151,401,2013,156,395,2010,158,393,2010,150,403,2021,161,399,2005,154,386,2008,153,410,2015,152,392,2012,153,395,2015,161,396,2011,156,394,2011,152,392,2011,154,399,2010,152,398,2011,152,396,2015,153,395,2015,153,395,2011,158,398,2012,158,396,2011,155,396,2016,155,395,2011,152,393,2010}, +{52, 151,397,2010,154,400,2013,155,398,2016,158,396,2012,157,393,2011,153,395,2014,155,399,2011,152,399,2009,151,396,2011,152,395,2013,156,395,2010,156,395,2011,156,396,2010,154,397,2013,155,396,2012,154,399,2012,153,398,2011,150,395,2013,155,396,2010,156,398,2012,157,398,2012,155,397,2014,154,397,2013,154,396,2013,152,397,2011,155,400,2013,154,401,2011,156,398,2014,157,395,2009,153,396,2011,154,399,2011,154,400,2009,154,397,2011,155,397,2010,153,396,2012,155,400,2013,157,400,2011,154,400,2013,156,395,2012,155,397,2011,155,397,2010,152,400,2013,154,402,2013,154,398,2012,155,398,2012,152,398,2012,153,401,2012,155,400,2011,154,398,2011,152,399,2012,154,399,2013,154,399,2012}, +{53, 154,399,2014,153,397,2011,155,398,2012,154,399,2013,156,399,2012,154,400,2012,154,399,2010,155,396,2012,155,398,2011,155,397,2009,155,399,2011,153,400,2012,154,401,2013,155,398,2010,153,398,2010,155,399,2011,155,400,2013,154,399,2012,155,399,2008,153,398,2010,156,401,2010,156,402,2010,154,398,2012,155,400,2011,157,400,2012,153,401,2014,156,400,2011,154,398,2012,157,399,2012,154,398,2011,153,398,2012,155,401,2011,153,402,2011,154,400,2015,155,396,2012,153,397,2009,155,399,2012,155,399,2011,154,398,2010,156,398,2010,154,397,2010,155,400,2014,157,401,2013,154,397,2010,153,398,2014,157,397,2012,153,397,2011,153,397,2012,155,400,2011,156,398,2012,155,395,2009,155,397,2012,155,401,2011}, +{52, 154,398,2011,154,398,2011,155,396,2011,154,397,2013,157,396,2011,156,400,2012,156,399,2012,154,397,2012,155,398,2012,155,398,2012,157,399,2011,154,398,2009,157,397,2010,156,399,2013,157,398,2011,152,400,2012,154,400,2011,157,398,2010,155,398,2011,155,399,2010,156,399,2012,158,401,2014,156,401,2011,152,398,2012,151,397,2013,156,398,2011,156,398,2011,153,398,2011,154,398,2012,154,399,2010,158,400,2015,156,397,2011,154,397,2012,153,399,2013,153,399,2015,157,398,2009,154,396,2013,154,397,2015,155,398,2013,154,397,2010,154,396,2012,156,398,2011,155,396,2010,155,395,2012,155,396,2012,157,395,2011,154,398,2014,153,395,2010,152,395,2012,154,398,2012,155,397,2012,155,396,2013}, +{52, 153,395,2012,155,395,2010,154,398,2014,159,399,2013,154,398,2012,154,397,2012,153,396,2010,156,396,2011,158,397,2013,157,398,2013,154,398,2012,153,399,2012,154,400,2013,154,397,2010,152,396,2015,154,399,2011,157,398,2013,158,400,2012,154,398,2013,152,397,2009,154,399,2013,153,400,2012,154,398,2014,153,397,2012,156,398,2013,156,398,2013,157,399,2012,154,400,2013,152,401,2016,156,403,2010,153,398,2012,154,397,2012,155,397,2009,155,402,2011,156,403,2011,154,398,2009,154,402,2009,157,406,2011,158,411,2014,157,404,2010,155,402,2007,157,400,2007,157,402,2010,158,403,2010,154,409,2015,159,407,2011,157,403,2012,156,397,2009,154,395,2008,158,395,2010,154,392,2005,152,399,2012}, +{53, 156,400,2012,153,398,2014,151,394,2011,149,391,2011,150,395,2013,156,396,2014,155,393,2012,154,389,2010,155,393,2014,157,395,2015,154,394,2011,151,395,2014,153,397,2012,154,394,2013,154,396,2014,152,395,2014,157,398,2013,157,397,2012,154,395,2012,152,400,2015,155,394,2011,155,392,2012,154,389,2010,152,396,2013,157,397,2013,153,395,2016,154,395,2013,157,390,2008,153,391,2014,155,393,2010,151,396,2016,157,397,2015,156,391,2015,152,391,2011,153,392,2014,157,393,2013,154,393,2014,155,393,2015,155,390,2010,156,392,2013,158,395,2014,156,392,2014,155,392,2012,154,393,2011,157,395,2012,156,395,2013,157,395,2012,155,390,2011,154,394,2012,159,393,2009,155,395,2015,155,393,2014,153,391,2014}, +{52, 155,394,2011,156,394,2011,155,393,2014,156,394,2010,151,395,2013,156,398,2013,156,393,2010,155,394,2012,156,397,2012,156,403,2015,157,397,2012,152,394,2011,156,395,2009,161,406,2010,165,409,2013,156,412,2012,155,402,2008,157,397,2004,156,407,2007,161,416,2012,155,414,2012,153,406,2007,156,402,2006,159,409,2008,163,406,2006,159,402,2010,158,407,2010,159,411,2015,158,404,2011,156,393,2011,153,396,2009,158,401,2011,162,409,2013,155,402,2013,151,398,2012,156,394,2009,157,395,2010,156,397,2013,157,397,2012,158,401,2012,159,398,2010,155,396,2013,157,396,2010,158,393,2012,157,402,2012,156,399,2010,154,401,2011,153,397,2009,157,396,2010,158,393,2009,155,399,2011,155,402,2015}, +{52, 158,404,2015,155,396,2014,154,395,2012,154,396,2013,158,403,2012,159,401,2011,156,398,2010,155,396,2011,155,393,2009,158,398,2010,156,400,2012,155,402,2013,156,397,2012,156,397,2015,156,396,2012,155,395,2010,158,396,2006,149,396,2017,166,397,2005,146,394,2013,166,403,2013,154,382,2013,156,396,2010,162,395,2011,156,402,2014,156,393,2014,154,391,2012,156,392,2012,160,396,2013,156,394,2014,158,390,2010,153,392,2013,155,394,2010,156,393,2013,155,392,2012,154,392,2011,156,396,2013,157,394,2011,157,392,2016,156,391,2010,152,393,2012,156,398,2012,159,401,2010,156,393,2012,157,394,2012,156,395,2011,157,401,2012,158,402,2012,156,402,2014,157,396,2008,156,396,2010,158,401,2010}, +{52, 159,404,2013,158,402,2011,158,399,2010,157,399,2010,159,401,2013,155,403,2014,155,401,2011,156,401,2009,160,401,2010,160,399,2010,156,397,2011,156,398,2009,157,401,2013,158,402,2014,155,399,2009,157,397,2010,160,401,2010,160,400,2012,156,400,2011,159,396,2011,156,399,2008,157,408,2013,158,406,2015,154,397,2011,156,390,2006,158,395,2007,160,403,2011,157,406,2015,157,401,2015,155,393,2008,155,392,2008,158,398,2011,158,396,2014,156,393,2012,154,395,2012,156,399,2015,154,396,2018,152,385,2019,150,382,2008,160,408,2004,165,408,2013,152,394,2013,150,395,2009,160,401,2011,156,404,2013,154,398,2013,157,395,2009,159,402,2012,156,402,2014,156,402,2011,159,398,2009,155,398,2012}, +{53, 155,400,2008,154,404,2014,158,404,2009,156,399,2012,157,400,2010,156,403,2009,155,402,2013,156,401,2014,158,397,2008,158,401,2012,156,404,2013,156,401,2007,157,399,2009,155,401,2010,157,401,2013,156,401,2012,155,399,2010,156,402,2009,159,403,2013,155,401,2012,157,398,2009,153,401,2010,155,400,2012,155,403,2016,156,397,2008,153,398,2008,157,399,2013,157,399,2013,157,403,2014,160,399,2010,156,399,2012,157,401,2013,155,400,2014,157,403,2013,158,399,2008,157,400,2009,156,402,2013,157,401,2013,156,404,2013,157,397,2007,157,402,2012,160,405,2011,159,405,2011,156,400,2011,158,399,2010,158,398,2007,156,401,2011,154,401,2012,157,402,2011,158,402,2013,159,392,2021,153,407,2010,161,394,2000}, +{52, 150,402,2014,161,398,2010,159,401,2013,158,402,2015,156,398,2015,158,396,2010,156,395,2011,157,400,2011,158,403,2014,156,400,2011,155,399,2011,155,396,2009,155,397,2010,156,399,2010,157,404,2014,157,404,2014,156,400,2011,155,402,2006,157,403,2011,157,402,2009,154,398,2005,155,399,2016,163,410,2011,155,397,2004,155,403,2013,158,394,2011,156,402,2013,164,405,2012,158,405,2016,149,396,2010,151,397,2010,160,400,2009,158,402,2009,151,398,2007,151,400,2009,158,403,2008,159,405,2012,158,402,2009,158,404,2008,160,409,2009,155,409,2011,152,408,2012,161,404,2005,166,401,2005,161,411,2009,163,408,2007,165,411,2008,160,407,2010,158,410,2011,157,404,2008,156,404,2011,160,405,2007}, +{52, 160,408,2012,160,414,2012,159,408,2010,158,403,2008,161,399,2001,159,402,2006,162,409,2009,156,410,2015,154,406,2011,166,399,2007,156,402,2011,159,404,2010,161,410,2011,156,404,2014,155,399,2009,161,397,2005,155,400,2009,157,404,2013,160,407,2011,160,403,2008,162,402,2010,154,400,2010,154,403,2011,161,403,2007,161,405,2010,157,407,2013,156,399,2006,160,401,2009,165,396,2005,154,409,2013,162,413,2013,160,408,2013,153,398,2008,158,396,2004,163,407,2010,167,412,2015,161,395,2009,152,390,2006,158,398,2009,165,416,2019,159,411,2018,149,397,2011,156,392,2006,163,401,2011,160,404,2013,157,392,2007,157,390,2004,158,393,2007,159,409,2015,167,420,2020,161,398,2010,151,392,2010}, +{53, 164,398,2005,161,405,2015,159,403,2012,157,397,2008,157,403,2009,161,405,2012,161,406,2015,159,401,2008,156,402,2008,161,406,2010,160,407,2009,158,408,2012,160,402,2008,159,407,2007,158,404,2007,161,407,2010,156,403,2009,156,409,2012,171,404,2009,154,411,2016,154,402,2007,160,405,2009,163,405,2009,159,403,2011,159,401,2009,160,408,2012,160,403,2008,155,403,2010,161,398,2008,159,400,2010,158,412,2013,164,412,2015,161,404,2011,161,394,2006,160,390,2004,157,399,2010,163,410,2016,161,409,2020,159,400,2012,159,393,2009,157,392,2009,162,394,2010,162,398,2011,160,394,2012,156,399,2018,161,403,2015,161,399,2014,154,397,2015,156,390,2012,165,386,2004,161,398,2013,157,404,2016,161,402,2013}, +{52, 157,394,2012,157,394,2008,165,393,2008,165,396,2010,160,403,2013,158,403,2014,158,403,2015,160,398,2011,158,394,2008,160,401,2013,164,400,2009,162,399,2011,157,397,2010,161,399,2009,160,405,2013,158,398,2009,156,401,2012,164,401,2009,164,401,2014,159,397,2011,158,397,2011,160,393,2010,159,396,2011,160,397,2012,158,395,2015,161,394,2011,161,393,2011,159,392,2012,158,391,2011,157,395,2015,161,398,2013,156,394,2013,158,396,2013,158,390,2010,159,394,2013,161,392,2010,155,395,2012,161,397,2012,160,398,2014,154,396,2013,153,392,2010,162,399,2012,166,396,2009,157,395,2014,159,394,2009,161,395,2010,159,404,2015,159,401,2014,157,394,2013,160,395,2010,162,397,2012,163,399,2012}, +{52, 158,396,2012,155,397,2012,159,395,2011,161,395,2013,161,396,2013,158,397,2014,157,398,2014,160,394,2013,160,393,2010,159,397,2013,157,394,2013,156,394,2014,159,393,2010,160,394,2011,158,393,2012,156,392,2011,155,394,2015,158,394,2011,156,393,2014,158,395,2013,159,392,2012,157,390,2011,157,394,2012,157,394,2013,157,393,2013,155,393,2012,156,395,2012,156,390,2012,159,390,2011,161,392,2012,161,393,2013,156,392,2010,155,391,2014,156,388,2013,154,388,2012,159,390,2012,158,394,2014,157,390,2013,157,393,2015,160,391,2013,157,392,2010,157,391,2012,157,393,2014,153,388,2012,157,390,2012,164,391,2013,161,397,2013,158,394,2014,155,394,2013,157,390,2012,161,392,2014,157,395,2013}, +{53, 157,397,2013,162,396,2010,163,396,2013,161,390,2006,159,394,2012,158,397,2011,155,400,2012,156,397,2011,164,398,2013,163,392,2009,157,390,2013,158,388,2009,160,400,2012,160,404,2015,153,398,2017,149,388,2010,158,391,2010,173,395,2009,168,395,2014,152,391,2015,148,392,2012,160,393,2011,159,397,2012,154,393,2013,155,394,2011,165,393,2009,165,393,2011,156,392,2013,156,393,2009,155,397,2015,162,399,2012,159,395,2014,159,391,2010,160,394,2010,162,398,2010,160,401,2013,157,392,2009,154,395,2013,160,399,2012,162,399,2012,160,399,2011,158,398,2013,160,394,2012,159,394,2010,156,399,2012,156,400,2012,160,396,2011,156,396,2009,157,398,2010,162,401,2017,165,398,2008,156,396,2013,159,398,2010}, +{52, 155,394,2014,156,398,2012,159,397,2012,159,402,2013,161,397,2014,160,394,2011,161,394,2010,157,394,2013,156,398,2014,156,397,2013,159,394,2010,159,394,2013,159,392,2012,158,393,2013,160,391,2015,157,393,2012,159,396,2011,158,393,2013,157,392,2013,159,390,2011,160,392,2010,157,395,2011,156,395,2012,158,393,2014,157,393,2014,161,388,2012,160,392,2012,157,393,2010,152,394,2013,155,391,2013,158,390,2014,158,392,2016,157,390,2014,158,387,2010,159,392,2012,161,393,2013,155,389,2013,155,390,2013,157,390,2012,158,391,2016,160,388,2013,153,387,2014,155,390,2013,157,388,2014,157,394,2015,159,391,2012,156,387,2013,161,389,2014,162,392,2015,159,391,2011,153,394,2011,153,392,2016}, +{52, 155,388,2014,160,384,2011,159,391,2013,162,389,2012,157,394,2018,157,388,2014,152,385,2009,159,384,2011,156,389,2016,155,388,2014,158,391,2015,163,385,2015,163,385,2010,159,382,2011,158,391,2015,156,391,2017,156,393,2018,161,390,2015,159,386,2014,157,384,2013,162,383,2011,162,388,2013,161,391,2013,158,391,2014,155,397,2015,158,395,2013,159,388,2011,159,383,2008,162,386,2011,161,387,2011,156,394,2015,155,395,2011,155,396,2016,159,391,2013,158,389,2012,160,387,2013,161,393,2014,161,390,2013,158,393,2014,159,388,2011,156,387,2012,156,393,2014,158,390,2014,159,388,2013,160,387,2011,160,390,2014,160,388,2014,158,388,2012,156,390,2014,158,392,2016,157,389,2014,158,386,2013}, +{53, 160,388,2012,161,388,2013,155,389,2015,155,387,2012,156,387,2011,156,389,2012,157,390,2016,157,385,2013,157,385,2013,163,387,2011,159,390,2016,158,389,2014,156,387,2013,158,387,2010,156,388,2016,158,387,2012,158,385,2015,161,386,2010,157,390,2015,158,387,2009,155,386,2014,159,391,2014,158,389,2013,157,387,2015,157,384,2014,157,385,2013,158,387,2014,157,388,2014,156,389,2014,159,386,2011,159,387,2012,159,389,2012,155,384,2013,154,390,2015,162,385,2008,152,386,2021,163,390,2011,154,385,2015,158,385,2013,157,387,2013,159,388,2017,158,383,2012,154,384,2015,158,384,2012,156,385,2014,159,386,2014,158,385,2017,158,386,2011,156,388,2013,159,392,2014,156,386,2014,158,387,2012,159,386,2009}, +{52, 158,390,2015,157,390,2015,155,387,2012,158,390,2013,161,388,2014,158,390,2016,161,391,2014,163,391,2011,161,389,2010,154,388,2011,153,389,2012,161,392,2015,163,389,2010,158,393,2016,160,389,2009,155,391,2013,160,389,2010,159,390,2013,156,383,2011,156,388,2015,160,385,2012,160,389,2017,163,380,2017,155,367,2027,151,390,2009,168,407,2001,161,395,2012,151,393,2016,160,395,2015,162,394,2014,157,391,2011,159,392,2009,163,390,2008,159,387,2011,158,392,2012,164,398,2012,161,406,2016,161,404,2019,160,396,2012,158,395,2007,157,387,2005,157,398,2010,165,402,2013,163,408,2013,156,395,2009,156,397,2009,159,397,2011,158,399,2013,161,401,2014,165,400,2010,159,398,2014,157,396,2010}, +{52, 154,398,2013,165,403,2010,166,402,2009,155,401,2014,159,403,2009,163,397,2008,163,399,2006,160,404,2011,156,409,2013,161,413,2015,165,401,2004,154,401,2011,165,409,2009,165,408,2012,155,400,2008,163,397,2003,162,406,2012,159,402,2009,154,399,2011,160,402,2008,162,403,2016,164,399,2013,161,395,2008,162,397,2011,162,407,2015,164,397,2011,156,390,2011,160,389,2008,160,396,2010,163,401,2013,163,400,2015,161,393,2010,161,390,2011,157,395,2013,158,399,2016,163,400,2016,162,393,2010,160,393,2011,163,392,2009,159,395,2012,160,396,2009,159,397,2011,160,395,2013,161,398,2013,159,393,2011,154,394,2012,160,397,2011,162,397,2011,157,394,2015,158,393,2011,159,394,2012,160,402,2011}, +{53, 159,397,2010,159,397,2013,161,396,2009,155,390,2010,162,397,2012,163,396,2011,157,393,2014,162,395,2011,158,395,2014,162,394,2013,158,394,2013,160,392,2008,160,390,2008,157,393,2012,159,393,2012,160,397,2014,161,398,2014,157,391,2011,157,388,2011,158,390,2012,159,396,2014,161,397,2015,161,391,2014,159,384,2010,157,391,2007,157,397,2015,162,395,2014,158,393,2013,154,390,2010,157,390,2013,161,388,2010,159,385,2013,159,390,2012,158,388,2012,158,388,2015,159,379,2022,154,382,2017,156,407,2000,170,400,2012,156,396,2018,159,390,2012,160,390,2011,156,390,2010,158,392,2011,161,390,2013,156,393,2016,157,387,2012,156,385,2011,158,388,2015,162,375,2024,153,378,2013,157,403,2002,163,402,2007}, +{52, 152,389,2014,153,386,2011,159,389,2015,162,384,2011,156,385,2019,158,386,2019,160,399,2014,162,391,2014,152,385,2012,156,390,2012,161,393,2014,160,393,2013,162,391,2010,160,396,2012,165,396,2010,158,401,2014,159,397,2009,160,388,2007,161,399,2012,165,393,2006,160,399,2014,159,403,2016,159,408,2014,168,405,2012,163,402,2013,157,395,2008,160,396,2005,161,404,2007,158,404,2008,158,408,2013,162,401,2008,155,404,2013,169,403,2005,165,406,2013,157,403,2013,158,399,2009,162,408,2013,164,406,2011,159,399,2009,157,399,2011,163,400,2006,159,405,2011,159,407,2012,157,404,2010,161,404,2011,163,402,2014,163,398,2008,160,399,2008,163,407,2010,159,409,2012,155,406,2010,152,396,2008}, +{52, 162,404,2010,171,404,2010,163,403,2011,157,402,2007,155,406,2010,156,406,2016,161,401,2007,161,402,2010,162,403,2012,162,403,2009,162,402,2005,158,401,2009,157,404,2009,159,404,2009,159,404,2014,168,404,2012,163,399,2008,159,398,2009,158,399,2009,160,404,2011,159,403,2011,158,408,2012,162,407,2012,162,403,2012,159,397,2008,160,401,2010,164,403,2010,161,401,2010,159,400,2011,158,403,2008,157,403,2011,161,404,2012,160,401,2011,161,400,2010,163,401,2011,162,403,2013,158,398,2007,157,402,2011,163,400,2010,160,398,2011,159,399,2011,165,403,2012,161,402,2010,155,400,2012,159,396,2009,160,400,2011,162,400,2012,159,401,2013,162,400,2009,160,399,2010,161,397,2013,162,399,2012}, +{53, 159,399,2010,160,402,2016,158,399,2010,161,396,2010,164,399,2010,159,398,2011,157,393,2012,162,397,2012,164,399,2010,158,402,2014,158,399,2012,161,397,2012,159,401,2012,167,399,2007,158,402,2015,157,401,2011,157,398,2009,162,401,2007,160,405,2012,162,402,2010,159,403,2013,161,402,2011,162,403,2010,161,398,2009,158,405,2011,160,406,2014,164,405,2007,158,396,2012,160,399,2009,161,400,2013,162,404,2011,160,401,2013,160,401,2009,154,400,2019,162,401,2012,160,393,2008,160,401,2009,161,399,2010,156,399,2010,160,401,2015,161,397,2010,158,398,2010,160,398,2010,162,398,2011,161,399,2010,159,400,2011,160,400,2012,158,400,2010,158,398,2013,158,397,2009,163,397,2010,163,401,2011,162,400,2010}, +{52, 157,400,2013,165,405,2014,162,402,2008,156,401,2012,164,400,2009,160,397,2009,158,401,2010,160,405,2011,158,406,2014,162,407,2013,164,399,2006,161,394,2006,160,396,2006,163,408,2013,159,406,2013,156,404,2012,161,401,2009,165,400,2012,161,393,2009,158,396,2010,162,400,2015,161,397,2012,155,398,2013,161,401,2012,160,396,2010,157,392,2012,160,395,2009,159,399,2012,159,399,2015,164,396,2013,160,397,2012,157,398,2011,159,400,2013,165,398,2008,159,393,2007,156,400,2012,160,402,2011,161,400,2012,163,397,2011,163,402,2008,161,403,2012,162,402,2013,159,400,2010,159,397,2007,161,398,2010,163,403,2014,163,403,2008,165,404,2012,168,406,2012,163,402,2010,157,401,2011,160,404,2011}, +{52, 161,403,2005,161,404,2012,167,403,2010,166,402,2009,161,402,2009,159,404,2010,163,398,2009,158,396,2010,156,408,2016,172,407,2012,169,406,2014,157,394,2011,160,392,2005,158,391,2008,157,401,2013,164,404,2014,165,402,2013,161,395,2009,160,394,2007,163,396,2009,160,402,2016,161,401,2011,160,402,2013,162,400,2012,161,397,2011,161,398,2009,165,400,2009,162,401,2012,164,403,2008,160,402,2010,160,401,2011,161,396,2008,163,398,2007,161,403,2015,166,400,2013,162,398,2011,160,398,2014,159,398,2012,161,394,2012,165,397,2011,162,398,2013,161,397,2013,160,396,2011,160,394,2009,163,395,2012,164,396,2014,162,398,2013,159,397,2012,161,398,2013,163,392,2010,160,392,2009,160,396,2011}, +{58, 165,399,2011,162,398,2012,162,398,2014,157,393,2012,158,396,2009,161,397,2011,162,395,2012,166,396,2011,161,395,2008,161,399,2014,164,396,2007,158,395,2012,158,397,2014,160,392,2010,161,396,2009,163,397,2014,162,398,2014,163,393,2010,161,394,2013,160,396,2010,160,395,2012,161,396,2011,164,394,2010,162,394,2017,161,398,2010,163,388,2009,163,405,2013,161,391,2011,157,396,2017,163,387,2006,161,399,2017,166,394,2009,158,394,2014,160,394,2011,159,393,2012,159,392,2012,161,396,2012,161,400,2013,164,395,2013,162,392,2012,160,388,2009,159,394,2012,161,397,2014,160,396,2013,159,395,2015,160,393,2012,160,392,2013,163,392,2011,161,393,2014,159,394,2013,159,397,2013,161,394,2014,162,393,2012,160,391,2010,160,395,2012,164,393,2010,160,391,2012,157,400,2018}, +{52, 164,389,2004,153,390,2017,165,391,2009,159,392,2012,164,396,2012,159,395,2017,165,392,2007,162,393,2009,160,398,2017,165,394,2010,160,390,2009,162,398,2012,161,399,2014,159,399,2011,161,400,2014,166,402,2010,163,401,2009,158,405,2011,162,403,2013,163,402,2007,161,410,2010,161,412,2010,162,406,2010,163,393,1999,162,407,2010,166,417,2011,159,406,2010,157,406,2010,167,410,2011,160,397,2009,158,390,2006,164,397,2005,164,407,2017,167,408,2016,162,395,2011,159,396,2006,160,395,2013,163,396,2014,161,391,2012,162,392,2009,163,393,2013,164,392,2011,162,393,2014,163,392,2011,157,389,2013,159,389,2013,161,387,2010,163,390,2011,162,394,2015,163,391,2014,163,387,2009,159,387,2013}, +{52, 158,392,2014,161,391,2013,159,390,2013,160,390,2010,161,387,2010,162,390,2010,158,391,2012,159,390,2010,156,388,2012,160,387,2012,160,393,2016,161,397,2016,161,387,2015,163,382,2006,160,386,2010,161,391,2014,162,394,2017,165,391,2014,162,392,2013,162,391,2011,160,394,2013,163,388,2009,161,389,2011,160,393,2011,160,397,2014,162,396,2010,159,396,2013,161,393,2010,163,395,2014,166,395,2007,157,393,2014,163,399,2014,163,395,2011,158,393,2010,162,396,2014,161,393,2012,162,395,2013,163,393,2010,161,396,2011,163,394,2011,159,395,2014,161,393,2013,161,392,2010,164,395,2012,163,397,2016,163,393,2012,159,395,2012,165,397,2012,165,396,2010,161,394,2010,160,396,2012,164,399,2015}, +{53, 164,395,2013,162,398,2011,161,396,2011,164,394,2012,165,396,2010,161,392,2008,162,396,2014,167,394,2012,163,397,2012,161,394,2013,163,398,2015,166,391,2010,161,391,2012,161,394,2010,162,398,2013,164,394,2011,163,394,2014,162,394,2014,160,392,2011,161,392,2012,165,393,2012,163,395,2013,164,397,2014,164,393,2011,161,392,2013,164,394,2012,162,397,2014,163,397,2013,163,395,2014,167,395,2010,165,400,2010,163,401,2013,162,401,2015,164,397,2009,161,400,2010,162,400,2013,169,400,2009,164,397,2009,161,402,2008,168,404,2010,166,406,2014,161,401,2011,161,401,2008,166,401,2008,168,404,2015,165,399,2009,159,403,2010,163,409,2008,165,408,2013,159,400,2010,161,394,2005,164,399,2007,164,406,2014}, +{52, 170,404,2011,162,405,2010,160,403,2013,160,404,2013,166,397,2011,165,396,2008,162,397,2008,160,404,2012,165,404,2014,164,398,2011,160,396,2009,162,398,2011,164,400,2013,165,402,2010,167,402,2011,158,403,2010,160,398,2007,165,400,2009,165,397,2009,163,403,2012,163,405,2015,161,400,2010,165,396,2008,166,401,2010,162,404,2015,168,408,2013,162,406,2014,162,394,2007,160,393,2009,164,399,2007,161,405,2014,162,408,2013,164,400,2009,161,398,2010,167,399,2009,163,402,2012,162,402,2014,165,403,2009,164,404,2011,162,404,2010,162,399,2010,164,400,2009,163,400,2007,163,404,2011,166,404,2011,163,405,2010,163,401,2008,163,400,2011,164,400,2010,162,400,2009,160,403,2012,161,404,2011}, +{52, 164,398,2008,161,397,2007,162,396,2009,165,399,2010,165,399,2012,159,396,2013,161,396,2009,162,399,2012,161,398,2011,161,395,2012,161,394,2013,164,395,2012,163,394,2011,161,399,2017,161,396,2012,159,396,2013,160,393,2012,164,396,2013,163,394,2010,162,397,2014,162,396,2012,166,395,2013,164,391,2011,158,394,2012,164,393,2014,163,393,2013,159,392,2010,163,396,2010,162,395,2017,164,392,2010,161,391,2012,160,390,2014,161,393,2010,162,394,2015,162,395,2014,164,392,2009,162,393,2015,162,394,2016,162,395,2010,162,396,2017,163,391,2013,161,385,2011,162,385,2007,159,391,2011,164,404,2018,165,398,2018,158,386,2012,156,385,2004,157,391,2013,161,394,2018,171,395,2010,159,386,2011}, +{53, 161,394,2011,164,394,2013,163,394,2015,164,389,2008,157,397,2011,166,392,2008,164,395,2015,166,391,2006,161,393,2012,166,400,2015,162,398,2012,165,394,2011,164,392,2011,166,392,2007,165,393,2012,167,397,2016,166,392,2014,163,391,2009,164,389,2013,163,391,2013,160,385,2012,164,389,2015,168,387,2012,163,386,2015,163,389,2016,164,385,2013,163,383,2014,163,381,2012,160,388,2017,164,386,2014,164,383,2018,164,379,2011,164,379,2012,161,388,2019,161,384,2014,160,384,2016,167,382,2012,164,380,2014,165,383,2016,162,382,2011,161,385,2018,169,379,2012,162,371,2008,158,378,2015,164,376,2017,166,360,2057,156,354,2005,162,425,1995,183,403,2007,150,390,2018,159,384,2015,172,392,2015,163,389,2012}, +{52, 160,390,2015,168,398,2016,172,398,2013,164,396,2011,162,395,2011,163,401,2009,166,406,2012,167,417,1996,169,412,2005,171,375,2020,158,393,2016,172,404,2010,165,403,2009,157,399,2010,163,400,2008,165,401,2011,165,401,2013,172,396,2011,169,402,2010,166,401,2013,164,400,2010,162,397,2010,163,399,2012,165,398,2012,167,400,2013,167,395,2010,167,397,2011,167,394,2010,163,393,2012,165,395,2014,167,398,2014,165,396,2014,163,395,2015,169,393,2012,167,392,2011,165,391,2012,164,394,2011,164,396,2013,166,398,2011,166,393,2011,163,395,2012,166,394,2011,166,396,2011,168,399,2015,167,398,2011,165,395,2010,164,395,2010,164,396,2010,165,396,2013,166,396,2013,167,394,2010,164,397,2014}, +{52, 166,392,2010,165,393,2010,165,395,2009,165,392,2010,163,393,2013,167,395,2012,167,391,2014,165,394,2013,167,387,2007,164,394,2017,169,389,2009,163,388,2015,164,389,2011,163,392,2016,166,393,2014,165,392,2014,166,392,2012,164,388,2013,165,389,2010,166,389,2013,166,391,2015,164,389,2010,165,392,2012,166,393,2013,165,392,2010,164,392,2013,166,391,2009,167,390,2010,163,392,2010,164,393,2015,165,395,2012,167,392,2010,166,393,2014,164,396,2014,166,391,2009,166,391,2011,164,391,2011,164,394,2013,165,394,2015,168,392,2008,165,389,2010,166,393,2010,167,395,2012,165,395,2015,167,394,2009,164,395,2012,164,397,2014,166,397,2011,166,391,2006,163,392,2007,165,398,2007,165,403,2014}, +{52, 165,401,2012,166,400,2009,164,396,2012,165,396,2009,166,394,2010,165,403,2013,168,402,2012,168,401,2013,165,394,2009,161,394,2008,162,399,2009,167,403,2013,168,400,2010,165,394,2009,162,396,2013,167,398,2012,165,391,2012,164,397,2010,163,397,2012,165,401,2011,161,391,2012,162,398,2013,167,396,2013,165,392,2011,163,388,2004,160,394,2013,163,398,2014,164,394,2013,164,391,2014,169,394,2008,164,395,2012,165,398,2015,166,395,2012,164,393,2009,164,390,2010,165,398,2012,166,400,2014,167,394,2011,165,391,2012,167,392,2008,163,395,2016,165,394,2011,165,397,2014,164,393,2011,162,393,2014,166,391,2010,163,395,2013,166,396,2011,166,393,2013,164,390,2012,160,390,2012,164,392,2011}, +{53, 166,393,2012,161,393,2014,163,395,2013,165,391,2011,162,390,2011,162,392,2011,162,393,2010,164,393,2014,163,396,2012,163,392,2011,163,392,2011,163,395,2011,165,393,2012,165,395,2012,160,394,2014,163,393,2010,164,390,2011,164,391,2011,163,393,2015,161,393,2012,164,389,2012,163,391,2012,163,390,2013,162,391,2013,162,388,2013,164,391,2012,164,390,2011,161,393,2013,163,390,2013,163,387,2014,165,390,2013,165,390,2013,163,391,2012,161,393,2015,161,390,2013,165,388,2012,164,391,2016,165,390,2009,159,393,2014,167,392,2012,164,390,2010,160,389,2012,163,392,2013,164,393,2013,166,390,2015,166,389,2011,162,389,2011,161,389,2013,164,390,2011,162,389,2013,162,390,2014,162,387,2013,164,388,2013}, +{52, 164,387,2016,161,389,2013,162,390,2012,165,391,2014,162,388,2011,161,388,2013,165,391,2014,165,385,2013,162,389,2012,164,392,2013,161,395,2014,167,392,2013,162,388,2012,159,387,2010,165,392,2013,167,395,2014,165,393,2016,165,389,2011,162,388,2011,164,390,2014,164,393,2011,167,394,2015,167,393,2014,164,388,2010,163,390,2012,165,392,2013,165,390,2014,160,390,2015,164,392,2013,167,394,2010,167,390,2011,163,388,2015,163,391,2012,164,392,2014,164,392,2014,166,393,2015,164,391,2015,163,390,2012,167,390,2014,162,392,2013,162,393,2014,164,392,2013,167,393,2012,163,390,2013,164,390,2010,164,392,2012,166,391,2014,164,391,2014,163,390,2013,165,389,2013,162,390,2014,164,391,2011}, +{52, 163,391,2014,165,392,2013,168,389,2012,164,390,2012,163,389,2014,164,391,2012,162,391,2013,164,391,2014,164,388,2013,166,388,2013,163,388,2014,161,389,2012,161,388,2012,163,391,2014,165,392,2015,163,389,2014,166,386,2012,166,389,2010,163,393,2013,164,393,2014,164,390,2012,163,389,2012,162,389,2011,164,391,2012,165,390,2014,166,391,2014,164,392,2011,163,392,2014,164,391,2010,161,390,2013,165,391,2011,167,391,2013,165,388,2011,163,389,2012,165,390,2010,164,391,2014,163,395,2014,163,390,2012,166,388,2013,165,391,2010,163,391,2014,165,391,2013,163,391,2012,164,392,2013,164,392,2013,163,391,2013,164,390,2013,163,390,2013,164,388,2016,162,388,2011,163,391,2015,162,392,2014}, +{53, 162,390,2013,165,389,2011,164,391,2012,163,392,2013,162,392,2012,162,391,2013,163,393,2013,165,390,2013,164,390,2012,162,391,2012,163,389,2011,164,390,2012,162,393,2015,163,394,2015,163,392,2015,166,386,2011,166,388,2013,161,389,2012,161,390,2013,164,394,2015,164,393,2015,163,387,2013,163,387,2011,163,390,2012,166,390,2012,164,388,2014,161,389,2013,162,391,2012,165,392,2016,165,392,2014,160,388,2014,163,388,2013,167,391,2014,163,390,2012,163,391,2012,162,392,2011,160,392,2014,164,390,2014,164,389,2014,163,389,2011,163,390,2014,165,391,2014,162,390,2011,160,390,2014,161,391,2014,163,386,2014,164,386,2014,164,389,2013,165,390,2014,163,390,2013,162,390,2015,162,390,2011,163,390,2017}, +{52, 164,389,2012,165,388,2012,165,391,2012,162,390,2013,164,390,2015,161,388,2012,160,392,2014,163,393,2013,166,388,2011,161,388,2011,163,387,2013,165,391,2015,163,392,2011,162,391,2014,160,390,2010,162,390,2011,164,393,2013,163,389,2014,163,389,2012,164,390,2012,166,392,2013,162,388,2014,160,389,2015,161,391,2015,164,390,2013,165,387,2011,162,389,2012,164,391,2013,167,389,2014,162,389,2011,162,390,2012,161,390,2013,163,391,2013,165,388,2013,165,390,2012,165,389,2012,162,390,2012,161,387,2012,162,392,2012,164,390,2013,160,388,2013,163,389,2011,168,390,2013,164,391,2014,162,389,2015,163,390,2012,161,389,2013,161,390,2014,164,388,2014,163,385,2012,165,391,2016,165,389,2013}, +{52, 162,391,2014,162,391,2013,162,388,2014,162,387,2013,164,388,2010,165,389,2012,165,391,2012,162,389,2012,161,389,2014,162,391,2013,162,390,2014,166,388,2014,163,387,2013,162,389,2013,164,391,2015,162,389,2013,162,389,2011,162,386,2011,160,389,2011,162,389,2013,167,396,2012,162,392,2016,163,392,2015,162,389,2014,164,391,2013,165,388,2013,161,390,2013,161,390,2012,163,395,2014,166,390,2013,165,389,2012,161,390,2010,162,392,2014,164,387,2013,161,390,2013,165,390,2013,163,392,2013,164,392,2013,166,392,2010,163,386,2012,161,388,2012,161,385,2011,160,392,2011,165,389,2011,162,388,2015,163,384,2013,164,385,2015,165,386,2012,165,386,2011,159,387,2015,161,387,2013,160,387,2013}, +{53, 165,384,2013,164,386,2014,163,381,2013,163,384,2012,165,387,2014,161,393,2017,163,391,2016,162,389,2013,165,386,2011,166,386,2010,162,387,2011,164,390,2012,164,392,2016,161,389,2013,164,391,2014,166,392,2011,163,388,2012,162,388,2013,164,390,2011,163,389,2013,164,392,2012,162,392,2014,162,392,2013,164,387,2010,162,389,2013,165,391,2014,166,391,2012,163,392,2012,160,388,2013,160,388,2009,165,389,2013,166,389,2015,165,390,2012,163,388,2016,162,390,2013,162,392,2015,162,399,2017,162,398,2014,164,395,2012,164,393,2007,165,399,2012,167,398,2008,163,398,2007,158,399,2010,164,412,2010,167,409,2010,158,398,2009,161,395,2004,167,396,2006,166,403,2008,164,404,2014,162,406,2017,166,397,2007}, +{53, 167,395,2010,167,393,2010,161,389,2012,162,393,2013,166,393,2016,165,388,2013,162,386,2014,165,395,2014,166,394,2017,164,387,2014,165,379,2012,163,381,2007,160,388,2013,164,394,2018,164,388,2016,163,383,2013,165,380,2013,164,383,2010,164,388,2012,160,390,2014,161,386,2012,160,384,2012,159,386,2013,164,382,2014,164,384,2015,164,383,2015,162,385,2015,163,386,2015,161,382,2012,160,382,2016,160,381,2009,160,381,2013,163,384,2017,167,386,2017,167,386,2016,160,385,2019,159,376,2012,159,378,2011,162,384,2013,164,387,2014,162,382,2016,163,381,2015,165,383,2013,164,383,2016,162,379,2013,158,385,2014,159,385,2014,163,384,2016,165,379,2014,162,378,2013,164,383,2014,163,384,2015,158,383,2017}, +}; +static const uint32_t duration_SPO2[] = +{ +1013, +1048, +1062, +1059, +1037, +1062, +1065, +1038, +1058, +1060, +1040, +1058, +1060, +1039, +1060, +1060, +1036, +1061, +1061, +1040, +1059, +1062, +1035, +1060, +1062, +1034, +1062, +1059, +1060, +1038, +1060, +1061, +1036, +1060, +1061, +1037, +1062, +1063, +1037, +1059, +1060, +1145, +1059, +1063, +1036, +1062, +1062, +1037, +1059, +1061, +1035, +1060, +1061, +1048, +1047, +1064, +1048, +1049, +1063, +}; + +static const uint8_t frame_SPO2[] = +{ +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16, +17, +18, +19, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +30, +31, +32, +33, +34, +35, +36, +37, +38, +39, +40, +41, +42, +43, +44, +45, +46, +47, +48, +49, +50, +51, +52, +53, +54, +55, +56, +57, +58, +59, +}; + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/pxialg_spo2.h b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/pxialg_spo2.h new file mode 100644 index 000000000..fdda92655 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/pxialg_spo2.h @@ -0,0 +1,152 @@ +#ifndef __PXIALG_SPO2_H__ +#define __PXIALG_SPO2_H__ + + +#include + + +#if defined(WIN32) && !defined(PXIALG_STATIC_LIB) +# ifdef PXIALG_EXPORTS +# define PXIALG_API __declspec(dllexport) +# else +# define PXIALG_API __declspec(dllimport) +# endif +#else +# define PXIALG_API +#endif // WIN32 + +#pragma pack(1) +typedef struct SpO2_mems { + int16_t data[3]; +} SpO2_mems_t; + +typedef struct SpO2_info { + float IR_DC; + float R_DC; + float G_DC; + float IR_AC; + float R_AC; + float G_AC; + float R_IR_Ratio; + float R_G_Ratio; + float G_IR_Ratio; + float Noise; + float SpO2_ref; + float PI; + float PVI; + float RMS; + float MEMS; + float Output[5]; + float xyz_mean[3]; +} SpO2_info_t; +#pragma pack() + +typedef enum { + SPO2_MSG_SUCCESS = 0, + SPO2_MSG_ALG_NOT_OPEN, + SPO2_MSG_ALG_REOPEN, + SPO2_MSG_ALG_NOT_SUPPORT, + SPO2_MSG_INVALID_ARGUMENT, + SPO2_MSG_MOVING_SPO2_READY = 0x100, + SPO2_MSG_MOVING_SPO2_NOT_READY, + SPO2_MSG_MOVING_SPO2_STOP, +}spo2_msg_code_t; + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +PXIALG_API uint32_t SpO2_OpenSize(void); +PXIALG_API int SpO2_Open(void *mem); +PXIALG_API int SpO2_Close(void); +PXIALG_API int SpO2_GetSpO2(float *spo2); +PXIALG_API int SpO2_GetReadyFlag(uint8_t *ready_flag); +PXIALG_API int SpO2_GetPeriodicity(float *periodicity); +PXIALG_API int SpO2_Version(void); +PXIALG_API int SpO2_Process(int touch_flag, int total_channel, int *input, int samples_per_ch, float time_in); +PXIALG_API int SpO2_ProcessD(int touch_flag, int total_channel, int *input, int samples_per_ch, float time_in); +PXIALG_API int SpO2_GetFilteredData(int touch_flag, int total_channel, int expo_R, int expo_IR, int DAC_R, int DAC_IR, float **filter_R, float **filter_IR, int *FilteredDataLength); + +//parameters +PXIALG_API int SpO2_SetIIRFilterRatio(float IIRFilterRatio); //0 ~ 0.5. bigger value more smooth. +PXIALG_API int SpO2_SetMotionDetectionLevel(float level); +PXIALG_API int SpO2_SetInputModelScale(float scale); +PXIALG_API int SpO2_SetInputCorrelationTh(float th); +PXIALG_API int SpO2_SetInputRatioLow(float ratio); +PXIALG_API int SpO2_SetInputCoefLow0(float coef); +PXIALG_API int SpO2_SetInputCoefLow1(float coef); +PXIALG_API int SpO2_SetInputCoefLow2(float coef); +PXIALG_API int SpO2_SetInputCoefLow3(float coef); +PXIALG_API int SpO2_SetInputCoefMid0(float coef); +PXIALG_API int SpO2_SetInputCoefMid1(float coef); +PXIALG_API int SpO2_SetInputCoefMid2(float coef); +PXIALG_API int SpO2_SetInputCoefMid3(float coef); +PXIALG_API int SpO2_SetInputCoefHigh0(float coef); +PXIALG_API int SpO2_SetInputCoefHigh1(float coef); +PXIALG_API int SpO2_SetInputCoefHigh2(float coef); +PXIALG_API int SpO2_SetInputCoefHigh3(float coef); +PXIALG_API int SpO2_SetInputRatioHighBound(float bound); +PXIALG_API int SpO2_SetInputRatioLowBound(float bound); +PXIALG_API int SpO2_SetInputFlagCheckHr(int value); +PXIALG_API int SpO2_SetOutputHighBound(float value); +PXIALG_API int SpO2_SetOutputLowBound(float value); +PXIALG_API int SpO2_Set_Init_Low_SpO2_Constrain(int value); +PXIALG_API int SpO2_Set_Init_Low_SpO2_Th(float value); + +PXIALG_API int SpO2_Set_Init_Low_SpO2_Check_Sec(int value); + +PXIALG_API int SpO2_Set_Motion_Rms_Th(float value); +PXIALG_API int SpO2_Set_Motion_Rms_Th2(float value); + +PXIALG_API int SpO2_Set_Correlation_Th2_Count(int value); +PXIALG_API int SpO2_Set_Input_Correlation_Th2(float value); + +PXIALG_API int SpO2_Set_Flag_Hold_Breathe_Mode(char value); + +PXIALG_API int SpO2_Set_Keep_Init_SpO2_Bound(float value); +PXIALG_API int SpO2_Set_Keep_Init_SpO2_Count_Th(int value); +PXIALG_API int SpO2_Set_SpO2_Bias_Value(float value); +PXIALG_API int SpO2_Set_SpO2_Outlier_Smooth_Coef(float value); +PXIALG_API int SpO2_Set_SpO2_Decrease_Coef(float value); + +PXIALG_API int SpO2_Set_Motion_MEMS_Th(float value); + +PXIALG_API int SpO2_Set_T1(float value); +PXIALG_API int SpO2_Set_T2(float value); +PXIALG_API int SpO2_Set_T3(float value); +PXIALG_API int SpO2_Set_T4(float value); +PXIALG_API int SpO2_Set_T5(float value); +PXIALG_API int SpO2_Set_Spo2_Force_Output_Second(int value); + +PXIALG_API int Spo2_Set_SpO2_First_Smooth_Th(float value); +PXIALG_API int Spo2_Set_SpO2_First_Smooth_Sec(int value); +PXIALG_API int Spo2_Set_SpO2_Correlation_Smooth_Th(float value); + +//set HR +PXIALG_API int SpO2_SetHrValue(int value); + +//get SPO2_Info +PXIALG_API int SpO2_GetInfo(SpO2_info_t *info); + +PXIALG_API int SpO2_SetMems(SpO2_mems_t *mems, int samples); + +PXIALG_API int SpO2_Set_Update_Sec(int spo2_update_sec); + +PXIALG_API int SpO2_SetMemsRmsThr(float mems_rms_thr); +PXIALG_API int SpO2_CalAvgSpO2(float mySpO2, float trust_flag, float mems_rms, float *result); //called every one second +PXIALG_API int SpO2_SetSkipDataLen(int len); +PXIALG_API int SpO2_SetChMapping(int8_t *alg_ch, int8_t ch_nr); + +PXIALG_API int Spo2_Set_Force_Output_Value(float value); +PXIALG_API int Spo2_Set_Force_Output_Value2(float value); + +PXIALG_API int SpO2_Set_Signal_Periodicity_Th(float value); + +#ifdef __cplusplus +} +#endif // __cplusplus + + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/test_library_SPO2.c b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/test_library_SPO2.c new file mode 100644 index 000000000..2f76e5259 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_spo2/V703/test_library_SPO2.c @@ -0,0 +1,432 @@ +// algorithm +#include "pxialg_spo2.h" +// HR algorithm +#include "pxialg.h" +// testpattern +#include "pah8009_testpattern_SPO2.h" +// platform +#include + +#include "pah800x_main.h" +//#include "system_clock.h" +//#include "i2c.h" +//#include "gpio_ctrl.h" +//#include "pah_comm.h" +#include +#include "nrf_delay.h" +#define array_szie(arr) (sizeof(arr) / sizeof(arr[0])) + +#define SAMPLES_PER_CHANNEL 25 +#define TOTAL_CHANNEL 3 + +//#define Open_Rest_Flow + +static SpO2_mems_t mems_data_raw[150]; //add item + +typedef struct +{ + void *pBuffer; + void *hr_pBuffer; +} pxialg_spo2_state; + +//#define parameter_printf(...) NRF_LOG_RAW_INFO(__VA_ARGS__) + +extern void spo2_log_printf(char s, float f); +//static void spo2_log_printf(char s, float f) +//{ +// parameter_printf("%s= "LOG_FLOAT_MARKER" \n",s, LOG_FLOAT(f)); + +//} + + + + +static void bubblesort(float *input,int count) +{ + int i,j; + float sort_temp; + for(i=0;i=25) ) + { + alg_count = alg_count -25; + if (ReadyFlag > 0) + { + LOG_PRINT("myHR = "LOG_FLOAT_MARKER" ",LOG_FLOAT(myHR)); + //nrf_delay_ms(10); + LOG_PRINT(",grade = "LOG_FLOAT_MARKER" ",LOG_FLOAT(hr_grader)); + //nrf_delay_ms(10); + LOG_PRINT(",spo2 = "LOG_FLOAT_MARKER" ",LOG_FLOAT(mySpO2)); + //nrf_delay_ms(10); + LOG_PRINT(",correlation = "LOG_FLOAT_MARKER" ",LOG_FLOAT(correlation)); + //nrf_delay_ms(10); + LOG_PRINT(",trust_flag = "LOG_FLOAT_MARKER" ",LOG_FLOAT(trust_flag)); + //nrf_delay_ms(10); + LOG_PRINT(", SignalPeriodicity = "LOG_FLOAT_MARKER" ",LOG_FLOAT(SignalPeriodicity)); + //nrf_delay_ms(10); + LOG_PRINT(",MEMS_RMS = "LOG_FLOAT_MARKER" ",LOG_FLOAT(MEMS_RMS)); + //nrf_delay_ms(10); + LOG_PRINT(",reason = %d \n",no_value_reason); + } + else + { + LOG_PRINT("myHR = "LOG_FLOAT_MARKER" ",LOG_FLOAT(myHR)); + //nrf_delay_ms(10); + LOG_PRINT(",grade = "LOG_FLOAT_MARKER" ",LOG_FLOAT(hr_grader)); + //nrf_delay_ms(10); + LOG_PRINT(",spo2 = "LOG_FLOAT_MARKER" ",LOG_FLOAT(mySpO2)); + //nrf_delay_ms(10); + LOG_PRINT(",correlation = "LOG_FLOAT_MARKER" ",LOG_FLOAT(correlation)); + //nrf_delay_ms(10); + LOG_PRINT(",trust_flag = "LOG_FLOAT_MARKER" ",LOG_FLOAT(trust_flag)); + //nrf_delay_ms(10); + LOG_PRINT(", SignalPeriodicity = "LOG_FLOAT_MARKER" ",LOG_FLOAT(SignalPeriodicity)); + //nrf_delay_ms(10); + LOG_PRINT(",MEMS_RMS = "LOG_FLOAT_MARKER" ",LOG_FLOAT(MEMS_RMS)); + //nrf_delay_ms(10); + LOG_PRINT(",reason = %d \n",no_value_reason); + + } + +// float new_spo2=mySpO2; + + + #if defined(Optimize_SPO2_flow) + //time_accu=time_accu+time; + LOG_PRINT("time_accu = %d\n",time_accu); + if(time_accu>=31000) + { + spo2_array[count]=mySpO2; + count=count+1; + + LOG_PRINT("Over_30_sec_Stop_measurement\n"); + LOG_PRINT("This_meausrement_suggest_spo2_value is"); + + bubblesort(spo2_array,count); + + if(count % 2 == 0) + { + //LOG_PRINT(" "LOG_FLOAT_MARKER" \n", LOG_FLOAT(spo2_array[count/2])); + LOG_PRINT(" "LOG_FLOAT_MARKER" \n",LOG_FLOAT((spo2_array[(int)(count/2)] + spo2_array[(int)(count/2) - 1]) / 2.0f)); + } + else + { + LOG_PRINT(" "LOG_FLOAT_MARKER"\n", LOG_FLOAT(spo2_array[(int)(count/2)]*1.0f)); + } + count=0; + nrf_delay_ms(50); + //add sensor stop here + SpO2_Close(); + PxiAlg_Close(); + free(pBuffer); + free(_spo2_state.hr_pBuffer); + //NRF_LOG_FLUSH(); + return; + + } + else + { + if(mySpO2>0) + { + spo2_array[count]=mySpO2; + count=count+1; + } + + } + #endif + } + else + { + + switch (ret_value) + { + case SPO2_MSG_ALG_NOT_OPEN: + LOG_PRINT("Algorithm is not initialized. \n"); + break; + + case SPO2_MSG_ALG_REOPEN: + LOG_PRINT("Algorithm is re initialized. \n"); + break; + + case SPO2_MSG_ALG_NOT_SUPPORT: + LOG_PRINT("Algorithm is not support. \n"); + break; + case SPO2_MSG_SUCCESS: + //LOG_PRINT("Algorithm is SUCCESS. \n"); + break; + default: + LOG_PRINT("Algorithm unhandle error = %d \n", ret_value); + break; + } + } + + + + nrf_delay_ms(40); + } + + LOG_PRINT("Out of memory. \n"); + nrf_delay_ms(10); + SpO2_Close(); + PxiAlg_Close(); + free(pBuffer); + free(_spo2_state.hr_pBuffer); + return; +} diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_stress/V6033/pxialg_hrv.h b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_stress/V6033/pxialg_hrv.h new file mode 100644 index 000000000..0e2a0079a --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/algorithm/pah_stress/V6033/pxialg_hrv.h @@ -0,0 +1,72 @@ +#ifndef _PXIALG_HRV_ +#define _PXIALG_HRV_ +#include "stdint.h" + +typedef struct +{ + void *pBuffer; + float collect_duration; + uint8_t has_got_sdnn; +} hrv_state_s; + + + +#if defined(WIN32) && !defined(PXIALG_STATIC_LIB) +# ifdef PXIALG_EXPORTS +# define PXIALG_API __declspec(dllexport) +# else +# define PXIALG_API __declspec(dllimport) +# endif +#else +# define PXIALG_API +#endif // WIN32 + + +#ifdef __cplusplus +extern "C" +{ +#endif + PXIALG_API int HRVReset(void); + PXIALG_API int HRVGetMemorySize(int enable_lhr, int test_seconds, int sampling_rate); + PXIALG_API int HRVOpen(void *p_buffer); + PXIALG_API int HRVProcess(int data_ready, float data); + PXIALG_API int HRVProcessD(int data_ready, uint32_t data); + PXIALG_API int HRVClose(void); + + PXIALG_API int HRVGetVersion(void); + PXIALG_API float HRVGetSDNN(void); + PXIALG_API int HRVGetSDNNLevel(int m_iAge, float dSDNN); + PXIALG_API float HRVGetLHRatio(float *nlf, float *nhf); + PXIALG_API float HRVGetRMSSD(void); + PXIALG_API int HRVGetSleepQuality(int age); + PXIALG_API int HRVGetOnlineRRIReportFlag(void); + PXIALG_API float HRVGetOnlineRRI(void); + PXIALG_API int HRVGetRawRRINum(void); + PXIALG_API float * HRVGetRawRRIBuf(void); + PXIALG_API float HRVGetNoiseRate(void); + PXIALG_API float HRVGetRRIStability(void); + PXIALG_API float HRVGetRRIQuality(void); + PXIALG_API int HRVGetReadyFlag(void); + PXIALG_API int HRVGetMotionFlag(void); + PXIALG_API int HRVGetAnomalyFlag(void); + PXIALG_API int HRVGetHRAvg(void); + + PXIALG_API void HRVSetSkipCounterTh(int SkipCounterTh); + PXIALG_API void HRVSetFreqOffset(float FreqOffset); + PXIALG_API void HRVSetDiffTime(float DiffTime, int SampleNum); + PXIALG_API void HRVSetPeakProcessReadyCounterTh(int PeakProcessReady3Counter_Th0, + int PeakProcessReady3Counter_Th1, + int PeakProcessReady3Counter_Th2, + int PeakProcessReady3Counter_Th3, + int m_PeakProcessReady3Counter_HeartRate_Th1, + int m_PeakProcessReady3Counter_HeartRate_Th2, + int m_PeakProcessReady3Counter_HeartRate_Th3); + + PXIALG_API float HRVGetStress(int grade); + +#ifdef __cplusplus +} +#endif + +#endif /* _PXIALG_HRV_ */ + diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah8009_factory_reg.h b/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah8009_factory_reg.h new file mode 100644 index 000000000..af20cbf7a --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah8009_factory_reg.h @@ -0,0 +1,94 @@ +#ifndef __pah8009_factory_reg_h__ +#define __pah8009_factory_reg_h__ + +// pah +#include "pah800x_factory_test.h" + + +static const uint8_t PAH_800x_REG_DEVICE_INIT_FACTORY[][2] = { +// { 0xEE,0x07 }, //SW RESET + { 0xE8,0x00 },//Close suspend + { 0xD1,0xD0 },//{R_GPIO_0_IEB, R_GPIO_1_IEB, R_GPIO_0_OEB, R_GPIO_1_OEB, R_GPIO_0_PULLL_EnH, R_GPIO_1_PULLL_EnH, R_GPIO_0_PULLH_EnH, R_GPIO_1_PULLH_EnH}; + { 0xD2,0x00 },//R_GPIO_0_Open_Drain_EnH(0xD2[5]), 1(0x20):GPIO default open-drain mode, 0(0x00):GPIO debug mode + { 0xD3,0x20 },//GPIO debug select +// { 0xD6,0x30 },//{Dummy, R_I2C_SLEW, R_I2C_DRV[1:0], Dummy[3:0]} +// { 0xD5,0x44 },//IO-level(I2C), 44:3.3V, 00:1.8V +// { 0xB2,0x25 }, + { 0x55,0x24 },//Soft Reset:04 Hard Reset:24 + { 0x52,0x12 },//VDDAY=1.63V +// { 0xA6,0xF7 },//Cmd_vdday_pwrsv_sel_EnH=0 + { 0xAE,0x3F },//R_LPO_Cali_mode=1 +}; + +static const uint8_t PAH_800x_REG_BRIGHTNESS_TEST_FACTORY[][2] = { + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x08,0x00 },//A period + { 0x09,0x08 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x08 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x08 },//C period + { 0x0E,0x01 },//RDB_FrameNum_A[6:0] + { 0x0F,0x01 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x77 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x52 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x44 },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0x44 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x00 },//RDB_expo_A[7:0] + { 0x18,0x01 },//RDB_expo_A[15:8] + { 0x19,0x00 },//RDB_expo_B[7:0] + { 0x1A,0x01 },//RDB_expo_B[15:8] + { 0x1B,0x00 },//RDB_expo_C[7:0] + { 0x1C,0x01 },//RDB_expo_C[15:8] + { 0x1D,0x2F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x4F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x2A },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0xEB,0x80 },//update_flag +// { 0x20,0xF7 },//Clear INT +}; + +static const uint8_t PAH_800x_REG_LEAK_LIGHT_TEST_FACTORY[][2] = { + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x08,0x00 },//A period + { 0x09,0x08 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x08 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x08 },//C period + { 0x0E,0x01 },//RDB_FrameNum_A[6:0] + { 0x0F,0x01 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x77 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x12 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x0A },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0x8A },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x00 },//RDB_expo_A[7:0] + { 0x18,0x02 },//RDB_expo_A[15:8] + { 0x19,0x00 },//RDB_expo_B[7:0] + { 0x1A,0x02 },//RDB_expo_B[15:8] + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1D,0x2F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x4F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x2A },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0xEB,0x80 },//update_flag +// { 0x20,0xF7 },//Clear INT +}; + + +//============================================================================ +// Public function +//============================================================================ +void factory_test_mode(factory_test_type test_type, bool expo_adjust_en, uint16_t expo_a, uint16_t expo_b, uint16_t expo_c); + + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah800x_factory_test.c b/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah800x_factory_test.c new file mode 100644 index 000000000..d4cd39c3c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah800x_factory_test.c @@ -0,0 +1,556 @@ +// pah +#include "pah800x_factory_test.h" +#include "pah8009_factory_reg.h" + +static uint16_t factory_test_ch[3] = {0}; + +//============================================================================ +// Static Global Variable +//============================================================================ +static pah_800x_test_t _factory_state; +static pah_verify_config_t g_config_table[test_type_num] = +{ + //factory_tesst_num=0 + { + .ch_spec[0] = + { + .verify_enabled = BRIGHTNESS_GLODEN_CHA_ENABLE, + .min_enabled = BRIGHTNESS_GLODEN_CHA_MIN_ENABLE, .max_enabled = BRIGHTNESS_GLODEN_CHA_MAX_ENABLE, + .min = BRIGHTNESS_GLODEN_CHA_MIN, .max = BRIGHTNESS_GLODEN_CHA_MAX + }, + .ch_spec[1] = + { + .verify_enabled = BRIGHTNESS_GLODEN_CHB_ENABLE, + .min_enabled = BRIGHTNESS_GLODEN_CHB_MIN_ENABLE, .max_enabled = BRIGHTNESS_GLODEN_CHB_MAX_ENABLE, + .min = BRIGHTNESS_GLODEN_CHB_MIN, .max = BRIGHTNESS_GLODEN_CHB_MAX + }, + .ch_spec[2] = + { + .verify_enabled = BRIGHTNESS_GLODEN_CHC_ENABLE, + .min_enabled = BRIGHTNESS_GLODEN_CHC_MIN_ENABLE, .max_enabled = BRIGHTNESS_GLODEN_CHC_MAX_ENABLE, + .min = BRIGHTNESS_GLODEN_CHC_MIN, .max = BRIGHTNESS_GLODEN_CHC_MAX + }, + .test_regs = + { + .init_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_DEVICE_INIT_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_DEVICE_INIT_FACTORY) + }, + .test_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_BRIGHTNESS_TEST_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_BRIGHTNESS_TEST_FACTORY) + } + } + }, + + //factory_tesst_num=1 + { + .ch_spec[0] = + { + .verify_enabled = BRIGHTNESS_TARGET_CHA_ENABLE, + .min_enabled = BRIGHTNESS_TARGET_CHA_MIN_ENABLE, .max_enabled = BRIGHTNESS_TARGET_CHA_MAX_ENABLE, + .min = BRIGHTNESS_TARGET_CHA_MIN, .max = BRIGHTNESS_TARGET_CHA_MAX + }, + .ch_spec[1] = + { + .verify_enabled = BRIGHTNESS_TARGET_CHB_ENABLE, + .min_enabled = BRIGHTNESS_TARGET_CHB_MIN_ENABLE, .max_enabled = BRIGHTNESS_TARGET_CHB_MAX_ENABLE, + .min = BRIGHTNESS_TARGET_CHB_MIN, .max = BRIGHTNESS_TARGET_CHB_MAX + }, + .ch_spec[2] = + { + .verify_enabled = BRIGHTNESS_TARGET_CHC_ENABLE, + .min_enabled = BRIGHTNESS_TARGET_CHC_MIN_ENABLE, .max_enabled = BRIGHTNESS_TARGET_CHC_MAX_ENABLE, + .min = BRIGHTNESS_TARGET_CHC_MIN, .max = BRIGHTNESS_TARGET_CHC_MAX + }, + .test_regs = + { + .init_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_DEVICE_INIT_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_DEVICE_INIT_FACTORY) + }, + .test_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_BRIGHTNESS_TEST_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_BRIGHTNESS_TEST_FACTORY) + } + } + }, + + //factory_tesst_num=2 + { + .ch_spec[0] = + { + .verify_enabled = LEAK_LIGHT_TARGET_CHA_ENABLE, + .min_enabled = LEAK_LIGHT_TARGET_CHA_MIN_ENABLE, .max_enabled = LEAK_LIGHT_TARGET_CHA_MAX_ENABLE, + .min = LEAK_LIGHT_TARGET_CHA_MIN, .max = LEAK_LIGHT_TARGET_CHA_MAX + }, + .ch_spec[1] = + { + .verify_enabled = LEAK_LIGHT_TARGET_CHB_ENABLE, + .min_enabled = LEAK_LIGHT_TARGET_CHB_MIN_ENABLE, .max_enabled = LEAK_LIGHT_TARGET_CHB_MAX_ENABLE, + .min = LEAK_LIGHT_TARGET_CHB_MIN, .max = LEAK_LIGHT_TARGET_CHB_MAX + }, + .ch_spec[2] = + { + .verify_enabled = LEAK_LIGHT_TARGET_CHC_ENABLE, + .min_enabled = LEAK_LIGHT_TARGET_CHC_MIN_ENABLE, .max_enabled = LEAK_LIGHT_TARGET_CHC_MAX_ENABLE, + .min = LEAK_LIGHT_TARGET_CHC_MIN, .max = LEAK_LIGHT_TARGET_CHC_MAX + }, + .test_regs = + { + .init_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_DEVICE_INIT_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_DEVICE_INIT_FACTORY) + }, + .test_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_LEAK_LIGHT_TEST_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_LEAK_LIGHT_TEST_FACTORY) + } + } + }, + + //factory_tesst_num=3 + { + .test_regs = + { + .init_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_DEVICE_INIT_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_DEVICE_INIT_FACTORY) + }, + .test_reg_arr = + { + .reg_arr = (pah_reg*)PAH_800x_REG_LEAK_LIGHT_TEST_FACTORY, + .reg_arr_len = PAH_ARRAY_SIZE(PAH_800x_REG_LEAK_LIGHT_TEST_FACTORY) + } + } + } + +}; + +//============================================================================ +// Private function +//============================================================================ +static void pah_sensor_factory_mode_init(factory_test_type test_type, bool expo_adjust_en, uint16_t expo_a, uint16_t expo_b, uint16_t expo_c); +static void pah_sensor_factory_mode_start(void); +static void pah_sensor_factory_mode_stop(void); +static void pah_sensor_factory_mode_task(void); +static void pah_sensor_factory_mode_verify_result(void); + +static pah_ret _pah_800x_hal_comm_write(uint8_t addr, const uint8_t *data, size_t write_size); +static pah_ret _pah_800x_hal_comm_read(uint8_t addr, uint8_t *data, size_t read_size); +static pah_ret _comm_write(uint8_t addr, uint8_t data); + +static pah_ret _pah_800x_hal_write_reg_arr(const pah_reg_arr *reg_arr); +static pah_ret _pah_800x_hal_write_reg_array(const uint8_t reg_array[][2], size_t length); +static pah_ret _pah_800x_hal_write_suspend_state(bool suspend); +static pah_ret _pah_800x_hal_write_interrupt_clear(void); +static pah_ret _pah_800x_hal_write_ch_exposure(uint16_t expo_a, uint16_t expo_b, uint16_t expo_c, uint8_t ch_num); +static pah_ret _pah_800x_hal_tg_toggle(bool enable); +static pah_ret _pah_800x_hal_update_flag(void); + +static pah_ret _pah_800x_hal_read_product_id(uint16_t *product_id); +static pah_ret _pah_800x_hal_read_ppg_interrupt(uint8_t *ppg_interrupt); +static pah_ret _pah_800x_hal_read_ppg_overflow(uint8_t *ppg_overflow, uint8_t *overflow_num); +static pah_ret _pah_800x_hal_read_ppg_adc(uint16_t *ppg_adc, uint8_t ch_num); +static pah_ret _pah_800x_hal_check_enable_channel(pah_800x_test_t *factory_state, const pah_reg_arr *reg_arr); + + +//============================================================================ +// Public function +//============================================================================ +void factory_test_mode(factory_test_type test_type, bool expo_adjust_en, uint16_t expo_a, uint16_t expo_b, uint16_t expo_c) +{ + LOG_PRINT("test_type=%d\n{\n factory_test_brightness_golden_sample=0\n " \ + "factory_test_brightness_target_sample=1\n factory_test_leak_light_target_sample=2\n " \ + "factory_test_power_noise=3\n factory_test_INT_high=4\n factory_test_INT_low=5\n}\n", test_type); + + pah_sensor_factory_mode_init(test_type, expo_adjust_en, expo_a, expo_b, expo_c); + + pah_sensor_factory_mode_start(); + + pah_delay_ms(25); + + if (test_type < factory_test_power_noise) + { + pah_sensor_factory_mode_task(); + pah_sensor_factory_mode_verify_result(); + pah_sensor_factory_mode_stop(); + } + else + { + return; + } + + pah_delay_ms(500); + + return; + +} + + +//============================================================================ +// Private function +//============================================================================ +static void pah_sensor_factory_mode_init(factory_test_type test_type, bool expo_adjust_en, uint16_t expo_a, uint16_t expo_b, uint16_t expo_c) +{ + DEBUG_PRINT("%s(%d)\n", __func__, test_type); + + memset(&_factory_state, 0, sizeof(_factory_state)); + + uint16_t product_id = 0; + _pah_800x_hal_read_product_id(&product_id); + DEBUG_PRINT("product_id = 0x%04X\n", product_id); + if (product_id != PAH_800x_PRODUCT_ID) + { + DEBUG_PRINT("Failed to verify product_id\n"); + } +/**/ + for (int ch_index=0; ch_index<3; ch_index++) + { + _factory_state.verify_config.ch_spec[ch_index] = g_config_table[test_type].ch_spec[ch_index]; + } + + _factory_state.verify_config.test_regs = g_config_table[test_type].test_regs; + _pah_800x_hal_write_reg_arr(&_factory_state.verify_config.test_regs.init_reg_arr); + _pah_800x_hal_write_reg_arr(&_factory_state.verify_config.test_regs.test_reg_arr); + _pah_800x_hal_check_enable_channel(&_factory_state, &_factory_state.verify_config.test_regs.test_reg_arr); +/**/ + if (expo_adjust_en) + { + for(uint8_t ch_num=0; ch_num 0); + if (has_ppg_interrupt > 0) + { + for (uint8_t ch_num=0; ch_num < PAH_800x_MAX_CH_NUM; ch_num++) + { + if (_factory_state.test_ch_enabled[ch_num]) + { + _pah_800x_hal_read_ppg_adc(&_factory_state.test_result.adc[ch_num], ch_num); + } + } + } + + //clear_interrupt(state, has_ppg_interrupt, state->ppg_result.has_overflow); + +} + +static void pah_sensor_factory_mode_verify_result(void) +{ + DEBUG_PRINT("%s\n", __func__); + LOG_PRINT("=============== Verify_Result ===============\n" \ + "{\n result=1 : pass\n result=0 : fail\n}\n"); + + for (int i=0; i _factory_state.verify_config.ch_spec[i].max) + { + _factory_state.verify_result.ch_result[i].is_passed = false; + } + else + { + _factory_state.verify_result.ch_result[i].is_passed = true; + } + printf("ch[%d] : (min, value, max)=(%d, %d, %d), result=%d \n",\ + i, _factory_state.verify_config.ch_spec[i].min, \ + _factory_state.test_result.adc[i], \ + _factory_state.verify_config.ch_spec[i].max, \ + _factory_state.verify_result.ch_result[i].is_passed); + } + else if (_factory_state.verify_config.ch_spec[i].verify_enabled + && _factory_state.verify_config.ch_spec[i].min_enabled) + { + if (_factory_state.test_result.adc[i] < _factory_state.verify_config.ch_spec[i].min) + { + _factory_state.verify_result.ch_result[i].is_passed = false; + } + else + { + _factory_state.verify_result.ch_result[i].is_passed = true; + } + printf("ch[%d] : (min, value)=(%d, %d), result=%d \n",\ + i, _factory_state.verify_config.ch_spec[i].min, \ + _factory_state.test_result.adc[i], \ + _factory_state.verify_result.ch_result[i].is_passed); + } + else if (_factory_state.verify_config.ch_spec[i].verify_enabled + && _factory_state.verify_config.ch_spec[i].max_enabled) + { + if (_factory_state.test_result.adc[i] > _factory_state.verify_config.ch_spec[i].max) + { + _factory_state.verify_result.ch_result[i].is_passed = false; + } + else + { + _factory_state.verify_result.ch_result[i].is_passed = true; + } + + factory_test_ch[i] = _factory_state.test_result.adc[i]; + + printf("ch[%d] : (value, max)=(%d, %d), result=%d \n",\ + i, _factory_state.test_result.adc[i], \ + _factory_state.verify_config.ch_spec[i].max, \ + _factory_state.verify_result.ch_result[i].is_passed); + } + } +} + + +//============================================================================ +// Private function (HAL) +//============================================================================ +static pah_ret _pah_800x_hal_comm_write(uint8_t addr, const uint8_t *data, size_t write_size) +{ + //return plat->comm.write(&plat->comm, addr, data, write_size); + //return plat->comm.write(addr, data, write_size); + return pah_comm_i2c_write(addr, data, write_size); +} + +static pah_ret _pah_800x_hal_comm_read(uint8_t addr, uint8_t *data, size_t read_size) +{ + + //return plat->comm.read(&plat->comm, addr, data, read_size); + return pah_comm_i2c_read(addr, data, read_size); +} + +static pah_ret _comm_write(uint8_t addr, uint8_t data) +{ + //return pah_800x_hal_comm_write( addr, &data, 1); + return _pah_800x_hal_comm_write(addr, &data, 1); +} +#define _comm_read(addr, data) _pah_800x_hal_comm_read(addr, data, 1) +#define _comm_burst_read(addr, data, read_size) _pah_800x_hal_comm_read(addr, data, read_size) + + +static pah_ret _pah_800x_hal_write_reg_arr(const pah_reg_arr *reg_arr) +{ + return _pah_800x_hal_write_reg_array(reg_arr->reg_arr, reg_arr->reg_arr_len); +} + +static pah_ret _pah_800x_hal_write_reg_array(const uint8_t reg_array[][2], size_t length) +{ + size_t i = 0; + uint8_t reg_value = 0; + for (i = 0; i < length; ++i) + { + //for trim bit + if(reg_array[i][0] == 0x14) + { + _comm_read(0x14, ®_value); + reg_value = (reg_value & 0x1F) | (reg_array[i][1] & 0xE0); + _comm_write(reg_array[i][0], reg_value); + } + else + _comm_write(reg_array[i][0], reg_array[i][1]); + } + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_write_suspend_state(bool suspend) +{ + uint8_t data = 0; + DEBUG_PRINT("%s(%d)\n", __func__, suspend); + if (suspend) + { + _comm_read(PAH_800x_ADDR_E8, &data); + PAH_SET_BIT(data, PAH_800x_ADDR_E8_CMD_SUSPEND_MODE_BIT); + _comm_write(PAH_800x_ADDR_E8, data); + } + else + { + _comm_read(PAH_800x_ADDR_E8, &data); + PAH_CLEAR_BIT(data, PAH_800x_ADDR_E8_CMD_SUSPEND_MODE_BIT); + _comm_write(PAH_800x_ADDR_E8, data); + + } + DEBUG_PRINT("%s(%d) end\n", __func__, suspend); + + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_write_interrupt_clear(void) +{ + uint8_t data = 0; + // DR interrupt + _comm_read(PAH_800x_ADDR_20, &data); + //PAH_CLEAR_BIT(data, PAH_800x_ADDR_20_BIT_DR_FLAG); + _comm_write(PAH_800x_ADDR_20, (data|0x04)); //SD-revise-20191205 + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_write_ch_exposure(uint16_t expo_a, uint16_t expo_b, uint16_t expo_c, uint8_t ch_num) +{ + //uint8_t data = 0; + DEBUG_PRINT("%s(%d, %d, %d, %d)\n", __func__, expo_a, expo_b, expo_c, ch_num); + + uint8_t a_exposure_low = PAH_UINT16_LOW(expo_a); + uint8_t a_exposure_high = PAH_UINT16_HIGH(expo_a); + uint8_t b_exposure_low = PAH_UINT16_LOW(expo_b); + uint8_t b_exposure_high = PAH_UINT16_HIGH(expo_b); + uint8_t c_exposure_low = PAH_UINT16_LOW(expo_c); + uint8_t c_exposure_high = PAH_UINT16_HIGH(expo_c); + + if(ch_num == PAH_800x_CH_NUM_A) + { + _comm_write(PAH_800x_ADDR_17, a_exposure_low); + _comm_write(PAH_800x_ADDR_18, a_exposure_high); + } + else if(ch_num == PAH_800x_CH_NUM_B) + { + _comm_write(PAH_800x_ADDR_19, b_exposure_low); + _comm_write(PAH_800x_ADDR_1A, b_exposure_high); + } + else if(ch_num == PAH_800x_CH_NUM_C) + { + _comm_write(PAH_800x_ADDR_1B, c_exposure_low); + _comm_write(PAH_800x_ADDR_1C, c_exposure_high); + } + + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_tg_toggle(bool enable) +{ + uint8_t data = 0; + DEBUG_PRINT("%s(%d)\n", __func__, enable); + _comm_read( PAH_800x_ADDR_07_TG, &data); + if(enable) + PAH_SET_BIT(data, PAH_800x_ADDR_07_TG_BIT_EN); + else + PAH_CLEAR_BIT(data, PAH_800x_ADDR_07_TG_BIT_EN); + _comm_write(PAH_800x_ADDR_07_TG, data); + + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_update_flag(void) +{ + _comm_write(PAH_800x_ADDR_EB, PAH_800x_ADDR_E8_UPDATE_FLAG); + + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_read_product_id(uint16_t *product_id) +{ + return _comm_burst_read(PAH_800x_ADDR_00_PRODUCT_ID, (uint8_t *)product_id,2); +} + +static pah_ret _pah_800x_hal_read_ppg_interrupt(uint8_t *ppg_interrupt) +{ + uint8_t data = 0; + _comm_read(PAH_800x_ADDR_20, &data); + if (ppg_interrupt) + *ppg_interrupt = PAH_CHECK_BIT(data, PAH_800x_ADDR_20_BIT_DR_FLAG); + + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_read_ppg_overflow(uint8_t *ppg_overflow, uint8_t *overflow_num) +{ + uint8_t data = 0; + _comm_read( PAH_800x_ADDR_20, &data); + if (ppg_overflow) + { + *ppg_overflow = PAH_CHECK_BIT(data, PAH_800x_ADDR_20_BIT_OVERFLOW_FLAG); + *overflow_num = (data&0x70)>>4; + } + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_read_ppg_adc(uint16_t *ppg_adc, uint8_t ch_num) +{ + uint16_t data = 0; + + if(ch_num == PAH_800x_CH_NUM_A) + _comm_burst_read(PAH_800x_ADDR_2E, (uint8_t*)&data, 2); + else if(ch_num == PAH_800x_CH_NUM_B) + _comm_burst_read(PAH_800x_ADDR_39, (uint8_t*)&data, 2); + else if(ch_num == PAH_800x_CH_NUM_C) + _comm_burst_read(PAH_800x_ADDR_44, (uint8_t*)&data, 2); + + //*ppg_adc = data >> 2; + *ppg_adc = data >> 2; + + return PAH_RET_SUCCESS; +} + +static pah_ret _pah_800x_hal_check_enable_channel(pah_800x_test_t *factory_state, const pah_reg_arr *reg_arr) +{ + for(int i=0;ireg_arr_len;i++) + { + if(reg_arr->reg_arr[i][0] == PAH_800x_ADDR_11_EnCh) + { + uint8_t data = reg_arr->reg_arr[i][1]; + factory_state->test_ch_enabled[0] = PAH_CHECK_BIT(data, 0); // CH A + factory_state->test_ch_enabled[1] = PAH_CHECK_BIT(data, 1); // CH B + factory_state->test_ch_enabled[2] = PAH_CHECK_BIT(data, 2); // CH C + } + } + + return PAH_RET_SUCCESS; +} + + +void pah8009_get_leaklight_data(uint16_t *ch0,uint16_t *ch1,uint16_t *ch2) +{ + *ch0 = factory_test_ch[0]; + *ch1 = factory_test_ch[1]; + *ch2 = factory_test_ch[2]; + + factory_test_ch[0] = 0; + factory_test_ch[1] = 0; + factory_test_ch[2] = 0; +} diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah800x_factory_test.h b/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah800x_factory_test.h new file mode 100644 index 000000000..7519958b8 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/factory/pah800x_factory_test.h @@ -0,0 +1,160 @@ +#ifndef __pah800x_factory_test_h__ +#define __pah800x_factory_test_h__ + +// pah +//#include "pah_800x.h" +#include "pah_unit.h" +#include "pah_800x_config.h" + + +//============================================================================ +// Definition +//============================================================================ + +/*---------Brightness Test Golden Option---------*/ +#define BRIGHTNESS_GLODEN_CHA_ENABLE true +#define BRIGHTNESS_GLODEN_CHA_MIN_ENABLE true +#define BRIGHTNESS_GLODEN_CHA_MAX_ENABLE true +#define BRIGHTNESS_GLODEN_CHA_MIN 7600 +#define BRIGHTNESS_GLODEN_CHA_MAX 8400 +#define BRIGHTNESS_GLODEN_CHB_ENABLE true +#define BRIGHTNESS_GLODEN_CHB_MIN_ENABLE true +#define BRIGHTNESS_GLODEN_CHB_MAX_ENABLE true +#define BRIGHTNESS_GLODEN_CHB_MIN 7600 +#define BRIGHTNESS_GLODEN_CHB_MAX 8400 +#define BRIGHTNESS_GLODEN_CHC_ENABLE true +#define BRIGHTNESS_GLODEN_CHC_MIN_ENABLE true +#define BRIGHTNESS_GLODEN_CHC_MAX_ENABLE true +#define BRIGHTNESS_GLODEN_CHC_MIN 7600 +#define BRIGHTNESS_GLODEN_CHC_MAX 8400 + +/*---------Brightness Test Target Option---------*/ +#define BRIGHTNESS_TARGET_CHA_ENABLE true +#define BRIGHTNESS_TARGET_CHA_MIN_ENABLE true +#define BRIGHTNESS_TARGET_CHA_MAX_ENABLE true +#define BRIGHTNESS_TARGET_CHA_MIN 2400 +#define BRIGHTNESS_TARGET_CHA_MAX 15200 +#define BRIGHTNESS_TARGET_CHB_ENABLE true +#define BRIGHTNESS_TARGET_CHB_MIN_ENABLE true +#define BRIGHTNESS_TARGET_CHB_MAX_ENABLE true +#define BRIGHTNESS_TARGET_CHB_MIN 2400 +#define BRIGHTNESS_TARGET_CHB_MAX 15200 +#define BRIGHTNESS_TARGET_CHC_ENABLE true +#define BRIGHTNESS_TARGET_CHC_MIN_ENABLE true +#define BRIGHTNESS_TARGET_CHC_MAX_ENABLE true +#define BRIGHTNESS_TARGET_CHC_MIN 4000 +#define BRIGHTNESS_TARGET_CHC_MAX 12000 + +/*---------Brightness Test Target Option---------*/ +#define LEAK_LIGHT_TARGET_CHA_ENABLE true +#define LEAK_LIGHT_TARGET_CHA_MIN_ENABLE false +#define LEAK_LIGHT_TARGET_CHA_MAX_ENABLE true +#define LEAK_LIGHT_TARGET_CHA_MIN 0 +#define LEAK_LIGHT_TARGET_CHA_MAX 160 +#define LEAK_LIGHT_TARGET_CHB_ENABLE true +#define LEAK_LIGHT_TARGET_CHB_MIN_ENABLE false +#define LEAK_LIGHT_TARGET_CHB_MAX_ENABLE true +#define LEAK_LIGHT_TARGET_CHB_MIN 0 +#define LEAK_LIGHT_TARGET_CHB_MAX 160 +#define LEAK_LIGHT_TARGET_CHC_ENABLE true +#define LEAK_LIGHT_TARGET_CHC_MIN_ENABLE false +#define LEAK_LIGHT_TARGET_CHC_MAX_ENABLE true +#define LEAK_LIGHT_TARGET_CHC_MIN 0 +#define LEAK_LIGHT_TARGET_CHC_MAX 160 + + +//============================================================================ +// Type Definition +//============================================================================ +typedef enum +{ + factory_test_brightness_golden_sample, + factory_test_brightness_target_sample, + factory_test_leak_light_target_sample, + factory_test_power_noise, + factory_test_INT_high, + factory_test_INT_low, + test_type_num, + +} factory_test_type; + +typedef struct +{ + bool verify_enabled; + + bool min_enabled; + bool max_enabled; + + uint16_t min; + uint16_t max; + +} pah_ch_verify_spec_t; + +typedef struct +{ + pah_reg_arr init_reg_arr; + pah_reg_arr test_reg_arr; + +} pah_verify_reg_t; + +typedef struct +{ + pah_ch_verify_spec_t ch_spec[PAH_800x_MAX_CH_NUM]; + + pah_verify_reg_t test_regs; + +} pah_verify_config_t; + +typedef struct +{ + bool has_data; + + // Avaiable only if has_data is true + bool has_overflow; + + uint8_t overflow_num; + + // Avaiable only if has_data is true + uint16_t exposure_time[PAH_800x_MAX_CH_NUM]; + uint16_t adc[PAH_800x_MAX_CH_NUM]; + +} pah_test_result_t; + +typedef struct +{ + uint16_t adc; + + bool is_passed; + +} pah_ch_verify_result_t; + +typedef struct +{ + pah_ch_verify_result_t ch_result[PAH_800x_MAX_CH_NUM]; + +} pah_verify_result_t; + +typedef struct +{ + // Config + //pah_plat plat; + pah_verify_config_t verify_config; + + bool test_ch_enabled[PAH_800x_MAX_CH_NUM]; + + // PPG state + pah_test_result_t test_result; + + // verify + pah_verify_result_t verify_result; + +} pah_800x_test_t; + + +//============================================================================ +// Public function +//============================================================================ +void factory_test_mode(factory_test_type test_type, bool expo_adjust_en, uint16_t expo_a, uint16_t expo_b, uint16_t expo_c); +void pah8009_get_leaklight_data(uint16_t *ch0,uint16_t *ch1,uint16_t *ch2); + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.c b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.c new file mode 100644 index 000000000..a208d8120 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.c @@ -0,0 +1,85 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2025-05-27 11:09:04 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-06-04 15:38:48 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.c + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +// pah +#include "pah800x_bsp.h" +#include "custom_utils.h" +#include "systick.h" + +//============================================================================ +// Definition +//============================================================================ +#define PAH800xx_I2C_SLAVE_ID 0x40 +#define I2C_PPG_PORT_ID 1 +#define PAH800xx_I2C_BUS I2C_BUS_2 + +//============================================================================ +// Public function +//============================================================================ +void pah_delay_ms(uint32_t ms) +{ + // pxi_nrf_delay_ms(ms); + LOS_Mdelay(ms); +} + +uint64_t pah_get_tick_count(void) +{ + // return pxi_nrf_get_tick_count(); + uint64_t cnt = uapi_systick_get_ms(); + // printf("cnt : %llu\n",cnt); + return cnt; +} + +pah_ret pah_comm_i2c_write(uint8_t addr, const uint8_t *data, size_t write_size) +{ + //DEBUG_PRINT("W A:0x%02x,D:0x%02x\n",addr,*data); + // pxi_nrf_i2c_write(addr, data, write_size); + custom_i2c_write_reg(PAH800xx_I2C_SLAVE_ID, addr, 1, data, write_size, PAH800xx_I2C_BUS); + + return PAH_RET_SUCCESS; +} + +pah_ret pah_comm_i2c_read(uint8_t addr, uint8_t *data, size_t read_size) +{ + // pxi_nrf_i2c_read(addr, data, read_size); + custom_i2c_read_regs(PAH800xx_I2C_SLAVE_ID, addr, 1 , data, read_size, PAH800xx_I2C_BUS); + //DEBUG_PRINT("R A:0x%02x,D:0x%02x\n",addr,*data); + return PAH_RET_SUCCESS; +} + +void pah_print( + int32_t fileline, + const char *funcname, + const char *filename, + const char *format, ...) +{ + UNUSED_VAR(fileline); + UNUSED_VAR(funcname); + UNUSED_VAR(filename); + + char dest[256]; + va_list argptr; + int char_num = 0; + + if (!format) + return; + + va_start(argptr, format); + char_num = vsprintf(dest, format, argptr); + va_end(argptr); + + //uart_printf("%s", dest); + + //dest[char_num] = '\n'; + // pxi_nrf_uart_transmit((uint8_t*)dest, (uint16_t)(char_num + 1)); +} + +void ReadGSensor(float *x, float *y, float *z) +{ + +} diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.h b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.h new file mode 100644 index 000000000..cae483f3b --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.h @@ -0,0 +1,46 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2025-05-27 11:09:04 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-05-27 11:32:50 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_bsp.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#ifndef __pah_800x_bsp_h__ +#define __pah_800x_bsp_h__ + +// c +#include +#include +#include +#include + +// pah +#include "pah_unit.h" +#include "pah_800x_config.h" + + +//============================================================================ +// Public function +//============================================================================ +#ifdef __cplusplus +extern "C" { +#endif + +void pah_delay_ms(uint32_t ms); +uint64_t pah_get_tick_count(void); +pah_ret pah_comm_i2c_write(uint8_t addr, const uint8_t *data, size_t write_size); +pah_ret pah_comm_i2c_read(uint8_t addr, uint8_t *data, size_t read_size); +void pah_print( + int32_t fileline, + const char *funcname, + const char *filename, + const char *format, ...); + +void ReadGSensor(float *x, float *y, float *z); + +#ifdef __cplusplus +} +#endif + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_main.c b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_main.c new file mode 100644 index 000000000..59697f05c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_main.c @@ -0,0 +1,1628 @@ +// pah +#include "pah800x_main.h" +//#include "pah_8009_reg_arr_default.h" +#include "pxialg_spo2.h" +#include "pxialg_hrv.h" +#include "pxivar.h" +#include "pah_8009_reg_arr_default_20220623.h" +#include "pah800x_factory_test.h" +#include "cmsis_os2.h" + +#ifdef SUPPORT_PPG_SERVICE +#include "ppg_service.h" +#endif +//============================================================================ +// Static Global Variable +//============================================================================ +static main_state _main; +static ppg_mems_data_t ppg_mems_data_buf[FIFO_SIZE] ; +static int _read_index = 0 ; +static int _write_index = 0 ; + +// hr algotirhm +static float hr = 0.0f; +static float hr_grader =0.0f; +static ppg_mems_data_t ppg_mems_data_alg; + +// spo2 algorithm +void *pBuffer = NULL; +void *hr_pBuffer = NULL; +static float myHR = 0.0f; +static float mySpO2 = 0.0f; +static float correlation = 0.0f; +static float trust_flag = 0.0f; +static float MEMS_RMS = 0.0f; +uint8_t mySPO2_ReadyFlag = 0 ; +static uint8_t no_value_reason = 0 ; +static float SignalPeriodicity=0.0f ; + +static int time_accu = 0 ; +static int count =0; +static float spo2_array[31]={0.0f}; + +static uint32_t data_buf_count_spo2_alg=0; + +static SpO2_info_t _spo2_detect_item; +pah8series_data_t pxialg_data_spo2; +static SpO2_mems_t mems_data_raw[150]; +#ifdef PPG_MEMS_Synchronize +//int16_t mems_int_data_in[90] ={0}; +int16_t mems_int_data_out[90]={0}; +int time_temp=0; +static uint8_t ppg_data_num=0; +uint8_t mems_data_polling_ready = 0 ; +#endif + + + + + +// Stress Algorithm +static hrv_state_s _hrv_state; +void *stress_pBuffer = NULL; +#define HRV_ENABLE_LHR 1 +#define HRV_SAMPLING_RATE 20 +#define HRV_COLLECTION_SECONDS 180 +static uint32_t duration_total = 0; +uint8_t SDNN_ReadyFlag = 0; +uint8_t Get_Stress = 0; +static float Stress = 0.0f; +static uint8_t HRAvg = 0; +static float SQ_Stress = 0.0f; +static uint8_t AnomalyFlag = 0; +uint8_t Stress_ReadyFlag = 0; +uint8_t Weak_Flag = 0; + +static uint32_t factory_data = 0; +static uint8_t work_mode = 0; + + +static osTimerId_t g_pah8009_timer = NULL; + +//============================================================================ +// Private function +//============================================================================ +static bool sensor_basic_verification(void); +static void process(uint64_t timestamp); +static void ppg_sensor_enable(void); +static void ppg_sensor_disable(void); +static void touch_sensor_enable(void); +static void touch_sensor_disable(void); + +static void report_touch_data(uint64_t timestamp, const int8_t *touch_flag); +static void report_ppg_data(const ppg_mems_data_t *ppg_mems_data_alg); +static void report_hr_data(const ppg_mems_data_t *ppg_mems_data_alg, int32_t ret, float hr, float hr_grader); +static void report_spo2_data(const ppg_mems_data_t *ppg_mems_data_alg, int32_t ret, float myHR, float mySpO2, float correlation, float trust_flag, float MEMS_RMS, int data_buf_count_spo2_alg, uint8_t no_value_reason, float SignalPeriodicity, int time_accu ); +static void report_stress_data(const ppg_mems_data_t *ppg_mems_data_alg, uint8_t Stress_ReadyFlag, uint32_t measuretime, float collect_time); + +static void error_handle(void); + + +static void bubblesort(float *input,int count) +{ + int i,j; + float sort_temp; + for(i=0;i= FIFO_SIZE) + tmp = 0 ; + if(tmp == _read_index) + return false; + ppg_mems_data_buf[tmp] = *data ; + _write_index = tmp ; + return true; +} + +bool pah_pop(ppg_mems_data_t *data) +{ + int tmp ; + if(isFIFOEmpty()) + return false; + tmp = _read_index + 1; + if(tmp >= FIFO_SIZE) + tmp = 0 ; + _read_index = tmp ; + *data = ppg_mems_data_buf[_read_index] ; + + return true; +} + + +//============================================================================ +// Public function +//============================================================================ +void pah_sensor_init(reg_config_type type) +{ + memset(&_main, 0, sizeof(_main)); + + pah_800x_reg_setting reg_setting; + memset(®_setting, 0, sizeof(reg_setting)); + + if (!sensor_basic_verification()) + { + // error_handle(); + LOG_PRINT("sensor_basic_verification failed\n"); + return; + } + + + // pah_800x + pah_800x_config pah_800x_config; + pah_800x_get_default_config(&pah_800x_config); + LOG_PRINT("PPG_SETTING_VESION = %d \n" ,PPG_SETTING_VERSION); + +#if (ENABLE_AE==0) + pah_800x_config.enable_ppg_convergence[0] = false; + pah_800x_config.enable_ppg_convergence[1] = false; + pah_800x_config.enable_ppg_convergence[2] = false; +#endif + +#if (ENABLE_AE_RECONVERGENCE==0) + pah_800x_config.enable_ppg_reconvergence_if_out_of_bounds[0] = false; + pah_800x_config.enable_ppg_reconvergence_if_out_of_bounds[1] = false; + pah_800x_config.enable_ppg_reconvergence_if_out_of_bounds[2] = false; +#endif + + if (type == pc_4mm_2g_ir_hrd) + { +#if (PC_4MM_2G_IR_HRD==1) + PAH_REG_ARR_SETUP(reg_setting.startup_init, PAH8009_REG_DEVICE_INIT); + PAH_REG_ARR_SETUP(reg_setting.ppg_enable, PAH8009_REG_PC_4MM_2G_IR_PPG); + PAH_REG_ARR_SETUP(reg_setting.touch_enable, PAH8009_REG_PC_4MM_2G_IR_TOUCH); +#endif + } + else if (type == diw_4mm_g_ir_hrd) + { +#if (DIW_4MM_G_IR_HRD==1) + PAH_REG_ARR_SETUP(reg_setting.startup_init, PAH8009_REG_DEVICE_INIT); + PAH_REG_ARR_SETUP(reg_setting.ppg_enable, PAH8009_REG_DIW_4MM_G_IR_PPG); + PAH_REG_ARR_SETUP(reg_setting.touch_enable, PAH8009_REG_DIW_4MM_G_IR_TOUCH); +#endif + } + else if (type == diw_4mm_ir_r_ir_spo2) + { +#if (DIW_4MM_IR_R_IR_SPO2==1) + for(int ch=0;ch 0 ? 0x80 : 0x00); + hr_data.rsv2 = 0; + + + int32_t ret = PxiAlg_Process_Expo((uint8_t*)&hr_data, ppg_mems_data_alg.MEMS_Data, ppg_mems_data_alg.ppg_data.exposure_time[1]); + + + if(PxiAlg_GetHrUpdateFlag()) + { + PxiAlg_HrGet(&hr); + PxiAlg_GetSigGrade(&hr_grader); + } + if(ppg_mems_data_alg.touch_flag==0) + { + hr = 0 ; + hr_grader = 0; + } + + // if(hr > 0) + printf("hr:%f\n",hr); + + report_hr_data(&ppg_mems_data_alg, ret, hr, hr_grader); + + + } + else + { + report_ppg_data(&ppg_mems_data_alg); + } + } + } +} + +// HRD- ALG- Task2 +void hr_alg_task2(uint8_t ppg_num) +{ +#ifdef PPG_MEMS_Synchronize + if(Check_alg_enable()) + { + if(Check_alg_enable()==MSG_ALG_ENABLE) + { + hr_algorithm_enable(); + }else if(Check_alg_enable()==MSG_ALG_DISABLE) + { + hr_algorithm_disable(); + } + Clear_alg_enable(); + } + + if(!isFIFOEmpty()) + { + for (int i=0; i 0 ? 0x80 : 0x00); + hr_data.rsv2 = 0; + + int32_t ret = PxiAlg_Process_Expo((uint8_t*)&hr_data, ppg_mems_data_alg.MEMS_Data, ppg_mems_data_alg.ppg_data.exposure_time[1]); + + + if(PxiAlg_GetHrUpdateFlag()) + { + PxiAlg_HrGet(&hr); + PxiAlg_GetSigGrade(&hr_grader); + } + + report_hr_data(&ppg_mems_data_alg, ret, hr, hr_grader); + + } + else + { + report_ppg_data(&ppg_mems_data_alg); + } + } + } + } +#endif +} + + + +// SPO2 +void spo2_algorithm_enable(void) +{ + if (_main.spo2_is_enabled) + { + return; + } + + + int version = SpO2_Version(); + DEBUG_PRINT("PxiAlg_Version() = %d\n", version); + + uint32_t buffer_size = SpO2_OpenSize(); + DEBUG_PRINT("SpO2_Open buffer_size = %d \n", buffer_size); + + pBuffer = malloc(buffer_size); + + if (SpO2_Open(pBuffer) != SPO2_MSG_SUCCESS) + { + DEBUG_PRINT("SpO2_Open() failed. \n"); + free(pBuffer); + return; + } + int8_t alg_ch[2] = {0, 1}; + + SpO2_SetChMapping(alg_ch, 2); + SpO2_SetInputRatioHighBound(94.0f); + SpO2_SetInputRatioLowBound(87.0f); + SpO2_SetInputModelScale(0.50f); + + SpO2_SetInputCoefHigh0(-36877.85546875f); + SpO2_SetInputCoefHigh1(1135.91394042969f); + SpO2_SetInputCoefHigh2(-11.6429319381714f); + SpO2_SetInputCoefHigh3(0.0398150011897087f); + + SpO2_SetInputCoefMid0(-1430.70520019531f); + SpO2_SetInputCoefMid1(50.1599006652832f); + SpO2_SetInputCoefMid2(-0.567422986030579f); + SpO2_SetInputCoefMid3(0.00219199992716312f); + + SpO2_SetInputCoefLow0(-8.19796657562256f); + SpO2_SetInputCoefLow1(1.74200701713562f); + SpO2_SetInputCoefLow2(-0.0173850003629923f); + SpO2_SetInputCoefLow3(0.000105999999505002f); + + SpO2_SetIIRFilterRatio(0.5f); + SpO2_SetInputCorrelationTh(0.850000078678131f); + SpO2_SetInputRatioLow(0.05f); + + SpO2_SetInputFlagCheckHr(1); + SpO2_SetMotionDetectionLevel(2.0f); + SpO2_Set_Update_Sec(1); + + SpO2_Set_Init_Low_SpO2_Constrain(0.0); + SpO2_SetOutputHighBound(100.0f); + SpO2_SetOutputLowBound(60.0f); + SpO2_Set_Keep_Init_SpO2_Bound(95.0f); + SpO2_Set_Keep_Init_SpO2_Count_Th(18.0f); + SpO2_Set_SpO2_Bias_Value(0.5f); + SpO2_Set_SpO2_Outlier_Smooth_Coef(5.5f); + SpO2_Set_SpO2_Decrease_Coef(0.5f); + SpO2_SetSkipDataLen(25); + + SpO2_Set_Flag_Hold_Breathe_Mode(0); + SpO2_Set_Input_Correlation_Th2(0.85000f); + SpO2_Set_Correlation_Th2_Count(30.0f); + SpO2_Set_Init_Low_SpO2_Th(94.5f); + SpO2_Set_Motion_Rms_Th(3000.0f); + SpO2_Set_Motion_Rms_Th2(1500.0f); + SpO2_Set_Motion_MEMS_Th(0.0f); + SpO2_Set_T1(0.85f); + SpO2_Set_Spo2_Force_Output_Second(15.0f); + + Spo2_Set_Force_Output_Value(97.50f); // Good Signal Force SpO2 + Spo2_Set_Force_Output_Value2(95.00f); // Bad Signal Force SpO2 + + SpO2_Set_Init_Low_SpO2_Check_Sec(20); + Spo2_Set_SpO2_First_Smooth_Th(95.0f); + Spo2_Set_SpO2_First_Smooth_Sec(15); + Spo2_Set_SpO2_Correlation_Smooth_Th(0.85f); + SpO2_Set_Signal_Periodicity_Th(0.50f); + + // static Hr-V301009 + PxiAlg_Close(); + version = PxiAlg_Version(); + DEBUG_PRINT("HR_Version = %d \r\n", version); + + + uint32_t Query_Mem_Size = PxiAlg_Query_Mem_Size(); + DEBUG_PRINT("HR_Mem_Size = %d \r\n", Query_Mem_Size); + + hr_pBuffer = malloc(Query_Mem_Size); + + + if(!PxiAlg_Open_Mem(hr_pBuffer)) + DEBUG_PRINT("PxiAlg_Open_Mem fail \n"); + + + PxiAlg_SetQualityThreshold(0.35f); + PxiAlg_SetHRSmoothWeight(0.9f); + PxiAlg_SetProcWindow(5.0f, 5.0f); + PxiAlg_SetTimeoutLength(30.0f); + PxiAlg_SetMemsScale(1); //MEMS 2/4/8/16G : 0/1/2/3 + PxiAlg_SetSkipSampleNum(10); + PxiAlg_SetMemsScaleBase(1, 0); //MEMS 2/4/8/16G : 0/1/2/3 + PxiAlg_SetForceOutputLink(15, 90, 60, 1, 0.9f); + PxiAlg_SetNormalOutput(200, 40, 1); + PxiAlg_SetForceRipple(3, 1); + PxiAlg_SetPackage(0, 1); + + myHR = 0.0f; + mySpO2 = 0.0f; + correlation = 0.0f; + trust_flag = 0.0f; + MEMS_RMS = 0.0f; + mySPO2_ReadyFlag = 0; + hr_grader = 0.0f; + data_buf_count_spo2_alg=0; + no_value_reason = 0 ; + SignalPeriodicity=0.0f ; + time_accu = 0 ; + count = 0 ; + memset(spo2_array, 0, sizeof(*spo2_array)); + _main.spo2_is_enabled = true; +} + +void spo2_algorithm_disable(void) +{ + if (!_main.spo2_is_enabled) + return; + PxiAlg_Close(); + SpO2_Close(); + free(pBuffer); + free(hr_pBuffer); + myHR = 0.0f; + mySpO2 = 0.0f; + correlation = 0.0f; + trust_flag = 0.0f; + MEMS_RMS = 0.0f; + mySPO2_ReadyFlag = 0; + hr_grader = 0.0f; + data_buf_count_spo2_alg=0; + + no_value_reason = 0 ; + SignalPeriodicity=0.0f ; + time_accu = 0 ; + + + _main.spo2_is_enabled = false; +} + +void spo2_alg_task(void) +{ + if(Check_alg_enable()) + { + if(Check_alg_enable()==MSG_ALG_ENABLE) + { + spo2_algorithm_enable(); + }else if(Check_alg_enable()==MSG_ALG_DISABLE) + { + spo2_algorithm_disable(); + } + Clear_alg_enable(); + } + + if(!isFIFOEmpty()) + { + if(pah_pop(&ppg_mems_data_alg)) //Get data from FIFO + { + if(_main.spo2_is_enabled) + { + // 13Bytes format to hr lib; + + int32_t RAW_DATA[2] ; + sRaw_Data_13Bytes hr_data; + + memset(&hr_data, 0, sizeof(hr_data)); + hr_data.loss = (uint8_t)ppg_mems_data_alg.ppg_data.overflow_num + 1; + hr_data.rawData = ppg_mems_data_alg.ppg_data.data[0]; + hr_data.non_zero1 = 1; + hr_data.non_zero2 = 2; + hr_data.non_zero3 = 3; + hr_data.frame_count = ppg_mems_data_alg.ppg_frame_count; + hr_data.time = ppg_mems_data_alg.duration; + hr_data.rsv = 0; + hr_data.touch = (ppg_mems_data_alg.touch_flag > 0 ? 0x80 : 0x00); + hr_data.rsv2 = 0; + + + int32_t ret = PxiAlg_Process_Expo((uint8_t*)&hr_data, ppg_mems_data_alg.MEMS_Data, ppg_mems_data_alg.ppg_data.exposure_time[0]); + + + + + if(PxiAlg_GetHrUpdateFlag()) + { + PxiAlg_HrGet(&myHR); + PxiAlg_GetSigGrade(&hr_grader); + } + + + int32_t spo2_raw_1=ppg_mems_data_alg.ppg_data.data[0]; + int32_t spo2_raw_2=ppg_mems_data_alg.ppg_data.data[1]; + + RAW_DATA[0]=spo2_raw_1; + RAW_DATA[1]=spo2_raw_2; + + mems_data_raw[0].data[0]=ppg_mems_data_alg.MEMS_Data[0]; + mems_data_raw[0].data[1]=ppg_mems_data_alg.MEMS_Data[1] ; + mems_data_raw[0].data[2]=ppg_mems_data_alg.MEMS_Data[2]; + + // SPO2 fill data on pah8series structure + pxialg_data_spo2.touch_flag = ppg_mems_data_alg.touch_flag ; + pxialg_data_spo2.time = ppg_mems_data_alg.duration ;; + pxialg_data_spo2.ppg_data = (int32_t*)RAW_DATA; + pxialg_data_spo2.nf_ppg_channel = 2; + pxialg_data_spo2.nf_ppg_per_channel = 1; + pxialg_data_spo2.frame_count = ppg_mems_data_alg.ppg_frame_count ; + pxialg_data_spo2.nf_mems = 1; + pxialg_data_spo2.mems_data = (int16_t*)mems_data_raw; + + + + // DEBUG_PRINT("data_buf_count_spo2_alg = %d \r\n", data_buf_count_spo2_alg); + + + SpO2_SetHrValue(myHR); + SpO2_SetMems(mems_data_raw, 1); + //int ret_value = SpO2_Process(ppg_mems_data_alg.touch_flag , 2, pxialg_data_spo2.ppg_data, 1); + int ret_value = SpO2_Process(ppg_mems_data_alg.touch_flag , 2, pxialg_data_spo2.ppg_data, 1,pxialg_data_spo2.time ); + + SpO2_GetSpO2(&mySpO2); + + // if(mySpO2 > 0) + printf("SpO2 : %f\n",mySpO2); + + SpO2_GetReadyFlag(&mySPO2_ReadyFlag); + SpO2_GetInfo(&_spo2_detect_item); + correlation =_spo2_detect_item.Noise; + trust_flag =_spo2_detect_item.Output[3]; + no_value_reason=_spo2_detect_item.Output[4]; + SpO2_GetPeriodicity(&SignalPeriodicity); + MEMS_RMS =_spo2_detect_item.RMS; + + + data_buf_count_spo2_alg++; + + #if defined(Optimize_SPO2_flow) + time_accu=time_accu+pxialg_data_spo2.time; + #endif + + if( (ret_value == 0 ) && (data_buf_count_spo2_alg>=25) ) + { + + #if defined(Optimize_SPO2_flow) + //time_accu=time_accu+pxialg_data->time; + DEBUG_PRINT("SPO2 Test Time = %d ,count =%d\n",time_accu,count); + if(time_accu>=60000) + { + spo2_array[count]=mySpO2; + count=count+1; + + LOG_PRINT("Over_30_sec_Stop_measurement\n"); + LOG_PRINT("This_meausrement_suggest_spo2_value is"); + + bubblesort(spo2_array,count); + + if(count % 2 == 0) + { + //log_printf(" "LOG_FLOAT_MARKER" \n", LOG_FLOAT(spo2_array[count/2])); + LOG_PRINT(" "LOG_FLOAT_MARKER" \n",LOG_FLOAT((spo2_array[(int)(count/2)] + spo2_array[(int)(count/2) - 1]) / 2.0f)); + } + else + { + LOG_PRINT(" "LOG_FLOAT_MARKER" \n", LOG_FLOAT(spo2_array[(int)(count/2)]*1.0f)); + } + + //log_pah8series_no_touch(); + spo2_algorithm_disable(); + pah_sensor_stop(); + count=0; + //add sensor stop here + } + else + { + if(mySpO2>0) + { + spo2_array[count]=mySpO2; + count=count+1; + } + } + #endif + //report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, Opt_SpO2, drop_flag, ascend_flag, mems_fla); + report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, no_value_reason, SignalPeriodicity, time_accu); + data_buf_count_spo2_alg = data_buf_count_spo2_alg -25; + } + else + { + //report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, Opt_SpO2, drop_flag, ascend_flag, mems_flag); + report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, no_value_reason, SignalPeriodicity, time_accu); + + switch (ret_value) + { + case SPO2_MSG_ALG_NOT_OPEN: + DEBUG_PRINT("Algorithm is not initialized. \n"); + break; + + case SPO2_MSG_ALG_REOPEN: + DEBUG_PRINT("Algorithm is re initialized. \n"); + break; + + case SPO2_MSG_ALG_NOT_SUPPORT: + DEBUG_PRINT("Algorithm is not support. \n"); + break; + + default: + // DEBUG_PRINT("Algorithm unhandle error = %d \n", ret_value); + break; + } + //return 1 ; + } + } + else + { + report_ppg_data(&ppg_mems_data_alg); + } + } + } +} + + + +// SPO2- ALG- Task2 +void spo2_alg_task2(uint8_t ppg_num) +{ +#ifdef PPG_MEMS_Synchronize + if(Check_alg_enable()) + { + if(Check_alg_enable()==MSG_ALG_ENABLE) + { + spo2_algorithm_enable(); + }else if(Check_alg_enable()==MSG_ALG_DISABLE) + { + spo2_algorithm_disable(); + } + Clear_alg_enable(); + } + + if(!isFIFOEmpty()) + { + for (int k=0; k 0 ? 0x80 : 0x00); + hr_data.rsv2 = 0; + + + int32_t ret = PxiAlg_Process_Expo((uint8_t*)&hr_data, ppg_mems_data_alg.MEMS_Data, ppg_mems_data_alg.ppg_data.exposure_time[0]); + + + + + if(PxiAlg_GetHrUpdateFlag()) + { + PxiAlg_HrGet(&myHR); + PxiAlg_GetSigGrade(&hr_grader); + } + + + int32_t spo2_raw_1=ppg_mems_data_alg.ppg_data.data[0]; + int32_t spo2_raw_2=ppg_mems_data_alg.ppg_data.data[1]; + + RAW_DATA[0]=spo2_raw_1; + RAW_DATA[1]=spo2_raw_2; + + mems_data_raw[0].data[0]=ppg_mems_data_alg.MEMS_Data[0]; + mems_data_raw[0].data[1]=ppg_mems_data_alg.MEMS_Data[1] ; + mems_data_raw[0].data[2]=ppg_mems_data_alg.MEMS_Data[2]; + + // SPO2 fill data on pah8series structure + pxialg_data_spo2.touch_flag = ppg_mems_data_alg.touch_flag ; + pxialg_data_spo2.time = ppg_mems_data_alg.duration ;; + pxialg_data_spo2.ppg_data = (int32_t*)RAW_DATA; + pxialg_data_spo2.nf_ppg_channel = 2; + pxialg_data_spo2.nf_ppg_per_channel = 1; + pxialg_data_spo2.frame_count = ppg_mems_data_alg.ppg_frame_count ; + pxialg_data_spo2.nf_mems = 1; + pxialg_data_spo2.mems_data = (int16_t*)mems_data_raw; + + + + //DEBUG_PRINT("data_buf_count_spo2_alg = %d \r\n", data_buf_count_spo2_alg); + + + SpO2_SetHrValue(myHR); + SpO2_SetMems(mems_data_raw, 1); + //int ret_value = SpO2_Process(ppg_mems_data_alg.touch_flag , 2, pxialg_data_spo2.ppg_data, 1); + int ret_value = SpO2_Process(ppg_mems_data_alg.touch_flag , 2, pxialg_data_spo2.ppg_data, 1,pxialg_data_spo2.time ); + + SpO2_GetSpO2(&mySpO2); + SpO2_GetReadyFlag(&mySPO2_ReadyFlag); + SpO2_GetInfo(&_spo2_detect_item); + correlation =_spo2_detect_item.Noise; + trust_flag =_spo2_detect_item.Output[3]; + no_value_reason=_spo2_detect_item.Output[4]; + SpO2_GetPeriodicity(&SignalPeriodicity); + MEMS_RMS =_spo2_detect_item.RMS; + + + data_buf_count_spo2_alg++; + + #if defined(Optimize_SPO2_flow) + time_accu=time_accu+pxialg_data_spo2.time; + #endif + + if( (ret_value == 0 ) && (data_buf_count_spo2_alg>=25) ) + { + + #if defined(Optimize_SPO2_flow) + //time_accu=time_accu+pxialg_data->time; + DEBUG_PRINT("SPO2 Test Time = %d ,count =%d\n",time_accu,count); + if(time_accu>=31000) + { + spo2_array[count]=mySpO2; + count=count+1; + + LOG_PRINT("Over_30_sec_Stop_measurement\n"); + LOG_PRINT("This_meausrement_suggest_spo2_value is"); + + bubblesort(spo2_array,count); + + if(count % 2 == 0) + { + //log_printf(" "LOG_FLOAT_MARKER" \n", LOG_FLOAT(spo2_array[count/2])); + LOG_PRINT(" "LOG_FLOAT_MARKER" \n",LOG_FLOAT((spo2_array[(int)(count/2)] + spo2_array[(int)(count/2) - 1]) / 2.0f)); + } + else + { + LOG_PRINT(" "LOG_FLOAT_MARKER" \n", LOG_FLOAT(spo2_array[(int)(count/2)]*1.0f)); + } + + //log_pah8series_no_touch(); + spo2_algorithm_disable(); + pah_sensor_stop(); + count=0; + //add sensor stop here + } + else + { + if(mySpO2>0) + { + spo2_array[count]=mySpO2; + count=count+1; + } + } + #endif + //report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, Opt_SpO2, drop_flag, ascend_flag, mems_fla); + report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, no_value_reason, SignalPeriodicity, time_accu); + data_buf_count_spo2_alg = data_buf_count_spo2_alg -25; + } + else + { + //report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, Opt_SpO2, drop_flag, ascend_flag, mems_flag); + report_spo2_data(&ppg_mems_data_alg, ret, mySpO2, myHR, correlation, trust_flag, MEMS_RMS,data_buf_count_spo2_alg, no_value_reason, SignalPeriodicity, time_accu); + + switch (ret_value) + { + case SPO2_MSG_ALG_NOT_OPEN: + DEBUG_PRINT("Algorithm is not initialized. \n"); + break; + + case SPO2_MSG_ALG_REOPEN: + DEBUG_PRINT("Algorithm is re initialized. \n"); + break; + + case SPO2_MSG_ALG_NOT_SUPPORT: + DEBUG_PRINT("Algorithm is not support. \n"); + break; + + default: + DEBUG_PRINT("Algorithm unhandle error = %d \n", ret_value); + break; + } + //return 1 ; + } + } + else + { + report_ppg_data(&ppg_mems_data_alg); + } + } + } + } +#endif +} + + + +// Stress +void stress_algorithm_enable(void) +{ + int buffer_size = 0; + if (_main.stress_is_enable) + { + return; + } + + LOG_PRINT("HRVGetVersion() = %d \n", HRVGetVersion()); + buffer_size = HRVGetMemorySize(HRV_ENABLE_LHR, HRV_COLLECTION_SECONDS, HRV_SAMPLING_RATE); + LOG_PRINT("HRVGetMemorySize(), open_size = %d \n", buffer_size); + + if (!buffer_size) + { + LOG_PRINT("HRVGetMemorySize(), failed to get memory size \n"); + return ; + } + + stress_pBuffer = (uint8_t*)malloc(buffer_size); + if (!stress_pBuffer) + { + LOG_PRINT("Out of memory \n"); + return ; + } + + if (!HRVOpen(stress_pBuffer)) + { + LOG_PRINT("HRVOpen() failed. \n"); + return ; + } + duration_total=0; + _hrv_state.collect_duration = 0; + + _main.stress_is_enable = true; +} + +void stress_algorithm_disable(void) +{ + if (!_main.stress_is_enable) + return; + HRVClose(); + free(stress_pBuffer); + + duration_total = 0; + SDNN_ReadyFlag = 0; + Get_Stress = 0; + Stress = 0.0f; + HRAvg = 0; + SQ_Stress = 0.0f; + AnomalyFlag = 0; + Stress_ReadyFlag = 0; + Weak_Flag = 0; + _main.stress_is_enable = false; +} + +void stress_alg_task(int grade) +{ + if(Check_alg_enable()) + { + if(Check_alg_enable()==MSG_ALG_ENABLE) + { + stress_algorithm_enable(); + }else if(Check_alg_enable()==MSG_ALG_DISABLE) + { + stress_algorithm_disable(); + } + Clear_alg_enable(); + } + + if(!isFIFOEmpty()) + { + if(pah_pop(&ppg_mems_data_alg)) //Get data from FIFO + { + if(_main.stress_is_enable) + { + uint32_t raw_data = ppg_mems_data_alg.ppg_data.data[1]; + uint8_t frame_count = ppg_mems_data_alg.ppg_frame_count; + uint8_t timeInterval = ppg_mems_data_alg.duration; + uint8_t touch_flag = ppg_mems_data_alg.touch_flag; + + // If using Interrupt mode call this API + HRVSetDiffTime(timeInterval,1); + + HRVProcess(touch_flag, raw_data); + + duration_total+=timeInterval; + + + if(Stress_ReadyFlag==0) + { + Stress_ReadyFlag=HRVGetReadyFlag(); + } + + if((duration_total>25000)&& Stress_ReadyFlag==0) + { + LOG_PRINT("PPG Raw data is too Weak\r\n"); + LOG_PRINT("TEST Stop\r\n"); + stress_algorithm_disable(); + Weak_Flag=1; + return ; + } + + if(Stress_ReadyFlag == 1 || HRVGetReadyFlag()) + { + Stress_ReadyFlag=1; + _hrv_state.collect_duration += timeInterval; + + if(_hrv_state.collect_duration > (HRV_COLLECTION_SECONDS * 1000)) + { + //int grade=100; + HRAvg = HRVGetHRAvg(); + Stress= HRVGetStress(grade); + SQ_Stress=HRVGetRRIQuality(); + AnomalyFlag= HRVGetAnomalyFlag(); + LOG_PRINT("HRAvg = %d Stress = %f HRV_Quality = %f AnomalyFlag= %d \n", HRAvg ,Stress,SQ_Stress,AnomalyFlag); + + if(SQ_Stress>0.4f) + { + LOG_PRINT("HRV_Quality Good\n"); + } + else + { + LOG_PRINT("HRV_Quality Weak\n"); + } + + + if(Stress >=80 && Stress<=100) + { + LOG_PRINT("Stress_Level High\n"); + } + else if(Stress >=60 && Stress<80) + { + LOG_PRINT("Stress_Level Medium\n"); + } + else if(Stress >=30 && Stress<60) + { + LOG_PRINT("Stress_Level Normal\n"); + } + else + { + LOG_PRINT("Stress_Level Relaxed\n"); + } + + stress_algorithm_disable(); + _hrv_state.has_got_sdnn = 1; + Get_Stress=1; + return ; + } + } + report_stress_data(&ppg_mems_data_alg,Stress_ReadyFlag, duration_total, _hrv_state.collect_duration ); + } + else + { + report_ppg_data(&ppg_mems_data_alg); + LOG_PRINT("Stress_Level Normal\n"); + } + } + } +} + + + + +//============================================================================ +// Private function +//============================================================================ +static bool sensor_basic_verification(void) +{ + uint16_t product_id = 0; + pah_800x_get_product_id(&product_id); + if (product_id != PAH_800x_PRODUCT_ID) + { + pah_800x_power_toggle(&_main.pah_800x, true); + pah_800x_get_product_id( &product_id); + } + + DEBUG_PRINT("product_id = 0x%04X\n", product_id); + if (product_id != PAH_800x_PRODUCT_ID) + { + DEBUG_PRINT("Failed to verify product_id\n"); + return false; + } + + return true; +} + +static void process(uint64_t timestamp) +{ + float mems_data[3] = { 0.0f, 0.0f, 0.0f }; + + // Task + pah_ret ret = pah_800x_task(&_main.pah_800x); + if (PAH_FAILED(ret)) + { + DEBUG_PRINT("pah_800x_task() failed, ret = %d\n", ret); + return; + } + + int8_t touch_flag = -1; + pah_800x_get_touch_flag(&_main.pah_800x, &touch_flag); + + // PRINT("touch_flag : %d\n",touch_flag); + + if (_main.ppg_is_enabled) + { + pah_800x_ppg_data ppg_data; + pah_800x_ppg_get_data(&_main.pah_800x, &ppg_data); + + if (ppg_data.has_data) + { + // LOG_PRINT("ppg data %d %d %d %d %d %d %d %d\n",ppg_data.has_data,ppg_data.overflow_num,ppg_data.data[0],ppg_data.data[1],ppg_data.data[2], + // ppg_data.exposure_time[0],ppg_data.exposure_time[1],ppg_data.exposure_time[2]); + // LOG_PRINT("ppg data %d %d %d %d %d %d\n",ppg_data.frame_period[0],ppg_data.frame_period[1],ppg_data.frame_period[2] + // ,ppg_data.adc[0],ppg_data.adc[1],ppg_data.adc[2]); + + // PRINT("ppg data : %d %d %d\n",ppg_data.data[0],ppg_data.data[1],ppg_data.data[2]); + + factory_data = ppg_data.data[0]; + + uint64_t duration = timestamp - _main.ppg_prev_report_timestamp; + + if (!_main.ppg_has_prev_report_timestamp) + { + _main.ppg_has_prev_report_timestamp = true; + duration = 50; + } + _main.ppg_prev_report_timestamp = timestamp; + + if (duration > UINT8_MAX) + { + // DEBUG_PRINT("duration > UINT8_MAX !!!:%llu\n",duration); + PRINT("duration > UINT8_MAX !!!:%llu\n",duration); + return; + } + + ppg_mems_data_t ppg_mems_data; + + /***********************G sensor explanation start***********************************/ + //If no G sensor, please set ppg_mems_data.MEMS_Data[3] = {0}; + //Please set G sensor default range = ±2G. + //If G sensor output data format is not 16bit, please change to 16bit format. + //For example: G sensor is 12bit + //ReadGSensor(&mems_data[0],&mems_data[1],&mems_data[2]) + //MEMS_SensorX() absolute data must be largest when let hand down at static state. + //MEMS_SensorZ() absolute data must be largest when let hand horizontal on the table at static state. + /***********************G sensor explanation end***********************************/ + + ppg_mems_data.MEMS_Data[0] = mems_data[0];//ReadGSensorX(); + ppg_mems_data.MEMS_Data[1] = mems_data[1];//ReadGSensorY(); + ppg_mems_data.MEMS_Data[2] = mems_data[2];//ReadGSensorZ(); + ppg_mems_data.duration = duration; + + ppg_mems_data.ppg_data = ppg_data ; + ppg_mems_data.touch_flag = touch_flag ; + ppg_mems_data.ppg_frame_count = _main.ppg_frame_count; //SD-revise-20200320 + + pah_push(&ppg_mems_data); + +#ifdef PPG_MEMS_Synchronize + time_temp+=duration; + mems_data_polling_ready=0; + if(time_temp>=Time_Interval) + { + mems_data_polling_ready=1; + time_temp =0; + } + ppg_data_num++; +#endif + ++_main.ppg_frame_count; + + //report_ppg_data(&ppg_mems_data); + + } + } + + if (_main.is_Auto_mode || _main.touch_is_enabled)//SD-reivse-20191205 + { + if ( _main.touch_last_is_touched != touch_flag) + { + _main.touch_last_is_touched = touch_flag; + + report_touch_data(timestamp, &touch_flag); + + bool is_touched = (touch_flag >= 1); + + if (_main.is_Auto_mode && is_touched)//SD-revise-20191205 + { + //touch_sensor_disable(); + ppg_sensor_enable(); + _main.alg_is_enabled = MSG_ALG_ENABLE; + } + else if (_main.is_Auto_mode && !is_touched) + { + ppg_sensor_disable(); + pah_800x_update_touch_setting(&_main.pah_800x); + //touch_sensor_enable(); + _main.alg_is_enabled = MSG_ALG_DISABLE; + } + } + } +} + +static void ppg_sensor_enable(void) +{ + if (_main.ppg_is_enabled) + return; + + pah_800x_ppg_toggle(&_main.pah_800x, true); + + _main.debug_print_header = true; + _main.ppg_has_prev_report_timestamp = false; + _main.ppg_prev_report_timestamp = pah_get_tick_count(); + _main.ppg_frame_count = 0; + + _main.ppg_is_enabled = true; + + _read_index = 0 ; + _write_index = 0 ; +#ifdef PPG_MEMS_Synchronize + ppg_data_num = 0 ; +#endif + //LOG_PRINT("ppg_sensor_enable\n"); +} + +static void ppg_sensor_disable(void) +{ + if (!_main.ppg_is_enabled) + return; + + pah_800x_ppg_toggle(&_main.pah_800x, false); + + _main.ppg_is_enabled = false; +} + +static void touch_sensor_enable(void) +{ + if (_main.touch_is_enabled) + return; + + pah_800x_touch_toggle(&_main.pah_800x, true); + + _main.touch_last_is_touched = 0;//default no touch => touch mode + + _main.touch_is_enabled = true; +} + +static void touch_sensor_disable(void) +{ + if (!_main.touch_is_enabled) + return; + + pah_800x_touch_toggle(&_main.pah_800x, false); + + _main.touch_is_enabled = false; +} + +static void report_touch_data(uint64_t timestamp, const int8_t *touch_flag) +{ + LOG_PRINT("TOUCH: time = { %llu }, touch_flag = { %d } \n", timestamp, *touch_flag ); +} + +static void report_ppg_data(const ppg_mems_data_t *ppg_mems_data_alg) +{ + if (_main.debug_print_header == true) + { + LOG_PRINT("Frame, Time, Touch_Flag, Data_Ready, Overflow_Flag, Overflow_Num, ppg0, ppg1, ppg2, Expo_A, Expo_B, Expo_C, MEMS_X, MEMS_Y, MEMS_Z\n"); + _main.debug_print_header = false; + } + + LOG_PRINT("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", + ppg_mems_data_alg->ppg_frame_count, ppg_mems_data_alg->duration, ppg_mems_data_alg->touch_flag, + ppg_mems_data_alg->ppg_data.has_data, ppg_mems_data_alg->ppg_data.has_overflow, ppg_mems_data_alg->ppg_data.overflow_num, + ppg_mems_data_alg->ppg_data.data[0], ppg_mems_data_alg->ppg_data.data[1], ppg_mems_data_alg->ppg_data.data[2], + ppg_mems_data_alg->ppg_data.exposure_time[0], ppg_mems_data_alg->ppg_data.exposure_time[1], ppg_mems_data_alg->ppg_data.exposure_time[2], + (int)(ppg_mems_data_alg->MEMS_Data[0]), (int)(ppg_mems_data_alg->MEMS_Data[1]), (int)(ppg_mems_data_alg->MEMS_Data[2])); +} + +static void report_hr_data(const ppg_mems_data_t *ppg_mems_data_alg, int32_t ret, float hr, float hr_grader) +{ + if (_main.debug_print_header == true) + { + LOG_PRINT("Frame, Time, Touch_Flag, Data_Ready, Overflow_Flag, Overflow_Num, PPG0, PPG1, PPG2, Expo_A, Expo_B, Expo_C, MEMS_X, MEMS_Y, MEMS_Z, ret, hr, hr_grade\n"); + + _main.debug_print_header = false; + } + + LOG_PRINT("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %f, %f\n", + ppg_mems_data_alg->ppg_frame_count, ppg_mems_data_alg->duration, ppg_mems_data_alg->touch_flag, + ppg_mems_data_alg->ppg_data.has_data, ppg_mems_data_alg->ppg_data.has_overflow, ppg_mems_data_alg->ppg_data.overflow_num, + ppg_mems_data_alg->ppg_data.data[0], ppg_mems_data_alg->ppg_data.data[1], ppg_mems_data_alg->ppg_data.data[2], + ppg_mems_data_alg->ppg_data.exposure_time[0], ppg_mems_data_alg->ppg_data.exposure_time[1], ppg_mems_data_alg->ppg_data.exposure_time[2], + (int)(ppg_mems_data_alg->MEMS_Data[0]), (int)(ppg_mems_data_alg->MEMS_Data[1]), (int)(ppg_mems_data_alg->MEMS_Data[2]), ret, hr, hr_grader); + +} + +//static void report_spo2_data(const ppg_mems_data_t *ppg_mems_data_alg, int32_t ret, float mySpO2, float myHR, float correlation, float trust_flag, float MEMS_RMS, int data_buf_count_spo2_alg, , float Opt_SpO2, int drop_flag, int ascend_flag, int mems_flag) +static void report_spo2_data(const ppg_mems_data_t *ppg_mems_data_alg, int32_t ret, float myHR, float mySpO2, float correlation, float trust_flag, float MEMS_RMS, int data_buf_count_spo2_alg, uint8_t no_value_reason, float SignalPeriodicity, int time_accu ) +{ + if (_main.debug_print_header == true) + { + + LOG_PRINT("Frame, Time, Touch_Flag, Data_Ready, Overflow_Flag, Overflow_Num, PPG0, PPG1, PPG2, Expo_A, Expo_B, Expo_C, MEMS_X, MEMS_Y, MEMS_Z, ret, spo2, myHR, hr_grader, correlation, MEMS_RMS, trust, no_value_reason, SignalPeriodicity, time_accu \n"); + _main.debug_print_header = false; + } + + if(data_buf_count_spo2_alg>=25) + { + LOG_PRINT("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %f, %f, %f, %f, %f, %f, %d, %f, %d\n", + ppg_mems_data_alg->ppg_frame_count, ppg_mems_data_alg->duration, ppg_mems_data_alg->touch_flag, + ppg_mems_data_alg->ppg_data.has_data, ppg_mems_data_alg->ppg_data.has_overflow, ppg_mems_data_alg->ppg_data.overflow_num, + ppg_mems_data_alg->ppg_data.data[0], ppg_mems_data_alg->ppg_data.data[1], ppg_mems_data_alg->ppg_data.data[2], + ppg_mems_data_alg->ppg_data.exposure_time[0], ppg_mems_data_alg->ppg_data.exposure_time[1], ppg_mems_data_alg->ppg_data.exposure_time[2], + (int)(ppg_mems_data_alg->MEMS_Data[0]), (int)(ppg_mems_data_alg->MEMS_Data[1]), (int)(ppg_mems_data_alg->MEMS_Data[2]), ret, mySpO2,myHR,hr_grader,correlation, MEMS_RMS,trust_flag,no_value_reason,SignalPeriodicity, time_accu); + } + else + { + LOG_PRINT("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", + ppg_mems_data_alg->ppg_frame_count, ppg_mems_data_alg->duration, ppg_mems_data_alg->touch_flag, + ppg_mems_data_alg->ppg_data.has_data, ppg_mems_data_alg->ppg_data.has_overflow, ppg_mems_data_alg->ppg_data.overflow_num, + ppg_mems_data_alg->ppg_data.data[0], ppg_mems_data_alg->ppg_data.data[1], ppg_mems_data_alg->ppg_data.data[2], + ppg_mems_data_alg->ppg_data.exposure_time[0], ppg_mems_data_alg->ppg_data.exposure_time[1], ppg_mems_data_alg->ppg_data.exposure_time[2], + (int)(ppg_mems_data_alg->MEMS_Data[0]), (int)(ppg_mems_data_alg->MEMS_Data[1]), (int)(ppg_mems_data_alg->MEMS_Data[2]), ret); + + + } +} + + +static void report_stress_data(const ppg_mems_data_t *ppg_mems_data_alg, uint8_t Stress_ReadyFlag, uint32_t measuretime, float collect_time) +{ + if (_main.debug_print_header == true) + { + LOG_PRINT("Frame, Time, Touch_Flag, Data_Ready, Overflow_Flag, Overflow_Num, PPG0, PPG1, PPG2, Expo_A, Expo_B, Expo_C, MEMS_X, MEMS_Y, MEMS_Z, Stress_Ready, measure_time, collect_time\n"); + + _main.debug_print_header = false; + } + + LOG_PRINT("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %f\n", + ppg_mems_data_alg->ppg_frame_count, ppg_mems_data_alg->duration, ppg_mems_data_alg->touch_flag, + ppg_mems_data_alg->ppg_data.has_data, ppg_mems_data_alg->ppg_data.has_overflow, ppg_mems_data_alg->ppg_data.overflow_num, + ppg_mems_data_alg->ppg_data.data[0], ppg_mems_data_alg->ppg_data.data[1], ppg_mems_data_alg->ppg_data.data[2], + ppg_mems_data_alg->ppg_data.exposure_time[0], ppg_mems_data_alg->ppg_data.exposure_time[1], ppg_mems_data_alg->ppg_data.exposure_time[2], + (int)(ppg_mems_data_alg->MEMS_Data[0]), (int)(ppg_mems_data_alg->MEMS_Data[1]), (int)(ppg_mems_data_alg->MEMS_Data[2]), Stress_ReadyFlag,duration_total, _hrv_state.collect_duration ); + +} +#ifdef PPG_MEMS_Synchronize +uint8_t get_ppg_data_num(void) +{ + return ppg_data_num; +} +void clear_ppg_data_num(void) +{ + ppg_data_num = 0; +} + +void mems_interpolation(int16_t *mems_int_data_in,uint8_t mems_num,uint8_t ppg_num) +{ + + // Customer Define MEMS-input X, Y, Z + // Put data in mems_int_data_in ,and mems_count + // Then call the PXI_MEMS_interp to do interpolation + + PXI_MEMS_interp(mems_int_data_in, mems_num, mems_int_data_out, ppg_num); + +} +#endif + +static void error_handle(void) +{ + while (true) + { + } +} + +uint16_t pah8009_get_chip_id(void) +{ + uint16_t product_id = 0; + pah_800x_get_product_id(&product_id); + return product_id; +} + +uint32_t pah8009_get_factory_data(void) +{ + uint32_t data = factory_data; + factory_data = 0; + return data; +} + +void pah8009_int_handler(void) +{ + ppg_interrupt_handle(); + ppg_sensor_task_interrupt(); + + if(work_mode == 1) + { + // PRINT("hr_alg_task \n"); + hr_alg_task(); + } + else if(work_mode == 2) + { + // PRINT("spo2_alg_task \n"); + spo2_alg_task(); + } + +} + +void pah8009_timer_handler(void) +{ + ppg_sensor_task_polling(); + + if(work_mode == 1) + { + // PRINT("hr_alg_task \n"); + hr_alg_task(); + } + else if(work_mode == 2) + { + // PRINT("spo2_alg_task \n"); + spo2_alg_task(); + } + +} + +static void pah8009_timer_callback(void) +{ +#ifdef SUPPORT_PPG_SERVICE + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_PPG_HRS_TIMER_CALLBACK); +#endif +} + +static void pah8009_timer_init(void) +{ + if(g_pah8009_timer == NULL) + g_pah8009_timer = osTimerNew((osTimerFunc_t)pah8009_timer_callback, osTimerPeriodic, NULL, NULL); +} + + +void pah8009_control(char *mode,uint8_t enable) +{ + // printf("mode : %s ,enable : %d\n",mode,enable); + if(!enable) + { +#ifdef POLLING_MODE + if(g_pah8009_timer != NULL) + osTimerStop(g_pah8009_timer); +#endif + pah_sensor_stop(); + } + else + { +#ifdef POLLING_MODE + pah8009_timer_init(); +#endif + if (strcmp(mode, "hrs") == 0) { + pah_sensor_init(diw_4mm_g_ir_hrd); + auto_mode_sensor_start(); + work_mode = 1; + // touch_only_sensor_start(); + // ppg_only_sensor_start(); + } else if (strcmp(mode, "hrv") == 0) { + // md = HRV_MODE; + } else if (strcmp(mode, "spo2") == 0) { + // md = SPO2_MODE; + pah_sensor_init(diw_4mm_ir_r_ir_spo2); + auto_mode_sensor_start(); + work_mode = 2; + } else if (strcmp(mode, "leaklight") == 0) { + // md = FT_LEAK_LIGHT_MODE; + factory_test_mode(factory_test_leak_light_target_sample, 0, 0, 0, 0); + } else if (strcmp(mode, "wear") == 0) { + pah_sensor_init(diw_4mm_g_ir_hrd); + touch_only_sensor_start(); + } +#ifdef POLLING_MODE + if(g_pah8009_timer != NULL) + osTimerStart(g_pah8009_timer,40); +#endif + } +} \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_main.h b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_main.h new file mode 100644 index 000000000..2e51b953c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah800x_main.h @@ -0,0 +1,192 @@ +#ifndef __pah_800x_main_h__ +#define __pah_800x_main_h__ + +// pah +#include "pah_800x.h" +#include "pah_unit.h" +#include "pah_800x_config.h" + + + +//static hr algotirhm +// #include "pxialg.h" + +// spo2 algorithm +// #include "pxialg_spo2.h" + +// Stress algorithm +// #include "pxialg_hrv.h" +#ifdef PPG_MEMS_Synchronize +//MEMS-INT +#include "pxi_interp.h" +#endif +//============================================================================ +// Functions +//============================================================================ +#ifdef __cplusplus +extern "C" { +#endif + + +//============================================================================ +// Definition +//============================================================================ +#ifdef PPG_MEMS_Synchronize +#define FIFO_SIZE 50 //FIFO Size is dependent on the CPU performance +#else +#define FIFO_SIZE 8 //FIFO Size is dependent on the CPU performance +#endif + +//============================================================================ +// Type Definition +//============================================================================ +#pragma pack(1) +typedef struct raw_data_13bytes_t +{ + uint8_t loss; + uint32_t rawData; + uint8_t non_zero1; + uint8_t non_zero2; + uint8_t non_zero3; + uint8_t frame_count; + uint8_t time; + uint8_t rsv; + uint8_t touch; + uint8_t rsv2; +} sRaw_Data_13Bytes; + +typedef enum { + MSG_ALG_NOCHANGE = 0, + MSG_ALG_ENABLE, + MSG_ALG_DISABLE, +} alg_msg_code_t; +#pragma pack() + +typedef enum +{ + pc_4mm_2g_ir_hrd, // PC 4.25mm for HRD wear + diw_4mm_g_ir_hrd, // DI+WALL 4.25mm for HRD hrs + diw_4mm_ir_r_ir_spo2, // DI+WALL 4.25mm for SPO2 spo2 + pc_22mm_2g_ir_hrd, // PC 2.2mm for HRD + di_18mm_g_g_hrd, // DI 1.8mm for HRD + +} reg_config_type; + +typedef struct { + + volatile bool has_interrupt; + volatile uint64_t interrupt_timestamp; + + // pah + pah_800x pah_800x; + + bool is_Auto_mode; + // ppg + bool ppg_is_enabled; + //bool ppg_only_is_enabled; + bool ppg_has_prev_report_timestamp; + uint64_t ppg_prev_report_timestamp; + uint8_t ppg_frame_count; + + // touch + bool touch_is_enabled; + //bool touch_only_is_enabled; + int touch_last_is_touched; + + // alg + uint8_t alg_is_enabled; + bool hr_is_enabled; + bool spo2_is_enabled; + bool stress_is_enable; + // debug + bool debug_print_header; + uint8_t debug_frame_count; + +} main_state; + +typedef struct { + float MEMS_Data[3] ; + pah_800x_ppg_data ppg_data; + uint8_t touch_flag; + uint8_t duration; + uint8_t ppg_frame_count; + //pah_800x_touch_data touch_data; +} ppg_mems_data_t; + + + + + +//============================================================================ +// Public function +//============================================================================ +void pah_sensor_init(reg_config_type type); +void touch_only_sensor_start(void); +void ppg_only_sensor_start(void); +void auto_mode_sensor_start(void); +void pah_sensor_stop(void); +void ppg_interrupt_handle(void); +void ppg_sensor_task_interrupt(void); +void ppg_sensor_task_polling(void); + + +bool isFIFOEmpty(void); +bool pah_push(ppg_mems_data_t *data); +bool pah_pop(ppg_mems_data_t *data); + + +uint8_t Check_alg_enable(void); +void Clear_alg_enable(void); + +//HRD +void hr_algorithm_enable(void); +void hr_algorithm_disable(void); +void hr_alg_task(void); +void hr_alg_task2(uint8_t ppg_num); + +//SPO2 +void spo2_algorithm_enable(void); +void spo2_algorithm_disable(void); +void spo2_alg_task(void); +void spo2_alg_task2(uint8_t ppg_num); + +//Stress +void stress_algorithm_enable(void); +void stress_algorithm_disable(void); +//void stress_alg_task(void); +void stress_alg_task(int grade); + +uint16_t pah8009_get_chip_id(void); +void pah8009_control(char *mode,uint8_t enable); +uint32_t pah8009_get_factory_data(void); +void pah8009_int_handler(void); + +/** + * @brief Macro to be used in a formatted string to a pass float number to the log. + * + * Macro should be used in formatted string instead of the %f specifier together with + * @ref LOG_FLOAT macro. + * Example: LOG_INFO("My float number" LOG_FLOAT_MARKER "\r\n", LOG_FLOAT(f))) + */ +#define LOG_FLOAT_MARKER "%c%d.%05d" + +/** + * @brief Macro for dissecting a float number into two numbers (integer and residuum). + */ +#define LOG_FLOAT(val) ((val >= 0.0f)?32:45),(int32_t)((val >= 0.0f)?val:val*-1) , (int32_t)(((val > 0) ? (val) - (int32_t)(val): (int32_t)(val) - (val))*100000) + + + +#ifdef PPG_MEMS_Synchronize +//MEMS Interpolation +//void mems_interpolation(uint8_t ppg_num); +void mems_interpolation(int16_t *mems_int_data_in,uint8_t mems_count,uint8_t ppg_num); +uint8_t get_ppg_data_num(void); +void clear_ppg_data_num(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_8009_reg_arr_default_20220623.h b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_8009_reg_arr_default_20220623.h new file mode 100644 index 000000000..abf28f21c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_8009_reg_arr_default_20220623.h @@ -0,0 +1,484 @@ +#ifndef __pah_8009_reg_arr_default_h__ +#define __pah_8009_reg_arr_default_h__ + +// c +#include + +//pah +#include "pah_800x_config.h" + + +static const uint8_t PAH8009_REG_DEVICE_INIT[][2] = { +// { 0xEE,0x07 }, //SW RESET + { 0xD1,0xD0 },//{R_GPIO_0_IEB, R_GPIO_1_IEB, R_GPIO_0_OEB, R_GPIO_1_OEB, R_GPIO_0_PULLL_EnH, R_GPIO_1_PULLL_EnH, R_GPIO_0_PULLH_EnH, R_GPIO_1_PULLH_EnH}; + { 0xD2,0x00+R_GPIO_SLEW+R_GPIO_0_OD_EnH },//R_GPIO_0_Open_Drain_EnH(0xD2[5]), 1(0x20):GPIO default open-drain mode, 0(0x00):GPIO debug mode + { 0xD3,0x20 },//GPIO debug select + { 0xD6,0x00+R_I2C_SLEW },//{Dummy, R_I2C_SLEW, Dummy[5:0]} +#if (INT_OD_EXTERNAL_PULLH) + { 0xD1,0xD0 },//{R_GPIO_0_IEB, R_GPIO_1_IEB, R_GPIO_0_OEB, R_GPIO_1_OEB, R_GPIO_0_PULLL_EnH, R_GPIO_1_PULLL_EnH, R_GPIO_0_PULLH_EnH, R_GPIO_1_PULLH_EnH}; + { 0xD2,0x20+R_GPIO_SLEW },//R_GPIO_0_Open_Drain_EnH(0xD2[5]), 1(0x20):GPIO default open-drain mode, 0(0x00):GPIO debug mode + { 0xD3,0x00 },//GPIO debug select + { 0xD6,0x00+R_I2C_SLEW },//{Dummy, R_I2C_SLEW, Dummy[5:0]} +#endif +#if (INT_OD_INTERNAL_PULLH) + { 0xD1,0xD2 },//{R_GPIO_0_IEB, R_GPIO_1_IEB, R_GPIO_0_OEB, R_GPIO_1_OEB, R_GPIO_0_PULLL_EnH, R_GPIO_1_PULLL_EnH, R_GPIO_0_PULLH_EnH, R_GPIO_1_PULLH_EnH}; + { 0xD2,0x20+R_GPIO_SLEW },//R_GPIO_0_Open_Drain_EnH(0xD2[5]), 1(0x20):GPIO default open-drain mode, 0(0x00):GPIO debug mode + { 0xD3,0x00 },//GPIO debug select + { 0xD6,0x00+R_I2C_SLEW },//{Dummy, R_I2C_SLEW, Dummy[5:0]} +#endif +#if (INT_PUP_WITHOUT_PULLH) + { 0xD1,0xD0 },//{R_GPIO_0_IEB, R_GPIO_1_IEB, R_GPIO_0_OEB, R_GPIO_1_OEB, R_GPIO_0_PULLL_EnH, R_GPIO_1_PULLL_EnH, R_GPIO_0_PULLH_EnH, R_GPIO_1_PULLH_EnH}; + { 0xD2,0x00+R_GPIO_SLEW },//R_GPIO_0_Open_Drain_EnH(0xD2[5]), 1(0x20):GPIO default open-drain mode, 0(0x00):GPIO debug mode + { 0xD3,0x00 },//GPIO debug select + { 0xD6,0x00+R_I2C_SLEW },//{Dummy, R_I2C_SLEW, Dummy[5:0]} +#endif +// { 0xD6,0x30 },//{Dummy, R_I2C_SLEW, R_I2C_DRV[1:0], Dummy[3:0]} +// { 0xD5,0x44 },//IO-level(I2C), 44:3.3V, 00:1.8V +// { 0xB2,0x25 }, + { 0x55,0x24 },//Soft Reset:04 Hard Reset:24 + { 0x52,0x12 },//VDDAY=1.63V +// { 0xA6,0xF7 },//Cmd_vdday_pwrsv_sel_EnH=0 + { 0xAE,0x3F },//R_LPO_Cali_mode=1 + { 0x20,0x05 },//Clear INT +}; +#ifndef LED_SUPPLIER_NEW +#ifdef DI_WALL_4mm +#define PPG_SETTING_VERSION 0x01 +#endif +#if (DIW_4MM_G_IR_HRD==1) +static const uint8_t PAH8009_REG_DIW_4MM_G_IR_PPG[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x08,0xE8 },//A period + { 0x09,0x03 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x08 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x0E,0x04 },//RDB_FrameNum_A[6:0] + { 0x0F,0x08 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x76 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x12 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x04 },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0x92 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x58 },//RDB_expo_A[7:0] + { 0x18,0x02 },//RDB_expo_A[15:8] + { 0x19,0x00 },//RDB_expo_B[7:0] + { 0x1A,0x01 },//RDB_expo_B[15:8] + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1D,0x1F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x2F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; + +static const uint8_t PAH8009_REG_DIW_4MM_G_IR_TOUCH[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x44 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x16,0x92 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0x04 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; +#endif +#if (DIW_4MM_IR_R_IR_SPO2==1) +static const uint8_t PAH8009_REG_DIW_4MM_IR_R_IR_PPG[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x00 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x05 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x08,0x00 },//A period + { 0x09,0x01 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x01 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x0E,0x40 },//RDB_FrameNum_A[6:0] + { 0x0F,0x40 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x77 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x52 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x44 },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0x84 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x40 },//RDB_expo_A[7:0] + { 0x18,0x00 },//RDB_expo_A[15:8] + { 0x19,0x40 },//RDB_expo_B[7:0] + { 0x1A,0x00 },//RDB_expo_B[15:8] + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1D,0x1F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x4F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; + + +static const uint8_t PAH8009_REG_DIW_4MM_IR_R_IR_TOUCH[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x00 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x05 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x44 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x16,0x92 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0x04 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; + +#endif + +#if (PC_4MM_2G_IR_HRD==1) +#ifdef PC_4mm +#define PPG_SETTING_VERSION 0x11 +#endif +static const uint8_t PAH8009_REG_PC_4MM_2G_IR_PPG[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x08,0xE8 },//A period + { 0x09,0x03 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x08 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x0E,0x04 },//RDB_FrameNum_A[6:0] + { 0x0F,0x08 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x76 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x12 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x44 },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0xC4 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x58 },//RDB_expo_A[7:0] + { 0x18,0x02 },//RDB_expo_A[15:8] + { 0x19,0x00 },//RDB_expo_B[7:0] + { 0x1A,0x01 },//RDB_expo_B[15:8] + { 0x1B,0x28 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1D,0x1F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x6F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; + +static const uint8_t PAH8009_REG_PC_4MM_2G_IR_TOUCH[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x44 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x16,0xD2 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x1B,0x28 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0x04 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; +#endif + + +#else +#ifdef DI_WALL_4mm +#define PPG_SETTING_VERSION 0x21 +#endif +#if (DIW_4MM_G_IR_HRD==1) +static const uint8_t PAH8009_REG_DIW_4MM_G_IR_PPG[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x08,0xE8 },//A period + { 0x09,0x03 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x08 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x0E,0x04 },//RDB_FrameNum_A[6:0] + { 0x0F,0x08 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x76 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x12 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x04 },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0x12 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x58 },//RDB_expo_A[7:0] + { 0x18,0x02 },//RDB_expo_A[15:8] + { 0x19,0x00 },//RDB_expo_B[7:0] + { 0x1A,0x01 },//RDB_expo_B[15:8] + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1D,0x1F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x2F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; + +static const uint8_t PAH8009_REG_DIW_4MM_G_IR_TOUCH[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x44 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x16,0x12 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0x04 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; +#endif + +#if (DIW_4MM_IR_R_IR_SPO2==1) +static const uint8_t PAH8009_REG_DIW_4MM_IR_R_IR_PPG[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x00 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x05 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x08,0x00 },//A period + { 0x09,0x01 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x01 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x0E,0x40 },//RDB_FrameNum_A[6:0] + { 0x0F,0x40 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x77 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x12 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x04 },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0x04 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x40 },//RDB_expo_A[7:0] + { 0x18,0x00 },//RDB_expo_A[15:8] + { 0x19,0x40 },//RDB_expo_B[7:0] + { 0x1A,0x00 },//RDB_expo_B[15:8] + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1D,0x1F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x4F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; + +static const uint8_t PAH8009_REG_DIW_4MM_IR_R_IR_TOUCH[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x00 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x05 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x44 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x16,0x12 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x1B,0x20 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0x04 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; +#endif + +//China LED + +#if (PC_4MM_2G_IR_HRD==1) +#ifdef PC_4mm +#define PPG_SETTING_VERSION 0x31 +#endif +static const uint8_t PAH8009_REG_PC_4MM_2G_IR_PPG[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x08,0xE8 },//A period + { 0x09,0x03 },//A period + { 0x0A,0x00 },//B period + { 0x0B,0x08 },//B period + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x0E,0x04 },//RDB_FrameNum_A[6:0] + { 0x0F,0x08 },//RDB_FrameNum_B[6:0] + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x76 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x14,0x12 },//{RDB_ChA_congain_sel[1:0], Dummy[0], R_LEDDAC_code0[4:0]} + { 0x15,0x44 },//{RDB_ChB_congain_sel[1:0], Dummy[0], R_LEDDAC_code1[4:0]} + { 0x16,0x04 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x17,0x58 },//RDB_expo_A[7:0] + { 0x18,0x02 },//RDB_expo_A[15:8] + { 0x19,0x00 },//RDB_expo_B[7:0] + { 0x1A,0x01 },//RDB_expo_B[15:8] + { 0x1B,0x28 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1D,0x1F },//{R_ChA_LED_EnH[2:0], R_ChA_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1E,0x6F },//{R_ChB_LED_EnH[2:0], R_ChB_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0xF7 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; + +static const uint8_t PAH8009_REG_PC_4MM_2G_IR_TOUCH[][2] = { + //{ 0xEE,0x07 }, + { 0x03,0x40 },//Golden report period[7:0] (1T=31.25us) + { 0x04,0x06 },//Golden report period[15:8] + { 0x05,0x00 },//Golden report period[19:16] + { 0x12,0x01 },//ChC_report_divider[7:0] + { 0x13,0x00 },//ChC_report_divider[9:8] + { 0x0C,0x00 },//C period + { 0x0D,0x01 },//C period + { 0x10,0x01 },//RDB_FrameNum_C[6:0] + { 0x11,0x44 },//{R_OnOff_mode_C_EnH, R_OnOff_mode_B_EnH, R_OnOff_mode_A_EnH, R_ChC_EnH, R_ChB_EnH, R_ChA_EnH} + { 0x16,0x12 },//{RDB_ChC_congain_sel[1:0], Dummy[0], R_LEDDAC_code2[4:0]} + { 0x1B,0x28 },//RDB_expo_C[7:0] + { 0x1C,0x00 },//RDB_expo_C[15:8] + { 0x1F,0x1F },//{R_ChC_LED_EnH[2:0], R_ChC_Pixel_EnH[3:0]}, [3]:pixel3, [2]:pixel2, [1]:pixel1, [0]:pixel0, enable high + { 0x22,0x04 },//RDB_Int_En[7:0], [2]:touch flag [1]:overflow [0]:data ready + { 0x26,0x20 },//{R_ADCdata_C_Sel[1:0], R_ADCdata_B_Sel[1:0], R_ADCdata_A_Sel[1:0]}, 0:on, 1:off(需開On-Off), 2:on-off(需開On-Off) + { 0x49,0x11 },//RDB_Touch_EnH + { 0x4A,0x00 },//R_TouchDetection_Th_Hi[7:0] + { 0x4B,0x07 },//R_TouchDetection_Th_Hi[13:8] + { 0x4C,0x00 },//R_TouchDetection_Th_Low[7:0] + { 0x4D,0x05 },//R_TouchDetection_Th_Low[13:8] + { 0x4E,0x00 },//R_TouchDetection_Count_Th[4:0] + { 0x4F,0x00 },//R_NoTouchDetection_Count_Th[4:0] + { 0xEB,0x80 },//update_flag +}; +#endif + +#endif + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x.c b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x.c new file mode 100644 index 000000000..da77ddbdc --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x.c @@ -0,0 +1,833 @@ +// pah +#include "pah_800x.h" + + +//============================================================================ +// Private function +//============================================================================ +static bool sensor_has_enabled(pah_800x *state); + +static pah_ret ppg_convergence_toggle(pah_800x *state, bool enable, uint8_t ch_num); + +static pah_ret ppg_reset_exposure(pah_800x *state, uint8_t ch_num); + +//static pah_ret touch_process(pah_800x *state, uint8_t *touch_flag); +static pah_ret ppg_process(pah_800x *state, pah_800x_ppg_data *ppg_result); +static pah_ret clear_interrupt(pah_800x *state, bool has_ppg_interrupt, bool has_overflow); + +static pah_ret ppg_converging(pah_800x *state, uint32_t ppg_value, uint8_t ch_num); +static uint16_t select_new_ppg_exposure(pah_800x *state, uint16_t old_ppg_exposure, uint16_t ppg_value, uint8_t ch_num); + +static bool is_touched(pah_800x *state); +static bool is_not_touched(pah_800x *state); + +static bool ppg_value_is_out_of_outer_bounds(pah_800x *state, uint32_t ppg_data, uint8_t ch_num); +static bool ppg_value_is_out_of_inner_bounds(pah_800x *state, uint16_t ppg_data, uint8_t ch_num); + +static pah_ret pah_800x_sw_reset(pah_800x *state); +///////////////////////////////////////////////////////////////////////////////////////////// + +//// comm + +static pah_ret pah_800x_hal_comm_write(uint8_t addr, const uint8_t *data, size_t write_size); +static pah_ret pah_800x_hal_comm_read(uint8_t addr, uint8_t *data, size_t read_size); + + +//// write +static pah_ret pah_800x_hal_write_reg_arr(const pah_reg_arr *reg_arr); +static pah_ret pah_800x_hal_write_reg_array(const uint8_t reg_array[][2], size_t length); +static pah_ret pah_800x_hal_write_suspend_state(bool suspend); +static pah_ret pah_800x_hal_write_interrupt_clear(void); +static pah_ret pah_800x_hal_write_interrupt_clear_v2(bool int_status_DR_FLAG_b); +static pah_ret pah_800x_hal_write_ppg_overflow_clear(void); +static pah_ret pah_800x_hal_write_exposure(uint16_t exposure, uint8_t ch_num); +static pah_ret pah_800x_hal_tg_toggle(bool enable); +static pah_ret pah_800x_hal_update_flag(void); +static pah_ret pah_800x_hal_write_sw_reset(void); +static pah_ret pah_800x_hal_reset_gpio_state(void); +//// read +static pah_ret pah_800x_hal_read_product_id(uint16_t *product_id); +static pah_ret pah_800x_hal_read_ppg_interrupt(uint8_t *ppg_interrupt); +static pah_ret pah_800x_hal_read_ppg_sync(uint32_t *ppg_data, uint8_t ch_num); +static pah_ret pah_800x_hal_read_ppg_overflow(uint8_t *ppg_overflow, uint8_t *overflow_num); +static pah_ret pah_800x_hal_read_ppg_exposure(uint16_t *als_exposure, uint8_t ch_num); +static pah_ret pah_800x_hal_touch_get_touch_flag(int8_t *touch_flag); +static pah_ret pah_800x_hal_touch_get_touch_info(int8_t *touch_flag,uint16_t *touch_value); + + +static pah_ret pah_800x_hal_check_enable_channel(pah_800x *state, const pah_reg_arr *reg_arr); +static pah_ret comm_write(uint8_t addr, uint8_t data); +static pah_ret pah_800x_hal_read_ppg_adc(uint16_t *ppg_adc, uint8_t ch_num); +static pah_ret pah_800x_hal_read_ppg_frame_period(uint16_t *ppg_frame_period, uint8_t ch_num); + + +//============================================================================ +// Public function +//============================================================================ +uint16_t pah_800x_get_i2c_default_slave_addr(void) +{ + return PAH_800x_DEFAULT_I2C_SLAVE_ID_1; +} + +void pah_800x_get_default_config(pah_800x_config *config) +{ + memset(config, 0, sizeof(*config)); + + config->enable_ppg_convergence[0] = PAH_800x_DEFAULT_ENABLE_PPG_CONVERGENCE; + config->enable_ppg_convergence[1] = PAH_800x_DEFAULT_ENABLE_PPG_CONVERGENCE; + config->enable_ppg_convergence[2] = false; + + config->enable_ppg_reconvergence_if_out_of_bounds[0] = PAH_800x_DEFAULT_ENABLE_PPG_RECONVERGENCE_IF_OUT_OF_BOUNDS; + config->enable_ppg_reconvergence_if_out_of_bounds[1] = PAH_800x_DEFAULT_ENABLE_PPG_RECONVERGENCE_IF_OUT_OF_BOUNDS; + config->enable_ppg_reconvergence_if_out_of_bounds[2] = false; + + for(int ch=0;chppg_convergence[ch].t_weight_normal_mode = PAH_800x_DEFAULT_PPG_CONVERGENCE_T_WEIGHT_NORMAL_MODE; + config->ppg_convergence[ch].t_weight_fast_mode = PAH_800x_DEFAULT_PPG_CONVERGENCE_T_WEIGHT_FAST_MODE; + config->ppg_convergence[ch].t_min = PAH_800x_DEFAULT_PPG_CONVERGENCE_T_MIN; + config->ppg_convergence[ch].t_max = PAH_800x_DEFAULT_PPG_CONVERGENCE_T_MAX; + config->ppg_convergence[ch].raw_outer_high_bound = PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_OUTER_HIGH_BOUND; + config->ppg_convergence[ch].raw_inner_high_target = PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_INNER_HIGH_TARGET; + config->ppg_convergence[ch].raw_inner_low_target = PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_INNER_LOW_TARGET; + config->ppg_convergence[ch].raw_outer_low_bound = PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_OUTER_LOW_BOUND; + config->ppg_convergence[ch].convergence_count = PAH_800x_DEFAULT_PPG_CONVERGENCE_COUNT; + config->ppg_initial_exposure[ch] = PAH_800x_DEFAULT_PPG_INITIAL_EXPOSURE; + } + +} + +pah_ret pah_800x_get_product_id(uint16_t *product_id) +{ + return pah_800x_hal_read_product_id(product_id); +} + +pah_ret pah_800x_init(pah_800x *state, const pah_800x_config *config) +{ + memset(state, 0, sizeof(*state)); + + // state->plat = *plat; + state->config = *config; + for(int ch=0;chenable_ppg_convergence[ch]); + if (config->enable_ppg_convergence[ch]) + { + DEBUG_PRINT("(t_weight_normal_mode, t_weight_fast_mode) = (%d, %d)\n", + config->ppg_convergence[ch].t_weight_normal_mode, + config->ppg_convergence[ch].t_weight_fast_mode); + DEBUG_PRINT("(t_min, t_max) = (%d, %d)\n", + config->ppg_convergence[ch].t_min, + config->ppg_convergence[ch].t_max); + DEBUG_PRINT("(raw_outer_high_bound, raw_inner_high_target) = (%d, %d)\n", + config->ppg_convergence[ch].raw_outer_high_bound, + config->ppg_convergence[ch].raw_inner_high_target); + DEBUG_PRINT("(raw_inner_low_target, raw_outer_low_bound) = (%d, %d)\n", + config->ppg_convergence[ch].raw_inner_low_target, + config->ppg_convergence[ch].raw_outer_low_bound); + } + } + + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_deinit(pah_800x *state) +{ + pah_800x_ppg_toggle(state, false); + pah_800x_touch_toggle(state, false); + pah_800x_power_toggle(state, false); + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_device_init(pah_800x *state, const pah_800x_reg_setting *reg_setting) +{ + DEBUG_PRINT("%s\n", __func__); + + //uint16_t *product_id; + uint16_t product_id; + state->reg_setting = *reg_setting; + + pah_800x_hal_write_suspend_state(false); + pah_800x_hal_write_sw_reset(); + pah_delay_ms(2); + pah_800x_power_toggle(state, true); + + // read id, delay for reg bank reset + //pah_800x_hal_read_product_id(product_id); + pah_800x_hal_read_product_id(&product_id); + pah_800x_hal_write_reg_arr(&state->reg_setting.startup_init); + + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_power_toggle(pah_800x *state, bool enable) +{ + DEBUG_PRINT("%s(%d, %d)\n", __func__, state->is_powered, enable); + + + if (enable) + { + if (state->is_powered == enable) + { + return PAH_RET_SUCCESS; + } + pah_800x_hal_write_suspend_state(false); + } + else + { + state->ppg_state.is_enabled = false; + state->touch_state.is_enabled = false; + + pah_800x_hal_write_suspend_state(false); + //pah_800x_hal_write_sw_reset(); + pah_delay_ms(2); + pah_800x_hal_write_suspend_state(true); + pah_800x_hal_reset_gpio_state(); + } + + state->is_powered = enable; + state->touch_state.touch_flag = TOUCH_TRALSE_VALUE; + + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_verify_product_id(pah_800x *state, uint16_t *product_id) +{ + return pah_800x_hal_read_product_id(product_id); +} + +pah_ret pah_800x_ppg_toggle(pah_800x *state, bool enable) +{ + DEBUG_PRINT("%s(%d, %d)\n", __func__, state->ppg_state.is_enabled, enable); + if (state->ppg_state.is_enabled == enable) + return PAH_RET_SUCCESS; + //pah_800x_hal_write_als_toggle( enable); + if (enable) + { + //load ppg setting + //comm_write(0xEB,0x80); +// for(uint8_t ch_num=0;ch_num < PAH_800x_MAX_CH_NUM;ch_num++) +// { +// ppg_reset_exposure(state,ch_num); +// pah_800x_hal_update_flag(); +// } + + pah_800x_hal_write_reg_arr(&state->reg_setting.ppg_enable); + + pah_800x_hal_check_enable_channel(state, &state->reg_setting.ppg_enable); + //DEBUG_PRINT("ch enable %d %d %d \n",state->ppg_state.ppg_ch_enabled[0],state->ppg_state.ppg_ch_enabled[1],state->ppg_state.ppg_ch_enabled[2]); + pah_800x_hal_update_flag(); + + pah_800x_hal_write_interrupt_clear(); + if(!state->touch_state.is_enabled) + pah_800x_hal_tg_toggle(true); + } + else + { + if(!state->touch_state.is_enabled) + pah_800x_hal_tg_toggle(false); + } + + + for(uint8_t ch_num=0;ch_num < PAH_800x_MAX_CH_NUM;ch_num++) + { + state->ppg_state.is_converging[ch_num] = enable; + state->ppg_state.cur_converging_count[ch_num] = 0; + } + + state->ppg_state.is_enabled = enable; + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_ppg_get_data(pah_800x *state, pah_800x_ppg_data *ppg_data) +{ + *ppg_data = state->ppg_result; + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_update_touch_setting(pah_800x *state) +{ + pah_800x_hal_write_reg_arr(&state->reg_setting.touch_enable); + pah_800x_hal_update_flag(); + + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_touch_toggle(pah_800x *state, bool enable) +{ + DEBUG_PRINT("%s(%d, %d)\n", __func__, state->touch_state.is_enabled, enable); + if (state->touch_state.is_enabled == enable) + return PAH_RET_SUCCESS; + + if (enable) + { + //load touch setting + pah_800x_hal_write_reg_arr(&state->reg_setting.touch_enable); + pah_800x_hal_update_flag(); + pah_800x_hal_tg_toggle(true); + } + else + pah_800x_hal_tg_toggle(false); + state->touch_state.is_enabled = enable; + + return PAH_RET_SUCCESS; +} + +pah_ret pah_800x_get_touch_flag(pah_800x *state, int8_t *touch_flag) +{ + *touch_flag = state->touch_flag; + return PAH_RET_SUCCESS; +} +pah_ret pah_800x_get_touch_value(pah_800x *state, uint16_t *touch_value) +{ + *touch_value = state->touch_value; + return PAH_RET_SUCCESS; +} + + +pah_ret pah_800x_task(pah_800x *state) +{ + uint8_t ppg_interrupt = 0; + bool has_ppg_interrupt = false; + memset(&state->ppg_result, 0, sizeof(state->ppg_result)); + state->touch_flag = -1; + //memset(&state->touch_result, 0, sizeof(state->touch_result)); + + //touch_process(state, &state->touch_flag); + pah_800x_hal_touch_get_touch_flag( &state->touch_flag); + //pah_800x_hal_touch_get_touch_info( &state->touch_flag,&state->touch_value); + + pah_800x_hal_read_ppg_interrupt(&ppg_interrupt); + + has_ppg_interrupt = (ppg_interrupt > 0); + //DEBUG_PRINT("%s(%d)(%d)\n", __func__, ppg_interrupt,state->touch_flag); + if (has_ppg_interrupt > 0) + { + ppg_process(state, &state->ppg_result); + } + + clear_interrupt(state, has_ppg_interrupt, state->ppg_result.has_overflow); + + return PAH_RET_SUCCESS; +} + + +//============================================================================ +// Private function +//============================================================================ +static bool sensor_has_enabled(pah_800x *state) +{ + return state->ppg_state.is_enabled + || state->touch_state.is_enabled; +} + +static pah_ret ppg_convergence_toggle(pah_800x *state, bool enable, uint8_t ch_num) +{ + //DEBUG_PRINT("%s(%d, %d, %d)\n", __func__, state->config.enable_ppg_convergence[ch_num], enable, ch_num); + + if (ch_num >= PAH_800x_MAX_CH_NUM) + return PAH_RET_INVALID_ARGUMENT; + + if (!state->config.enable_ppg_convergence[ch_num]) + return PAH_RET_SUCCESS; + + if (enable && state->ppg_state.cur_converging_count[ch_num] < state->config.ppg_convergence[ch_num].convergence_count) + { + state->ppg_state.cur_converging_count[ch_num]++; + return PAH_RET_SUCCESS; + } + else + { + state->ppg_state.cur_converging_count[ch_num] = 0; + } + state->ppg_state.is_converging[ch_num] = enable; + + return PAH_RET_SUCCESS; +} + +static pah_ret ppg_reset_exposure(pah_800x *state, uint8_t ch_num) +{ + //DEBUG_PRINT("%s(%d)\n", __func__, state->config.ppg_initial_exposure[ch_num]); + if (!state->config.enable_ppg_convergence[ch_num]) + return PAH_RET_SUCCESS; + + return pah_800x_hal_write_exposure( state->config.ppg_initial_exposure[ch_num],ch_num); +} +/*static pah_ret touch_process(pah_800x *state, uint8_t *touch_flag) +{ + + pah_800x_touch_get_touch_flag( touch_flag); + + return PAH_RET_SUCCESS; +}*/ + + +static pah_ret ppg_process(pah_800x *state, pah_800x_ppg_data *ppg_result) +{ + uint32_t ppg_value[PAH_800x_MAX_CH_NUM] = {0}; + uint8_t ppg_overflow = 0; + uint8_t overflow_num = 0; + uint16_t ppg_exposure = 0; + uint16_t ppg_adc = 0; + uint16_t ppg_frame_period = 0; + if (!state->ppg_state.is_enabled) + return PAH_RET_SUCCESS; + + for(uint8_t ch_num=0; ch_num < PAH_800x_MAX_CH_NUM; ch_num++) + { + if(state->ppg_state.ppg_ch_enabled[ch_num]) + { + pah_800x_hal_read_ppg_sync(&ppg_value[ch_num], ch_num); + pah_800x_hal_read_ppg_exposure(&ppg_exposure, ch_num); + pah_800x_hal_read_ppg_frame_period(&ppg_frame_period,ch_num); + pah_800x_hal_read_ppg_adc(&ppg_adc,ch_num); + ppg_converging(state, ppg_adc, ch_num);//SD-revise-20191205 + + ppg_result->data[ch_num] = ppg_value[ch_num]; + ppg_result->exposure_time[ch_num] = ppg_exposure; + ppg_result->frame_period[ch_num] = ppg_frame_period; + ppg_result->adc[ch_num] = ppg_adc; + } + } + pah_800x_hal_read_ppg_overflow(&ppg_overflow,&overflow_num); + ppg_result->has_data = true; + ppg_result->has_overflow = (ppg_overflow > 0); + ppg_result->overflow_num = overflow_num; + + return PAH_RET_SUCCESS; +} + +static pah_ret clear_interrupt(pah_800x *state, bool has_ppg_interrupt, bool has_overflow) +{ + + //pah_800x_hal_write_interrupt_clear(); + pah_800x_hal_write_interrupt_clear_v2(has_ppg_interrupt); + return PAH_RET_SUCCESS; +} + +static pah_ret ppg_converging(pah_800x *state, uint32_t ppg_adc, uint8_t ch_num) +{ + if (ch_num >= PAH_800x_MAX_CH_NUM) + return PAH_RET_INVALID_ARGUMENT; + + if (!state->config.enable_ppg_convergence[ch_num]) + return PAH_RET_SUCCESS; + + if (state->config.enable_ppg_reconvergence_if_out_of_bounds[ch_num] + && !state->ppg_state.is_converging[ch_num] + && is_touched(state) + && ppg_value_is_out_of_outer_bounds(state, ppg_adc, ch_num)) + { + ppg_convergence_toggle(state, true, ch_num); + } + else + { + state->ppg_state.cur_converging_count[ch_num] = 0; + } + + if (!state->ppg_state.is_converging[ch_num]) + return PAH_RET_SUCCESS; + + if (ppg_value_is_out_of_inner_bounds(state, ppg_adc, ch_num)) + { + uint16_t ppg_exposure = 0; + uint16_t new_ppg_exposure = 0; + + pah_800x_hal_read_ppg_exposure(&ppg_exposure, ch_num); + //DEBUG_PRINT("ppg converging[%d] exposure time %d ppg_value %d \n",ch_num, ppg_exposure,ppg_value); + new_ppg_exposure = select_new_ppg_exposure(state, ppg_exposure, ppg_adc, ch_num); + if(new_ppg_exposure==ppg_exposure) + { + return PAH_RET_SUCCESS; + } + + if (new_ppg_exposure > state->config.ppg_convergence[ch_num].t_max) + { + new_ppg_exposure = state->config.ppg_convergence[ch_num].t_max; + ppg_convergence_toggle(state, false, ch_num); + + DEBUG_PRINT("ppg converging complete: (exposure, t_max) = (%d)\n", new_ppg_exposure, state->config.ppg_convergence[ch_num].t_max); + } + else if (new_ppg_exposure < state->config.ppg_convergence[ch_num].t_min) + { + new_ppg_exposure = state->config.ppg_convergence[ch_num].t_min; + ppg_convergence_toggle(state, false, ch_num); + + DEBUG_PRINT("ppg converging complete: (exposure, t_min) = (%d)\n", new_ppg_exposure, state->config.ppg_convergence[ch_num].t_min); + } + + pah_800x_hal_write_exposure(new_ppg_exposure, ch_num); + pah_800x_hal_update_flag(); + + } + else + { + ppg_convergence_toggle(state, false, ch_num); + + DEBUG_PRINT("ppg converging complete: (low_target, als_lux_sync, high_target) = (%d, %d, %d)\n", + state->config.ppg_convergence[ch_num].raw_inner_low_target, ppg_adc, + state->config.ppg_convergence[ch_num].raw_inner_high_target); + } + + return PAH_RET_SUCCESS; +} + +static uint16_t select_new_ppg_exposure(pah_800x *state, uint16_t old_ppg_exposure, uint16_t ppg_value, uint8_t ch_num) +{ + int32_t new_ppg_exposure = (int32_t)old_ppg_exposure; + + if (ppg_value < state->config.ppg_convergence[ch_num].raw_outer_low_bound) + new_ppg_exposure += state->config.ppg_convergence[ch_num].t_weight_fast_mode; + else if (ppg_value < state->config.ppg_convergence[ch_num].raw_inner_low_target) + new_ppg_exposure += state->config.ppg_convergence[ch_num].t_weight_normal_mode; + else if (ppg_value > state->config.ppg_convergence[ch_num].raw_outer_high_bound) + { + if(new_ppg_exposure==state->config.ppg_convergence[ch_num].t_min) + { + return new_ppg_exposure; + } + new_ppg_exposure -= state->config.ppg_convergence[ch_num].t_weight_fast_mode; + + }else if (ppg_value > state->config.ppg_convergence[ch_num].raw_inner_high_target) + new_ppg_exposure -= state->config.ppg_convergence[ch_num].t_weight_normal_mode; + + return new_ppg_exposure; +} + +static bool is_touched(pah_800x *state) +{ + return state->touch_flag == 1; +} + +static bool is_not_touched(pah_800x *state) +{ + return state->touch_flag == 0; +} + +static bool ppg_value_is_out_of_outer_bounds(pah_800x *state, uint32_t ppg_data, uint8_t ch_num) +{ + return (ppg_data < state->config.ppg_convergence[ch_num].raw_outer_low_bound) + || (ppg_data > state->config.ppg_convergence[ch_num].raw_outer_high_bound); +} + +static bool ppg_value_is_out_of_inner_bounds(pah_800x *state, uint16_t ppg_data, uint8_t ch_num) +{ + return (ppg_data < state->config.ppg_convergence[ch_num].raw_inner_low_target) + || (ppg_data > state->config.ppg_convergence[ch_num].raw_inner_high_target); +} + +static pah_ret pah_800x_sw_reset(pah_800x *state) +{ + //set sw reset should not in suspend mode + if (state->is_powered == false) + return PAH_RET_FAILED; + + return pah_800x_hal_write_sw_reset(); +} +//////////////////////////////////////////////////////////////////////////////////////////// + + + +//=========================================================================== +// Private function +//=========================================================================== +static pah_ret pah_800x_hal_comm_write(uint8_t addr, const uint8_t *data, size_t write_size) +{ + //return plat->comm.write(&plat->comm, addr, data, write_size); + //return plat->comm.write(addr, data, write_size); + return pah_comm_i2c_write(addr, data, write_size); +} + +static pah_ret pah_800x_hal_comm_read(uint8_t addr, uint8_t *data, size_t read_size) +{ + + //return plat->comm.read(&plat->comm, addr, data, read_size); + return pah_comm_i2c_read(addr, data, read_size); +} + +static pah_ret comm_write(uint8_t addr, uint8_t data) +{ + //return pah_800x_hal_comm_write( addr, &data, 1); + return pah_800x_hal_comm_write(addr, &data, 1); +} +#define comm_read(addr, data) pah_800x_hal_comm_read(addr, data, 1) +#define comm_burst_read(addr, data, read_size) pah_800x_hal_comm_read(addr, data, read_size) + + +//=========================================================================== +// Private function (HAL) +//=========================================================================== +static pah_ret pah_800x_hal_write_reg_arr(const pah_reg_arr *reg_arr) +{ + return pah_800x_hal_write_reg_array(reg_arr->reg_arr, reg_arr->reg_arr_len); +} + +static pah_ret pah_800x_hal_write_reg_array(const uint8_t reg_array[][2], size_t length) +{ + size_t i = 0; + uint8_t reg_value = 0; + for (i = 0; i < length; ++i) + { + //for trim bit + if (reg_array[i][0] == 0x14) + { + comm_read(0x14, ®_value); + reg_value = (reg_value & 0x1F) | (reg_array[i][1] & 0xE0); + comm_write(reg_array[i][0], reg_value); + } + else + comm_write(reg_array[i][0], reg_array[i][1]); + } + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_write_suspend_state(bool suspend) +{ + uint8_t data = 0; + DEBUG_PRINT("%s(%d)\n", __func__, suspend); + if (suspend) + { + pah_800x_hal_write_interrupt_clear(); + comm_read(PAH_800x_ADDR_E8, &data); + PAH_SET_BIT(data, PAH_800x_ADDR_E8_CMD_SUSPEND_MODE_BIT); + comm_write(PAH_800x_ADDR_E8, data); + } + else + { + comm_read(PAH_800x_ADDR_E8, &data); + PAH_CLEAR_BIT(data, PAH_800x_ADDR_E8_CMD_SUSPEND_MODE_BIT); + comm_write(PAH_800x_ADDR_E8, data); + + } + DEBUG_PRINT("%s(%d) end\n", __func__, suspend); + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_write_interrupt_clear(void) +{ + uint8_t data = 0; + // DR interrupt + comm_read(PAH_800x_ADDR_20, &data); + //PAH_CLEAR_BIT(data, PAH_800x_ADDR_20_BIT_DR_FLAG); + comm_write(PAH_800x_ADDR_20, (data|0x04)); //SD-revise-20191205 + return PAH_RET_SUCCESS; +} +static pah_ret pah_800x_hal_write_interrupt_clear_v2(bool int_status_DR_FLAG_b) +{ + uint8_t data = 0; + bool int_status_DR_FLAG = 0; + // DR interrupt + comm_read(PAH_800x_ADDR_20, &data); + int_status_DR_FLAG = PAH_CHECK_BIT(data, PAH_800x_ADDR_20_BIT_DR_FLAG) ; + + if(int_status_DR_FLAG_b==int_status_DR_FLAG) + { + comm_write(PAH_800x_ADDR_20, (data|0x04)); //SD-revise-20191205 + }else if((int_status_DR_FLAG_b)==0 &&(int_status_DR_FLAG==1)) + { + comm_write(PAH_800x_ADDR_20, ((data|0x04)&0xFE)); //SD-revise-20191205 + } + return PAH_RET_SUCCESS; +} + + +static pah_ret pah_800x_hal_write_ppg_overflow_clear(void) +{ + uint8_t data = 0; + // Clear ppg_overflow flag + comm_read(PAH_800x_ADDR_20, &data); + PAH_SET_BIT(data, PAH_800x_ADDR_20_BIT_OVERFLOW_FLAG); + comm_write( PAH_800x_ADDR_20, data); + // Recover + PAH_CLEAR_BIT(data, PAH_800x_ADDR_20_BIT_OVERFLOW_FLAG); + comm_write(PAH_800x_ADDR_20, data); + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_write_exposure(uint16_t exposure, uint8_t ch_num) +{ + //uint8_t data = 0; + uint8_t exposure_low = PAH_UINT16_LOW(exposure); + uint8_t exposure_high = PAH_UINT16_HIGH(exposure); + + if(ch_num == PAH_800x_CH_NUM_A) + { + comm_write(PAH_800x_ADDR_17, exposure_low); + comm_write(PAH_800x_ADDR_18, exposure_high); + } + else if(ch_num == PAH_800x_CH_NUM_B) + { + comm_write(PAH_800x_ADDR_19, exposure_low); + comm_write(PAH_800x_ADDR_1A, exposure_high); + } + else if(ch_num == PAH_800x_CH_NUM_C) + { + comm_write(PAH_800x_ADDR_1B, exposure_low); + comm_write(PAH_800x_ADDR_1C, exposure_high); + } + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_read_product_id(uint16_t *product_id) +{ + return comm_burst_read(PAH_800x_ADDR_00_PRODUCT_ID, (uint8_t *)product_id,2); +} + +static pah_ret pah_800x_hal_read_ppg_interrupt(uint8_t *ppg_interrupt) +{ + uint8_t data = 0; + comm_read(PAH_800x_ADDR_20, &data); + if (ppg_interrupt) + *ppg_interrupt = PAH_CHECK_BIT(data, PAH_800x_ADDR_20_BIT_DR_FLAG); + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_read_ppg_sync(uint32_t *ppg_data, uint8_t ch_num) +{ + if(ch_num == PAH_800x_CH_NUM_A) + comm_burst_read(PAH_800x_ADDR_27_RAWDATA_A_SYNC, (uint8_t*)ppg_data, 3); + else if(ch_num == PAH_800x_CH_NUM_B) + comm_burst_read(PAH_800x_ADDR_32_RAWDATA_B_SYNC, (uint8_t*)ppg_data, 3); + else if(ch_num == PAH_800x_CH_NUM_C) + comm_burst_read(PAH_800x_ADDR_3D_RAWDATA_C_SYNC, (uint8_t*)ppg_data, 3); + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_read_ppg_overflow(uint8_t *ppg_overflow, uint8_t *overflow_num) +{ + uint8_t data = 0; + comm_read( PAH_800x_ADDR_20, &data); + if (ppg_overflow) + { + *ppg_overflow = PAH_CHECK_BIT(data, PAH_800x_ADDR_20_BIT_OVERFLOW_FLAG); + *overflow_num = (data&0x70)>>4; + } + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_read_ppg_exposure(uint16_t *ppg_exposure, uint8_t ch_num) +{ + if(ch_num == PAH_800x_CH_NUM_A) + comm_burst_read(PAH_800x_ADDR_2A, (uint8_t*)ppg_exposure, 2); + else if(ch_num == PAH_800x_CH_NUM_B) + comm_burst_read(PAH_800x_ADDR_35, (uint8_t*)ppg_exposure, 2); + else if(ch_num == PAH_800x_CH_NUM_C) + comm_burst_read(PAH_800x_ADDR_40, (uint8_t*)ppg_exposure, 2); + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_read_ppg_frame_period( uint16_t *ppg_frame_period, uint8_t ch_num) +{ + if(ch_num == PAH_800x_CH_NUM_A) + comm_burst_read(PAH_800x_ADDR_2C, (uint8_t*)ppg_frame_period, 2); + else if(ch_num == PAH_800x_CH_NUM_B) + comm_burst_read(PAH_800x_ADDR_37, (uint8_t*)ppg_frame_period, 2); + else if(ch_num == PAH_800x_CH_NUM_C) + comm_burst_read(PAH_800x_ADDR_42, (uint8_t*)ppg_frame_period, 2); + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_read_ppg_adc(uint16_t *ppg_adc, uint8_t ch_num) +{ + uint16_t data = 0; + + if(ch_num == PAH_800x_CH_NUM_A) + comm_burst_read(PAH_800x_ADDR_2E, (uint8_t*)&data, 2); + else if(ch_num == PAH_800x_CH_NUM_B) + comm_burst_read(PAH_800x_ADDR_39, (uint8_t*)&data, 2); + else if(ch_num == PAH_800x_CH_NUM_C) + comm_burst_read(PAH_800x_ADDR_44, (uint8_t*)&data, 2); + + //*ppg_adc = data >> 2; + *ppg_adc = data >> 2; + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_touch_get_touch_flag(int8_t *touch_flag) +{ + uint8_t data = 0; + uint16_t data1 = 0; +// comm_read(PAH_800x_ADDR_20, &data); + comm_burst_read(PAH_800x_ADDR_44, (uint8_t*)&data1, 2); + comm_read(PAH_800x_ADDR_20, &data); + // printf("data : %d, data1 : %d\n",data,data1); + if (touch_flag) + *touch_flag = PAH_CHECK_BIT(data, PAH_800x_ADDR_20_BIT_TOUCH_FLAG); + + return PAH_RET_SUCCESS; +} +static pah_ret pah_800x_hal_touch_get_touch_info(int8_t *touch_flag,uint16_t *touch_value) +{ + uint8_t data = 0; + uint16_t data1 = 0; +// comm_read(PAH_800x_ADDR_20, &data); + comm_burst_read(PAH_800x_ADDR_44, (uint8_t*)&data1, 2); + *touch_value =data1>>2; + comm_read(PAH_800x_ADDR_20, &data); + if (touch_flag) + *touch_flag = PAH_CHECK_BIT(data, PAH_800x_ADDR_20_BIT_TOUCH_FLAG); + + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_tg_toggle(bool enable) +{ + uint8_t data = 0; + comm_read( PAH_800x_ADDR_07_TG, &data); + if(enable) + PAH_SET_BIT(data, PAH_800x_ADDR_07_TG_BIT_EN); + else + PAH_CLEAR_BIT(data, PAH_800x_ADDR_07_TG_BIT_EN); + comm_write(PAH_800x_ADDR_07_TG, data); + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_update_flag(void) +{ + comm_write(PAH_800x_ADDR_EB, PAH_800x_ADDR_E8_UPDATE_FLAG); + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_write_sw_reset(void) +{ + comm_write(PAH_800x_ADDR_EE, PAH_800x_ADDR_EE_SW_RESET); + + return PAH_RET_SUCCESS; +} + +static pah_ret pah_800x_hal_check_enable_channel(pah_800x *state, const pah_reg_arr *reg_arr) +{ + for(int i=0;ireg_arr_len;i++) + { + if(reg_arr->reg_arr[i][0] == PAH_800x_ADDR_11_EnCh) + { + uint8_t data = reg_arr->reg_arr[i][1]; + state->ppg_state.ppg_ch_enabled[0] = PAH_CHECK_BIT(data, 0); // CH A + state->ppg_state.ppg_ch_enabled[1] = PAH_CHECK_BIT(data, 1); // CH B + state->ppg_state.ppg_ch_enabled[2] = PAH_CHECK_BIT(data, 2); // CH C + } + } + + return PAH_RET_SUCCESS; +} + + +static pah_ret pah_800x_hal_reset_gpio_state(void) +{ + uint8_t data = 0; + + comm_read(PAH_800x_ADDR_D2, &data); + PAH_SET_BIT(data, PAH_800x_ADDR_D2_OD_EnH); + comm_write(PAH_800x_ADDR_D2, data); + + return PAH_RET_SUCCESS; +} diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x.h b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x.h new file mode 100644 index 000000000..2500dc690 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x.h @@ -0,0 +1,158 @@ +#ifndef __pah_800x_h__ +#define __pah_800x_h__ + +// pah +#include "pah_unit.h" +#include "pah_800x_config.h" + + +//============================================================================ +// Definition +//============================================================================ +#define TOUCH_TRALSE_VALUE (-1) + + +//============================================================================ +// Type Definition +//============================================================================ +typedef struct +{ + uint16_t t_weight_normal_mode; + uint16_t t_weight_fast_mode; + uint16_t t_min; + uint16_t t_max; + + uint16_t raw_outer_high_bound; + uint16_t raw_inner_high_target; + uint16_t raw_inner_low_target; + uint16_t raw_outer_low_bound; + + uint16_t convergence_count; +} pah_800x_ppg_convergence; + +typedef struct +{ + uint16_t ppg_initial_exposure[PAH_800x_MAX_CH_NUM]; + + bool enable_ppg_convergence[PAH_800x_MAX_CH_NUM]; + pah_800x_ppg_convergence ppg_convergence[PAH_800x_MAX_CH_NUM]; + bool enable_ppg_reconvergence_if_out_of_bounds[PAH_800x_MAX_CH_NUM]; + +} pah_800x_config; + +typedef struct +{ + bool is_enabled; + + bool is_converging[PAH_800x_MAX_CH_NUM]; + + bool ppg_ch_enabled[PAH_800x_MAX_CH_NUM]; + uint16_t cur_converging_count[PAH_800x_MAX_CH_NUM]; +} pah_800x_ppg_state; + +typedef struct +{ + bool has_data; + uint32_t data[PAH_800x_MAX_CH_NUM]; + + + // Avaiable only if has_data is true + bool has_overflow; + + uint8_t overflow_num; + + // Avaiable only if has_data is true + uint16_t exposure_time[PAH_800x_MAX_CH_NUM]; + uint16_t adc[PAH_800x_MAX_CH_NUM]; + uint16_t frame_period[PAH_800x_MAX_CH_NUM]; + +} pah_800x_ppg_data; + +typedef struct +{ + bool is_enabled; + + int8_t touch_flag; + +} pah_800x_touch_state; + +typedef struct +{ + pah_reg_arr startup_init; + pah_reg_arr ppg_enable; + pah_reg_arr touch_enable; + +} pah_800x_reg_setting; + +typedef struct +{ + // Config + //pah_plat plat; + pah_800x_config config; + + // Power state + bool is_powered; + + // PPG state + pah_800x_ppg_state ppg_state; + pah_800x_ppg_data ppg_result; + + // TOUCH state + pah_800x_touch_state touch_state; + int8_t touch_flag; + uint16_t touch_value; + // Other + pah_800x_reg_setting reg_setting; + +} pah_800x; + + +//============================================================================ +// Public function +//============================================================================ +#ifdef __cplusplus +extern "C" { +#endif + + +// Info +uint16_t pah_800x_get_i2c_default_slave_addr(void); +void pah_800x_get_default_config(pah_800x_config *config); +pah_ret pah_800x_get_product_id( uint16_t *product_id); + +// Init +pah_ret pah_800x_init(pah_800x *state, const pah_800x_config *config); +pah_ret pah_800x_deinit(pah_800x *state); + +// Device init +pah_ret pah_800x_device_init(pah_800x *state, const pah_800x_reg_setting *reg_setting); + +// Config +//pah_ret pah_800x_set_ppg_convergence(pah_800x *state,uint8_t ch_num, const pah_800x_ppg_convergence *ppg_convergence); + +// Power +pah_ret pah_800x_power_toggle(pah_800x *state, bool enable); + +// Basic verification +pah_ret pah_800x_verify_product_id(pah_800x *state, uint16_t *product_id); + +// PPG +pah_ret pah_800x_ppg_toggle(pah_800x *state, bool enable); +pah_ret pah_800x_ppg_get_data(pah_800x *state, pah_800x_ppg_data *ppg_data); + +// TOUCH +pah_ret pah_800x_touch_toggle(pah_800x *state, bool enable); +pah_ret pah_800x_get_touch_flag(pah_800x *state, int8_t *touch_flag); +pah_ret pah_800x_get_touch_value(pah_800x *state, uint16_t *touch_value); +pah_ret pah_800x_update_touch_setting(pah_800x *state); + +// Task +pah_ret pah_800x_task(pah_800x *state); + + + +#ifdef __cplusplus +} +#endif + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x_config.h b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x_config.h new file mode 100644 index 000000000..0e3d8530f --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_800x_config.h @@ -0,0 +1,163 @@ +#ifndef __pah_800x_config_h__ +#define __pah_800x_config_h__ + +// pah +#include "pah800x_bsp.h" +#include "debug_print.h" + +/* + * Select LED Supplier + * If Use new Supplier LED , Need to define LED_SUPPLIER_NEW +*/ +//#define LED_SUPPLIER_NEW + + +/* + * Select Cover Type +*/ +#define DI_WALL_4mm +//#define PC_4mm + +/* + * Select HW and ALG configuration + * PC_4MM_2G_IR_HRD : Printing Cover with 4mm 2 Green and 1 IR LED for HRD algorithm use (PAH8009ES) + * DIW_4MM_G_IR_HRD : DI+Wall Cover with 4mm 1 Green and 1 IR LED for HRD algorithm use (PAH8009ES) + * DIW_4MM_IR_R_IR_SPO2 : DI+Wall Cover with 4mm 1 IR LED and 1 RED for SpO2 algorithm use (PAH8009ES) + * This definition will enable the PPG register setting corresponding to different HW and ALG configuration + */ + +#define PC_4MM_2G_IR_HRD 1 +#define DIW_4MM_G_IR_HRD 1 +#define DIW_4MM_IR_R_IR_SPO2 1 + +//#endif + +//============================================================================ +// Debug Option +//============================================================================ +#define ENABLE_AE 1 +#define ENABLE_AE_RECONVERGENCE 1 + + +// #define PAH_800x_ENABLE_DEBUG_PRINT +// #define PAH_800x_ENABLE_LOG_PRINT + +#ifdef PAH_800x_ENABLE_LOG_PRINT +#define LOG_PRINT(fmt, ...) \ + do { \ + PRINT(fmt" ", ##__VA_ARGS__); \ + } while (0) +#else +#define LOG_PRINT(...) do {} while (0) +#endif +#ifdef PAH_800x_ENABLE_DEBUG_PRINT +#define DEBUG_PRINT(fmt, ...) \ + do { \ + PRINT(fmt" ", ##__VA_ARGS__); \ + } while (0) +#else +#define DEBUG_PRINT(...) do {} while (0) +#endif + +/* + * Select Interrupt or Polling Mode + * This definition will enable the corresponding demo functionin main.c + * If select INT mode, then slect following INT configuration type + */ +#define INTERRUPT_MODE 1 +#define POLLING_MODE 0 +#define Test_pattern_mode 0 + +/* + * Select INT HW configuration type + * INT_OD_EXTERNAL_PULLH : INT open-drain type with external pull-high resistor + * INT_OD_INTERNAL_PULLH : INT open-drain type with internal pull-high resistor + * INT_PUP_WITHOUT_PULLH : INT push-pull type without any pull-high resistor + * If user select POLLING_MODE, all define need to set 0 + * This definition will enable the GPIO register setting corresponding to different INT HW configuration + */ +#define INT_OD_EXTERNAL_PULLH 1 +#define INT_OD_INTERNAL_PULLH 0 +#define INT_PUP_WITHOUT_PULLH 0 + + +/* +* Configure VBUS Type + * Define VBUS_18V=1, compatible with VBUS=1.8V or 3.3V (default) + * Define VBUS_18V=0, only support VBUS=3.3V + * If user want to define VBUS_18V=0, or VBUS not 1.8V/3.3V, please contact with PixArt for evaluation + */ +#define VBUS_18V 1 +#if (VBUS_18V) + #define R_GPIO_0_OD_EnH (0x20) + #define R_GPIO_SLEW (0x01) + #define R_I2C_SLEW (0x40) + #define R_SCL_Sel (0x00) + #define R_SDA_Sel (0x00) +#else + #define R_GPIO_0_OD_EnH (0x20) + #define R_GPIO_SLEW 0 + #define R_I2C_SLEW 0 + #define R_SCL_Sel (0x40) + #define R_SDA_Sel (0x04) +#endif + +#define Time_Interval 400 +/* +If Customer platform use G-Sensor with FIFO,they can refer this flow to run pxi alg to get alg output +*/ +//#define PPG_MEMS_Synchronize +#define Optimize_SPO2_flow + +//****** Demo 800X mode Select ******// +//============HRD-INT================// +//#define touch_only_hrd_en +//#define ppg_only_hrd_en +#define auto_hrd_en + +//============HRD-Polling================// +//#define touch_only_polling_hrd_en +//#define ppg_only_polling_hrd_en +//#define auto_polling_hrd_en + + +//============SPO2-INT================// +//#define touch_only_spo2_en +//#define ppg_only_spo2_en +//#define auto_spo2_en + +//============SPO2-Polling================// +//#define touch_only_polling_spo2_en +//#define ppg_only_polling_spo2_en +//#define auto_polling_spo2_en + + +//============Stress-INT================// +//#define touch_only_stress_en +//#define ppg_only_stress_en +//#define auto_stress_en + +//============Stress-Polling================// +//#define touch_only_polling_stress_en +//#define ppg_only_polling_stress_en +//#define auto_polling_stress_en + +//=========== Test_pattern======== // +//#define hrd_testpattern_en +//#define spo2_testpattern_en + +//=========== Factory _Test=========// +//#define factory_test_en + + +//============HRD-INT====PC Cover============// +//#define touch_only_hrd_en_pc +//#define ppg_only_hrd_en_pc +//#define auto_hrd_en_pc + +//============HRD-Polling======PC Cover==========// +//#define touch_only_polling_hrd_en_pc +//#define ppg_only_polling_hrd_en_pc +//#define auto_polling_hrd_en_pc + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_unit.h b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_unit.h new file mode 100644 index 000000000..64a1a7e67 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/pah8009/sensor/pah_unit.h @@ -0,0 +1,340 @@ +#ifndef __pah_unit_h__ +#define __pah_unit_h__ + +// c +#include +#include +#include +#include +#include +#include + + +//============================================================================ +// Default +//============================================================================ +#define PAH_800x_DEFAULT_PPG_INITIAL_EXPOSURE (400) + +#define PAH_800x_DEFAULT_ENABLE_PPG_CONVERGENCE true + + +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_COUNT (0) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_T_WEIGHT_NORMAL_MODE (8) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_T_WEIGHT_FAST_MODE (16) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_T_MIN (10) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_T_MAX (1792) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_OUTER_HIGH_BOUND (12288) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_INNER_HIGH_TARGET (10240) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_INNER_LOW_TARGET (8192) +#define PAH_800x_DEFAULT_PPG_CONVERGENCE_RAW_OUTER_LOW_BOUND (6144) + +#define PAH_800x_DEFAULT_ENABLE_PPG_RECONVERGENCE_IF_OUT_OF_BOUNDS true + + +//============================================================================ +// Definition +//============================================================================ + +// I2C 7-bit ID +#define PAH_800x_DEFAULT_I2C_SLAVE_ID_1 (0x40) +#define PAH_800x_DEFAULT_I2C_SLAVE_ID_2 (0x10) + +#define PAH_800x_PRODUCT_ID (0x8008) + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pah_ret.h + * + * Copyright (c) 2016-2018 PixArt Imaging Inc. + * All Rights Reserved. + * Confidential and Proprietary - PixArt Imaging Inc. + **/ + +typedef enum { + + PAH_RET_SUCCESS = 0, // Success + + PAH_RET_PENDING, + + PAH_RET_FAILED, // Unknown error, generally there exists bug in this driver + + PAH_RET_PLAT_FAILED, // Platform API failed + PAH_RET_VERIFY_FAILED, // Verify device failed + + PAH_RET_NOT_IMPLEMENTED, // This API is not supported or is not implemented + + PAH_RET_INVALID_ARGUMENT, // Invalid argument to API + PAH_RET_INVALID_OPERATION, // This operation is not available at this time + + PAH_RET_FIFO_CKS_FAILED, // Failed to compare check sum with fifo data + PAH_RET_FIFO_OVERFLOW, // Fifo in device is overflow + + PAH_RET_ASYNC_PENDING, + +} pah_ret; + +typedef enum { + PAH_800x_CH_NUM_A = 0, + PAH_800x_CH_NUM_B, + PAH_800x_CH_NUM_C, + PAH_800x_MAX_CH_NUM, +} pah_800x_ch_num; + +#define PAH_SUCCEEDED(ret) (ret == PAH_RET_SUCCESS) +#define PAH_FAILED(ret) (!PAH_SUCCEEDED(ret)) + + +#define PAH_CHECK_RET(ret) \ + if (PAH_FAILED(ret)) { \ + return ret; \ + } + +#define PAH_CHECK_NULL(p) \ + if (!p) { \ + return PAH_RET_INVALID_ARGUMENT; \ + } + + + +/** + * @file pah_plat.h + * + * Copyright (c) 2016-2018 PixArt Imaging Inc. + * All Rights Reserved. + * Confidential and Proprietary - PixArt Imaging Inc. + **/ + + + + +//============================================================================ +// Definition +//============================================================================ + +//============================================================================ +// Macro +//============================================================================ +#ifndef __FILENAME__ +# define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + +/** + * @file pah_util.h + * + * Copyright (c) 2016-2018 PixArt Imaging Inc. + * All Rights Reserved. + * Confidential and Proprietary - PixArt Imaging Inc. + **/ + + + +#define PAH_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#define PAH_SET_BIT(var,pos) do { ((var) |= (1 << (pos))); } while(0) +#define PAH_CLEAR_BIT(var,pos) do { ((var) &= ~(1 << (pos))); } while(0) +#define PAH_CHECK_BIT(var,pos) (((var) >> (pos)) & 1) + +// +// PAH_SET_BITSLICE +// +// ex1: +// // var = 0x00 : 00000000 +// // pos = 2 : ^ +// // mask = 0x3C : 00111100 +// // value = 0x0D : 1101 +// // ret = 0x34 : 00110100 +// uint8_t data = 0x00; +// uint8_t ret = PAH_SET_BITSLICE(data, 2, 0x3C, 0x0D); +// +// ex2: +// // var = 0x6D : 01101101 +// // pos = 6 : ^ +// // mask = 0xC0 : 11000000 +// // value = 0x02 : 10 +// // ret = 0xAD : 10101101 +// uint8_t data = 0x6D; +// uint8_t ret = PAH_SET_BITSLICE(data, 6, 0xC0, 0x02); +// +#define PAH_SET_BITSLICE(var, pos, mask, value) \ + ((var & ~mask) | ((value << pos) & mask)) + +// +// PAH_GET_BITSLICE +// +// ex1: +// // var = 0x5D : 01011101 +// // pos = 2 : ^ +// // mask = 0x3C : 00111100 +// // ret = 0x07 : 0111 +// uint8_t ret = PAH_GET_BITSLICE(0x5D, 2, 0x3C); +// +// ex2: +// // var = 0xA6 : 10100110 +// // pos = 5 : ^ +// // mask = 0xE0 : 11100000 +// // ret = 0x05 : 101 +// uint8_t ret = PAH_GET_BITSLICE(0xA6, 5, 0xE0); +// +#define PAH_GET_BITSLICE(var, pos, mask) \ + ((var & mask) >> pos) + +#define PAH_UINT64_HIGH(var) ((uint32_t)(var >> 32)) +#define PAH_UINT64_LOW(var) ((uint32_t)(var & UINT32_MAX)) + +#define PAH_UINT16_HIGH(var) ((uint8_t)(var >> 8)) +#define PAH_UINT16_LOW(var) ((uint8_t)(var & UINT8_MAX)) + +#define PAH_UNUSED_VAR(var) (void)(var) +#define UNUSED_VAR(var) (void)(var) + +#ifndef __FILENAME__ +# define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pah_reg.h + * + * Copyright (c) 2016-2018 PixArt Imaging Inc. + * All Rights Reserved. + * Confidential and Proprietary - PixArt Imaging Inc. + **/ + + + + +//============================================================================ +// Definition +//============================================================================ +typedef const uint8_t (pah_reg)[2]; + + +typedef struct { + + pah_reg *reg_arr; + uint32_t reg_arr_len; + +} pah_reg_arr; + + +#define PAH_REG_ARR_SETUP(pah_reg_arr, reg_array) \ + do { \ + pah_reg_arr.reg_arr = (pah_reg*)reg_array; \ + pah_reg_arr.reg_arr_len = PAH_ARRAY_SIZE(reg_array); \ + } while(0) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//============================================================================ +// Register address +//============================================================================ + +/*#define PAH_800x_ADDR_00_PRODUCT_ID (0x00) +#define PAH_800x_ADDR_03 (0x03) +#define PAH_800x_ADDR_03_BIT_R_PS_EN (0) +#define PAH_800x_ADDR_03_BIT_R_ALS_EN (1) +#define PAH_800x_ADDR_03_BIT_SW_SUSPEND (5) + +#define PAH_800x_ADDR_04 (0x04) +#define PAH_800x_ADDR_04_BIT_ALS_OVERFLOW_ECO (7) + +#define PAH_800x_ADDR_09 (0x09) +#define PAH_800x_ADDR_09_BIT_ALS_INTERRUPT (2) +#define PAH_800x_ADDR_09_BIT_PS_INTERRUPT (5) +#define PAH_800x_ADDR_09_BIT_PS_APPROACH (6) + +#define PAH_800x_ADDR_10_PS_ONOFF_SYNC (0x10) + +#define PAH_800x_ADDR_11 (0x11) +#define PAH_800x_ADDR_11_BIT_R_LED_CONTROL_OUT_EN (4) +#define PAH_800x_ADDR_11_BIT_R_PS_INTERRUPT_EN (7) + +#define PAH_800x_ADDR_0E_ALS_LUX_SYNC (0x0E) + +#define PAH_800x_ADDR_34 (0x34) +#define PAH_800x_ADDR_34_BIT_R_EXPOSURE_ALS_F0 (0) + +#define PAH_800x_ADDR_35 (0x35) +#define PAH_800x_ADDR_35_BIT_R_EXPOSURE_ALS_F0 (0) + +#define PAH_800x_ADDR_38 (0x38) +#define PAH_800x_ADDR_38_BIT_0_LOCK_EXPOTIME (0) +#define PAH_800x_ADDR_38_BIT_1_CLEAR_ALS_OVERFLOW_ECO (1) + +#define PAH_800x_ADDR_EC (0xEC) +#define PAH_800x_ADDR_EC_BIT_7_R_CLK_MANUAL (7)*/ + +#define PAH_800x_ADDR_00_PRODUCT_ID (0x00) + +#define PAH_800x_ADDR_07_TG (0X07) +#define PAH_800x_ADDR_07_TG_BIT_EN (0) + +#define PAH_800x_ADDR_20 (0x20) +#define PAH_800x_ADDR_20_BIT_DR_FLAG (0) +#define PAH_800x_ADDR_20_BIT_OVERFLOW_FLAG (1) +#define PAH_800x_ADDR_20_BIT_TOUCH_FLAG (2) + +//expo A Sync +#define PAH_800x_ADDR_2A (0x2A) +#define PAH_800x_ADDR_2B (0x2B) + +#define PAH_800x_ADDR_35 (0x35) +#define PAH_800x_ADDR_36 (0x36) + +#define PAH_800x_ADDR_40 (0x40) +#define PAH_800x_ADDR_41 (0x41) + +#define PAH_800x_ADDR_11_EnCh (0x11) + +//expo A write +#define PAH_800x_ADDR_17 (0x17) +#define PAH_800x_ADDR_18 (0x18) + +#define PAH_800x_ADDR_19 (0x19) +#define PAH_800x_ADDR_1A (0x1A) + +#define PAH_800x_ADDR_1B (0x1B) +#define PAH_800x_ADDR_1C (0x1C) + +//frame period + +#define PAH_800x_ADDR_2C (0x2C) +#define PAH_800x_ADDR_2D (0x2D) + +#define PAH_800x_ADDR_37 (0x37) +#define PAH_800x_ADDR_38 (0x38) + +#define PAH_800x_ADDR_42 (0x42) +#define PAH_800x_ADDR_43 (0x43) + +//adc + +#define PAH_800x_ADDR_2E (0x2E) +#define PAH_800x_ADDR_2F (0x2F) + +#define PAH_800x_ADDR_39 (0x39) +#define PAH_800x_ADDR_3A (0x3A) + +#define PAH_800x_ADDR_44 (0x44) +#define PAH_800x_ADDR_45 (0x45) + +#define PAH_800x_ADDR_27_RAWDATA_A_SYNC (0x27) +#define PAH_800x_ADDR_32_RAWDATA_B_SYNC (0x32) +#define PAH_800x_ADDR_3D_RAWDATA_C_SYNC (0x3D) + +#define PAH_800x_ADDR_E8 (0xE8) +#define PAH_800x_ADDR_E8_CMD_SUSPEND_MODE_BIT (0) + +#define PAH_800x_ADDR_EB (0xEB) +#define PAH_800x_ADDR_E8_UPDATE_FLAG (0x80) + +#define PAH_800x_ADDR_EE (0xEE) +#define PAH_800x_ADDR_EE_SW_RESET (0x1F)//(0x07) +#define PAH_800x_ADDR_D2 (0xD2) +#define PAH_800x_ADDR_D2_OD_EnH (5) + +#endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/ppgBleService/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/ppgBleService/CMakeLists.txt index a1f51df1b..7bb540ac6 100644 --- a/code/sdk/zhihui/drivers/ppg/ppgBleService/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/ppg/ppgBleService/CMakeLists.txt @@ -37,7 +37,7 @@ set(MAIN_COMPONENT ) set(PUBLIC_DEFINES - +SUPPORT_PPG_BLE_SERVICE ) set(PRIVATE_DEFINES diff --git a/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt index 8315e769d..3fa48fd43 100644 --- a/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt @@ -9,14 +9,12 @@ set(PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR} ) set(PRIVATE_HEADER - ${ROOT_DIR}/middleware/services/gui/uikit/utils/interfaces/innerkits - ${ROOT_DIR}/middleware/services/gui/uikit/utils/interfaces/kits - ${ROOT_DIR}/application/wearable/nativeapp/nativeui/heartrate/include ) set(SOURCES -${CMAKE_CURRENT_SOURCE_DIR}/ppg_at_cmd.cpp -${CMAKE_CURRENT_SOURCE_DIR}/ppg_service.cpp +${CMAKE_CURRENT_SOURCE_DIR}/ppg_at_cmd.c +${CMAKE_CURRENT_SOURCE_DIR}/ppg_service.c +${CMAKE_CURRENT_SOURCE_DIR}/ppg_hal.c ) @@ -24,20 +22,8 @@ set(COMPONENT_PUBLIC_CCFLAGS ) set(COMPONENT_CCFLAGS - -std=c++11 - -Wno-error - -Wno-unused-parameter - -fno-exceptions - -fno-unwind-tables - -fno-asynchronous-unwind-tables - -Wno-undef - -Wno-bitwise-op-parentheses - -Wno-shift-op-parentheses - -nostdlibinc - -nostdinc - -nostdlib - -Wno-c++11-narrowing - -Wno-error=unused-function +-Wno-incompatible-function-pointer-types +-Wno-unused-function ) set(WHOLE_LINK diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.cpp b/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.c similarity index 97% rename from code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.cpp rename to code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.c index de8421c1e..3ba0f2dee 100644 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.cpp +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.c @@ -86,8 +86,11 @@ static uint32_t ppg_do_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) md = PPG_SERVICE_CMD_TYPE_FPC_TEST; } else if (strcmp(mode, "factory") == 0) { md = PPG_SERVICE_CMD_TYPE_FACTORY_TEST; + } else if (strcmp(mode, "wear") == 0) { + md = PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_TEST; } + if(enabled == 0 ) { if (md == PPG_SERVICE_CMD_TYPE_DO_SPO2_TEST) diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.h b/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.h index a2906e2dc..876828dea 100644 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.h +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.h @@ -6,8 +6,8 @@ * History: \n * 2022-07-20, Create file. \n */ -#ifndef HX3695_AT_PROCESS_H -#define HX3695_AT_PROCESS_H +#ifndef PPG_AT_PROCESS_H +#define PPG_AT_PROCESS_H #include #include diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_hal.c b/code/sdk/zhihui/drivers/ppg/service/ppg_hal.c new file mode 100644 index 000000000..0d767607c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_hal.c @@ -0,0 +1,168 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-03-13 15:08:38 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-06-04 09:50:09 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include "ppg_hal.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" +#include "pm_control.h" + + +#include "custom_utils.h" + + +#ifdef PPG_HX3695 +#include "tyhx_hrs_custom.h" +#include "hx3695.h" +#endif + +#ifdef PPG_PAH8009 +#include "pah800x_main.h" +#endif + +#ifdef SUPPORT_CYWEE_SERVICE +#include "cywee_service.h" +#endif + + +// S_AGPIO_L26 心率复位 PPG reset +#define GPIO_PIN_PRG_RESET S_AGPIO_L26 +// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚 +#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0 + +void ppg_power_on(void) +{ + // printf("ppg_power_on\n"); + uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_HIGH); + + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH); + LOS_Mdelay(50); +} + +void ppg_power_off(void) +{ + // printf("ppg_power_off\n"); + uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_LOW); + + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW); + LOS_Mdelay(50); +} + +uint8_t ppg_get_hrs(void) +{ + uint8_t hrs = 0; +#ifdef PPG_HX3695 + hrs = hx3695_get_hrs(); + // printf("ppg_get_hrs : %d\n",hrs); +#endif + return hrs; +} + +uint8_t ppg_get_spo2(void) +{ + uint8_t spo2 = 0; +#ifdef PPG_HX3695 + spo2 = hx3695_get_spo2(); +#endif + return spo2; +} + +uint8_t ppg_get_wear_status(void) +{ + uint8_t wear_status = 0; +#ifdef PPG_HX3695 + wear_status = hx3695_get_wear_status(); +#endif + return wear_status; +} + +uint16_t ppg_get_chip_id(void) +{ + uint16_t chip_id = 0; +#ifdef PPG_HX3695 + chip_id = hx3695_chip_check(); +#elif defined PPG_PAH8009 + chip_id = pah8009_get_chip_id(); +#endif + return chip_id; +} + +void ppg_timer_handler(uint8_t mode) +{ + // printf("ppg_agc_timer_handler\n"); +#ifdef PPG_HX3695 + if(mode == AGC_TIMER_MODE) + agc_timeout_handler(NULL); + else if(mode == HRS_TIMER_MODE) + heart_rate_meas_timeout_handler(NULL); + else if(mode == WEAR_TIMER_MODE) + wear_mode_timeout_handler(NULL); +#elif defined PPG_PAH8009 + pah8009_timer_handler(); +#endif +} + + +void ppg_int_handler(void) +{ +#ifdef PPG_PAH8009 + pah8009_int_handler(); +#endif +} + +void ppg_send_cmd_to_driver(char* mode, uint8_t enable) +{ + // printf("ppg_send_cmd_to_driver \n"); + if(enable) + ppg_power_on(); +#ifdef PPG_HX3695 + hx3695_control(mode,enable); +#elif defined PPG_PAH8009 + pah8009_control(mode,enable); +#endif + if(!enable) + ppg_power_off(); +} + +void ppg_get_leaklight_data(uint32_t *ch0,uint32_t *ch1,uint32_t *ch2) +{ +#ifdef PPG_HX3695 + FT_RESULTS_t ft_result = hx3695_factroy_test(LEAK_LIGHT_TEST); + *ch0 = ft_result.gr_data_final; + *ch1 = ft_result.red_data_final; + *ch2 = ft_result.ir_data_final; +#elif defined PPG_VC9202 + vc9202_get_leaklight_data(ch0,ch1,ch2); +#elif defined PPG_PAH8009 + pah8009_get_leaklight_data(ch0,ch1,ch2); +#endif +} + +uint32_t ppg_get_factory_data(void) +{ + uint32_t data = 0; +#ifdef PPG_PAH8009 + data = pah8009_get_factory_data(); +#endif + return data; +} \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_hal.h b/code/sdk/zhihui/drivers/ppg/service/ppg_hal.h new file mode 100644 index 000000000..35f5431e4 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_hal.h @@ -0,0 +1,55 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-06-07 11:18:26 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-05-30 15:49:50 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.h + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ +#ifndef PPG_HAL_H__ +#define PPG_HAL_H__ +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "stdint.h" +#include "tyhx_hrs_custom.h" + +#define AGC_TIMER_MODE 0 +#define HRS_TIMER_MODE 1 +#define WEAR_TIMER_MODE 2 + +#ifdef PPG_HX3695 +#define PPG_CHIP_ID 0x65 +#elif defined PPG_PAH8009 +#define PPG_CHIP_ID 0x8008 +#else +#define PPG_CHIP_ID 0 +#endif + +typedef uint32_t PPG_CMD_TYPE_T ; + +void ppg_send_cmd_to_driver(char* mode, uint8_t enable); +void ppg_timer_handler(uint8_t mode); +uint16_t ppg_get_chip_id(void); +uint8_t ppg_get_hrs(void); +uint8_t ppg_get_spo2(void); +uint8_t ppg_get_wear_status(void); +void ppg_wear_status_update(uint8_t status); +void ppg_power_on(void); +void ppg_power_off(void); +void ppg_int_handler(void); +void ppg_get_leaklight_data(uint32_t *ch0,uint32_t *ch1,uint32_t *ch2); +uint32_t ppg_get_factory_data(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_service.c b/code/sdk/zhihui/drivers/ppg/service/ppg_service.c new file mode 100644 index 000000000..3fa8f5b16 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_service.c @@ -0,0 +1,343 @@ + +#include "pinctrl.h" +#include "debug_print.h" +#include "soc_osal.h" +#include "tcxo.h" +#include "irmalloc.h" +#include "errcode.h" +#include "common_def.h" +#include "chip_core_irq.h" +#include "chip_io.h" +#include "gpio.h" +#include "pm_veto.h" +#include "rtc.h" +#include "timer.h" +#include "systick.h" +#include "cmsis_os2.h" +#include "ppg_service.h" +#include "los_printf.h" +#include "thread_init.h" +#include "custom_utils.h" +#include "custom_save_runtime.h" +#include "ppg_hal.h" + +#ifdef PPG_HX3695 +#include "hx3695.h" +#endif + +#if defined(PPG_VC9202) +#include "vc9202_hal.h" +#include "vc9202_user.h" +#elif defined(PPG_VC921X) +#include "vc921x_hal.h" +#include "vc921x_user_app.h" +#elif defined(PPG_GH3X2X) +#include "gh3x2x_hal.h" +#include "gh3x2x_afe_drv.h" +#else +#endif + +static bool g_ppg_service_initialled = false; + +uint8_t card_databuf[64] = {0}; +uint8_t light_databuf[64] = {0}; + +osTimerId_t g_ppg_service_timer = NULL; + + +/*** + * 其他cmd在Header里定义,对外开放 +*/ + + +#define PPG_SERVICE_MSG_COUNT 16 +#define PPG_SERVICE_TASK_SIZE 0x1000 +#define PPG_SERVICE_TASK_PRIO 5 + +#define MAG_CHECK_MS 20 +static unsigned long g_app_queue= 0xFFFFFFFF; + +static bool ppg_service_running_stat = false; +static bool ppg_sensor_exist = false; + +static uint8_t wear_mode_state = 0; +static uint8_t keep_in_wear_det_mod = 1; //持续坚持 佩戴检测模式 + + +void set_keep_in_wear_det_mode(uint8_t mod) +{ + keep_in_wear_det_mod = mod; +} + + +void uapi_ppg_service_deinit(void) +{ + ppg_service_running_stat = false; +} + +uint32_t ppg_suspend(void) +{ + return custom_i2c_suspend(); +} +uint32_t ppg_resume(void) +{ + return custom_i2c_resume(); +} + + +errcode_t send_ppg_cmd_msg(int cmd) +{ + errcode_t ret; + if (ppg_sensor_exist == false) + return OSAL_FAILURE; + + // printf("send_ppg_cmd_msg cmd : 0x%x\n",cmd); + + PPG_CMD_TYPE_T mail = 0; + mail = cmd; + ret = osal_msg_queue_write_copy(g_app_queue, (void *)&mail, + sizeof(PPG_CMD_TYPE_T), 0); + if (ret != OSAL_SUCCESS) { + PRINT("Error ppg Check MSG 0x%02X send failed! err=0x%x! \r\n",cmd, ret); + } + return ret; +} + +static void ppg_service_check_task(void *arg) +{ + unused(arg); + int32_t ret; + uint32_t mail; + uint32_t msgsize = (uint32_t)sizeof(PPG_CMD_TYPE_T); + + while (1) { + ret = osal_msg_queue_read_copy(g_app_queue, (void *)&mail, &msgsize, + OSAL_MSGQ_WAIT_FOREVER); + if (ret != OSAL_SUCCESS) { + continue; + } + if((wear_mode_state == 1) && (mail > 0x10) && mail != PPG_SERVICE_CMD_TYPE_STOP_WEAR_MODE_TEST) + { +#ifdef PPG_HX3695 + // uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_STOP); + wear_mode_state = 0; + + ppg_send_cmd_to_driver("wear",0); + ppg_service_running_stat = false; +#endif + } + char* cmd = "hrs"; + int enable = 1; + if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_HRS_TIMER_CALLBACK){ +// #ifdef PPG_HX3695 +// heart_rate_meas_timeout_handler(NULL); +// #endif + // ppg_hrs_timer_handler(); + ppg_timer_handler(HRS_TIMER_MODE); + continue; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_AGC_TIMER_CALLBACK){ +// #ifdef PPG_HX3695 +// agc_timeout_handler(NULL); +// #endif + ppg_timer_handler(AGC_TIMER_MODE); + continue; + }else if(mail == PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_TIMER_CALLBACK){ +// #ifdef PPG_HX3695 +// wear_mode_timeout_handler(NULL); +// #endif + // ppg_wear_timer_handler(); + ppg_timer_handler(WEAR_TIMER_MODE); + continue; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_TEST){ + //do_cywee_service_check_msg(CYWEE_SERVICE_CMD_OPEN_GET_ACC,NULL); + // uapi_save_runtime_log(RUNTIME_LOG_HEART_DRIVER_MEASURE); + cmd = "hrs"; + enable = 1; + // uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); + // if (cnt == 0) + // { + // uapi_pm_add_sleep_veto(PM_ID_HEART); + // } + + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_HRV_TEST){ + cmd = "hrv"; + enable = 1; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_SPO2_TEST){ + cmd = "spo2"; + enable = 1; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST){ + cmd = "leaklight"; + enable = 1; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_GRAYCARD_TEST){ + cmd = "graycard"; + enable = 1; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_TEST){ + if (keep_in_wear_det_mod == 0) continue;; + // uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_START); + cmd = "wear"; + enable = 1; + wear_mode_state = 1; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_LED_OFF_MODE_TEST){ + cmd = "ledoff"; + enable = 0; + }else if (mail == PPG_SERVICE_CMD_TYPE_DO_SINGLE_CHECK_MODE_TEST){ + cmd = "single"; + enable = 1; + }else if (mail == PPG_SERVICE_CMD_TYPE_STOP_WEAR_MODE_TEST){ + if (keep_in_wear_det_mod == 0) continue; + cmd = "wear"; + enable = 0; + wear_mode_state = 0; + }else if (mail == PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST){ + // uapi_save_runtime_log(RUNTIME_LOG_HEART_DRIVER_MEASURE_END); + cmd = "hrs"; + enable = 0; + // uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); + // if (cnt == 1) + // { + // uapi_pm_remove_sleep_veto(PM_ID_HEART); + // } + }else if (mail == PPG_SERVICE_CMD_TYPE_STOP_SPO2_TEST){ + + cmd = "spo2"; + enable = 0; + } + else if (mail == PPG_SERVICE_CMD_TYPE_OPEN_HRS_BLE) + { +#ifdef PPG_HX3695 + // hx3695_set_hrs_ble_swtich(1); +#endif + continue ; + } + else if (mail == PPG_SERVICE_CMD_TYPE_CLOSE_HRS_BLE) + { +#ifdef PPG_HX3695 + // hx3695_set_hrs_ble_swtich(0); +#endif + continue ; + }else if (mail == PPG_SERVICE_CMD_TYPE_INT_HANDLER){ +// #ifdef PPG_VC9202 +// vc9202_usr_interrupt_handler(SPORT_TYPE_NORMAL,0); +// #elif defined PPG_VC921X +// cmd = "int"; +// enable = 1; +// ppg_send_cmd_to_vc921x_driver(cmd,enable); +// #elif defined PPG_GH3X2X +// hal_gh3x2x_afe_int_handler_call_back(); +// GH3X2X_AFE_ChipPro(); +// #elif defined PPG_PAH8009 +// hal_gh3x2x_afe_int_handler_call_back(); +// GH3X2X_AFE_ChipPro(); +// #endif + ppg_int_handler(); + continue; + } + else if (mail == PPG_SERVICE_CMD_TYPE_FPC_TEST){ +#ifdef PPG_VC9202 + cmd = "fpc"; + enable = 1; +#endif + } + else if (mail == PPG_SERVICE_CMD_TYPE_FACTORY_TEST){ +#ifdef PPG_VC9202 + cmd = "factory"; + enable = 1; +#endif + } + if (ppg_service_running_stat == true && enable ==1 ) + { + PRINT_ERR("ppg service already started! \r\n"); + continue ; + }else if ( ppg_service_running_stat == false && enable == 0 ) + { + PRINT_ERR("ppg service already stopped! \r\n"); + continue ; + } + + ppg_send_cmd_to_driver(cmd,enable); + + if(enable == 1) + ppg_service_running_stat = true; + else + ppg_service_running_stat = false; + +#ifdef PPG_HX3695 + if((strcmp(cmd, "wear") != 0) && (enable == 0)) + { + if (keep_in_wear_det_mod == 1) + { + uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_START); + ppg_send_cmd_to_driver("wear",1); + wear_mode_state = 1; + ppg_service_running_stat = true; + } + } +#endif + + } + +} +void create_ppg_queue(void) +{ + if (osal_msg_queue_create("ppg_service_queue", PPG_SERVICE_MSG_COUNT, &g_app_queue, + 0, sizeof(PPG_CMD_TYPE_T)) != ERRCODE_SUCC) { + PRINT_ERR("[ppg][service] app create mail fail\n"); + } +} +errcode_t uapi_ppg_service_init(void) +{ + PRINT("uapi_ppg_service_init !\r\n"); + + ppg_power_on(); + + if (ppg_get_chip_id() != PPG_CHIP_ID) + { + //TODO 没找到3695,退出线程 + PRINT("ppg not exist!\r\n"); + ppg_power_off(); + return ERRCODE_FAIL; + } + + ppg_power_off(); + + ppg_sensor_exist = true; + + app_task_definition_t taskcfg={0}; + taskcfg.create_queue_handle = create_ppg_queue; + taskcfg.attr.name="ppg_service"; + taskcfg.attr.priority = osPriorityBelowNormal4; + taskcfg.attr.stack_size = PPG_SERVICE_TASK_SIZE; + taskcfg.func = ppg_service_check_task; + taskcfg.use_mem = USE_EXTEND_MEM; + + errcode_t ret=uapi_create_osThread_custom(&taskcfg); + if(ret != ERRCODE_SUCC) + { + PRINT("create ppg_service failed %d!\r\n",ret); + return ERRCODE_FAIL; + } + + + // g_ppg_service_timer = osTimerNew((osTimerFunc_t)ppg_int_callback, osTimerPeriodic, NULL, NULL); + + return ERRCODE_SUCC; +} + +void ppg_int_callback(pin_t pin, uintptr_t param) +{ + uapi_gpio_clear_interrupt(pin); + // uint32_t tm; + // uapi_get_timestampe_ms(&tm); + // PRINT("ppg_int_callback %d 0x%X tm : %d \n",pin,param,tm); + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_INT_HANDLER); +} +// void ppg_service_service_resume(void) +// { +// DEBUG_PRINTF("ppg_service_service resume!\r\n"); +// ppg_service_check_timer_callback(0); +// } +// void ppg_service_service_suspend(void) +// { +// DEBUG_PRINTF("ppg_service_service suspend!\r\n"); +// } + diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp b/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp deleted file mode 100644 index 72492c79b..000000000 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp +++ /dev/null @@ -1,533 +0,0 @@ -/** - * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n - * - * Description: Test source \n - * Author: @CompanyNameTag \n - * History: \n - * 2022-08-16, Create file. \n - */ - -#include "wearable_log.h" -#include "securec.h" -#include "broadcast_service.h" -#include "broadcast_feature.h" -#include "service_id_define.h" -#include "samgr_lite.h" -#include "thread_adapter.h" -#include "graphic_service.h" - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif /* __cplusplus */ -#endif /* __cplusplus */ - -#include "pinctrl.h" -#include "debug_print.h" -#include "soc_osal.h" -#include "tcxo.h" -#include "irmalloc.h" -#include "errcode.h" -#include "common_def.h" - -#include "chip_core_irq.h" -#include "chip_io.h" -#include "gpio.h" -#include "pm_veto.h" - -#include "rtc.h" -#include "timer.h" -#include "systick.h" -#include "cmsis_os2.h" -#include "ppg_service.h" -#include "los_printf.h" - -#include "thread_init.h" -#include "custom_utils.h" -#include "custom_save_runtime.h" - -#if defined(PPG_VC9202) -#include "vc9202_hal.h" -#include "vc9202_user.h" -#elif defined(PPG_VC921X) -#include "vc921x_hal.h" -#include "vc921x_user_app.h" -#elif defined(PPG_GH3X2X) -#include "gh3x2x_hal.h" -#include "gh3x2x_afe_drv.h" -#else -#include "hx3695_hal.h" -#include "hx3695.h" -#endif - -static bool g_ppg_service_initialled = false; - -uint8_t card_databuf[64] = {0}; -uint8_t light_databuf[64] = {0}; - -osTimerId_t g_ppg_service_timer = NULL; - - -/*** - * 其他cmd在Header里定义,对外开放 -*/ - - -#define PPG_SERVICE_MSG_COUNT 16 -#define PPG_SERVICE_TASK_SIZE 0x1000 -#define PPG_SERVICE_TASK_PRIO 5 - -#define MAG_CHECK_MS 20 -static unsigned long g_app_queue= 0xFFFFFFFF; - -static bool ppg_service_running_stat = false; -static bool ppg_sensor_exist = false; - -static uint8_t wear_mode_state = 0; -static uint8_t keep_in_wear_det_mod = 1; //持续坚持 佩戴检测模式 - - -void set_keep_in_wear_det_mode(uint8_t mod) -{ - keep_in_wear_det_mod = mod; -} - -#ifdef PPG_HX3695 -//漏光测试 -errcode_t update_leaklight_event_notify(uint8_t *data) -{ - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "send lightdata to ui %s",data); - CustomEventPublish(TOPIC_EVENT_LEAKLIGHT_UPDATA,(uint8_t*)data,strlen((char*)data)); - return 0; -} -errcode_t update_leaklight_event_sendmsg_toUI(uint8_t *data) -{ - /**通过UI事件发送Notify*/ - GraphicService::GetInstance()->PostGraphicEvent(std::bind(update_leaklight_event_notify, data)); - return ERRCODE_SUCC; -} - - -//灰卡测试 -errcode_t update_graycard_event_notify(uint8_t *data) -{ - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "send carddata to ui %s",data); - CustomEventPublish(TOPIC_EVENT_GRAYCARD_UPDATA,(uint8_t*)data,strlen((char*)data)); - return 0; -} -errcode_t update_graycard_event_sendmsg_toUI(uint8_t *data) -{ - /**通过UI事件发送Notify*/ - GraphicService::GetInstance()->PostGraphicEvent(std::bind(update_graycard_event_notify, data)); - return ERRCODE_SUCC; -} - - -//血氧 -errcode_t update_spo2_event_notify(uint8_t spo2) -{ - CustomEventPublish(TOPIC_EVENT_SPO2_UPDATE,(uint8_t*)&spo2,sizeof(spo2)); - return 0; -} -errcode_t update_spo2_event_sendmsg_toUI(uint8_t spo2) -{ - /**通过UI事件发送Notify*/ - GraphicService::GetInstance()->PostGraphicEvent(std::bind(update_spo2_event_notify, spo2)); - return ERRCODE_SUCC; -} - -//心率 -errcode_t update_hrs_event_notify(uint8_t hrs) -{ - CustomEventPublish(TOPIC_EVENT_HEARTRATE_UPDATA,(uint8_t*)&hrs,sizeof(hrs)); - return 0; -} -errcode_t update_hrs_event_sendmsg_toUI(uint8_t hrs) -{ - /**通过UI事件发送Notify*/ - GraphicService::GetInstance()->PostGraphicEvent(std::bind(update_hrs_event_notify, hrs)); - return ERRCODE_SUCC; -} - - -//穿戴状态 -errcode_t update_wearstatus_event_notify(int32_t wearstatus) -{ - CustomEventPublish(TOPIC_EVENT_WEARSTATE_UPDATE,(uint8_t*)&wearstatus,sizeof(wearstatus)); - return 0; -} -errcode_t update_wearstatus_event_sendmsg_toUI(int32_t wearstatus) -{ - /**通过UI事件发送Notify*/ - GraphicService::GetInstance()->PostGraphicEvent(std::bind(update_wearstatus_event_notify, wearstatus)); - return ERRCODE_SUCC; -} - -//静息心率 -errcode_t update_static_hrs_event_notify(int32_t hrs) -{ - CustomEventPublish(TOPIC_EVENT_STATIC_HEARTRATE_UPDATA,(uint8_t*)&hrs,sizeof(hrs)); - return 0; -} -errcode_t update_static_hrs_event_sendmsg_toUI(int32_t hrs) -{ - /**通过UI事件发送Notify*/ - GraphicService::GetInstance()->PostGraphicEvent(std::bind(update_static_hrs_event_notify, hrs)); - return ERRCODE_SUCC; -} - -#include "hx3695_hal.h" -#include "hx3695.h" -void hx3695_msg_callback(uint8_t msg_type, uint8_t *msg_data, int32_t msg_datalen) -{ - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "hx3695_msg_callback"); - FT_CUSTOM_RESULTS_t sensor_data; // 使用更通用的名称 sensor_data -#if 1 - if (msg_datalen < sizeof(FT_CUSTOM_RESULTS_t)) { - // 数据长度不足以填充整个结构体 - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Invalid data length for SPO2 update"); - //return; - } -#endif - memcpy(&sensor_data, msg_data, sizeof(FT_CUSTOM_RESULTS_t)); - switch(msg_type) - { - case HX3695_MSG_TYPE_HRS_UPDATE: - //每秒心率 - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_HRS_UPDATE = %d", sensor_data.lastesthrs); - update_hrs_event_sendmsg_toUI(sensor_data.lastesthrs); - break; - case HX3695_MSG_TYPE_HRV_UPDATE: - break; - case HX3695_MSG_TYPE_SPO2_UPDATE: - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_SPO2_UPDATE = %d", sensor_data.lastestspo2); - update_spo2_event_sendmsg_toUI(sensor_data.lastestspo2); - break; - case HX3695_MSG_TYPE_LEAKLIGHT_UPDATE: - memset_s(light_databuf,64,0,64); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "LEAKLIGHT_UPDATE"); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_leak_green_UPDATE = %d", sensor_data.leak_green); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_leak_red_UPDATE = %d", sensor_data.leak_red); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_leak_ir_UPDATE = %d", sensor_data.leak_ir); - sprintf((char *)light_databuf,"%d,%d,%d",sensor_data.leak_green,sensor_data.leak_red,sensor_data.leak_ir); - update_leaklight_event_sendmsg_toUI(light_databuf); - break; - case HX3695_MSG_TYPE_GRAYCARD_UPDATE: - memset_s(card_databuf,64,0,64); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GRAYCARD_UPDATE"); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_card_green_UPDATE = %d", sensor_data.card_green); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_card_red_UPDATE = %d", sensor_data.card_red); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_card_ir_UPDATE = %d", sensor_data.card_ir); - sprintf((char *)card_databuf,"%d,%d,%d",sensor_data.card_green,sensor_data.card_red,sensor_data.card_ir); - update_graycard_event_sendmsg_toUI(card_databuf); - break; - case HX3695_MSG_TYPE_WEARSTAT_UPDATE: - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_WEARSTATUS_UPDATE = %d", sensor_data.wearstatus); - update_wearstatus_event_sendmsg_toUI(sensor_data.wearstatus); - break; - case HX3695_MSG_TYPE_STATIC_HRS_UPDATE: - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HX3695_MSG_TYPE_STATIC_HRS_UPDATE = %d", sensor_data.lastesthrs); - update_static_hrs_event_sendmsg_toUI(sensor_data.lastesthrs); - break; - default: - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Unknown sensor message type"); - break; - } -} - -#endif - -void uapi_ppg_service_deinit(void) -{ - ppg_service_running_stat = false; -} - -uint32_t ppg_suspend(void) -{ - return custom_i2c_suspend(); -} -uint32_t ppg_resume(void) -{ - return custom_i2c_resume(); -} - - -errcode_t send_ppg_cmd_msg(int cmd) -{ - errcode_t ret; - if (ppg_sensor_exist == false) - return OSAL_FAILURE; - - PPG_CMD_TYPE_T mail = 0; - mail = cmd; - ret = osal_msg_queue_write_copy(g_app_queue, (void *)&mail, - sizeof(PPG_CMD_TYPE_T), 0); - if (ret != OSAL_SUCCESS) { - PRINT_ERR("Error ppg Check MSG 0x%02X send failed! err=0x%x! \r\n",cmd, ret); - } - return ret; -} - -static void ppg_service_check_task(void *arg) -{ - unused(arg); - int32_t ret; - uint32_t mail; - uint32_t msgsize = (uint32_t)sizeof(PPG_CMD_TYPE_T); - - while (1) { - ret = osal_msg_queue_read_copy(g_app_queue, (void *)&mail, &msgsize, - OSAL_MSGQ_WAIT_FOREVER); - if (ret != OSAL_SUCCESS) { - continue; - } - if((wear_mode_state == 1) && (mail > 0x10) && mail != PPG_SERVICE_CMD_TYPE_STOP_WEAR_MODE_TEST) - { - uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_STOP); - wear_mode_state = 0; -#ifdef PPG_HX3695 - ppg_send_cmd_to_driver("wear",0); -#endif - ppg_service_running_stat = false; - } - char* cmd = "hrs"; - int enable = 1; - if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_320TIMER_CALLBACK){ -#ifdef PPG_HX3695 - heart_rate_meas_timeout_handler(NULL); -#endif - continue; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_40TIMER_CALLBACK){ -#ifdef PPG_HX3695 - agc_timeout_handler(NULL); -#endif - continue; - }else if(mail == PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_5000TIMER_CALLBACK){ -#ifdef PPG_HX3695 - wear_mode_timeout_handler(NULL); -#endif - continue; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_TEST){ - //do_cywee_service_check_msg(CYWEE_SERVICE_CMD_OPEN_GET_ACC,NULL); - uapi_save_runtime_log(RUNTIME_LOG_HEART_DRIVER_MEASURE); - cmd = "hrs"; - enable = 1; - // uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); - // if (cnt == 0) - // { - // uapi_pm_add_sleep_veto(PM_ID_HEART); - // } - - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_HRV_TEST){ - cmd = "hrv"; - enable = 1; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_SPO2_TEST){ - cmd = "spo2"; - enable = 1; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST){ - cmd = "leaklight"; - enable = 1; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_GRAYCARD_TEST){ - cmd = "graycard"; - enable = 1; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_TEST){ - if (keep_in_wear_det_mod == 0) continue;; - uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_START); - cmd = "wear"; - enable = 1; - wear_mode_state = 1; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_LED_OFF_MODE_TEST){ - cmd = "ledoff"; - enable = 0; - }else if (mail == PPG_SERVICE_CMD_TYPE_DO_SINGLE_CHECK_MODE_TEST){ - cmd = "single"; - enable = 1; - }else if (mail == PPG_SERVICE_CMD_TYPE_STOP_WEAR_MODE_TEST){ - if (keep_in_wear_det_mod == 0) continue; - cmd = "wear"; - enable = 0; - wear_mode_state = 0; - }else if (mail == PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST){ - uapi_save_runtime_log(RUNTIME_LOG_HEART_DRIVER_MEASURE_END); - cmd = "hrs"; - enable = 0; - // uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); - // if (cnt == 1) - // { - // uapi_pm_remove_sleep_veto(PM_ID_HEART); - // } - }else if (mail == PPG_SERVICE_CMD_TYPE_STOP_SPO2_TEST){ - - cmd = "spo2"; - enable = 0; - } - else if (mail == PPG_SERVICE_CMD_TYPE_OPEN_HRS_BLE) - { -#ifdef PPG_HX3695 - hx3695_set_hrs_ble_swtich(1); -#endif - continue ; - } - else if (mail == PPG_SERVICE_CMD_TYPE_CLOSE_HRS_BLE) - { -#ifdef PPG_HX3695 - hx3695_set_hrs_ble_swtich(0); -#endif - continue ; - }else if (mail == PPG_SERVICE_CMD_TYPE_INT_HANDLER){ -#ifdef PPG_VC9202 - vc9202_usr_interrupt_handler(SPORT_TYPE_NORMAL,0); -#elif defined PPG_VC921X - cmd = "int"; - enable = 1; - ppg_send_cmd_to_vc921x_driver(cmd,enable); -#elif defined PPG_GH3X2X - hal_gh3x2x_afe_int_handler_call_back(); - GH3X2X_AFE_ChipPro(); -#endif - continue; - } - else if (mail == PPG_SERVICE_CMD_TYPE_FPC_TEST){ -#ifdef PPG_VC9202 - cmd = "fpc"; - enable = 1; -#endif - } - else if (mail == PPG_SERVICE_CMD_TYPE_FACTORY_TEST){ -#ifdef PPG_VC9202 - cmd = "factory"; - enable = 1; -#endif - } - if (ppg_service_running_stat == true && enable ==1 ) - { - PRINT_ERR("ppg service already started! \r\n"); - continue ; - }else if ( ppg_service_running_stat == false && enable == 0 ) - { - PRINT_ERR("ppg service already stopped! \r\n"); - continue ; - } - -#ifdef PPG_VC9202 - ppg_send_cmd_to_vc9202_driver(cmd,enable); -#elif defined(PPG_VC921X) - ppg_send_cmd_to_vc921x_driver(cmd,enable); -#elif defined(PPG_GH3X2X) - ppg_send_cmd_to_gh3x2x_driver(cmd,enable); -#endif - - if(enable == 1) - ppg_service_running_stat = true; - else - ppg_service_running_stat = false; - - if((strcmp(cmd, "wear") != 0) && (enable == 0)) - { - if (keep_in_wear_det_mod == 1) - { - uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_START); -#ifdef PPG_HX3695 - ppg_send_cmd_to_driver("wear",1); -#endif - wear_mode_state = 1; - ppg_service_running_stat = true; - } - } - - } - -} -void create_ppg_queue(void) -{ - if (osal_msg_queue_create("ppg_service_queue", PPG_SERVICE_MSG_COUNT, &g_app_queue, - 0, sizeof(PPG_CMD_TYPE_T)) != ERRCODE_SUCC) { - PRINT_ERR("[ppg][service] app create mail fail\n"); - } -} -errcode_t uapi_ppg_service_init(void) -{ - - - PRINT("uapi_ppg_service_init !\r\n"); - - tyhx_poweron(); - -#ifdef PPG_HX3695 - - if ( hx3695_chip_check() == false) - { - //TODO 没找到3695,退出线程 - PRINT("3695 not exist!\r\n"); - tyhx_poweroff(); - return ERRCODE_FAIL; - } - hx3695_register_msg_callback(hx3695_msg_callback);//注册驱动回调 - // //ppg_send_cmd_to_driver("wear",0); -#elif defined(PPG_VC9202) - if ( vc9202_drv_get_chip_id() != 0x21) - { - //TODO 没找到3695,退出线程 - PRINT("PPG_VC9202 not exist!\r\n"); - tyhx_poweroff(); - return ERRCODE_FAIL; - } -#elif defined(PPG_GH3X2X) - if (GH3X2X_AFE_CheckChipId() != 0) - { - //TODO 没找到3695,退出线程 - PRINT("PPG_GH3X2X not exist!\r\n"); - tyhx_poweroff(); - return ERRCODE_FAIL; - } -#endif - - tyhx_poweroff(); - - ppg_sensor_exist = true; - - app_task_definition_t taskcfg={0}; - taskcfg.create_queue_handle = create_ppg_queue; - taskcfg.attr.name="ppg_service"; - taskcfg.attr.priority = osPriorityBelowNormal4; - taskcfg.attr.stack_size = PPG_SERVICE_TASK_SIZE; - taskcfg.func = ppg_service_check_task; - taskcfg.use_mem = USE_EXTEND_MEM; - - errcode_t ret=uapi_create_osThread_custom(&taskcfg); - if(ret != ERRCODE_SUCC) - { - PRINT("create ppg_service failed %d!\r\n",ret); - return ERRCODE_FAIL; - } - - - // g_ppg_service_timer = osTimerNew((osTimerFunc_t)ppg_int_callback, osTimerPeriodic, NULL, NULL); - - return ERRCODE_SUCC; -} - -void ppg_int_callback(pin_t pin, uintptr_t param) -{ - uapi_gpio_clear_interrupt(pin); - uint32_t tm; - uapi_get_timestampe_ms(&tm); - // PRINT("ppg_int_callback %d 0x%X tm : %d \n",pin,param,tm); - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_INT_HANDLER); -} -// void ppg_service_service_resume(void) -// { -// DEBUG_PRINTF("ppg_service_service resume!\r\n"); -// ppg_service_check_timer_callback(0); -// } -// void ppg_service_service_suspend(void) -// { -// DEBUG_PRINTF("ppg_service_service suspend!\r\n"); -// } - - -#ifdef __cplusplus -#if __cplusplus -} -#endif /* __cplusplus */ -#endif /* __cplusplus */ diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_service.h b/code/sdk/zhihui/drivers/ppg/service/ppg_service.h index 012a1d8df..a7aa9ab32 100644 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_service.h +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_service.h @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-03-27 09:07:00 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2025-01-06 16:57:23 + * @LastEditTime: 2025-05-30 14:44:51 * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/service/ppg_service.h * @Description: * @@ -30,9 +30,10 @@ extern "C" { #include "errcode.h" #include "platform_core.h" -#define PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_5000TIMER_CALLBACK 0x09 -#define PPG_SERVICE_CMD_TYPE_DO_PPG_40TIMER_CALLBACK 0x0A -#define PPG_SERVICE_CMD_TYPE_DO_PPG_320TIMER_CALLBACK 0x10 +#define PPG_SERVICE_CMD_TYPE_INT_HANDLER 0x08 +#define PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_TIMER_CALLBACK 0x09 +#define PPG_SERVICE_CMD_TYPE_DO_PPG_AGC_TIMER_CALLBACK 0x0A +#define PPG_SERVICE_CMD_TYPE_DO_PPG_HRS_TIMER_CALLBACK 0x10 #define PPG_SERVICE_CMD_TYPE_DO_PPG_TEST 0x11 #define PPG_SERVICE_CMD_TYPE_DO_HRV_TEST 0x12 #define PPG_SERVICE_CMD_TYPE_DO_SPO2_TEST 0x13 @@ -46,7 +47,6 @@ extern "C" { #define PPG_SERVICE_CMD_TYPE_DO_SINGLE_CHECK_MODE_TEST 0x23 #define PPG_SERVICE_CMD_TYPE_OPEN_HRS_BLE 0x24 #define PPG_SERVICE_CMD_TYPE_CLOSE_HRS_BLE 0x25 -#define PPG_SERVICE_CMD_TYPE_INT_HANDLER 0x26 #define PPG_SERVICE_CMD_TYPE_FPC_TEST 0x27 #define PPG_SERVICE_CMD_TYPE_FACTORY_TEST 0x28 diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_hal.c b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_hal.c index 5e2d2341f..815e80656 100644 --- a/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_hal.c +++ b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_hal.c @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-03-13 15:08:38 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2024-12-24 10:25:14 + * @LastEditTime: 2025-05-15 17:15:13 * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c * @Description: * @@ -26,10 +26,6 @@ #endif #ifdef PPG_HX3695 -#include "tyhx_hrs_custom.h" -#include "hx3695.h" -#include "hx3695_hal.h" -#include "hx3695.h" hx3695_msg_callback_t g_send_msg_toUI = NULL; @@ -156,7 +152,7 @@ void ppg_send_cmd_to_vc9202_driver(char* mode, uint8_t enable) #endif { // ppg_service_running_stat = true; - uapi_pm_control(PM_APP_WAKE_NEEDED); + // uapi_pm_control(PM_APP_WAKE_NEEDED); tyhx_poweron(); #ifdef PPG_HX3695 hx3695_init(md); @@ -205,7 +201,7 @@ void ppg_send_cmd_to_vc9202_driver(char* mode, uint8_t enable) #endif - uapi_pm_control(PM_APP_WAKE_NONEED); + // uapi_pm_control(PM_APP_WAKE_NONEED); tyhx_poweroff(); } } \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_hal.c b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_hal.c index 477d9eee4..648fb7eef 100644 --- a/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_hal.c +++ b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_hal.c @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-03-13 15:08:38 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2024-12-16 16:40:25 + * @LastEditTime: 2025-05-15 11:56:40 * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c * @Description: * @@ -51,7 +51,7 @@ void ppg_send_cmd_to_vc921x_driver(char* mode, uint8_t enable) if (enable == 1) { // ppg_service_running_stat = true; - uapi_pm_control(PM_APP_WAKE_NEEDED); + // uapi_pm_control(PM_APP_WAKE_NEEDED); tyhx_poweron(); vc921x_device = get_vc921x_device(); @@ -68,7 +68,7 @@ void ppg_send_cmd_to_vc921x_driver(char* mode, uint8_t enable) } else { - uapi_pm_control(PM_APP_WAKE_NONEED); + // uapi_pm_control(PM_APP_WAKE_NONEED); vc921x_device->ops->stop_work(); tyhx_poweroff(); } diff --git a/code/sdk/zhihui/drivers/rotary_encoder/mixo/mixo_ots_driver.c b/code/sdk/zhihui/drivers/rotary_encoder/mixo/mixo_ots_driver.c index 16fc440ea..be7f6998f 100644 --- a/code/sdk/zhihui/drivers/rotary_encoder/mixo/mixo_ots_driver.c +++ b/code/sdk/zhihui/drivers/rotary_encoder/mixo/mixo_ots_driver.c @@ -32,9 +32,9 @@ static void put_crown_result(int16_t x) { return; } - if(abs(x)>=8 ) + if(abs(x)>=16 ) { - ots_result += x/8; //大于4的值除以4, 代表角度, 单位0.5° + ots_result += x/16; //大于4的值除以4, 代表角度, 单位0.5° } else { diff --git a/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c b/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c index 6f714c6a5..b88bff8bd 100644 --- a/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c +++ b/code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-06-17 14:31:08 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2025-05-12 18:56:38 + * @LastEditTime: 2025-06-06 16:19:51 * @FilePath: /FD230/code/sdk/application/wearable/service/factorytest_service/factorytest_protocol.c * @Description: * @@ -21,7 +21,10 @@ #include "app_at_process.h" #include "cywee_hal.h" +#ifdef SUPPORT_PPG_SERVICE #include "ppg_service.h" +#endif + #include "button_porting.h" #ifdef SUPPORT_CAT1_SERVICE #include "cat1_ctl.h" @@ -407,20 +410,23 @@ void aging_task(void) return; } uapi_get_timestampe_ss(¤t_time); - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_SINGLE_CHECK_MODE_TEST); + + uint32_t green = 0; + uint32_t red = 0; + uint32_t ir = 0; + +#ifdef SUPPORT_PPG_SERVICE + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST); LOS_Msleep(1000); - #ifdef PPG_HX3695 - FT_RESULTS_t ft_result = hx3695_factroy_test(SINGLE_CHECK_TEST); - #endif + ppg_get_leaklight_data(&green,&red,&ir); send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); - #ifdef PPG_HX3695 - PRINT("ft_result.gr_data_final : %d , ft_result.red_data_final : %d , ft_result.ir_data_final : %d\r\n",ft_result.gr_data_final,ft_result.red_data_final,ft_result.ir_data_final); - if(!(ft_result.gr_data_final && ft_result.red_data_final && ft_result.ir_data_final)) +#endif + PRINT("green : %d , red : %d , ft_result.ir_data_final : %d\r\n",green,red,ir); + if(!green && !red && !ir) { aging_t.ppg_error++; aging_t.fail_num++; } - #endif PRINT("current_time - enter_time[%d]\n",current_time - enter_time); }while(current_time - enter_time <= 2 * 60); @@ -1459,7 +1465,9 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint { //获取 ppg_id uint8_t ppg_id; - uapi_ppg_get_id(&ppg_id); +#ifdef SUPPORT_PPG_SERVICE + ppg_get_chip_id(&ppg_id); +#endif PRINT("0x%x\n",ppg_id); factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST, BLE_TEST_CMD_SOFT_TEST_SUB_MODE_HRS, @@ -1467,48 +1475,22 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint &ppg_id, 1); - } else if(testitem == 0x02) - { - //关闭所有LED - uint8_t send_data = 0x00; - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LED_OFF_MODE_TEST); - factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST, - BLE_TEST_CMD_SOFT_TEST_SUB_MODE_HRS, - 0x02, - &send_data, - 1); - } else if(testitem == 0x03) + }else if(testitem == 0x03) { //打开心率检测 -#ifdef PPG_HX3695 - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_SINGLE_CHECK_MODE_TEST); -#elif defined PPG_VC9202 + uint8_t databuf[4] = {0}; +#ifdef SUPPORT_PPG_SERVICE send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_PPG_TEST); -#endif LOS_Msleep(1000); - uint8_t databuf[4] = {0}; -#ifdef PPG_HX3695 - FT_RESULTS_t ft_result = hx3695_factroy_test(SINGLE_CHECK_TEST); - databuf[0] = (uint8_t)((ft_result.gr_data_final & 0xFF000000) >> 24); - databuf[1] = (uint8_t)((ft_result.gr_data_final & 0x00FF0000) >> 16); - databuf[2] = (uint8_t)((ft_result.gr_data_final & 0x0000FF00) >> 8); - databuf[3] = (uint8_t)((ft_result.gr_data_final & 0x000000FF) >> 0); -#elif defined PPG_VC9202 - uint32_t ppg_data = vc9202_get_hr_ppg_data(); - if(!ppg_data) - { - LOS_Msleep(1000); - ppg_data = vc9202_get_hr_ppg_data(); - } - PRINT("ppg_data : %d \n",ppg_data); - databuf[0] = (uint8_t)((ppg_data & 0xFF000000) >> 24); - databuf[1] = (uint8_t)((ppg_data & 0x00FF0000) >> 16); - databuf[2] = (uint8_t)((ppg_data & 0x0000FF00) >> 8); - databuf[3] = (uint8_t)((ppg_data & 0x000000FF) >> 0); -#endif + uint32_t data = ppg_get_factory_data(); + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); + databuf[0] = (uint8_t)((data & 0xFF000000) >> 24); + databuf[1] = (uint8_t)((data & 0x00FF0000) >> 16); + databuf[2] = (uint8_t)((data & 0x0000FF00) >> 8); + databuf[3] = (uint8_t)((data & 0x000000FF) >> 0); +#endif PRINT("%2X %2X %2X %2X \r\n",databuf[0],databuf[1],databuf[2],databuf[3]); @@ -1521,44 +1503,21 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint } else if(testitem == 0x04) { //打开血氧检测 -#ifdef PPG_HX3695 - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_SINGLE_CHECK_MODE_TEST); -#elif defined PPG_VC9202 + uint8_t databuf[4] = {0}; +#ifdef SUPPORT_PPG_SERVICE send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_SPO2_TEST); -#endif LOS_Msleep(1000); - uint8_t databuf[8] = {0}; -#ifdef PPG_HX3695 - FT_RESULTS_t ft_result = hx3695_factroy_test(SINGLE_CHECK_TEST); - databuf[0] = (uint8_t)((ft_result.red_data_final & 0xFF000000) >> 24); - databuf[1] = (uint8_t)((ft_result.red_data_final & 0x00FF0000) >> 16); - databuf[2] = (uint8_t)((ft_result.red_data_final & 0x0000FF00) >> 8); - databuf[3] = (uint8_t)((ft_result.red_data_final & 0x000000FF) >> 0); -#elif defined PPG_VC9202 - uint32_t red_data = 0; - uint32_t ir_data = 0; - vc9202_get_spo2_ppg_data(&ir_data,&red_data); - PRINT("ir_data : %d ,red_data : %d \n",ir_data,red_data); - if(!ir_data && !red_data) - { - LOS_Msleep(1000); - vc9202_get_spo2_ppg_data(&ir_data,&red_data); - } - - databuf[0] = (uint8_t)((ir_data & 0xFF000000) >> 24); - databuf[1] = (uint8_t)((ir_data & 0x00FF0000) >> 16); - databuf[2] = (uint8_t)((ir_data & 0x0000FF00) >> 8); - databuf[3] = (uint8_t)((ir_data & 0x000000FF) >> 0); - - databuf[4] = (uint8_t)((red_data & 0xFF000000) >> 24); - databuf[5] = (uint8_t)((red_data & 0x00FF0000) >> 16); - databuf[6] = (uint8_t)((red_data & 0x0000FF00) >> 8); - databuf[7] = (uint8_t)((red_data & 0x000000FF) >> 0); + uint32_t data = ppg_get_factory_data(); + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_SPO2_TEST); + + databuf[0] = (uint8_t)((data & 0xFF000000) >> 24); + databuf[1] = (uint8_t)((data & 0x00FF0000) >> 16); + databuf[2] = (uint8_t)((data & 0x0000FF00) >> 8); + databuf[3] = (uint8_t)((data & 0x000000FF) >> 0); #endif - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); - PRINT("%2X %2X %2X %2X \r\n",databuf[0],databuf[1],databuf[2],databuf[3]); - PRINT("%2X %2X %2X %2X \r\n",databuf[4],databuf[5],databuf[6],databuf[7]); + + PRINT("%2X %2X %2X %2X \r\n",databuf[0],databuf[1],databuf[2],databuf[3]); factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST, BLE_TEST_CMD_SOFT_TEST_SUB_MODE_HRS, @@ -1568,6 +1527,7 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint } else if(testitem == 0x05) { +#ifdef SUPPORT_PPG_SERVICE //灰卡测试 send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_GRAYCARD_TEST); LOS_Msleep(1000); @@ -1617,6 +1577,7 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint 8); #endif send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); +#endif // PRINT("%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\r\n", // databuf[0],databuf[1],databuf[2],databuf[3], // databuf[4],databuf[5],databuf[6],databuf[7], @@ -1627,55 +1588,33 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint } else if(testitem == 0x06) { //漏光测试 - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST); - LOS_Msleep(1000); uint8_t databuf[12] = {0}; -#ifdef PPG_HX3695 - FT_RESULTS_t ft_result = hx3695_factroy_test(LEAK_LIGHT_TEST); - - databuf[0] = (uint8_t)((ft_result.gr_data_final & 0xFF000000) >> 24); - databuf[1] = (uint8_t)((ft_result.gr_data_final & 0x00FF0000) >> 16); - databuf[2] = (uint8_t)((ft_result.gr_data_final & 0x0000FF00) >> 8); - databuf[3] = (uint8_t)((ft_result.gr_data_final & 0x000000FF) >> 0); - - databuf[4] = (uint8_t)((ft_result.red_data_final & 0xFF000000) >> 24); - databuf[5] = (uint8_t)((ft_result.red_data_final & 0x00FF0000) >> 16); - databuf[6] = (uint8_t)((ft_result.red_data_final & 0x0000FF00) >> 8); - databuf[7] = (uint8_t)((ft_result.red_data_final & 0x000000FF) >> 0); - databuf[8] = (uint8_t)((ft_result.ir_data_final & 0xFF000000) >> 24); - databuf[9] = (uint8_t)((ft_result.ir_data_final & 0x00FF0000) >> 16); - databuf[10] = (uint8_t)((ft_result.ir_data_final & 0x0000FF00) >> 8); - databuf[11] = (uint8_t)((ft_result.ir_data_final & 0x000000FF) >> 0); -#elif defined PPG_VC9202 - uint32_t led_cur = 0; - uint32_t apre_val = 0; - uint32_t aps_val = 9; - vc9202_get_leaklight_data(&led_cur,&apre_val,&aps_val); - PRINT("led_cur : %d ,apre_val : %d ,aps_val : %d \n",led_cur,apre_val,aps_val); + uint32_t green = 0; + uint32_t red = 0; + uint32_t ir = 0; - if(!led_cur && !apre_val && !aps_val) - { - LOS_Msleep(1000); - vc9202_get_leaklight_data(&led_cur,&apre_val,&aps_val); - } +#ifdef SUPPORT_PPG_SERVICE + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST); + LOS_Msleep(1000); + ppg_get_leaklight_data(&green,&red,&ir); + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); +#endif + databuf[0] = (uint8_t)((green & 0xFF000000) >> 24); + databuf[1] = (uint8_t)((green & 0x00FF0000) >> 16); + databuf[2] = (uint8_t)((green & 0x0000FF00) >> 8); + databuf[3] = (uint8_t)((green & 0x000000FF) >> 0); - databuf[0] = (uint8_t)((led_cur & 0xFF000000) >> 24); - databuf[1] = (uint8_t)((led_cur & 0x00FF0000) >> 16); - databuf[2] = (uint8_t)((led_cur & 0x0000FF00) >> 8); - databuf[3] = (uint8_t)((led_cur & 0x000000FF) >> 0); + databuf[4] = (uint8_t)((red & 0xFF000000) >> 24); + databuf[5] = (uint8_t)((red & 0x00FF0000) >> 16); + databuf[6] = (uint8_t)((red & 0x0000FF00) >> 8); + databuf[7] = (uint8_t)((red & 0x000000FF) >> 0); - databuf[4] = (uint8_t)((apre_val & 0xFF000000) >> 24); - databuf[5] = (uint8_t)((apre_val & 0x00FF0000) >> 16); - databuf[6] = (uint8_t)((apre_val & 0x0000FF00) >> 8); - databuf[7] = (uint8_t)((apre_val & 0x000000FF) >> 0); + databuf[8] = (uint8_t)((ir & 0xFF000000) >> 24); + databuf[9] = (uint8_t)((ir & 0x00FF0000) >> 16); + databuf[10] = (uint8_t)((ir & 0x0000FF00) >> 8); + databuf[11] = (uint8_t)((ir & 0x000000FF) >> 0); - databuf[8] = (uint8_t)((aps_val & 0xFF000000) >> 24); - databuf[9] = (uint8_t)((aps_val & 0x00FF0000) >> 16); - databuf[10] = (uint8_t)((aps_val & 0x0000FF00) >> 8); - databuf[11] = (uint8_t)((aps_val & 0x000000FF) >> 0); -#endif - send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST); // PRINT("%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\r\n", // databuf[0],databuf[1],databuf[2],databuf[3], diff --git a/code/sdk/zhihui/utils/custom_utils.c b/code/sdk/zhihui/utils/custom_utils.c index 12d076e26..2fe7483c2 100644 --- a/code/sdk/zhihui/utils/custom_utils.c +++ b/code/sdk/zhihui/utils/custom_utils.c @@ -1490,7 +1490,7 @@ void power_on_cat1(void) void power_off_cat1(void) { - #ifdef FD230 + #if defined(FD230) && !defined(BOARD_W9) uapi_cat1_reset(1); uapi_cat1_power_on(0); #else diff --git a/code/sdk/zhihui/utils/custom_utils_at_cmd.c b/code/sdk/zhihui/utils/custom_utils_at_cmd.c index 97b4f1f72..74809c62c 100644 --- a/code/sdk/zhihui/utils/custom_utils_at_cmd.c +++ b/code/sdk/zhihui/utils/custom_utils_at_cmd.c @@ -559,6 +559,7 @@ static uint32_t custom_get_cywee_id(uint8_t *para, uint32_t paraLen, char *strCo UNUSED(strCommonCmd); uint8_t id; uapi_cywee_get_id(&id); + wstp_print("cywee_id[%x]\n",id); return ERRCODE_SUCC; }