Compare commits

...

39 Commits

Author SHA1 Message Date
Anatole SCHRAMM
cd851cf044 Added a new freertos shell command to interact with freertos concepts (tasks, notifications, queue etc), not feature complete yet though 2025-07-31 16:21:03 +02:00
Anatole SCHRAMM
3cbb87e390 Added the tls_os_time_delay_until function (which is just a wrapper to freertos's vTaskDelayUntil function) 2025-07-31 16:18:52 +02:00
Anatole SCHRAMM
3a8e2fcf7a Removed useless new line in function body 2025-07-31 16:17:29 +02:00
Anatole SCHRAMM
58e81b77e6 Added verbose log 2025-07-31 16:16:38 +02:00
Anatole SCHRAMM
0549ebe68d Added a function to the app_utils collection which parses a time and date string to fill a struct tm 2025-07-31 16:15:31 +02:00
Anatole SCHRAMM
54e69e424a Checking if the rtc is running and starting it by setting the compile time and date if not the case 2025-07-31 16:11:07 +02:00
Anatole SCHRAMM
1affef42cf Added tls_is_rtc_running function telling if the RTC ip is alive or not 2025-07-31 16:09:16 +02:00
fe879e300a Working on BLE rf modem sleep feature - continued 2023-05-01 20:25:04 +02:00
54a22beaf7 Continued working on BLE rf modem sleep feature : issue when trying to wake rf modem up before sending data by writing to a characteristic 2023-05-01 19:21:13 +02:00
13e7553d09 Added new experimental functions to put the BLE modem to sleep to reduce power consumption 2023-04-23 20:33:11 +02:00
e6b1595bae Updated the gadget bridge parser sources to test the new features 2023-04-23 20:32:05 +02:00
cf50df7468 Added a way to retrieve the BLE device MAC address plus other things for test purposes 2023-04-23 20:31:27 +02:00
18b602bbca Implemented a random number generating function which returns a 6 digit random number 2023-04-23 20:29:42 +02:00
082c2c6a6c Added a comment to know what was the default IO capability 2023-04-23 20:21:18 +02:00
anschrammh
6433aaa697 Preparing the ble_service to work in bt_controller sleep mode to save power. This will at the end be implemented in the W800_Smart_Watch ble_service module 2023-04-20 13:18:25 +02:00
anschrammh
0f376fd528 Now setting a default passkey when starting the BLE service/server 2023-04-18 23:15:10 +02:00
anschrammh
166581caeb Added the tls_bt_sm_ioact_2_str utility function 2023-04-18 23:15:09 +02:00
anschrammh
9269e279ef Updated the nimble stack configuration to prompt the user to enter a passkey when trying to pair it's phone with the host 2023-04-18 23:15:08 +02:00
anschrammh
b37dab16d5 Now handling pairing by asking to enter a passkey on the phone side. This
passkey is then verified with the code entered on the host side. Also
handling the repeat pairing event by reperforming the pairing process.
2023-04-18 23:13:47 +02:00
Anatole SCHRAMM
7c78142f88 Changed some BLE stack parameters as I'm trying to make bonding with passcode work 2023-04-18 17:03:12 +02:00
anschrammh
f5b68838f7 Added two new functions performing a precise blocking delay in micro and milli seconds 2023-04-13 13:23:46 +02:00
338c7e18e6 Added the possibility to set the battery service's battery value and started to add a descriptor to play around with nimble 2023-04-10 21:34:14 +02:00
5206181a32 Fixed potential memory leak, added the music state and music info events type 2023-04-09 17:03:53 +02:00
b3bf6ce896 Documented almost every function of the API, implemented the http request command which is useless since GadgetBridge does not have internet permissions :( 2023-04-09 12:41:38 +02:00
bfba12e43b Cleaned the wm_type_def.h file by reorganizing the types defines 2023-04-09 08:05:36 +02:00
e71c020d97 Implemented the gadget_bridge parser feature as well as a few commands like the music control or the find device phone feature 2023-04-08 22:43:52 +02:00
a9e5589e87 Minor change 2023-04-08 20:04:19 +02:00
Anatole SCHRAMM
74b90f9fee Finished to define the API, started to implement some of it 2023-04-06 14:27:05 +02:00
anschrammh
34ad38d34a Started to write the module used to interact/communicate with the gadget bridge Android app.
The API will contain functions to send data to the app as well as a parser used to decode and extract data sent from the app.
It will internally use/access the NUS BLE service exposed by the ble_service.c file
2023-04-05 08:03:58 +02:00
anschrammh
0e1bed0452 Added the uint32_t type, will have to clean the mess up in this file someday 2023-04-05 07:59:12 +02:00
anschrammh
3fc2297f17 Updated the nano shell commands to use the new bluetooth modem start API which as the option to set the modem in bluetooth only mode 2023-04-05 07:58:09 +02:00
anschrammh
1faa5b3c84 Aligned ble_modem code with the W800SmartWatch ble modem code, corrected an english mistake in a comment 2023-04-04 08:21:58 +02:00
44edace353 Added new commands to change the CPU clock speed, as well as close the clock to some peripherals in order to make power consumption testing easier on the chip 2023-04-02 21:16:31 +02:00
d798868660 Merge branch 'master' of http://192.168.0.17/git/Th3maz1ng/W801_SDK_dev_env into HEAD 2023-03-31 16:11:35 +02:00
c04c035a4a Rephrased comment 2023-03-31 16:09:54 +02:00
anschrammh
f7c692c751 Changed the parameter passed to the size utility 2023-03-31 16:09:12 +02:00
cb4a9d77e3 Added corrections to the BLE module 2023-03-31 15:53:30 +02:00
anschrammh
5b5032ec2f Changed the parameter passed to the size utility 2023-03-14 19:34:26 +01:00
anschrammh
0ccd981c11 Added the ble folder to the include path 2023-03-14 19:27:53 +01:00
21 changed files with 3065 additions and 162 deletions

View File

@ -1,4 +1,7 @@
#include "app_utils.h"
#include <math.h>
#include "utils.h"
#include "wm_crypto_hard.h"
static uint32_t millis_cnt = 0;
@ -10,4 +13,98 @@ uint32_t millis(void)
void millis_run_cb(void *arg)
{
millis_cnt++;
}
}
void us_delay(uint32_t us)
{
struct tls_timer_cfg timer_config =
{
.is_repeat = false,
.unit = TLS_TIMER_UNIT_US,
.timeout = 0xFFFFFFFF,
};
uint8_t timer_id = tls_timer_create(&timer_config);
if(WM_TIMER_ID_INVALID == timer_id) return;
tls_timer_start(timer_id);
// Perform a blocking delay
while(tls_timer_read(timer_id) < us);
tls_timer_destroy(timer_id);
}
void ms_delay(uint32_t ms)
{
struct tls_timer_cfg timer_config =
{
.is_repeat = false,
.unit = TLS_TIMER_UNIT_MS,
.timeout = 0xFFFFFFFF,
};
uint8_t timer_id = tls_timer_create(&timer_config);
if(WM_TIMER_ID_INVALID == timer_id) return;
tls_timer_start(timer_id);
// Perform a blocking delay
while(tls_timer_read(timer_id) < ms);
tls_timer_destroy(timer_id);
}
uint32_t random_gen_6_digit(void)
{
unsigned char random_buf[6] = {0};
uint32_t output_num = 0;
tls_crypto_random_init(0x19031998, CRYPTO_RNG_SWITCH_16);
tls_crypto_random_bytes(random_buf, sizeof random_buf);
tls_crypto_random_stop();
for(uint8_t i = 0; i < sizeof random_buf; i++)
{
// Ensures the last digit is not 0
if(i == (sizeof random_buf) - 1 && random_buf[i] % 10 == 0)random_buf[i]++;
output_num += (random_buf[i] % 10) * pow(10, i);
}
return output_num;
}
void time_date_to_tm(const char *time_date, struct tm *time)
{
if(!time_date) return;
/* Months are on three letters :
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
*/
const char *MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const unsigned long int MONTHS_CNT = sizeof(MONTHS)/sizeof(*MONTHS);
char month[4];
time->tm_mon = 0;
sscanf(time_date, "%d:%d:%d %s %d %d",
&time->tm_hour,
&time->tm_min,
&time->tm_sec,
month,
&time->tm_mday,
&time->tm_year);
for(unsigned long int i = 0; i < MONTHS_CNT; i++)
{
if(strcasecmp(MONTHS[i], month) == 0)
{
time->tm_mon = i;
break;
}
}
// Adjust year value
time->tm_year -= 1900;
}

View File

@ -7,4 +7,19 @@ uint32_t millis(void);
void millis_run_cb(void *arg);
void us_delay(uint32_t us);
void ms_delay(uint32_t ms);
uint32_t random_gen_6_digit(void);
/**
* @brief Function parsing a string having format : __TIME__" "__DATE__
* and filling the given struct tm accordingly.
*
* @param time_date a string having the proper time and date format
* @param time a pointer to the struct tm to fill
*/
void time_date_to_tm(const char *time_date, struct tm *time);
#endif //APP_UTILS_H

View File

@ -2,6 +2,7 @@
#include "app_common.h"
#include "host/ble_hs.h"
#include "FreeRTOS.h"
#include "wm_bt.h"
#include "wm_bt_def.h"
#include "wm_bt_app.h"
#include "wm_bt_util.h"
@ -10,14 +11,34 @@
//Is needed for the BT off workaround
#include "wm_wifi.h"
bool ble_modem_on(bool startService)
static bool _ble_modem_is_sleeping = false;
static bool _ble_modem_wakeup_order = false;
static void _ble_modem_sleep_enter_cb(uint32_t sleep_duration_ms)
{
}
static void _ble_modem_sleep_exit_cb(void)
{
if(_ble_modem_wakeup_order)
{
tls_bt_ctrl_sleep(false);
tls_bt_ctrl_wakeup();
_ble_modem_wakeup_order = false;
_ble_modem_is_sleeping = false;
}
}
bool ble_modem_on(bool bluetoothOnly, bool startService)
{
int status = BLE_HS_ENOERR;
bool serviceStartSuccess = true;
uint8_t uart_no = 0xFF;
tls_appl_trace_level = TLS_BT_LOG_VERBOSE; //Should be set with a config define
if(bt_adapter_state == WM_BT_STATE_ON) {
if(bt_adapter_state == WM_BT_STATE_ON)
{
TLS_BT_APPL_TRACE_VERBOSE("ble modem already on"NEW_LINE);
return true;
}
@ -25,14 +46,33 @@ bool ble_modem_on(bool startService)
TLS_BT_APPL_TRACE_DEBUG("ble modem running, uart_no=%d, log_level=%d"NEW_LINE, uart_no,
tls_appl_trace_level);
status = tls_bt_init(uart_no);
if((status != BLE_HS_ENOERR) && (status != BLE_HS_EALREADY)) {
TLS_BT_APPL_TRACE_ERROR("%s, tls_bt_init ret:%s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
if(tls_bt_register_sleep_callback(_ble_modem_sleep_enter_cb, _ble_modem_sleep_exit_cb) != TLS_BT_STATUS_SUCCESS)
{
TLS_BT_APPL_TRACE_ERROR("%s, failed to register rf modem sleep callbacks"NEW_LINE, __FUNCTION__);
}
// Start the ble service if it was asked and if it is not yet started
if(startService && !ble_service_is_started())
serviceStartSuccess = ble_service_start();
if((status != BLE_HS_ENOERR) && (status != BLE_HS_EALREADY))
{
TLS_BT_APPL_TRACE_ERROR("%s, tls_bt_init ret:%s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
}
else
{
// We disable the sleep mode if it was enabled
if(!ble_modem_is_sleeping())
{
if(!ble_modem_wake())
TLS_BT_APPL_TRACE_ERROR("%s, ble_modem_wake failed"NEW_LINE, __FUNCTION__);
}
// If we successfully started the modem, we can set it's working mode.
if(bluetoothOnly)
tls_rf_bt_mode(true);
// Start the ble service if it was asked and if it is not yet started
if(startService && !ble_service_is_started())
serviceStartSuccess = ble_service_start();
}
return ((status == BLE_HS_ENOERR || status == BLE_HS_EALREADY) && serviceStartSuccess) ? true : false;
}
@ -49,6 +89,12 @@ bool ble_modem_off(void)
return TLS_BT_STATUS_SUCCESS;
}
if(ble_modem_is_sleeping())
{
if(!ble_modem_wake())
TLS_BT_APPL_TRACE_ERROR("%s, ble_modem_wake failed"NEW_LINE, __FUNCTION__);
}
if(ble_service_is_started())
{
serviceStopSuccess = ble_service_stop();
@ -88,4 +134,40 @@ bool is_ble_modem_on(void)
if(bt_adapter_state == WM_BT_STATE_OFF || bt_system_action != WM_BT_SYSTEM_ACTION_IDLE)
return false;
return true;
}
}
bool ble_modem_sleep(void)
{
tls_bt_status_t status = tls_bt_ctrl_sleep(true);
if(status == TLS_BT_STATUS_SUCCESS)
{
_ble_modem_is_sleeping = true;
TLS_BT_APPL_TRACE_DEBUG("ble modem sleeping"NEW_LINE);
return true;
}
return false;
}
bool ble_modem_wake(void)
{
/*tls_bt_status_t status = tls_bt_ctrl_sleep(false);
if(status == TLS_BT_STATUS_SUCCESS)
{
if(tls_bt_ctrl_wakeup() == TLS_BT_STATUS_SUCCESS)
{
_ble_modem_is_sleeping = false;
TLS_BT_APPL_TRACE_DEBUG("ble modem awaken"NEW_LINE);
return true;
}
}
return false;*/
_ble_modem_wakeup_order = true;
return true;
}
bool ble_modem_is_sleeping(void)
{
return _ble_modem_is_sleeping;
}

View File

@ -10,7 +10,7 @@
* @return true on success
* @return false on failure
*/
bool ble_modem_on(bool startService);
bool ble_modem_on(bool bluetoothOnly, bool startService);
/**
* @brief Turns the BLE modem off
@ -29,4 +29,32 @@ bool ble_modem_off(void);
*/
bool is_ble_modem_on(void);
#endif //BLE_MODEM_H
/**
* @brief Sets the BLE modem to sleep during IDLE times.
* This will lead to a latency penalty of arround 10 seconds,
* upon receiving a new frame but reduces power consumption when using BLE.
*
* @return true if the modem was successfully set to sleep.
* @return false if not
*/
bool ble_modem_sleep(void);
/**
* @brief Disables the sleep state of the BLE modem. Latency will increase and power
* consumption also.
*
* @return true if the modem woke up successfully
* @return false otherwise
*/
bool ble_modem_wake(void);
/**
* @brief Returns true if the BLE modem is allowed to sleep during IDLE times, false
* if it is not allowed to sleep.
*
* @return true if it is sleeping or allowed to sleep
* @return false otherwise
*/
bool ble_modem_is_sleeping(void);
#endif //BLE_MODEM_H

View File

@ -5,16 +5,20 @@
#include "services/gap/ble_svc_gap.h"
#include "wm_bt_util.h"
#include "bluetooth_sig_values.h"
#include "FreeRTOS.h"
#define USABLE_DEFAULT_MTU (20) //23 - 3 of header bytes
/* ble service internal workings attributes */
static volatile ble_service_state_e _ble_service_state = BLE_SERVICE_MODE_STOPPED;
static nus_data_rx_fn_t _ble_service_nus_data_rx_cb = NULL;
static ble_service_state_change_fn_t _ble_service_state_change_cb = NULL;
static uint32_t _pairing_passkey = 0;
/* Connection handle to the connected device : only one simultaneous connection */
static uint16_t ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE;
static uint16_t usable_mtu = USABLE_DEFAULT_MTU;
static uint8_t _device_mac_address[6] = {0x00};
/**
* @brief Structure used to store the various data to carry out a chunked notification or indication data transfer
@ -29,7 +33,8 @@ typedef struct
bool transfer_in_progress; // Is a transfer already in progress ?
} data_being_sent_t;
// Only one transfer of a type () can occur at any given time
// Only one transfer of a type can occur at any given time ie
// one notification and one indication can happen at the same time but not more.
static data_being_sent_t notification_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false};
static data_being_sent_t indication_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false};
@ -37,7 +42,8 @@ static struct ble_gap_event_listener ble_gap_event_listener;
static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
static uint16_t battery_level_char_handle = 0;
static uint8_t battery_level_value = 42;
// Default battery value set to 100%
static uint8_t _battery_level_value = 100;
static int gatt_nus_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
@ -60,7 +66,18 @@ static struct ble_gatt_svc_def gatt_svc[] =
.uuid = BLE_UUID16_DECLARE(0x2A19),
.val_handle = &battery_level_char_handle,
.access_cb = &(battery_level_char_access_cb),
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
/*.descriptors = (struct ble_gatt_dsc_def[])
{
{
.uuid = BLE_UUID,
.access_cb = ,
.att_flags = BLE_ATT_F_READ;
},
{
.uuid = NULL
}
}*/
},
{
.uuid = NULL
@ -100,6 +117,7 @@ static bool ble_service_define_gatt(const struct ble_gatt_svc_def *gatt_svc);
static bool ble_service_advertise(bool enable);
static int ble_gap_event_cb(struct ble_gap_event *event, void *arg);
static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg);
static int ble_conn_gap_event_cb(struct ble_gap_event *event, void *arg);
static void print_conn_desc(const struct ble_gap_conn_desc *desc);
// Raw because it doesn't handle payload fragmentation if mtu size is smaller than the payload size
static bool ble_service_send_raw_custom_notification(uint16_t characteristic_handle, const uint8_t *data, uint16_t length);
@ -111,15 +129,16 @@ static int ble_gatt_mtu_cb(uint16_t conn_handle, const struct ble_gatt_error *er
const char *ble_service_state_2_str(ble_service_state_e state)
{
switch(state) {
CASE_RETURN_STR(BLE_SERVICE_MODE_STOPPED)
CASE_RETURN_STR(BLE_SERVICE_MODE_IDLE)
CASE_RETURN_STR(BLE_SERVICE_MODE_ADVERTISING)
CASE_RETURN_STR(BLE_SERVICE_MODE_CONNECTED)
CASE_RETURN_STR(BLE_SERVICE_MODE_INDICATING)
CASE_RETURN_STR(BLE_SERVICE_MODE_EXITING)
switch(state)
{
CASE_RETURN_STR(BLE_SERVICE_MODE_STOPPED)
CASE_RETURN_STR(BLE_SERVICE_MODE_IDLE)
CASE_RETURN_STR(BLE_SERVICE_MODE_ADVERTISING)
CASE_RETURN_STR(BLE_SERVICE_MODE_CONNECTED)
CASE_RETURN_STR(BLE_SERVICE_MODE_INDICATING)
CASE_RETURN_STR(BLE_SERVICE_MODE_EXITING)
default:
return "unkown ble service state";
return "Unkown ble service state";
}
}
@ -268,11 +287,48 @@ bool ble_service_is_device_connected(void)
return _ble_service_state == BLE_SERVICE_MODE_CONNECTED;
}
const uint8_t *ble_service_get_device_mac_address(void)
{
// We only need to read from efuse section once.
if(
_device_mac_address[0] == 0 &&
_device_mac_address[1] == 0 &&
_device_mac_address[2] == 0 &&
_device_mac_address[3] == 0 &&
_device_mac_address[4] == 0 &&
_device_mac_address[5] == 0
)
{
extern int tls_get_bt_mac_addr(u8 *mac);
tls_get_bt_mac_addr(_device_mac_address);
// Make sure the device address is compliant with the random address specification :
_device_mac_address[5] |= 0xC0;
}
return _device_mac_address;
}
void ble_service_register_state_change_cb(ble_service_state_change_fn_t ble_service_state_change_cb)
{
_ble_service_state_change_cb = ble_service_state_change_cb;
}
ble_service_state_e ble_service_get_state(void)
{
return _ble_service_state;
}
void ble_service_set_pairing_passkey(uint32_t passkey)
{
_pairing_passkey = passkey;
}
uint32_t ble_service_get_active_pairing_passkey(void)
{
return _pairing_passkey;
}
bool ble_service_update_connection_parameters(
uint16_t itvl_min,
uint16_t itvl_max,
@ -297,7 +353,7 @@ bool ble_service_update_connection_parameters(
gap_params_to_apply.min_ce_len = min_ce_len;
gap_params_to_apply.max_ce_len = max_ce_len;
if ((status = ble_gap_update_params(ble_device_conn_handle, &gap_params_to_apply)) != BLE_HS_ENOERR)
if((status = ble_gap_update_params(ble_device_conn_handle, &gap_params_to_apply)) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_update_params failed %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
return false;
@ -325,9 +381,9 @@ bool ble_service_request_mtu_exchange(void)
return true;
}
bool ble_service_nus_send_data(const uint8_t *data, uint16_t length)
bool ble_service_send_nus_data(const uint8_t *data, uint16_t length)
{
// The NUS TX is using notifications
// The NUS is TX is using notifications
if(notification_data.transfer_in_progress)
{
TLS_BT_APPL_TRACE_WARNING("%s, a transfer is already in progress"NEW_LINE, __FUNCTION__);
@ -341,10 +397,16 @@ bool ble_service_nus_send_data(const uint8_t *data, uint16_t length)
return ble_service_send_custom_notification(gatt_nus_char_tx_handle, &notification_data);
}
void ble_service_nus_register_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb)
void ble_service_register_nus_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb)
{
_ble_service_nus_data_rx_cb = nus_data_rx_cb;
}
void ble_service_set_battery_value(uint8_t value)
{
_battery_level_value = value > 100 ? 100 : value;
}
/**
* PRIVATE FUNCTION DEFINITION
* Used for the internal workings of the service
@ -448,6 +510,8 @@ static bool ble_service_advertise(bool enable)
if(enable)
{
if(!ble_modem_is_sleeping())ble_modem_sleep();
struct ble_hs_adv_fields advertisement_fields = {0};
uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM;
@ -456,15 +520,9 @@ static bool ble_service_advertise(bool enable)
advertisement_fields.appearance = ble_svc_gap_device_appearance();
advertisement_fields.appearance_is_present = 1;
// Set the name of a watch supported by GB
#ifdef GADGETBRIDGE_SUPPORT
static const char dev_name[12] = "Bangle.js 2";
advertisement_fields.name = (uint8_t *)dev_name;//ble_svc_gap_device_name();
advertisement_fields.name_len = 11;//strlen(ble_svc_gap_device_name());
#else
// Set the name of the BLE device
advertisement_fields.name = (uint8_t *)ble_svc_gap_device_name();
advertisement_fields.name_len = strlen(ble_svc_gap_device_name());
#endif
advertisement_fields.name_is_complete = 1;
@ -482,15 +540,10 @@ static bool ble_service_advertise(bool enable)
return false;
}
// We the device address
uint8_t device_addr[6] = {0};
extern int tls_get_bt_mac_addr(u8 *mac);
tls_get_bt_mac_addr(device_addr);
// We set the device address
const uint8_t *device_mac_address = ble_service_get_device_mac_address();
// Make sure the the device address is compliant with the random address specification :
device_addr[5] |= 0xC0;
if((status = ble_hs_id_set_rnd(device_addr)) != BLE_HS_ENOERR)
if((status = ble_hs_id_set_rnd(device_mac_address)) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_ERROR("%s, ble_hs_id_set_rnd failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
return false;
@ -499,12 +552,12 @@ static bool ble_service_advertise(bool enable)
{
TLS_BT_APPL_TRACE_VERBOSE("addr type : %s"NEW_LINE"device addr : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE,
tls_bt_addr_type_2_str(own_addr_type),
device_addr[5],
device_addr[4],
device_addr[3],
device_addr[2],
device_addr[1],
device_addr[0]);
device_mac_address[5],
device_mac_address[4],
device_mac_address[3],
device_mac_address[2],
device_mac_address[1],
device_mac_address[0]);
}
// We are now ready to configure the advertisement parameters
@ -560,6 +613,17 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
_ble_service_state = BLE_SERVICE_MODE_CONNECTED;
usable_mtu = USABLE_DEFAULT_MTU;
ble_device_conn_handle = event->connect.conn_handle;
// We register an event callback on the connection,
// this allows to be notified on the passkey action event
if((status = ble_gap_set_event_cb(event->connect.conn_handle, &(ble_conn_gap_event_cb), NULL)) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_set_event_cb %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
}
//We call the state change callback if registered
if(_ble_service_state_change_cb)_ble_service_state_change_cb(_ble_service_state);
if(ble_modem_is_sleeping())ble_modem_wake();
}
else
{
@ -623,12 +687,16 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
}
_ble_service_state = BLE_SERVICE_MODE_ADVERTISING;
}
//We call the state change callback if registered
if(_ble_service_state_change_cb)_ble_service_state_change_cb(_ble_service_state);
break;
case BLE_GAP_EVENT_CONN_UPDATE:
TLS_BT_APPL_TRACE_DEBUG("Conn update status : %d"NEW_LINE, event->conn_update.status);
TLS_BT_APPL_TRACE_DEBUG("Conn update status : %s"NEW_LINE, tls_bt_rc_2_str(event->conn_update.status));
if((status = ble_gap_conn_find(event->connect.conn_handle, &desc)) == BLE_HS_ENOERR)
{
print_conn_desc(&desc);
TLS_BT_APPL_TRACE_VERBOSE("ble_gap_security_initiate %s"NEW_LINE, tls_bt_rc_2_str(ble_gap_security_initiate(ble_device_conn_handle)));
}
else
{
@ -647,6 +715,20 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
event->subscribe.cur_notify,
event->subscribe.prev_notify
);
if(gatt_nus_char_tx_handle == event->subscribe.attr_handle)
{
if(event->subscribe.cur_notify || event->subscribe.cur_indicate)
{
//We call the state change callback if registered
if(_ble_service_state_change_cb)_ble_service_state_change_cb(BLE_SERVICE_MODE_SUBSCRIBED);
}
else if(!event->subscribe.cur_notify && !event->subscribe.cur_indicate)
{
//We call the state change callback if registered
if(_ble_service_state_change_cb)_ble_service_state_change_cb(BLE_SERVICE_MODE_UNSUBSCRIBED);
}
}
break;
case BLE_GAP_EVENT_MTU:
TLS_BT_APPL_TRACE_VERBOSE("MTU update : %u"NEW_LINE, event->mtu.value);
@ -654,7 +736,7 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
break;
case BLE_GAP_EVENT_NOTIFY_TX:
if(event->notify_tx.indication == 0) // Notification
{
{
TLS_BT_APPL_TRACE_VERBOSE("Type : notification"NEW_LINE);
if(event->notify_tx.status != BLE_HS_ENOERR)
{
@ -683,7 +765,7 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
else
{
TLS_BT_APPL_TRACE_VERBOSE("last data chunk sent, end of the transfer"NEW_LINE);
// All data has been sent, end of the transfer
// All data have been sent, end of the transfer
reset_data_being_sent(&notification_data);
}
}
@ -704,6 +786,136 @@ static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg)
return BLE_HS_ENOERR;
}
static int ble_conn_gap_event_cb(struct ble_gap_event *event, void *arg)
{
int status = BLE_HS_ENOERR;
struct ble_gap_conn_desc desc;
TLS_BT_APPL_TRACE_EVENT("%s : %s"NEW_LINE, __FUNCTION__, tls_bt_gap_evt_2_str(event->type));
switch(event->type)
{
case BLE_GAP_EVENT_PASSKEY_ACTION:
TLS_BT_APPL_TRACE_VERBOSE("conn_handle : %u"NEW_LINE
"action : %s"NEW_LINE,
event->passkey.conn_handle,
tls_bt_sm_ioact_2_str(event->passkey.params.action));
if(BLE_SM_IOACT_NUMCMP == event->passkey.params.action)
{
TLS_BT_APPL_TRACE_VERBOSE("numcmp : %u"NEW_LINE,
event->passkey.params.numcmp);
}
struct ble_sm_io sm_io = {
.action = BLE_SM_IOACT_DISP,
.passkey = _pairing_passkey,
};
if((status = ble_sm_inject_io(event->passkey.conn_handle, &sm_io)) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_ERROR("%s, ble_sm_inject_io %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
}
break;
case BLE_GAP_EVENT_CONN_UPDATE:
TLS_BT_APPL_TRACE_DEBUG("Conn update status : %s"NEW_LINE, tls_bt_rc_2_str(event->conn_update.status));
if((status = ble_gap_conn_find(event->connect.conn_handle, &desc)) == BLE_HS_ENOERR)
{
print_conn_desc(&desc);
}
else
{
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_conn_find %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
}
break;
case BLE_GAP_EVENT_ENC_CHANGE:
TLS_BT_APPL_TRACE_DEBUG("Enc change status : (%u) -> %s"NEW_LINE, event->enc_change.status, tls_bt_rc_2_str(event->enc_change.status));
break;
case BLE_GAP_EVENT_REPEAT_PAIRING:
{
// If this event is triggered, then we shall remove the device from the bonded device list
// and tell it to pair again.
uint16_t conn_handle = event->repeat_pairing.conn_handle;
TLS_BT_APPL_TRACE_VERBOSE("conn_handle : %u"NEW_LINE
"cur_key_size : %u"NEW_LINE
"cur_authenticated : %u"NEW_LINE
"cur_sc : %u"NEW_LINE
"new_key_size : %u"NEW_LINE
"new_authenticated : %u"NEW_LINE
"new_sc : %u"NEW_LINE
"new_bonding : %u"NEW_LINE,
event->repeat_pairing.conn_handle,
event->repeat_pairing.cur_key_size,
event->repeat_pairing.cur_authenticated,
event->repeat_pairing.cur_sc,
event->repeat_pairing.new_key_size,
event->repeat_pairing.new_authenticated,
event->repeat_pairing.new_sc,
event->repeat_pairing.new_bonding);
if((status = ble_gap_conn_find(conn_handle, &desc)) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_conn_find %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
return status;
}
TLS_BT_APPL_TRACE_VERBOSE("sec_state_encrypted : %u"NEW_LINE
"sec_state_authenticated : %u"NEW_LINE
"sec_state_bonded : %u"NEW_LINE
"sec_state_key_size : %u"NEW_LINE
"our_id_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE
"our_ota_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE
"peer_id_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE
"peer_ota_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE,
desc.sec_state.encrypted,
desc.sec_state.authenticated,
desc.sec_state.bonded,
desc.sec_state.key_size,
desc.our_id_addr.type,
desc.our_id_addr.val[5],
desc.our_id_addr.val[4],
desc.our_id_addr.val[3],
desc.our_id_addr.val[2],
desc.our_id_addr.val[1],
desc.our_id_addr.val[0],
desc.our_ota_addr.type,
desc.our_ota_addr.val[5],
desc.our_ota_addr.val[4],
desc.our_ota_addr.val[3],
desc.our_ota_addr.val[2],
desc.our_ota_addr.val[1],
desc.our_ota_addr.val[0],
desc.peer_id_addr.type,
desc.peer_id_addr.val[5],
desc.peer_id_addr.val[4],
desc.peer_id_addr.val[3],
desc.peer_id_addr.val[2],
desc.peer_id_addr.val[1],
desc.peer_id_addr.val[0],
desc.peer_ota_addr.type,
desc.peer_ota_addr.val[5],
desc.peer_ota_addr.val[4],
desc.peer_ota_addr.val[3],
desc.peer_ota_addr.val[2],
desc.peer_ota_addr.val[1],
desc.peer_ota_addr.val[0]);
if((status = ble_gap_unpair(&desc.peer_id_addr)) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_unpair %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
return status;
}
return BLE_GAP_REPEAT_PAIRING_RETRY;
}
break;
default:
TLS_BT_APPL_TRACE_WARNING("unhandled event !"NEW_LINE);
}
return BLE_HS_ENOERR;
}
static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
int status = BLE_HS_ENOERR;
@ -714,7 +926,7 @@ static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_hand
if(attr_handle == battery_level_char_handle)
{
TLS_BT_APPL_TRACE_VERBOSE("battery level reading"NEW_LINE);
if((status = os_mbuf_append(ctxt->om, &battery_level_value, sizeof(battery_level_value))) != BLE_HS_ENOERR)
if((status = os_mbuf_append(ctxt->om, &_battery_level_value, sizeof(_battery_level_value))) != BLE_HS_ENOERR)
{
TLS_BT_APPL_TRACE_ERROR("%s, battery level os_mbuf : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
}
@ -729,12 +941,12 @@ static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_hand
static int gatt_nus_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
TLS_BT_APPL_TRACE_EVENT("gatt_nus_char_access_cb op : %s"NEW_LINE, tls_bt_access_opt_2_str(ctxt->op));
//TLS_BT_APPL_TRACE_EVENT("gatt_nus_char_access_cb op : %s"NEW_LINE, tls_bt_access_opt_2_str(ctxt->op));
switch(ctxt->op)
{
case BLE_GATT_ACCESS_OP_WRITE_CHR:
{
if(ble_modem_is_sleeping())ble_modem_wake();
struct os_mbuf *om_buf = ctxt->om;
while(om_buf)
{
@ -774,4 +986,4 @@ static void reset_data_being_sent(data_being_sent_t * const data)
{
memset(data, 0, sizeof(data_being_sent_t));
}
}
}

View File

@ -15,10 +15,14 @@ typedef enum
BLE_SERVICE_MODE_IDLE,
BLE_SERVICE_MODE_ADVERTISING,
BLE_SERVICE_MODE_CONNECTED,
BLE_SERVICE_MODE_SUBSCRIBED,
BLE_SERVICE_MODE_UNSUBSCRIBED,
BLE_SERVICE_MODE_INDICATING,
BLE_SERVICE_MODE_EXITING
} ble_service_state_e;
typedef void (*ble_service_state_change_fn_t)(ble_service_state_e service_state);
/**
* @brief Resturns the corresponding enum name as a string
*
@ -60,12 +64,42 @@ bool ble_service_is_started(void);
bool ble_service_is_device_connected(void);
/**
* @brief Returns the current state of the ble service
* @brief Returns the MAC address of the BLE device.
*
* @return ble_service_state_e
* @return a pointer to a constant array of size 6 containing the address.
*/
const uint8_t *ble_service_get_device_mac_address(void);
/**
* @brief Registers a callback function called every time the state of the BLE service changes.
* For example, you can register a callback to know if a device connected to the service, or disconnected
*
* @param ble_service_state_change_cb the function to register as the callback. The ble_service_state parameter is set to the new state.
*/
void ble_service_register_state_change_cb(ble_service_state_change_fn_t ble_service_state_change_cb);
/**
* @brief Returns the current state of the ble service.
*
* @return ble_service_state_e enum value
*/
ble_service_state_e ble_service_get_state(void);
/**
* @brief Sets the passkey which is asked by the phone when trying to pair the device for the first time.
*
* @param passkey the passkey to set, might be mandatory to be a 6 digit number.
*/
void ble_service_set_pairing_passkey(uint32_t passkey);
/**
* @brief Returns the passkey needed for pairing which was previously set by the @ref ble_service_set_pairing_passkey
* function.
*
* @return uint32_t the number representing the passkey.
*/
uint32_t ble_service_get_active_pairing_passkey(void);
/**
* @brief Asks to update the current connection parameters
* /!\ A connection should be already active before calling this function.
@ -103,7 +137,7 @@ bool ble_service_request_mtu_exchange(void);
* @return true on success
* @return false on failure
*/
bool ble_service_nus_send_data(const uint8_t *data, uint16_t length);
bool ble_service_send_nus_data(const uint8_t *data, uint16_t length);
/**
* @brief Registers a function which will be called every time data is received by the nus rx
@ -111,6 +145,13 @@ bool ble_service_nus_send_data(const uint8_t *data, uint16_t length);
*
* @param nus_data_rx_cb a pointer to the function to call of type nus_data_rx_fn_t
*/
void ble_service_nus_register_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb);
void ble_service_register_nus_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb);
#endif //BLE_APP_H
/**
* @brief Sets the battery level in percents sent by the BLE battery service
*
* @param value the battery level to set in percents
*/
void ble_service_set_battery_value(uint8_t value);
#endif //BLE_APP_H

View File

@ -2,7 +2,7 @@
#define BLUETOOTH_SIG_VALUES_H
#define BLE_DEVICE_APPEARANCE (0x00C2) //Smart Watch
#define BLE_DEVICE_NAME "W800SmartWatch"
#define BLE_DEVICE_NAME "MDBT42Q_DEV"
#define BLE_DEVICE_ADV_SERVICE (0x180F) //Battery Service

1519
app/ble/gadget_bridge.c Normal file

File diff suppressed because it is too large Load Diff

322
app/ble/gadget_bridge.h Normal file
View File

@ -0,0 +1,322 @@
/**
* @file gadget_bridge.h
* @author Anatole SCHRAMM-HENRY
* @brief Header file exposing the API used to communicate/interact with the GadgetBridge Android application
* over BLE.
* @version 0.1
* @date 2023-04-04
*
* @copyright MIT
*
*/
#ifndef GADGET_BRIDGE_H
#define GADGET_BRIDGE_H
#include "wm_type_def.h"
#include <time.h>
/**
* @brief GADGET_BRIDGE_PARSER_BUFFER_SIZE allows to set the size of the buffer
* which is internally used by the parser to do it's job.
*
*/
#define GADGET_BRIDGE_PARSER_BUFFER_SIZE (300)
/**
* @brief GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD permits to set a size threshold used to free up
* some space in the parser's internal buffer when the threshold is reached.
* This ensures that we can keep on feeding new data and not get stuck.
*
*/
#define GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD (100)
/**
* @brief GADGET_BRIDGE_PARSER_MAX_BODY_SIZE defines the max body size that will be saved in the event_data
* structure when parsing the body of a notification.
*
*/
#define GADGET_BRIDGE_PARSER_MAX_BODY_SIZE (200)
/**
* @brief GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE defines the max title size that will be saved in the event_data
* structure when parsing the title of a notification.
*
*/
#define GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE (100)
typedef enum gadget_bridge_toast_type
{
GADGET_BRIDGE_TOAST_TYPE_INFO = 0,
GADGET_BRIDGE_TOAST_TYPE_WARN,
GADGET_BRIDGE_TOAST_TYPE_ERROR,
} gadget_bridge_toast_type_e;
typedef enum gadget_bridge_music_control
{
GADGET_BRIDGE_MUSIC_CONTROL_PLAY = 0,
GADGET_BRIDGE_MUSIC_CONTROL_PAUSE,
GADGET_BRIDGE_MUSIC_CONTROL_PLAYPAUSE,
GADGET_BRIDGE_MUSIC_CONTROL_NEXT,
GADGET_BRIDGE_MUSIC_CONTROL_PREVIOUS,
GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEUP,
GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEDOWN,
GADGET_BRIDGE_MUSIC_CONTROL_FORWARD,
GADGET_BRIDGE_MUSIC_CONTROL_REWIND,
} gadget_bridge_music_control_e;
typedef enum gadget_bridge_call_action
{
GADGET_BRIDGE_CALL_ACTION_ACCEPT = 0,
GADGET_BRIDGE_CALL_ACTION_END,
GADGET_BRIDGE_CALL_ACTION_INCOMING,
GADGET_BRIDGE_CALL_ACTION_OUTGOING,
GADGET_BRIDGE_CALL_ACTION_REJECT,
GADGET_BRIDGE_CALL_ACTION_START,
GADGET_BRIDGE_CALL_ACTION_IGNORE,
GADGET_BRIDGE_CALL_ACTION_UNKNOWN,
} gadget_bridge_call_action_e;
typedef enum gadget_bridge_notification_action
{
GADGET_BRIDGE_NOTIFICATION_ACTION_DISMISS = 0,
GADGET_BRIDGE_NOTIFICATION_ACTION_DISMISS_ALL,
GADGET_BRIDGE_NOTIFICATION_ACTION_OPEN,
GADGET_BRIDGE_NOTIFICATION_ACTION_MUTE,
GADGET_BRIDGE_NOTIFICATION_ACTION_REPLY,
} gadget_bridge_notification_action_e;
typedef enum gadget_bridge_http_request_method
{
GADGET_BRIDGE_HTTP_REQUEST_GET = 0,
GADGET_BRIDGE_HTTP_REQUEST_POST,
GADGET_BRIDGE_HTTP_REQUEST_HEAD,
GADGET_BRIDGE_HTTP_REQUEST_PUT,
GADGET_BRIDGE_HTTP_REQUEST_PATCH,
GADGET_BRIDGE_HTTP_REQUEST_DELETE,
} gadget_bridge_http_request_method_e;
typedef enum gadget_bridge_parser_code
{
GADGET_BRIDGE_PARSER_CODE_OK = 0,
GADGET_BRIDGE_PARSER_CODE_PARSING,
GADGET_BRIDGE_PARSER_CODE_BUFFER_FULL,
GADGET_BRIDGE_PARSER_CODE_DATA_TOO_LONG,
} gadget_bridge_parser_code_e;
typedef struct http_header
{
const char *key;
const char *value;
} http_header_t;
typedef enum gadget_bridge_event_type
{
GADGET_BRIDGE_EVENT_TYPE_NONE = 0,
GADGET_BRIDGE_EVENT_TYPE_SET_TIME,
GADGET_BRIDGE_EVENT_TYPE_NOTIFY,
GADGET_BRIDGE_EVENT_TYPE_CALL,
GADGET_BRIDGE_EVENT_TYPE_WEATHER,
GADGET_BRIDGE_EVENT_TYPE_FIND,
GADGET_BRIDGE_EVENT_TYPE_ACT,
GADGET_BRIDGE_EVENT_TYPE_MUSIC_INFO,
GADGET_BRIDGE_EVENT_TYPE_MUSIC_STATE,
GADGET_BRIDGE_EVENT_TYPE_UNKNOWN,
} gadget_bridge_event_type_e;
typedef enum gadget_bridge_notification_type
{
GADGET_BRIDGE_NOTIFICATION_TYPE_SMS = 0,
GADGET_BRIDGE_NOTIFICATION_TYPE_EMAIL,
GADGET_BRIDGE_NOTIFICATION_TYPE_GADGET_BRIDGE,
GADGET_BRIDGE_NOTIFICATION_TYPE_UNKNOWN,
} gadget_bridge_notification_type_e;
typedef enum
{
GADGET_BRIDGE_MUSIC_STATE_PAUSE = 0,
GADGET_BRIDGE_MUSIC_STATE_PLAY,
GADGET_BRIDGE_MUSIC_STATE_UNKNOWN,
} gadget_bridge_music_state_e;
typedef struct gadget_bridge_event_data
{
gadget_bridge_event_type_e event_type;
union
{
struct
{
struct tm gm_time;
struct tm local_time;
int8_t time_zone;
} time;
struct
{
uint32_t handle;
gadget_bridge_notification_type_e notification_type;
char *title;
char *body;
} notification;
struct
{
char *phone_number;
char *contact;
gadget_bridge_call_action_e call_action;
} call;
struct
{
float temperature_celsius;
uint8_t humidity;
char *weather_desc;
float wind_speed_kmh;
uint16_t wind_dir;
char *location;
} weather;
struct
{
bool find;
} find;
struct
{
bool heart_rate_monitor;
bool steps;
uint8_t heart_rate_interval;
} act;
struct
{
gadget_bridge_music_state_e music_state;
uint16_t position_in_seconds;
uint8_t shuffle;
uint8_t repeat;
} music_state;
struct
{
char *artist;
char *track;
uint16_t duration_in_seconds;
} music_info;
};
} gadget_bridge_event_data_t;
typedef void (*parser_event_callback_t)(const gadget_bridge_event_data_t *gadget_bridge_event_data);
/**
* @brief Sends an Android toast to GadgetBridge to be displayed on the phone.
*
* @param toast_type the type of the toast (INFO, WARN or ERROR).
* @param message a string representing the message to display.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_toast(gadget_bridge_toast_type_e toast_type, const char *message);
/**
* @brief Sends up to two firmwares version to GadgetBridge.
* These are displayed in the display details section of the watch in GadgetBridge.
*
* @param fw1 a string representing the first firmware version.
* @param fw2 a string representing the second firmware version.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_firmware_version(const char *fw1, const char *fw2);
/**
* @brief Sends the current battery status to GadgetBridge.
*
* @param battery_level_in_percent the current battery level from 0 to 100%.
* @param battery_level_in_V the current battery voltage in volts (3.942 for example).
* @param is_charging a boolean which indicates if the battery is currently charging or not.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_battery_status(uint8_t battery_level_in_percent, float battery_level_in_V, bool is_charging);
/**
* @brief Sends the find phone command to GagdetBridge, this will make the phone ring and vibrate
* so that you can locate it.
*
* @param find_phone a boolean which indicates to make the phone rind and vibrate or not.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_find_phone(bool find_phone);
/**
* @brief Sends a command to control the music playback of the phone through GadgetBridge.
*
* @param music_control an enumeration value indicating the action to perform:
* PLAY, PAUSE, NEXT, PREVIOUS, VOLUMEUP etc..
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_music_control(gadget_bridge_music_control_e music_control);
bool gadget_bridge_handle_call(gadget_bridge_call_action_e call_action);
bool gadget_bridge_handle_notification(gadget_bridge_call_action_e notification_action, uint32_t handle, const char *phone_number, const char *message);
/**
* @brief Sends the provided activity data to GadgetBridge. This will then be displayed
* on the app in the activity section.
*
* @param heart_rate_in_bpm the current heart rate in beat per minute
* @param step_count the number of new steps since the last time the count was sent.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_count);
/**
* @brief Tells GadgetBridge to perform an HTTP request for us.
* @note THIS DOES NOT WORK as GadgetBridge don't and will never have network permission... what a pitty !
*
* @param id an unsigned integer representing the ID of the http request
* @param url a string representing the URL to fetch
* @param http_request_method a enumeration value specifying the http verb to use : GET, POST, PATCH etc..
* @param http_body the body to include in the request (not implemented yet)
* @param http_headers various headers to include in the request (not implemented yet)
* @return true if the request has been successfully sent to GadgetBridge
* @return false otherwise
*/
bool gadget_bridge_send_http_request(uint32_t id, const char *url, gadget_bridge_http_request_method_e http_request_method, const char *http_body, const http_header_t *http_headers);
//bool gadget_bridge_send_force_calendar_sync(void);
/**
* @brief Registers a callback function used to listen for GadgetBridge events.
*
* @param parser_event_callback
*/
void gadget_bridge_parser_register_event_callback(parser_event_callback_t parser_event_callback);
/**
* @brief Feeds new data to the GadgetBridge parser.
*
* @param data the new chunk of data to parse, it will be copied to the parser's internal buffer,
* so you can free the memory containing the string after calling the function.
* @param length the length in bytes of the new chunk.
* @return gadget_bridge_parser_code_e GADGET_BRIDGE_PARSER_CODE_OK if no error occured.
*/
gadget_bridge_parser_code_e gadget_bridge_parser_feed(const char *data, uint16_t length);
/**
* @brief Call this function to run the parser.
* It should be safe to call if in a loop like : while((code = gadget_bridge_parser_run()) == GADGET_BRIDGE_PARSER_CODE_PARSING);
*
* @return gadget_bridge_parser_code_e the parser's execution status code.
*/
gadget_bridge_parser_code_e gadget_bridge_parser_run(void);
const char *gadget_bridge_parser_code_2_str(gadget_bridge_parser_code_e parser_code);
const char *gadget_bridge_event_type_2_str(gadget_bridge_event_type_e event_type);
const char *gadget_bridge_notification_type_2_str(gadget_bridge_notification_type_e notification_type);
const char *gadget_bridge_music_state_2_str(gadget_bridge_music_state_e music_state);
void gadget_bridge_parser_debug(void);
#endif //GADGET_BRIDGE_H

View File

@ -165,6 +165,15 @@ void user_main(void *param)
u8 tmr_millis_id = tls_timer_create(&tmr_millis);
tls_timer_start(tmr_millis_id);
//Let's start the RTC if not already running
if(!tls_is_rtc_running())
{
shell_printf("Starting RTC"NEW_LINE);
struct tm curr_time;
time_date_to_tm(__TIME__" "__DATE__, &curr_time);
tls_set_rtc(&curr_time);
}
//We create a task for the nano_shell process
u8 *nano_shell_task_stack = NULL, *nano_shell_server_task_stack = NULL;

View File

@ -1,3 +1,4 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -7,11 +8,15 @@
#include "task.h"
#include "lwip/netif.h"
#include "app_common.h"
#include "app_utils.h"
#include "nano_shell_interface.h"
#include "wm_gpio_afsel.h"
#include "wm_cpu.h"
#include "wm_bt.h"
#include "ble_modem.h"
#include "ble_service.h"
#include "gadget_bridge.h"
extern int wm_printf(const char *fmt,...);
extern u32 tls_mem_get_avail_heapsize(void);
@ -90,15 +95,81 @@ static void tls_rtc_irq_cb(void *arg)
rtc_time.tm_sec,
rtc_time.tm_mday,
rtc_time.tm_mon,
rtc_time.tm_year);
rtc_time.tm_year + 1900);
tls_rtc_timer_stop();
}
static void parser_event_cb(const gadget_bridge_event_data_t *gadget_bridge_event_data)
{
shell_printf("----------->Event of type : %s\n", gadget_bridge_event_type_2_str(gadget_bridge_event_data->event_type));
switch(gadget_bridge_event_data->event_type)
{
case GADGET_BRIDGE_EVENT_TYPE_SET_TIME:
shell_printf("%d:%d:%d %d/%d/%d\n%d\n",
gadget_bridge_event_data->time.local_time.tm_hour,
gadget_bridge_event_data->time.local_time.tm_min,
gadget_bridge_event_data->time.local_time.tm_sec,
gadget_bridge_event_data->time.local_time.tm_mday,
gadget_bridge_event_data->time.local_time.tm_mon,
gadget_bridge_event_data->time.local_time.tm_year + 1900,
gadget_bridge_event_data->time.time_zone);
break;
case GADGET_BRIDGE_EVENT_TYPE_NOTIFY:
shell_printf("%u\n%s\n%s\n%s\n",
gadget_bridge_event_data->notification.handle,
gadget_bridge_notification_type_2_str(gadget_bridge_event_data->notification.notification_type),
gadget_bridge_event_data->notification.title,
gadget_bridge_event_data->notification.body);
break;
break;
case GADGET_BRIDGE_EVENT_TYPE_CALL:
shell_printf("%u\n%s\n%s\n",
gadget_bridge_event_data->call.call_action,
gadget_bridge_event_data->call.contact,
gadget_bridge_event_data->call.phone_number);
break;
case GADGET_BRIDGE_EVENT_TYPE_WEATHER:
shell_printf("%.2f\n%u\n%s\n%.2f\n%u\n%s\n",
gadget_bridge_event_data->weather.temperature_celsius,
gadget_bridge_event_data->weather.humidity,
gadget_bridge_event_data->weather.weather_desc,
gadget_bridge_event_data->weather.wind_speed_kmh,
gadget_bridge_event_data->weather.wind_dir,
gadget_bridge_event_data->weather.location);
break;
case GADGET_BRIDGE_EVENT_TYPE_FIND:
shell_printf("%d\n",gadget_bridge_event_data->find.find);
break;
case GADGET_BRIDGE_EVENT_TYPE_ACT:
shell_printf("%d\n%d\n%u\n",
gadget_bridge_event_data->act.heart_rate_monitor,
gadget_bridge_event_data->act.steps,
gadget_bridge_event_data->act.heart_rate_interval);
break;
case GADGET_BRIDGE_EVENT_TYPE_MUSIC_STATE:
shell_printf("%s\n%u\n%u\n%u\n",
gadget_bridge_music_state_2_str(gadget_bridge_event_data->music_state.music_state),
gadget_bridge_event_data->music_state.position_in_seconds,
gadget_bridge_event_data->music_state.shuffle,
gadget_bridge_event_data->music_state.repeat);
break;
case GADGET_BRIDGE_EVENT_TYPE_MUSIC_INFO:
shell_printf("%s\n%s\n%u\n",
gadget_bridge_event_data->music_info.artist,
gadget_bridge_event_data->music_info.track,
gadget_bridge_event_data->music_info.duration_in_seconds);
break;
default:
shell_printf("Unhandled\n");
}
}
static void nus_data_rx_cb(const uint8_t *data, uint16_t length)
{
shell_printf("%s, received data : "NEW_LINE"#", __FUNCTION__);
//shell_printf("%s, received data : "NEW_LINE"#", __FUNCTION__);
//shell_putc('"');
for (uint16_t i = 0; i < length; i++)
{
if (data[i] < 32)
@ -106,7 +177,13 @@ static void nus_data_rx_cb(const uint8_t *data, uint16_t length)
else
shell_putc(data[i]);
}
shell_puts("#"NEW_LINE);
//shell_printf("\","NEW_LINE);
shell_printf("# ");
gadget_bridge_parser_feed((const char *)data, length);
gadget_bridge_parser_code_e code;
while((code = gadget_bridge_parser_run()) == GADGET_BRIDGE_PARSER_CODE_PARSING);
shell_printf("Gadget bridge parser code : %s"NEW_LINE, gadget_bridge_parser_code_2_str(code));
//shell_puts("#"NEW_LINE);
}
int _system(const shell_cmd_t *pcmd, int argc, char *const argv[])
@ -132,6 +209,35 @@ int _system(const shell_cmd_t *pcmd, int argc, char *const argv[])
uint32_t total_mem_size = (unsigned int)&__heap_end - (unsigned int)&__heap_start;
shell_printf("Free OS heap : %u/%u byte(s)"NEW_LINE"tls heap size : %u/%u byte(s)"NEW_LINE, xPortGetFreeHeapSize(), configTOTAL_HEAP_SIZE, tls_mem_get_avail_heapsize(), total_mem_size);
}
else if(strcmp(argv[1], "cpu_clock") == 0)
{
if(argc == 3)
{
uint8_t clock = strtoul(argv[2], NULL, 10);
if(clock < 2 || clock > 240)
{
shell_printf("Bad clock !"NEW_LINE
"Available options are :"NEW_LINE
"\t- 2, 40, 80, 160, 240"NEW_LINE);
}
else
{
uint8_t div = 480/clock;
tls_sys_clk_set(div);
tls_sys_clk sys_clk;
tls_sys_clk_get(&sys_clk);
shell_printf("Clock set to %u : cpu(%u), wlan(%u) and APB(%u)"NEW_LINE, clock, sys_clk.cpuclk, sys_clk.wlanclk, sys_clk.apbclk);
}
}
else
{
tls_sys_clk sys_clk;
tls_sys_clk_get(&sys_clk);
shell_printf("Clocks : cpu(%u), wlan(%u) and APB(%u)"NEW_LINE, sys_clk.cpuclk, sys_clk.wlanclk, sys_clk.apbclk);
}
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
@ -139,7 +245,10 @@ int _system(const shell_cmd_t *pcmd, int argc, char *const argv[])
}
else
{
shell_printf("List of system actions :"NEW_LINE"list_task"NEW_LINE"ram_usage"NEW_LINE);
shell_printf("List of system actions :"NEW_LINE
"list_task"NEW_LINE
"ram_usage"NEW_LINE
"cpu_clock 2|40|80|160|240"NEW_LINE);
}
return 0;
}
@ -437,6 +546,27 @@ int _pmu(const shell_cmd_t *pcmd, int argc, char *const argv[])
shell_printf("Waking up out of standby mode"NEW_LINE);
tls_pmu_timer0_stop();
}
else if(strcmp(argv[1], "periph_clock_en") == 0 && argc == 3)
{
if(strcmp(argv[2], "0"))
{
tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LCD);
tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_I2S);
tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_PSRAM);
tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_TOUCH_SENSOR);
//tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_BT);
shell_printf("Open peripheral clocks"NEW_LINE);
}
else
{
tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LCD);
tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_I2S);
tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_PSRAM);
tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_TOUCH_SENSOR);
//tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_BT);
shell_printf("Closed peripheral clocks"NEW_LINE);
}
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
@ -444,13 +574,16 @@ int _pmu(const shell_cmd_t *pcmd, int argc, char *const argv[])
}
else
{
shell_printf("List of pmu actions :"NEW_LINE"sleep <duration(s)>"NEW_LINE"standby <duration(s)>"NEW_LINE);
shell_printf("List of pmu actions :"NEW_LINE"sleep <duration(s)>"NEW_LINE"standby <duration(s)>"NEW_LINE
"periph_clock_en 0|1"NEW_LINE);
}
return 0;
}
int _rtc(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
bool cmd_found = true;
if(argc > 1)
{
if(strcmp(argv[1], "get") == 0)
@ -464,7 +597,7 @@ int _rtc(const shell_cmd_t *pcmd, int argc, char *const argv[])
rtc_time.tm_sec,
rtc_time.tm_mday,
rtc_time.tm_mon,
rtc_time.tm_year);
rtc_time.tm_year + 1900);
}
else if(strcmp(argv[1], "set") == 0)
{
@ -485,6 +618,8 @@ int _rtc(const shell_cmd_t *pcmd, int argc, char *const argv[])
rtc_time.tm_mon,
rtc_time.tm_year);
rtc_time.tm_year -= 1900;
tls_set_rtc(&rtc_time);
tls_rtc_isr_register(&(tls_rtc_irq_cb), NULL);
}
@ -507,38 +642,58 @@ int _rtc(const shell_cmd_t *pcmd, int argc, char *const argv[])
rtc_time.tm_mon,
rtc_time.tm_year);
rtc_time.tm_year -= 1900;
tls_rtc_timer_start(&(rtc_time));
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
cmd_found = false;
}
}
else
{
cmd_found = false;
}
if(!cmd_found)
{
shell_printf("List of rtc actions :"NEW_LINE"get"NEW_LINE"set <h> <m> <s> <d> <m> <y>"NEW_LINE"alarm <h> <m> <s> <d> <m> <y>"NEW_LINE);
}
return 0;
}
static void demo_timer_irq(void *arg)
{
bool *sleeping = arg;
if(*sleeping)
ble_modem_sleep();
else
ble_modem_wake();
}
int _bluetooth(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "enable") == 0)
if(strcmp(argv[1], "enable") == 0 && argc == 4)
{
if(argc == 3)
{
bool result = ble_modem_on(true);
shell_printf("Enabling bluetooth modem with ble service : %d"NEW_LINE, result);
bool btOnly = atoi(argv[2]) == 1;
bool service = atoi(argv[3]) == 1;
bool result = ble_modem_on(btOnly, service);
shell_printf("Enabling bluetooth : %d with bt only : %d and service : %d"NEW_LINE, result, btOnly, service);
if(result)
ble_service_nus_register_data_rx_cb(&(nus_data_rx_cb));
}
else
{
shell_printf("Enabling bluetooth modem only : %d"NEW_LINE, ble_modem_on(false));
}
{
gadget_bridge_parser_register_event_callback(&(parser_event_cb));
ble_service_register_nus_data_rx_cb(&(nus_data_rx_cb));
ble_service_set_pairing_passkey(123456);
if(!ble_modem_is_sleeping())ble_modem_sleep();
}
}
else if(strcmp(argv[1], "disable") == 0)
{
@ -550,56 +705,126 @@ int _bluetooth(const shell_cmd_t *pcmd, int argc, char *const argv[])
shell_printf("Starting demo : %d"NEW_LINE"Use a BLE app to find the device"NEW_LINE, result /*demo_ble_server_on()*/);
if(result)
{
ble_service_nus_register_data_rx_cb(&(nus_data_rx_cb));
ble_service_register_nus_data_rx_cb(&(nus_data_rx_cb));
}
}
else if(strcmp(argv[1], "stop_demo") == 0)
{
shell_printf("Stopping demo : %d"NEW_LINE, ble_service_stop() /*demo_ble_server_off()*/);
ble_service_nus_register_data_rx_cb(NULL);
ble_service_register_nus_data_rx_cb(NULL);
}
else if(strcmp(argv[1], "mtu_exch") == 0)
{
shell_printf("MTU exchange request : %d"NEW_LINE, ble_service_request_mtu_exchange());
}
else if(strcmp(argv[1], "mac_addr") == 0)
{
const uint8_t *mac = ble_service_get_device_mac_address();
shell_printf("The device MAC address is : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE,
mac[5],
mac[4],
mac[3],
mac[2],
mac[1],
mac[0]);
}
else if(strcmp(argv[1], "send_ble_notif") == 0 && argc > 2)
{
char cmd[200] = "";
bool found = false;
if(strcmp(argv[2], "toast") == 0)
bool to_return = false;
if(strcmp(argv[2], "toast") == 0 && argc == 5)
{
sprintf(cmd, "{\"t\":\"info\",\"msg\":\"%s\"} \n", argv[3]);
found = true;
gadget_bridge_toast_type_e toast_type = GADGET_BRIDGE_TOAST_TYPE_INFO;
if(strcmp(argv[3], "warn") == 0)
{
toast_type = GADGET_BRIDGE_TOAST_TYPE_WARN;
}
else if(strcmp(argv[3], "error") == 0)
{
toast_type = GADGET_BRIDGE_TOAST_TYPE_ERROR;
}
to_return = gadget_bridge_send_toast(toast_type, argv[4]);
}
else if(strcmp(argv[2], "bat") == 0)
else if(strcmp(argv[2], "ver") == 0 && argc == 5)
{
to_return = gadget_bridge_send_firmware_version(argv[3], argv[4]);
}
else if(strcmp(argv[2], "bat") == 0 && argc == 6)
{
sprintf(cmd, "{\"t\":\"status\",\"bat\":%s,\"chg\":%s,\"volt\":%s} \n", argv[3], argv[4], argv[5]);
found = true;
uint8_t percent = atoi(argv[3]);
bool charging = atoi(argv[4]);
float volt = strtof(argv[5], NULL);
to_return = gadget_bridge_send_battery_status(percent, volt, charging);
}
else if(strcmp(argv[2], "findPhone") == 0)
else if(strcmp(argv[2], "find_phone") == 0 && argc == 4)
{
strcpy(cmd, "{\"t\":\"findPhone\",\"n\":true} \n");
found = true;
to_return = gadget_bridge_send_find_phone(strcmp(argv[3], "true") == 0);
}
else if(strcmp(argv[2], "music") == 0)
else if(strcmp(argv[2], "music") == 0 && argc == 4)
{
sprintf(cmd, "{\"t\":\"music\",\"n\":\"%s\"} \n", argv[3]);
found = true;
gadget_bridge_music_control_e music_control = GADGET_BRIDGE_MUSIC_CONTROL_PAUSE;
if(strcmp(argv[3], "pause") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_PAUSE;
else if(strcmp(argv[3], "play") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_PLAY;
else if(strcmp(argv[3], "playpause") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_PLAYPAUSE;
else if(strcmp(argv[3], "next") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_NEXT;
else if(strcmp(argv[3], "previous") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_PREVIOUS;
else if(strcmp(argv[3], "volumeup") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEUP;
else if(strcmp(argv[3], "volumedown") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEDOWN;
else if(strcmp(argv[3], "forward") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_FORWARD;
else if(strcmp(argv[3], "rewind") == 0)
music_control = GADGET_BRIDGE_MUSIC_CONTROL_REWIND;
to_return = gadget_bridge_send_music_control(music_control);
}
else if(strcmp(argv[2], "notify") == 0)
{
sprintf(cmd, "{\"t\":\"notify\",\"n\":\"%s\",\"id\":%s,\"tel\":\"%s\",\"msg\":\"%s\"} \n", argv[3], argv[4], argv[5], argv[6]);
found = true;
}
if(found)
else if(strcmp(argv[2], "act") == 0 && argc == 5)
{
shell_printf("Sending ble ntf with content : #%s# -> %s"NEW_LINE, cmd, ble_service_nus_send_data((const uint8_t *)cmd, strlen(cmd)) ? "success" : "failure");
to_return = gadget_bridge_send_activity_data(atoi(argv[3]), atoi(argv[4]));
}
/*else if(strcmp(argv[2], "calendar") == 0 && argc == 3)
{
to_return = gadget_bridge_send_force_calendar_sync();
}*/
else if(strcmp(argv[2], "http") == 0 && argc == 6)
{
to_return = gadget_bridge_send_http_request(atoi(argv[3]), argv[4], GADGET_BRIDGE_HTTP_REQUEST_GET, NULL, NULL);
}
else
{
shell_printf("Unknown %s action, list of send_ble_notif actions :"NEW_LINE"toast \"msg\""NEW_LINE"bat \"XX%%\" 1|0 X.X"NEW_LINE"findPhone"NEW_LINE"music play|pause|previous|next"NEW_LINE"notify reply|dismiss_all id \"tel\" \"msg\""NEW_LINE, argv[2]);
shell_printf("Unknown %s action, list of send_ble_notif actions :"NEW_LINE"toast info|warn|error \"msg\""NEW_LINE"bat \"XX%%\" 1|0 X.X"NEW_LINE"find_phone true|false"NEW_LINE"music play|pause|playpause|previous|next|volumeup|volumedown|forward|rewind"NEW_LINE"notify reply|dismiss_all id \"tel\" \"msg\""NEW_LINE
"act hrm steps"NEW_LINE
"ver \"version 1\" \"version 2\""NEW_LINE
, argv[2]);
}
shell_printf("Sending ble ntf : %d"NEW_LINE, to_return);
if(found)
{
shell_printf("Sending ble ntf with content : #%s# -> %s"NEW_LINE, cmd, ble_service_send_nus_data((const uint8_t *)cmd, strlen(cmd)) ? "success" : "failure");
}
/*else
{
shell_printf("Unknown %s action, list of send_ble_notif actions :"NEW_LINE"toast \"msg\""NEW_LINE"bat \"XX%%\" 1|0 X.X"NEW_LINE"find_phone true|false"NEW_LINE"music play|pause|previous|next"NEW_LINE"notify reply|dismiss_all id \"tel\" \"msg\""NEW_LINE
"act hrm steps"NEW_LINE, argv[2]);
}*/
}
else if(strcmp(argv[1], "up_conn_param") == 0)
{
@ -618,15 +843,93 @@ int _bluetooth(const shell_cmd_t *pcmd, int argc, char *const argv[])
shell_printf("BLE connection update request : %d"NEW_LINE, ble_service_update_connection_parameters(itvl_min, itvl_max, latency, supervision_timeout, min_ce_len, max_ce_len));
}
else if(strcmp(argv[1], "ble_tx_power") == 0)
{
if(argc == 3)
{
int8_t tx_power = strtoul(argv[2], NULL, 10);
shell_printf("Setting BLE TX power to : %d -> %u"NEW_LINE, tx_power, tls_ble_set_tx_power(TLS_BLE_PWR_TYPE_DEFAULT, tx_power));
}
else // We simply return the current tx_power
{
shell_printf("Current BLE TX power is : %d"NEW_LINE, tls_ble_get_tx_power(TLS_BLE_PWR_TYPE_DEFAULT));
}
}
else if(strcmp(argv[1], "bt_tx_power") == 0)
{
if(argc == 3)
{
int8_t tx_power = strtoul(argv[2], NULL, 10);
shell_printf("Setting BT TX power to : %d -> %u"NEW_LINE, tx_power, tls_bredr_set_tx_power(tx_power, tx_power));
}
else // We simply return the current tx_power
{
int8_t min_pow = 0, max_pow = 0;
tls_bredr_get_tx_power(&min_pow, &max_pow);
shell_printf("Current BT TX power is : min(%d) max(%d)"NEW_LINE, min_pow, max_pow);
}
}
else if(strcmp(argv[1], "ble_modem_sleep") == 0)
{
if(argc == 3)
{
static bool sleeping;
sleeping = strtoul(argv[2], NULL, 10);
static uint8_t timer_id = WM_TIMER_ID_INVALID;
if(timer_id == WM_TIMER_ID_INVALID)
{
struct tls_timer_cfg timer_cfg;
timer_cfg.unit = TLS_TIMER_UNIT_MS;
timer_cfg.timeout = 2000;
timer_cfg.is_repeat = 0;
timer_cfg.callback = (tls_timer_irq_callback)demo_timer_irq;
timer_cfg.arg = &sleeping;
timer_id = tls_timer_create(&timer_cfg);
}
tls_timer_start(timer_id);
}
}
else if(strcmp(argv[1], "ble_modem_wake") == 0)
{
shell_printf("BLE modem waking up : %d"NEW_LINE, tls_bt_ctrl_wakeup());
}
else if(strcmp(argv[1], "ble_modem_mode") == 0)
{
if(strcmp(argv[2], "bt") == 0)
{
tls_rf_bt_mode(1);
shell_printf("BLE modem set to bt only mode"NEW_LINE);
}
else
{
tls_rf_bt_mode(0);
shell_printf("BLE modem set to bt/wifi"NEW_LINE);
}
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[1]);
}
}
}
else
{
shell_printf("List of bluetooth actions :"NEW_LINE"enable"NEW_LINE"disable"NEW_LINE"start_demo"NEW_LINE"stop_demo"NEW_LINE"send_ble_notif toast \"msg\"|bat \"%%\"|findPhone|music|notify"NEW_LINE"mtu_exch"NEW_LINE
"up_conn_param itvl_min itvl_max latency supervision_timeout min_ce_len max_ce_len"NEW_LINE);
shell_printf("List of bluetooth actions :"NEW_LINE
"enable 0|1 0|1"NEW_LINE
"disable"NEW_LINE
"start_demo"NEW_LINE
"stop_demo"NEW_LINE
"send_ble_notif toast \"msg\"|bat \"%%\"|findPhone|music|notify"NEW_LINE
"mtu_exch"NEW_LINE
"up_conn_param itvl_min itvl_max latency supervision_timeout min_ce_len max_ce_len"NEW_LINE
"ble_tx_power 1|2|3|4|5"NEW_LINE
"bt_tx_power 1|2|3|4|5"NEW_LINE
"ble_modem_sleep 1|0"NEW_LINE
"ble_modem_wake"NEW_LINE
"ble_modem_mode bt|bt_wifi"NEW_LINE
"mac_addr"NEW_LINE);
}
return 0;
}
@ -665,6 +968,154 @@ int _exit_remote_access(const shell_cmd_t *pcmd, int argc, char *const argv[])
return 0;
}
int _utils(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "random") == 0)
{
uint32_t random = random_gen_6_digit();
shell_printf("Random 6 digit number is : %u"NEW_LINE, random);
}
}
else
{
shell_printf("List of %s actions :"NEW_LINE
"random"NEW_LINE, argv[0]);
}
return 0;
}
tls_os_task_t task_handle = NULL;
u8 *task_stack = NULL;
#define TASK_STK_SIZE (256)
void task_function(void *param)
{
(void)param;
for(;;)
{
char *notification_data = (char *)ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
shell_printf("%s got notification : #%s#"NEW_LINE, __func__, notification_data);
}
}
void task_free_function(void)
{
task_handle = NULL;
tls_mem_free(task_stack);
task_stack = NULL;
}
int _freertos(const shell_cmd_t *pcmd, int argc, char * const argv[])
{
bool cmd_found = true;
if(argc > 1)
{
if(strcmp(argv[1], "task") == 0)
{
if(argc > 2)
{
if(strcmp(argv[2], "create") == 0)
{
if(task_handle == NULL)
{
task_stack = tls_mem_alloc(TASK_STK_SIZE * sizeof(StackType_t));
if(task_stack)
{
if(tls_os_task_create(&task_handle, "demo_task", &(task_function), NULL, task_stack, TASK_STK_SIZE * sizeof(StackType_t), 62, 0) == TLS_OS_SUCCESS)
{
shell_printf("Task created"NEW_LINE);
}
else
{
shell_printf("Failed to create task"NEW_LINE);
tls_mem_free(task_stack);
}
}
else
{
shell_printf("Failed to allocate task stack"NEW_LINE);
}
}
else
{
shell_printf("Task already created"NEW_LINE);
}
}
else if(strcmp(argv[2], "destroy") == 0)
{
if(task_handle)
{
if(tls_os_task_del_by_task_handle(task_handle, &(task_free_function)) == TLS_OS_SUCCESS)
{
shell_printf("Task deleted"NEW_LINE);
}
else
{
shell_printf("Failed to delete task"NEW_LINE);
}
}
else
{
printf("No task to destroy"NEW_LINE);
}
}
else if(strcmp(argv[2], "notify") == 0)
{
if(argc > 3)
{
if(task_handle)
{
if(xTaskNotify(task_handle, (uint32_t)argv[3], eSetValueWithoutOverwrite) == pdFAIL)
{
shell_printf("Failed to notify task"NEW_LINE);
}
}
else
{
shell_printf("No task to notify"NEW_LINE
"Use: freertos task create, to start the task"NEW_LINE);
}
}
else
{
cmd_found = false;
}
}
else
{
cmd_found = false;
}
}
else
{
cmd_found = false;
}
}
else
{
cmd_found = false;
}
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
cmd_found = false;
}
if(!cmd_found)
{
shell_printf("List of %s actions :"NEW_LINE
"task create"NEW_LINE
"task destroy"NEW_LINE
"task notify \"msg\""NEW_LINE, argv[0]);
}
return 0;
}
NANO_SHELL_ADD_CMD(bus,
_bus,
"Command to interact with the SPI bus",
@ -717,3 +1168,12 @@ NANO_SHELL_ADD_CMD(exit,
_exit_remote_access,
"Disconnect from Nano-Shell remote access",
" Use this command to disconnect from Nano-Shell remote access"NEW_LINE);
NANO_SHELL_ADD_CMD(utils,
_utils,
"Command used to test various utils functions",
" Use this command to try various utility functions out lilke random and more"NEW_LINE);
NANO_SHELL_ADD_CMD(freertos,
_freertos,
"Command to test various FreeRTOS concepts",
" Use this command to interact with various FreeRTOS concepts (tasks, queues, notifications...)"NEW_LINE);

View File

@ -58,6 +58,16 @@ void tls_set_rtc(struct tm *tblock);
*/
void tls_get_rtc(struct tm *tblock);
/** NOT PART OF THE OFFICIAL SDK **/
/**
* @brief Checks if the RTC peripheral is running or not
*
* @return true
* @return false
*/
bool tls_is_rtc_running(void);
/**********************************/
/**
* @brief This function is used to register pmu rtc interrupt
*

View File

@ -772,6 +772,8 @@ tls_os_status_t tls_os_queue_flush(tls_os_queue_t *queue);
*/
void tls_os_time_delay(u32 ticks);
void tls_os_time_delay_until(u32 * const previous_wake_time, const u32 duration_in_ticks);
u8 tls_os_timer_active(tls_os_timer_t *timer);
u32 tls_os_timer_expirytime(tls_os_timer_t *timer);

View File

@ -11,30 +11,47 @@
#define __WM_TYPE_DEF_H__
#include <stdbool.h>
// Defining types under the uX forme.
#ifdef u8
#undef u8
#endif
#ifdef s8
#undef s8
#endif
typedef unsigned char u8;
#ifdef u16
#undef u16
#endif
#ifdef s16
#undef s16
#endif
typedef unsigned short u16;
#ifdef u32
#undef u32
#endif
#ifdef s32
#undef s32
#endif
typedef unsigned int u32;
#ifdef u64
#undef u64
#endif
typedef unsigned long long u64;
// Defining types under the sX forme.
#ifdef s8
#undef s8
#endif
typedef signed char s8;
#ifdef s16
#undef s16
#endif
typedef signed short s16;
#ifdef s32
#undef s32
#endif
typedef signed int s32;
#ifdef s64
#undef s64
#endif
typedef signed long long s64;
#ifdef u_char
#undef u_char
@ -51,16 +68,6 @@ typedef unsigned char INT8U;
#endif
typedef signed char INT8S;
//typedef unsigned char bool;
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
typedef unsigned long long u64;
typedef long long s64;
#if defined(_NEWLIB_VERSION_H__)
#ifdef int32_t
#undef int32_t
@ -78,57 +85,28 @@ typedef int int32_t;
typedef unsigned int uint32_t;
#endif
#ifdef int32
#undef int32
#endif
typedef int int32;
#ifdef uint32
#undef uint32
#endif
typedef unsigned int uint32;
#ifdef int16
#undef int16
#endif
typedef short int16;
#ifdef uint16
#undef uint16
#endif
typedef unsigned short uint16;
#ifdef ULONG
#undef ULONG
#endif
typedef unsigned long ULONG;
// Defining types under the uX_t forme.
#ifdef u8_t
#undef u8_t
#endif
typedef unsigned char u8_t;
#ifdef uint8_t
#undef uint8_t
#endif
typedef unsigned char uint8_t;
#ifdef u16_t
#undef u16_t
#endif
typedef unsigned short u16_t;
#ifdef uint16_t
#undef uint16_t
#endif
typedef unsigned short uint16_t;
#ifdef u32_t
#undef u32_t
#endif
typedef unsigned int u32_t;
#ifdef u64_t
#undef u64_t
#endif
typedef unsigned long long u64_t;
// Defining types under the sX_t forme.
#ifdef s8_t
#undef s8_t
#endif
@ -143,6 +121,103 @@ typedef signed short s16_t;
#undef s32_t
#endif
typedef signed int s32_t;
#ifdef s64_t
#undef s64_t
#endif
typedef signed long long s64_t;
// Defining types under the intX forme.
#ifdef int8
#undef int8
#endif
typedef signed char int8;
#ifdef int16
#undef int16
#endif
typedef signed short int16;
#ifdef int32
#undef int32
#endif
typedef signed int int32;
#ifdef int64
#undef int64
#endif
typedef signed long long int64;
// Defining types under the uintX forme.
#ifdef uint8
#undef uint8
#endif
typedef unsigned char uint8;
#ifdef uint16
#undef uint16
#endif
typedef unsigned short uint16;
#ifdef uint32
#undef uint32
#endif
typedef unsigned int uint32;
#ifdef uint64
#undef uint64
#endif
typedef unsigned long long uint64;
// Defining types under the intX_t forme.
#ifdef int8_t
#undef int8_t
#endif
typedef signed char int8_t;
#ifdef int16_t
#undef int16_t
#endif
typedef signed short int16_t;
#ifdef int32_t
#undef int32_t
#endif
typedef signed int int32_t;
#ifdef int64_t
#undef int64_t
#endif
typedef signed long long int64_t;
// Defining types under the uintX_t forme.
#ifdef uint8_t
#undef uint8_t
#endif
typedef unsigned char uint8_t;
#ifdef uint16_t
#undef uint16_t
#endif
typedef unsigned short uint16_t;
#ifdef uint32_t
#undef uint32_t
#endif
typedef unsigned int uint32_t;
#ifdef uint64_t
#undef uint64_t
#endif
typedef unsigned long long uint64_t;
#ifdef ULONG
#undef ULONG
#endif
typedef unsigned long ULONG;
#if (GCC_COMPILE==0)
#ifdef size_t
#undef size_t
@ -155,7 +230,6 @@ typedef unsigned int size_t;
#endif
typedef signed char err_t;
#ifdef mem_ptr_t
#undef mem_ptr_t
#endif

View File

@ -82,6 +82,15 @@ void tls_get_rtc(struct tm *tblock)
tblock->tm_sec = ctrl1 & 0x0000003f;
}
/** NOT PART OF THE OFFICIAL SDK **/
bool tls_is_rtc_running(void)
{
int ctrl2 = tls_reg_read32(HR_PMU_RTC_CTRL2);
return ctrl2 & (1 << 16) ? true : false;
}
/**********************************/
void PMU_RTC_IRQHandler(void)
{
tls_reg_write32(HR_PMU_INTERRUPT_SRC, BIT(4)); /* clear rtc interrupt */

View File

@ -1173,7 +1173,6 @@ int tls_uart_tx_length(u16 uart_no)
int tls_uart_write(u16 uart_no, char *buf, u16 writesize)
{
return tls_uart_write_async(uart_no, buf, writesize);
}

View File

@ -178,6 +178,23 @@ const char *tls_bt_access_opt_2_str(uint8_t op)
}
}
const char *tls_bt_sm_ioact_2_str(uint8_t ioact)
{
switch(ioact)
{
CASE_RETURN_STR(BLE_SM_IOACT_NONE)
CASE_RETURN_STR(BLE_SM_IOACT_OOB)
CASE_RETURN_STR(BLE_SM_IOACT_INPUT)
CASE_RETURN_STR(BLE_SM_IOACT_DISP)
CASE_RETURN_STR(BLE_SM_IOACT_NUMCMP)
CASE_RETURN_STR(BLE_SM_IOACT_OOB_SC)
CASE_RETURN_STR(BLE_SM_IOACT_MAX_PLUS_ONE)
default:
return "unknown io action type";
}
}
static void async_evt_func(struct ble_npl_event *ev)
{
ble_async_t *bat = (ble_async_t *)ev->arg;

View File

@ -56,6 +56,7 @@ const char *tls_bt_gap_evt_2_str(uint32_t event);
const char *tls_bt_rc_2_str(uint32_t event);
const char *tls_bt_addr_type_2_str(uint8_t addr_type);
const char *tls_bt_access_opt_2_str(uint8_t op);
const char *tls_bt_sm_ioact_2_str(uint8_t ioact);
extern int tls_bt_util_init(void);
extern int tls_bt_util_deinit(void);

View File

@ -61,11 +61,11 @@
#endif
#ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT
#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (24)
#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (10) // Default 24
#endif
#ifndef MYNEWT_VAL_MSYS_1_BLOCK_SIZE
#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292)
#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (150) // Default 292
#endif
#ifndef MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT
@ -425,7 +425,7 @@
/*** @apache-mynewt-nimble/nimble/host */
#ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU
#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (512)
#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) // 512
#endif
#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO
@ -707,7 +707,7 @@
#endif
#ifndef MYNEWT_VAL_BLE_SM_IO_CAP
#define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT)
#define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_DISPLAY_ONLY)// Default (BLE_HS_IO_NO_INPUT_OUTPUT)
#endif
#ifndef MYNEWT_VAL_BLE_SM_KEYPRESS
@ -925,7 +925,7 @@
/*** @apache-mynewt-nimble/nimble/transport/socket */
#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT
#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (36)
#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (15) // Default 36
#endif
#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE
@ -947,11 +947,11 @@
#endif
#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT
#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (16)
#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (10) // Default 16
#endif
#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT
#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (96)
#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (20) // Default 96
#endif
#ifndef MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE

View File

@ -1419,6 +1419,11 @@ u32 tls_os_timer_expirytime(tls_os_timer_t *timer)
vTaskDelay(ticks);
}
void tls_os_time_delay_until(u32 * const previous_wake_time, const u32 duration_in_ticks)
{
vTaskDelayUntil(previous_wake_time, duration_in_ticks);
}
/*
*********************************************************************************************************
* task stat info

View File

@ -59,6 +59,7 @@ $$(IMAGEODIR)/$(1).elf: $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1)) $$(DEPENDS_
@mkdir -p $$(IMAGEODIR)
$(LINK) -Wl,--gc-sections -Wl,-zmax-page-size=1024 -Wl,--whole-archive $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1)) $$(if $$(LINKFLAGS_$(1)),$$(LINKFLAGS_$(1))) -Wl,--no-whole-archive $(LINKFLAGS) $(MAP) -o $$@
$(SIZE) -A -t $(IMAGEODIR)/$(TARGET).elf
$(SIZE) -B $(IMAGEODIR)/$(TARGET).elf
endef
$(BINODIR)/%.bin: $(IMAGEODIR)/%.elf