pinebuds/services/ble_app/app_hid/app_hid.c

945 lines
34 KiB
C

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
/**
****************************************************************************************
* @addtogroup APP
* @{
****************************************************************************************
*/
#include "rwip_config.h" // SW configuration
#include <stdio.h>
#include <string.h>
#if (BLE_APP_HID)
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "app.h" // Application Definitions
#include "app_sec.h" // Application Security Module API
#include "app_task.h" // Application task definitions
#include "app_hid.h" // HID Application Module Definitions
#include "hogpd_task.h" // HID Over GATT Profile Device Role Functions
#include "prf_types.h" // Profile common types Definition
#include "arch.h" // Platform Definitions
#include "prf.h"
#include "ke_timer.h" // kernel timer
#if (NVDS_SUPPORT)
#include "nvds.h" // NVDS Definitions
#endif //(NVDS_SUPPORT)
#if (DISPLAY_SUPPORT)
#include "app_display.h" // Application Display Module
#endif //(DISPLAY_SUPPORT)
#include "co_utils.h" // Common functions
#if (KE_PROFILING)
#include "ke_mem.h"
#endif //(KE_PROFILING)
/*
* DEFINES
****************************************************************************************
*/
/// Length of the HID Mouse Report
#define APP_HID_MOUSE_REPORT_LEN (6)
/// Length of the Report Descriptor for an HID Mouse
#define APP_HID_MOUSE_REPORT_MAP_LEN (sizeof(app_hid_mouse_report_map))
/// Duration before connection update procedure if no report received (mouse is silent) - 20s
#define APP_HID_SILENCE_DURATION_1 (2000)
/// Duration before disconnection if no report is received after connection update - 60s
#define APP_HID_SILENCE_DURATION_2 (6000)
/// Number of reports that can be sent
#define APP_HID_NB_SEND_REPORT (10)
/*
* ENUMERATIONS
****************************************************************************************
*/
/// States of the Application HID Module
enum app_hid_states
{
/// Module is disabled (Service not added in DB)
APP_HID_DISABLED,
/// Module is idle (Service added but profile not enabled)
APP_HID_IDLE,
/// Module is enabled (Device is connected and the profile is enabled)
APP_HID_ENABLED,
/// The application can send reports
APP_HID_READY,
/// Waiting for a report
APP_HID_WAIT_REP,
APP_HID_STATE_MAX,
};
/*
* LOCAL VARIABLE DEFINITIONS
****************************************************************************************
*/
/// HID Application Module Environment Structure
static struct app_hid_env_tag app_hid_env;
/// HID Mouse Report Descriptor
static const uint8_t app_hid_mouse_report_map[] =
{
/**
* --------------------------------------------------------------------------
* Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* --------------------------------------------------------------------------
* Byte 0 | Not Used | Middle| Right | Left |
* --------------------------------------------------------------------------
* Byte 1 | X Axis Relative Movement |
* --------------------------------------------------------------------------
* Byte 2 | Y Axis Relative Movement |
* --------------------------------------------------------------------------
* Byte 3 | Wheel Relative Movement |
* --------------------------------------------------------------------------
*/
0x05, 0x01, /// USAGE PAGE (Generic Desktop)
0x09, 0x02, /// USAGE (Mouse)
0xA1, 0x01, /// COLLECTION (Application)
0x85, 0x01, /// REPORT ID (1) - MANDATORY
0x09, 0x01, /// USAGE (Pointer)
0xA1, 0x00, /// COLLECTION (Physical)
/**
* ----------------------------------------------------------------------------
* BUTTONS
* ----------------------------------------------------------------------------
*/
0x05, 0x09, /// USAGE PAGE (Buttons)
0x19, 0x01, /// USAGE MINIMUM (1)
0x29, 0x08, /// USAGE MAXIMUM (8)
0x15, 0x00, /// LOGICAL MINIMUM (0)
0x25, 0x01, /// LOGICAL MAXIMUM (1)
0x75, 0x01, /// REPORT SIZE (1)
0x95, 0x08, /// REPORT COUNT (8)
0x81, 0x02, /// INPUT (Data, Variable, Absolute)
/**
* ----------------------------------------------------------------------------
* MOVEMENT DATA
* ----------------------------------------------------------------------------
*/
0x05, 0x01, /// USAGE PAGE (Generic Desktop)
0x16, 0x08, 0xFF, /// LOGICAL MINIMUM (-255)
0x26, 0xFF, 0x00, /// LOGICAL MAXIMUM (255)
0x75, 0x10, /// REPORT SIZE (16)
0x95, 0x02, /// REPORT COUNT (2)
0x09, 0x30, /// USAGE (X)
0x09, 0x31, /// USAGE (Y)
0x81, 0x06, /// INPUT (Data, Variable, Relative)
0x15, 0x81, /// LOGICAL MINIMUM (-127)
0x25, 0x7F, /// LOGICAL MAXIMUM (127)
0x75, 0x08, /// REPORT SIZE (8)
0x95, 0x01, /// REPORT COUNT (1)
0x09, 0x38, /// USAGE (Wheel)
0x81, 0x06, /// INPUT (Data, Variable, Relative)
0xC0, /// END COLLECTION (Physical)
0xC0 /// END COLLECTION (Application)
};
/*
* GLOBAL FUNCTION DEFINITIONS
****************************************************************************************
*/
void app_hid_init(void)
{
#if (NVDS_SUPPORT)
// Length of the mouse timeout value
uint8_t length = NVDS_LEN_MOUSE_TIMEOUT;
#endif
// Reset the environment
memset(&app_hid_env, 0, sizeof(app_hid_env));
app_hid_env.nb_report = APP_HID_NB_SEND_REPORT;
/*
* Get the timeout value from the NVDS - This value is used each time a report is received
* from the PS2 driver, store it in the environment.
*/
#if (NVDS_SUPPORT)
if (nvds_get(NVDS_TAG_MOUSE_TIMEOUT, &length, (uint8_t *)&app_hid_env.timeout) != NVDS_OK)
#endif
{
app_hid_env.timeout = APP_HID_SILENCE_DURATION_1;
}
}
/*
****************************************************************************************
* @brief Function called when get GAP manager command complete events.
*
****************************************************************************************
*/
void app_hid_start_mouse(void)
{
/*-----------------------------------------------------------------------------------
* CONFIGURE THE MOUSE
*----------------------------------------------------------------------------------*/
#if (PS2_SUPPORT)
// Default mouse rate (200 report/s)
uint8_t rate = 200;
#if (NVDS_SUPPORT)
uint8_t length = NVDS_LEN_MOUSE_SAMPLE_RATE;
// Get sample rate from NVDS
if (nvds_get(NVDS_TAG_MOUSE_SAMPLE_RATE, &length, &rate) == NVDS_OK)
{
// Check if value is among supported set
if ((rate != 10) && (rate != 20) && (rate != 40) && (rate != 60) &&
(rate != 80) && (rate != 100) && (rate != 200) )
{
// Default value
rate = 200;
}
}
#endif //(NVDS_SUPPORT)
// Start PS2_mouse
ps2_mouse_start(rate, &app_hid_send_mouse_report);
#endif //(PS2_SUPPORT)
}
void app_hid_add_hids(void)
{
struct hogpd_db_cfg *db_cfg;
// Prepare the HOGPD_CREATE_DB_REQ message
struct gapm_profile_task_add_cmd *req = KE_MSG_ALLOC_DYN(GAPM_PROFILE_TASK_ADD_CMD,
TASK_GAPM, TASK_APP,
gapm_profile_task_add_cmd, sizeof(struct hogpd_db_cfg));
// Fill message
req->operation = GAPM_PROFILE_TASK_ADD;
#if BLE_CONNECTION_MAX>1
req->sec_lvl = PERM(SVC_AUTH, ENABLE)|PERM(SVC_MI, ENABLE);
#else
req->sec_lvl = PERM(SVC_AUTH, ENABLE);
#endif
req->prf_task_id = TASK_ID_HOGPD;
req->app_task = TASK_APP;
req->start_hdl = 0;
// Set parameters
db_cfg = (struct hogpd_db_cfg* ) req->param;
// Only one HIDS instance is useful
db_cfg->hids_nb = 1;
// The device is a mouse
db_cfg->cfg[0].svc_features = HOGPD_CFG_MOUSE;
// Only one Report Characteristic is requested
db_cfg->cfg[0].report_nb = 1;
/// db_cfg->cfg[0].report_id = 1;
db_cfg->cfg[0].report_id[0] = 1;
// The report is an input report
db_cfg->cfg[0].report_char_cfg[0] = HOGPD_CFG_REPORT_IN;
// HID Information
db_cfg->cfg[0].hid_info.bcdHID = 0x0111; // HID Version 1.11
db_cfg->cfg[0].hid_info.bCountryCode = 0x00;
db_cfg->cfg[0].hid_info.flags = HIDS_REMOTE_WAKE_CAPABLE | HIDS_NORM_CONNECTABLE;
// Send the message
ke_msg_send(req);
}
/*
****************************************************************************************
* @brief Function called when get connection complete event from the GAP
*
****************************************************************************************
*/
void app_hid_enable_prf(uint8_t conidx)
{
// Requested connection parameters
struct gapc_conn_param conn_param;
uint16_t ntf_cfg;
// Store the connection handle
app_hid_env.conidx = conidx;
// Allocate the message
struct hogpd_enable_req * req = KE_MSG_ALLOC(HOGPD_ENABLE_REQ,
KE_BUILD_ID(prf_get_task_from_id(TASK_ID_HOGPD), conidx),
TASK_APP,
hogpd_enable_req);
// Fill in the parameter structure
req->conidx = conidx;
// Notifications are disabled
ntf_cfg = 0;
// Go to Enabled state
app_hid_env.state = APP_HID_ENABLED;
#if (NVDS_SUPPORT)
// If first connection with the peer device
if (app_sec_get_bond_status())
{
// Length of the value read in NVDS
uint8_t length = NVDS_LEN_MOUSE_NTF_CFG;
// Notification configuration
if (nvds_get(NVDS_TAG_MOUSE_NTF_CFG, &length, (uint8_t *)&ntf_cfg) != NVDS_OK)
{
// If we are bonded this information should be present in the NVDS
ASSERT_ERR(0);
}
// CCC enable notification
if ((ntf_cfg & HOGPD_CFG_REPORT_NTF_EN ) != 0)
{
// The device is ready to send reports to the peer device
app_hid_env.state = APP_HID_READY;
app_hid_env.nb_report = APP_HID_NB_SEND_REPORT;
// Restart the mouse timeout timer if needed
if (app_hid_env.timeout != 0)
{
ke_timer_set(APP_HID_MOUSE_TIMEOUT_TIMER, TASK_APP, (uint16_t)(app_hid_env.timeout));
app_hid_env.timer_enabled = true;
}
}
}
#endif //(NVDS_SUPPORT)
req->ntf_cfg[conidx] = ntf_cfg;
/*
* Requested connection interval: 10ms
* Latency: 25
* Supervision Timeout: 2s
*/
conn_param.intv_min = 8;
conn_param.intv_max = 8;
conn_param.latency = 25;
conn_param.time_out = 200;
appm_update_param(conidx, &conn_param);
// Send the message
ke_msg_send(req);
}
/*
****************************************************************************************
* @brief Function called from PS2 driver
*
****************************************************************************************
*/
void app_hid_send_mouse_report(struct ps2_mouse_msg report)
{
// app_display_update_hid_value_screen(report.b, report.x, report.y, report.w);
switch (app_hid_env.state)
{
case (APP_HID_READY):
{
// Check if the report can be sent
if (app_hid_env.nb_report)
{
// Buffer used to create the Report
uint8_t report_buff[APP_HID_MOUSE_REPORT_LEN];
// X, Y and wheel relative movements
int16_t x;
int16_t y;
#if (DISPLAY_SUPPORT)
// Display all the received information on the LCD screen
//app_display_update_hid_value_screen(report.b, report.x, report.y, report.w);
#endif //(DISPLAY_SUPPORT)
// Clean the report buffer
memset(&report_buff[0], 0, APP_HID_MOUSE_REPORT_LEN);
// Set the button states
report_buff[0] = (report.b & 0x07);
// If X value is negative
if (report.b & 0x10)
{
report.x = ~report.x;
report.x += 1;
x = (int16_t)report.x;
x *= (-1);
}
else
{
x = (int16_t)report.x;
}
// If Y value is negative
if (report.b & 0x20)
{
report.y = ~report.y;
report.y += 1;
y = (int16_t)report.y;
}
else
{
y = (int16_t)report.y;
y *= (-1);
}
// Set the X and Y movement value in the report
co_write16p(&report_buff[1], x);
co_write16p(&report_buff[3], y);
report_buff[5] =(signed char) (-1) * report.w;
// Allocate the HOGPD_REPORT_UPD_REQ message
struct hogpd_report_upd_req * req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_UPD_REQ,
prf_get_task_from_id(TASK_ID_HOGPD),
TASK_APP,
hogpd_report_upd_req,
APP_HID_MOUSE_REPORT_LEN);
req->conidx = app_hid_env.conidx;
//now fill report
req->report.hid_idx = app_hid_env.conidx;
req->report.type = HOGPD_REPORT; //HOGPD_BOOT_MOUSE_INPUT_REPORT;//
req->report.idx = 0; //0 for boot reports and report map
req->report.length = APP_HID_MOUSE_REPORT_LEN;
memcpy(&req->report.value[0], &report_buff[0], APP_HID_MOUSE_REPORT_LEN);
ke_msg_send(req);
app_hid_env.nb_report--;
// Restart the mouse timeout timer if needed
if (app_hid_env.timeout != 0)
{
ke_timer_set(APP_HID_MOUSE_TIMEOUT_TIMER, TASK_APP, (uint16_t)(app_hid_env.timeout));
app_hid_env.timer_enabled = true;
}
}
} break;
case (APP_HID_WAIT_REP):
{
// Requested connection parameters
struct gapc_conn_param conn_param;
/*
* Requested connection interval: 10ms
* Latency: 25
* Supervision Timeout: 2s
*/
conn_param.intv_min = 8;
conn_param.intv_max = 8;
conn_param.latency = 25;
conn_param.time_out = 200;
appm_update_param(app_hid_env.conidx, &conn_param);
// Restart the mouse timeout timer if needed
if (app_hid_env.timeout != 0)
{
ke_timer_set(APP_HID_MOUSE_TIMEOUT_TIMER, TASK_APP, (uint16_t)(app_hid_env.timeout));
app_hid_env.timer_enabled = true;
}
// Go back to the ready state
app_hid_env.state = APP_HID_READY;
} break;
case (APP_HID_IDLE):
{
// Try to restart advertising if needed
} break;
// DISABLE and ENABLED states
default:
{
// Drop the message
} break;
}
#if (KE_PROFILING)
// app_display_hdl_env_size(0xFFFF, ke_get_mem_usage(KE_MEM_ENV));
// app_display_hdl_db_size(0xFFFF, ke_get_mem_usage(KE_MEM_ATT_DB));
// app_display_hdl_msg_size((uint16_t)ke_get_max_mem_usage(), ke_get_mem_usage(KE_MEM_KE_MSG));
#endif //(KE_PROFILING)
}
/*
* MESSAGE HANDLERS
****************************************************************************************
*/
static int hogpd_ctnl_pt_ind_handler(ke_msg_id_t const msgid,
struct hogpd_ctnl_pt_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if (param->conidx == app_hid_env.conidx)
{
//make use of param->hid_ctnl_pt
struct hogpd_report_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_CFM,
prf_get_task_from_id(TASK_ID_HOGPD),/* src_id */
TASK_APP,
hogpd_report_cfm,
0);
req->conidx = param->conidx; ///app_hid_env.conidx; ///???
/// Operation requested (read/write @see enum hogpd_op)
req->operation = HOGPD_OP_REPORT_WRITE;
/// Status of the request
req->status = GAP_ERR_NO_ERROR; ///???
/// Report Info
//req->report;
/// HIDS Instance
req->report.hid_idx = app_hid_env.conidx; ///???
/// type of report (@see enum hogpd_report_type)
req->report.type = -1;//outside
/// Report Length (uint8_t)
req->report.length = 0;
/// Report Instance - 0 for boot reports and report map
req->report.idx = 0;
/// Report data
// Send the message
ke_msg_send(req);
}
return (KE_MSG_CONSUMED);
}
static int hogpd_ntf_cfg_ind_handler(ke_msg_id_t const msgid,
struct hogpd_ntf_cfg_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if (app_hid_env.conidx == param->conidx)
{
if ((param->ntf_cfg[param->conidx] & HOGPD_CFG_REPORT_NTF_EN ) != 0)
{
// The device is ready to send reports to the peer device
app_hid_env.state = APP_HID_READY;
}
else
{
// Come back to the Enabled state
if (app_hid_env.state == APP_HID_READY)
{
app_hid_env.state = APP_HID_ENABLED;
}
}
#if (NVDS_SUPPORT)
// Store the notification configuration in the database
if (nvds_put(NVDS_TAG_MOUSE_NTF_CFG, NVDS_LEN_MOUSE_NTF_CFG,
(uint8_t *)&param->ntf_cfg[param->conidx]) != NVDS_OK)
{
// Should not happen
ASSERT_ERR(0);
}
#endif
}
return (KE_MSG_CONSUMED);
}
static int hogpd_report_req_ind_handler(ke_msg_id_t const msgid,
struct hogpd_report_req_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if ((param->operation == HOGPD_OP_REPORT_READ) && (param->report.type == HOGPD_REPORT_MAP))
{
struct hogpd_report_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_CFM,
src_id, ///prf_get_task_from_id(TASK_ID_HOGPD),/* src_id */
dest_id, ///TASK_APP,
hogpd_report_cfm,
APP_HID_MOUSE_REPORT_MAP_LEN);
req->conidx = app_hid_env.conidx; ///???
/// Operation requested (read/write @see enum hogpd_op)
req->operation = HOGPD_OP_REPORT_READ;
/// Status of the request
req->status = GAP_ERR_NO_ERROR; ///???
/// Report Info
//req->report;
/// HIDS Instance
req->report.hid_idx = param->report.hid_idx;/// ???///app_hid_env.conidx; ///???
/// type of report (@see enum hogpd_report_type)
req->report.type = HOGPD_REPORT_MAP;
/// Report Length (uint8_t)
req->report.length = APP_HID_MOUSE_REPORT_MAP_LEN;
/// Report Instance - 0 for boot reports and report map
req->report.idx = 0;
/// Report data
memcpy(&req->report.value[0], &app_hid_mouse_report_map[0], APP_HID_MOUSE_REPORT_MAP_LEN);
// Send the message
ke_msg_send(req);
}
else
{
if (param->report.type == HOGPD_BOOT_MOUSE_INPUT_REPORT)
{ //request of boot mouse report
struct hogpd_report_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_CFM,
prf_get_task_from_id(TASK_ID_HOGPD),/* src_id */
TASK_APP,
hogpd_report_cfm,
0/*param->report.length*/);
req->conidx = param->conidx; ///app_hid_env.conidx; ///???
/// Operation requested (read/write @see enum hogpd_op)
req->operation = HOGPD_OP_REPORT_READ;
/// Status of the request
req->status = GAP_ERR_NO_ERROR; ///???
/// HIDS Instance
req->report.hid_idx = app_hid_env.conidx; ///???
/// type of report (@see enum hogpd_report_type)
req->report.type = param->report.type;//-1;//outside
/// Report Length (uint8_t)
req->report.length = 0; //param->report.length;
/// Report Instance - 0 for boot reports and report map
req->report.idx = param->report.idx; //0;
/// Report data
// Send the message
ke_msg_send(req);
}
else
if (param->report.type == HOGPD_REPORT)
{ //request of mouse report
struct hogpd_report_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_CFM,
prf_get_task_from_id(TASK_ID_HOGPD),/* src_id */
TASK_APP,
hogpd_report_cfm,
8/*param->report.length*/);
req->conidx = param->conidx; ///app_hid_env.conidx; ///???
/// Operation requested (read/write @see enum hogpd_op)
req->operation = HOGPD_OP_REPORT_READ;
/// Status of the request
req->status = GAP_ERR_NO_ERROR; ///???
/// Report Info
//req->report;
/// HIDS Instance
req->report.hid_idx = app_hid_env.conidx; ///???
/// type of report (@see enum hogpd_report_type)
req->report.type = param->report.type;//-1;//outside
/// Report Length (uint8_t)
req->report.length = 8; //param->report.length;
/// Report Instance - 0 for boot reports and report map
req->report.idx = param->report.idx; //0;
/// Report data
memset(&req->report.value[0], 0, 8); //???
req->report.value[0] = param->report.hid_idx; /// HIDS Instance
req->report.value[1] = param->report.type; /// type of report (@see enum hogpd_report_type)
req->report.value[2] = param->report.length; /// Report Length (uint8_t)
req->report.value[3] = param->report.idx; /// Report Instance - 0 for boot reports and report map
// Send the message
ke_msg_send(req);
}
else
{
struct hogpd_report_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_CFM,
prf_get_task_from_id(TASK_ID_HOGPD),/* src_id */
TASK_APP,
hogpd_report_cfm,
8/*param->report.length*/);
req->conidx = param->conidx; ///app_hid_env.conidx; ///???
/// Operation requested (read/write @see enum hogpd_op)
req->operation = HOGPD_OP_REPORT_READ;
/// Status of the request
req->status = GAP_ERR_NO_ERROR; ///???
/// Report Info
//req->report;
/// HIDS Instance
req->report.hid_idx = app_hid_env.conidx; ///???
/// type of report (@see enum hogpd_report_type)
req->report.type = param->report.type;//-1;//outside
/// Report Length (uint8_t)
req->report.length = 8; //param->report.length;
/// Report Instance - 0 for boot reports and report map
req->report.idx = param->report.idx; //0;
/// Report data
memset(&req->report.value[0], 0, 8); //???
req->report.value[0] = param->report.hid_idx; /// HIDS Instance
req->report.value[1] = param->report.type; /// type of report (@see enum hogpd_report_type)
req->report.value[2] = param->report.length; /// Report Length (uint8_t)
req->report.value[3] = param->report.idx; /// Report Instance - 0 for boot reports and report map
// Send the message
ke_msg_send(req);
}
}
return (KE_MSG_CONSUMED);
}
static int hogpd_proto_mode_req_ind_handler(ke_msg_id_t const msgid,
struct hogpd_proto_mode_req_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if ((param->conidx == app_hid_env.conidx) && (param->operation == HOGPD_OP_PROT_UPDATE))
{
//make use of param->proto_mode
struct hogpd_proto_mode_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_PROTO_MODE_CFM,
prf_get_task_from_id(TASK_ID_HOGPD),/* src_id */
TASK_APP,
hogpd_proto_mode_cfm,
0);
/// Connection Index
req->conidx = app_hid_env.conidx;
/// Status of the request
req->status = GAP_ERR_NO_ERROR;
/// HIDS Instance
req->hid_idx = app_hid_env.conidx;
/// New Protocol Mode Characteristic Value
req->proto_mode = param->proto_mode;
// Send the message
ke_msg_send(req);
}
else
{
struct hogpd_proto_mode_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_PROTO_MODE_CFM,
prf_get_task_from_id(TASK_ID_HOGPD),/* src_id */
TASK_APP,
hogpd_proto_mode_cfm,
0);
/// Status of the request
req->status = ATT_ERR_APP_ERROR;
/// Connection Index
req->conidx = app_hid_env.conidx;
/// HIDS Instance
req->hid_idx = app_hid_env.conidx;
/// New Protocol Mode Characteristic Value
req->proto_mode = param->proto_mode;
// Send the message
ke_msg_send(req);
}
return (KE_MSG_CONSUMED);
}
static int hogpd_report_upd_handler(ke_msg_id_t const msgid,
struct hogpd_report_upd_rsp const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if (app_hid_env.conidx == param->conidx)
{
if (GAP_ERR_NO_ERROR == param->status)
{
if (app_hid_env.nb_report < APP_HID_NB_SEND_REPORT)
{
app_hid_env.nb_report++;
}
}
else
{
// we get this message if error occur while sending report
// most likely - disconnect
// Go back to the ready state
app_hid_env.state = APP_HID_IDLE;
// change mode
// restart adv
// Try to restart advertising if needed
//report was not success - need to restart???
}
}
return (KE_MSG_CONSUMED);
}
static int hogpd_enable_rsp_handler(ke_msg_id_t const msgid,
struct hogpd_enable_rsp const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
return (KE_MSG_CONSUMED);
}
/**
****************************************************************************************
* @brief Function called when the APP_HID_MOUSE_TIMEOUT_TIMER expires.
*
* @param[in] msgid Id of the message received.
* @param[in] param Pointer to the parameters of the message.
* @param[in] dest_id ID of the receiving task instance (TASK_GAP).
* @param[in] src_id ID of the sending task instance.
*
* @return If the message was consumed or not.
****************************************************************************************
*/
static int app_hid_mouse_timeout_timer_handler(ke_msg_id_t const msgid,
void const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
app_hid_env.timer_enabled = false;
if (app_hid_env.state == APP_HID_READY)
{
// Requested connection parameters
struct gapc_conn_param conn_param;
// Length
#if (NVDS_SUPPORT)
uint8_t length = NVDS_LEN_MOUSE_TIMEOUT;
#endif
// Timer value
uint16_t timer_val;
/*
* Request an update of the connection parameters
* Requested connection interval: 10ms
* Latency: 200
* Supervision Timeout: 5s
*/
conn_param.intv_min = 8;
conn_param.intv_max = 8;
conn_param.latency = 200;
conn_param.time_out = 500;
appm_update_param(app_hid_env.conidx, &conn_param);
// Go to the Wait for Report state
app_hid_env.state = APP_HID_WAIT_REP;
#if (NVDS_SUPPORT)
// Get the timer value from the NVDS
if (nvds_get(NVDS_TAG_MOUSE_ENERGY_SAFE, &length, (uint8_t *)&timer_val) != NVDS_OK)
#endif
{
timer_val = APP_HID_SILENCE_DURATION_2;
}
// Relaunch the timer
ke_timer_set(APP_HID_MOUSE_TIMEOUT_TIMER, TASK_APP, timer_val);
app_hid_env.timer_enabled = true;
}
else if (app_hid_env.state == APP_HID_WAIT_REP)
{
// Disconnect the link with the device
appm_disconnect(app_hid_env.conidx);
// Go back to the ready state
app_hid_env.state = APP_HID_IDLE;
}
return (KE_MSG_CONSUMED);
}
/**
****************************************************************************************
* @brief
*
* @param[in] msgid Id of the message received.
* @param[in] param Pointer to the parameters of the message.
* @param[in] dest_id ID of the receiving task instance (TASK_GAP).
* @param[in] src_id ID of the sending task instance.
*
* @return If the message was consumed or not.
****************************************************************************************
*/
static int app_hid_msg_dflt_handler(ke_msg_id_t const msgid,
void const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
// Drop the message
return (KE_MSG_CONSUMED);
}
/**
****************************************************************************************
* @brief Set the value of the Report Map Characteristic in the database
****************************************************************************************
*/
void app_hid_set_report_map(void);
/*
* LOCAL VARIABLE DEFINITIONS
****************************************************************************************
*/
/// Default State handlers definition
const struct ke_msg_handler app_hid_msg_handler_list[] =
{
// Note: first message is latest message checked by kernel so default is put on top.
{KE_MSG_DEFAULT_HANDLER, (ke_msg_func_t)app_hid_msg_dflt_handler},
{HOGPD_ENABLE_RSP, (ke_msg_func_t)hogpd_enable_rsp_handler},
/// notification configuration changed
{HOGPD_NTF_CFG_IND, (ke_msg_func_t)hogpd_ntf_cfg_ind_handler},
{HOGPD_REPORT_REQ_IND, (ke_msg_func_t)hogpd_report_req_ind_handler},
{HOGPD_PROTO_MODE_REQ_IND, (ke_msg_func_t)hogpd_proto_mode_req_ind_handler},
{HOGPD_CTNL_PT_IND, (ke_msg_func_t)hogpd_ctnl_pt_ind_handler},
{HOGPD_REPORT_UPD_RSP, (ke_msg_func_t)hogpd_report_upd_handler},
{APP_HID_MOUSE_TIMEOUT_TIMER, (ke_msg_func_t)app_hid_mouse_timeout_timer_handler},
};
const struct ke_state_handler app_hid_table_handler =
{&app_hid_msg_handler_list[0], (sizeof(app_hid_msg_handler_list)/sizeof(struct ke_msg_handler))};
#endif //(BLE_APP_HID)
/// @} APP