fix all board compile for v3.0

fix all board compile for v3.0
This commit is contained in:
supowang
2021-08-11 16:30:15 +08:00
parent 1f694e2156
commit 8253a953bd
615 changed files with 96466 additions and 80894 deletions

View File

@@ -1,44 +0,0 @@
#include "tos_k.h"
#define USE_ESP8266
#ifdef USE_LWIP
#include "lwip/api.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#endif
#ifdef USE_ESP8266
#include "esp8266.h"
#endif
void application_entry(void *arg)
{
extern void mqtt_basic_thread(void);
#ifdef USE_LWIP
dns_init();
MX_LWIP_Init();
#endif
#ifdef USE_ESP8266
extern int esp8266_sal_init(hal_uart_port_t uart_port);
extern int esp8266_join_ap(const char *ssid, const char *pwd);
esp8266_sal_init(HAL_UART_PORT_0);
esp8266_join_ap("dcxajichu", "githubdev");
#endif
#ifdef USE_NB_BC35
extern int bc35_28_95_sal_init(hal_uart_port_t uart_port);
bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
mqtt_basic_thread();
while (1) {
printf("This is a mqtt demo!\r\n");
tos_task_delay(1000);
}
}

View File

@@ -1,250 +0,0 @@
#include "dev_sign_api.h"
#include "mqtt_api.h"
char DEMO_PRODUCT_KEY[IOTX_PRODUCT_KEY_LEN + 1] = {0};
char DEMO_DEVICE_NAME[IOTX_DEVICE_NAME_LEN + 1] = {0};
char DEMO_DEVICE_SECRET[IOTX_DEVICE_SECRET_LEN + 1] = {0};
void *HAL_Malloc(uint32_t size);
void HAL_Free(void *ptr);
void HAL_Printf(const char *fmt, ...);
int HAL_GetProductKey(char product_key[IOTX_PRODUCT_KEY_LEN + 1]);
int HAL_GetDeviceName(char device_name[IOTX_DEVICE_NAME_LEN + 1]);
int HAL_GetDeviceSecret(char device_secret[IOTX_DEVICE_SECRET_LEN]);
uint64_t HAL_UptimeMs(void);
int HAL_Snprintf(char *str, const int len, const char *fmt, ...);
#define EXAMPLE_TRACE(fmt, ...) \
do { \
HAL_Printf("%s|%03d :: ", __func__, __LINE__); \
HAL_Printf(fmt, ##__VA_ARGS__); \
HAL_Printf("%s", "\r\n"); \
} while(0)
void example_message_arrive(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
iotx_mqtt_topic_info_t *topic_info = (iotx_mqtt_topic_info_pt) msg->msg;
switch (msg->event_type) {
case IOTX_MQTT_EVENT_PUBLISH_RECEIVED:
/* print topic name and topic message */
EXAMPLE_TRACE("Message Arrived:");
EXAMPLE_TRACE("Topic : %.*s", topic_info->topic_len, topic_info->ptopic);
EXAMPLE_TRACE("Payload: %.*s", topic_info->payload_len, topic_info->payload);
EXAMPLE_TRACE("\n");
break;
default:
break;
}
}
int example_subscribe(void *handle)
{
int res = 0;
const char *fmt = "/%s/%s/user/get";
char *topic = NULL;
int topic_len = 0;
topic_len = strlen(fmt) + strlen(DEMO_PRODUCT_KEY) + strlen(DEMO_DEVICE_NAME) + 1;
topic = HAL_Malloc(topic_len);
if (topic == NULL) {
EXAMPLE_TRACE("memory not enough");
return -1;
}
memset(topic, 0, topic_len);
HAL_Snprintf(topic, topic_len, fmt, DEMO_PRODUCT_KEY, DEMO_DEVICE_NAME);
res = IOT_MQTT_Subscribe(handle, topic, IOTX_MQTT_QOS0, example_message_arrive, NULL);
if (res < 0) {
EXAMPLE_TRACE("subscribe failed");
HAL_Free(topic);
return -1;
}
HAL_Free(topic);
return 0;
}
int example_publish(void *handle)
{
int res = 0;
const char *fmt = "/%s/%s/user/get";
char *topic = NULL;
int topic_len = 0;
char *payload = "{\"message\":\"hello!\"}";
topic_len = strlen(fmt) + strlen(DEMO_PRODUCT_KEY) + strlen(DEMO_DEVICE_NAME) + 1;
topic = HAL_Malloc(topic_len);
if (topic == NULL) {
EXAMPLE_TRACE("memory not enough");
return -1;
}
memset(topic, 0, topic_len);
HAL_Snprintf(topic, topic_len, fmt, DEMO_PRODUCT_KEY, DEMO_DEVICE_NAME);
res = IOT_MQTT_Publish_Simple(0, topic, IOTX_MQTT_QOS0, payload, strlen(payload));
if (res < 0) {
EXAMPLE_TRACE("publish failed, res = %d", res);
HAL_Free(topic);
return -1;
}
HAL_Free(topic);
return 0;
}
void example_event_handle(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
EXAMPLE_TRACE("msg->event_type : %d", msg->event_type);
}
/*
* NOTE: About demo topic of /${productKey}/${deviceName}/user/get
*
* The demo device has been configured in IoT console (https://iot.console.aliyun.com)
* so that its /${productKey}/${deviceName}/user/get can both be subscribed and published
*
* We design this to completely demonstrate publish & subscribe process, in this way
* MQTT client can receive original packet sent by itself
*
* For new devices created by yourself, pub/sub privilege also requires being granted
* to its /${productKey}/${deviceName}/user/get for successfully running whole example
*/
int mqtt_basic_thread(int argc, char *argv[])
{
void *pclient = NULL;
int res = 0;
int loop_cnt = 0;
iotx_mqtt_param_t mqtt_params;
HAL_GetProductKey(DEMO_PRODUCT_KEY);
HAL_GetDeviceName(DEMO_DEVICE_NAME);
HAL_GetDeviceSecret(DEMO_DEVICE_SECRET);
EXAMPLE_TRACE("mqtt example");
/* Initialize MQTT parameter */
/*
* Note:
*
* If you did NOT set value for members of mqtt_params, SDK will use their default values
* If you wish to customize some parameter, just un-comment value assigning expressions below
*
**/
memset(&mqtt_params, 0x0, sizeof(mqtt_params));
/**
*
* MQTT connect hostname string
*
* MQTT server's hostname can be customized here
*
* default value is ${productKey}.iot-as-mqtt.cn-shanghai.aliyuncs.com
*/
/* mqtt_params.host = "something.iot-as-mqtt.cn-shanghai.aliyuncs.com"; */
/**
*
* MQTT connect port number
*
* TCP/TLS port which can be 443 or 1883 or 80 or etc, you can customize it here
*
* default value is 1883 in TCP case, and 443 in TLS case
*/
/* mqtt_params.port = 1883; */
/**
*
* MQTT request timeout interval
*
* MQTT message request timeout for waiting ACK in MQTT Protocol
*
* default value is 2000ms.
*/
/* mqtt_params.request_timeout_ms = 2000; */
/**
*
* MQTT clean session flag
*
* If CleanSession is set to 0, the Server MUST resume communications with the Client based on state from
* the current Session (as identified by the Client identifier).
*
* If CleanSession is set to 1, the Client and Server MUST discard any previous Session and Start a new one.
*
* default value is 0.
*/
/* mqtt_params.clean_session = 0; */
/**
*
* MQTT keepAlive interval
*
* KeepAlive is the maximum time interval that is permitted to elapse between the point at which
* the Client finishes transmitting one Control Packet and the point it starts sending the next.
*
* default value is 60000.
*/
/* mqtt_params.keepalive_interval_ms = 60000; */
/**
*
* MQTT write buffer size
*
* Write buffer is allocated to place upstream MQTT messages, MQTT client will be limitted
* to send packet no longer than this to Cloud
*
* default value is 1024.
*
*/
/* mqtt_params.write_buf_size = 1024; */
/**
*
* MQTT read buffer size
*
* Write buffer is allocated to place downstream MQTT messages, MQTT client will be limitted
* to recv packet no longer than this from Cloud
*
* default value is 1024.
*
*/
/* mqtt_params.read_buf_size = 1024; */
/**
*
* MQTT event callback function
*
* Event callback function will be called by SDK when it want to notify user what is happening inside itself
*
* default value is NULL, which means PUB/SUB event won't be exposed.
*
*/
mqtt_params.handle_event.h_fp = example_event_handle;
pclient = IOT_MQTT_Construct(&mqtt_params);
if (NULL == pclient) {
EXAMPLE_TRACE("MQTT construct failed");
return -1;
}
res = example_subscribe(pclient);
if (res < 0) {
IOT_MQTT_Destroy(&pclient);
return -1;
}
while (1) {
if (0 == loop_cnt % 20) {
example_publish(pclient);
}
IOT_MQTT_Yield(pclient, 200);
loop_cnt += 1;
}
return 0;
}

View File

@@ -1,405 +0,0 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#ifndef _TOS_AT_EVTDRV_H_
#define _TOS_AT_EVTDRV_H_
#include "tos_evtdrv.h"
#include "tos_at_utils_evtdrv.h"
#include "tos_hal.h"
#define AT_AGENT_ECHO_OK "OK"
#define AT_AGENT_ECHO_FAIL "FAIL"
#define AT_AGENT_ECHO_ERROR "ERROR"
#define AT_DATA_CHANNEL_NUM 6
#define AT_DATA_CHANNEL_FIFO_BUFFER_SIZE (2048 + 1024)
#define AT_UART_RX_FIFO_BUFFER_SIZE (2048 + 1024)
#define AT_RECV_CACHE_SIZE 2048
#define AT_CMD_BUFFER_SIZE 512
#define AT_PARSER_TASK_STACK_SIZE 2048
#define AT_PARSER_TASK_PRIO 2
#define EVENT_AT_UART_INCOMING (1u << 0)
#define EVENT_AT_PARSE_STATUS_OVERFLOW (1u << 1)
#define EVENT_AT_PARSE_STATUS_EVENT (1u << 2)
#define EVENT_AT_PARSE_STATUS_EXPECT (1U << 3)
#define EVENT_AT_PARSE_STATUS_NEWLINE (1U << 4)
typedef enum at_status_en {
AT_STATUS_OK,
AT_STATUS_ERROR,
AT_STATUS_INVALID_ARGS,
} at_status_t;
typedef struct at_cache_st {
uint8_t *buffer;
size_t buffer_size;
size_t recv_len;
size_t curr_len;
size_t last_data;
} at_cache_t;
typedef enum at_parse_status_en {
AT_PARSE_STATUS_NONE,
AT_PARSE_STATUS_NEWLINE,
AT_PARSE_STATUS_EVENT,
AT_PARSE_STATUS_EXPECT,
AT_PARSE_STATUS_OVERFLOW,
} at_parse_status_t;
typedef enum at_echo_status_en {
AT_ECHO_STATUS_NONE,
AT_ECHO_STATUS_OK,
AT_ECHO_STATUS_FAIL,
AT_ECHO_STATUS_ERROR,
AT_ECHO_STATUS_EXPECT,
} at_echo_status_t;
typedef enum at_channel_status_en {
AT_CHANNEL_STATUS_NONE, /*< usually means we are try to get a channel status with invalid id */
AT_CHANNEL_STATUS_HANGING, /*< channel is not used */
AT_CHANNEL_STATUS_WORKING, /*< channel is being using */
AT_CHANNEL_STATUS_BROKEN, /*< channel is broken(module link to remote server is broken) */
} at_channel_status_t;
typedef struct at_data_channel_st {
uint8_t is_free;
k_chr_fifo_t rx_fifo;
uint8_t *rx_fifo_buffer;
at_channel_status_t status;
const char *remote_ip;
const char *remote_port;
} at_data_channel_t;
typedef struct at_echo_st {
char *buffer;
size_t buffer_size;
char *echo_expect;
evtdrv_task_id_t module_task_id;
evtdrv_event_flag_t event_flags;
int line_num;
at_echo_status_t status;
size_t __w_idx;
evtdrv_event_flag_t __expect_event;
} at_echo_t;
typedef void (*at_event_callback_t)(void);
typedef struct at_event_st {
const char *event_header;
at_event_callback_t event_callback;
} at_event_t;
typedef struct at_agent_st {
evtdrv_task_id_t at_task_id;
at_data_channel_t data_channel[AT_DATA_CHANNEL_NUM];
at_event_t *event_table;
size_t event_table_size;
at_echo_t *echo;
at_cache_t recv_cache;
at_timer_t timer;
char *cmd_buf;
hal_uart_t uart;
k_chr_fifo_t uart_rx_fifo;
uint8_t *uart_rx_fifo_buffer;
} at_agent_t;
#define AT_AGENT ((at_agent_t *)(&at_agent))
/**
* @brief Write data to a channel.
* Write data to a channel with certain id.
*
* @attention None
*
* @param[in] channel_id id of the channel.
* @param[in] buffer data buffer to write.
* @param[in] buffer_len length of the buffer.
*
* @return errcode
* @retval -1 write failed(error).
* @retval none -1 the number of bytes written.
*/
int tos_at_channel_write(int channel_id, uint8_t *buffer, size_t buffer_len);
/**
* @brief Read data from a channel.
* Read data from a channel with a timeout.
*
* @attention None
*
* @param[in] channel_id id of the channel.
* @param[out] buffer buffer to hold the data read.
* @param[in] buffer_len length of the buffer.
* @param[in] timeout timeout.
*
* @return errcode
* @retval -1 read failed(error).
* @retval none -1 the number of bytes read.
*/
int tos_at_channel_read_timed(int channel_id, uint8_t *buffer, size_t buffer_len, uint32_t timeout);
/**
* @brief Read data from a channel.
* Read data from a channel.
*
* @attention None
*
* @param[in] channel_id id of the channel.
* @param[out] buffer buffer to hold the data read.
* @param[in] buffer_len length of the buffer.
*
* @return errcode
* @retval -1 read failed(error).
* @retval none -1 the number of bytes read.
*/
int tos_at_channel_read(int channel_id, uint8_t *buffer, size_t buffer_len);
/**
* @brief Allocate a channel.
* Allocate a channel with certain id.
*
* @attention None
*
* @param[in] channel_id id of the channel.
* @param[in] ip remote ip of the channel.
* @param[in] port remote port of the channel.
*
* @return errcode
* @retval -1 allocate failed(error).
* @retval none -1 the id of the channel.
*/
int tos_at_channel_alloc_id(int channel_id, const char *ip, const char *port);
/**
* @brief Allocate a channel.
* Allocate a channel.
*
* @attention None
*
* @param[in] ip remote ip of the channel.
* @param[in] port remote port of the channel.
*
* @return errcode
* @retval -1 allocate failed(error).
* @retval none -1 the id of the channel.
*/
int tos_at_channel_alloc(const char *ip, const char *port);
/**
* @brief Free a channel.
* Free a channel with certain id.
*
* @attention None
*
* @param[in] channel_id id of the channel.
*
* @return errcode
* @retval -1 free failed(error).
* @retval 0 free successfully.
*/
int tos_at_channel_free(int channel_id);
/**
* @brief Set channel broken.
*
* @attention None
*
* @param[in] channel_id id of the channel.
*
* @return errcode
* @retval -1 set failed(error).
* @retval 0 set successfully.
*/
__API__ int tos_at_channel_set_broken(int channel_id);
/**
* @brief Judge whether channel is working.
*
* @attention None
*
* @param[in] channel_id id of the channel.
*
* @return at channel status(type of at_channel_status_t)
*/
__API__ int tos_at_channel_is_working(int channel_id);
/**
* @brief Initialize the at framework.
*
* @attention None
*
* @param[in] uart_port port number of the uart thougth which the module connect to the MCU.
* @param[in] event_table the listened event table.
* @param[in] event_table_size the size of the listened event table.
*
* @return errcode
* @retval -1 initialize failed(error).
* @retval 0 initialize successfully.
*/
__API__ int tos_at_init(hal_uart_port_t uart_port, evtdrv_task_id_t at_task_id, at_event_t *event_table, size_t event_table_size);
/**
* @brief De-initialize the at framework.
*
* @attention None
*
* @return
None
*/
void tos_at_deinit(void);
/**
* @brief Create a echo struct.
*
* @attention None
*
* @param[in] echo pointer to the echo struct.
* @param[out] buffer buffer to hold the received message from the module.
* @param[in] buffer_size size of the buffer.
* @param[in] echo_expect the expected echo message.
*
* @return errcode
* @retval -1 create failed(error).
* @retval 0 create successfully.
*/
int tos_at_echo_create(at_echo_t *echo, char *buffer, size_t buffer_size, char *echo_expect, evtdrv_task_id_t module_task_id, evtdrv_event_flag_t event_flags);
/**
* @brief Execute an at command.
*
* @attention None
*
* @param[in] echo pointer to the echo struct.
* @param[in] timeout command wait timeout .
* @param[in] cmd at command.
*
* @return errcode
* @retval -1 execute failed(error).
* @retval 0 execute successfully.
*/
int tos_at_cmd_exec(at_echo_t *echo, uint32_t timeout, const char *cmd, ...);
/**
* @brief Send raw data througth uart.
*
* @attention None
*
* @param[in] echo pointer to the echo struct.
* @param[in] timeout command wait timeout .
* @param[in] buf data to send.
* @param[in] size size of the buf.
*
* @return errcode
* @retval -1 execute failed(error).
* @retval 0 execute successfully.
*/
int tos_at_raw_data_send(at_echo_t *echo, uint32_t timeout, const uint8_t *buf, size_t size);
/**
* @brief Write byte to the at uart.
* The function called by the uart interrupt, to put the data from the uart to the at framework.
*
* @attention None
*
* @param[in] data uart received data.
*
* @return None
*/
void tos_at_uart_input_byte(uint8_t data);
/**
* @brief Read data from the uart.
* Read data from the uart, usually called in listened event callback.
*
* @attention None
*
* @param[out] buffer buffer to hold the data read from the uart.
* @param[in] buffer_len length of the buffer.
*
* @return length of the data read from the uart.
*/
int tos_at_uart_read(uint8_t *buffer, size_t buffer_len);
/**
* @brief Read data from the uart.
* Read data from the uart until meet a '\n', usually called in listened event callback.
*
* @attention None
*
* @param[out] buffer buffer to hold the data read from the uart.
* @param[in] buffer_len length of the buffer.
*
* @return length of the data read from the uart.
*/
int tos_at_uart_readline(uint8_t *buffer, size_t buffer_len);
/**
* @brief Read data from the uart.
* Read data from the uart until no more incoming data, usually called in listened event callback.
*
* @attention None
*
* @param[out] buffer buffer to hold the data read from the uart.
* @param[in] buffer_len length of the buffer.
*
* @return length of the data read from the uart.
*/
int tos_at_uart_drain(uint8_t *buffer, size_t buffer_len);
/**
* @brief Get the remote ip of a channel.
* Get the remote ip of a channel with certain id.
*
* @attention None
*
* @param[in] channel_id id of the channel.
*
* @return remote ip of the channel.
*/
const char *tos_at_agent_channel_ip_get(int channel_id);
/**
* @brief Get the remote port of a channel.
* Get the remote port of a channel with certain id.
*
* @attention None
*
* @param[in] channel_id id of the channel.
*
* @return remote port of the channel.
*/
const char *tos_at_agent_channel_port_get(int channel_id);
evtdrv_event_flag_t tos_at_evtdrv_task(evtdrv_event_flag_t event);
#endif /* _TOS_AT_EVTDRV_H_ */

View File

@@ -1,23 +0,0 @@
#ifndef _TOS_AT_UTILS_EVTDRV_H_
#define _TOS_AT_UTILS_EVTDRV_H_
typedef struct at_timer_st {
evtdrv_tick_t end_time;
} at_timer_t;
void at_delay(evtdrv_tick_t tick);
void at_delay_ms(uint32_t millisec);
int at_timer_is_expired(at_timer_t *tmr);
void at_timer_countdown(at_timer_t *tmr, evtdrv_tick_t tick);
void at_timer_countdown_ms(at_timer_t *tmr, uint32_t millisec);
evtdrv_tick_t at_timer_remain(at_timer_t *tmr);
void at_timer_init(at_timer_t *tmr);
#endif//_TOS_AT_UTILS_EVTDRV_H_

View File

@@ -1,756 +0,0 @@
#include "tos_at_evtdrv.h"
__STATIC__ at_agent_t at_agent;
__STATIC__ int at_uart_getchar(uint8_t *data, k_tick_t timeout)
{
k_err_t err;
at_delay(1);
err = tos_chr_fifo_pop(&AT_AGENT->uart_rx_fifo, data);
return err == K_ERR_NONE ? 0 : -1;
}
__STATIC__ at_event_t *at_event_do_get(char *buffer, size_t buffer_len)
{
int i = 0;
at_event_t *event_table = K_NULL, *event = K_NULL;
size_t event_table_size = 0, event_len;
event_table = AT_AGENT->event_table;
event_table_size = AT_AGENT->event_table_size;
for (i = 0; i < event_table_size; ++i) {
event = &event_table[i];
event_len = strlen(event->event_header);
if (buffer_len < event_len) {
continue;
}
if (strncmp(event->event_header, buffer, event_len) == 0) {
return event;
}
}
return K_NULL;
}
__STATIC__ at_event_t *at_get_event(void)
{
char *buffer;
size_t buffer_len;
at_cache_t *at_cache = K_NULL;
at_cache = &AT_AGENT->recv_cache;
buffer = (char *)at_cache->buffer;
buffer_len = at_cache->recv_len;
return at_event_do_get(buffer, buffer_len);
}
__API__ int tos_at_uart_read(uint8_t *buffer, size_t buffer_len)
{
uint8_t data;
size_t read_len = 0;
while (K_TRUE) {
if (at_uart_getchar(&data, TOS_TIME_FOREVER) != 0) {
return read_len;
}
buffer[read_len++] = data;
if (read_len == buffer_len) {
return buffer_len;
}
}
}
__API__ int tos_at_uart_readline(uint8_t *buffer, size_t buffer_len)
{
uint8_t data;
size_t read_len = 0;
while (K_TRUE) {
if (at_uart_getchar(&data, TOS_TIME_FOREVER) != 0) {
return read_len;
}
buffer[read_len++] = data;
if (data == '\n') {
return read_len;
} else if (read_len == buffer_len) {
return buffer_len;
}
}
}
__API__ int tos_at_uart_drain(uint8_t *buffer, size_t buffer_len)
{
uint8_t data;
size_t read_len = 0;
while (K_TRUE) {
if (at_uart_getchar(&data, TOS_TIME_NOWAIT) != 0) {
return read_len;
}
buffer[read_len++] = data;
if (read_len == buffer_len) {
return buffer_len;
}
}
}
__STATIC__ int at_is_echo_expect(void)
{
char *recv_buffer, *expect;
size_t recv_buffer_len, expect_len;
at_echo_t *at_echo = K_NULL;
at_cache_t *at_cache = K_NULL;
at_echo = AT_AGENT->echo;
if (!at_echo || !at_echo->echo_expect) {
return 0;
}
at_cache = &AT_AGENT->recv_cache;
recv_buffer = (char *)at_cache->buffer;
recv_buffer_len = at_cache->recv_len;
expect = at_echo->echo_expect;
expect_len = strlen(expect);
if (recv_buffer_len < expect_len) {
return 0;
}
if (strncmp(expect, recv_buffer, expect_len) == 0) {
return 1;
}
return 0;
}
__STATIC__ void at_echo_buffer_copy(at_cache_t *at_cache, at_echo_t *echo)
{
uint8_t *recv_buffer = K_NULL;
size_t recv_buffer_len, copy_len, remain_len;
recv_buffer = at_cache->buffer;
recv_buffer_len = at_cache->recv_len;
remain_len = echo->buffer_size - echo->__w_idx;
if (remain_len == 0) {
return;
}
copy_len = remain_len < recv_buffer_len ? remain_len : recv_buffer_len;
memcpy(echo->buffer + echo->__w_idx, recv_buffer, copy_len);
echo->__w_idx += copy_len;
++echo->line_num;
}
__STATIC__ int at_uart_send(const uint8_t *buf, size_t size, uint32_t timeout)
{
return tos_hal_uart_write(&AT_AGENT->uart, buf, size, timeout);
}
__API__ int tos_at_echo_create(at_echo_t *echo, char *buffer, size_t buffer_size, char *echo_expect, evtdrv_task_id_t module_task_id, evtdrv_event_flag_t event_flags)
{
if (!echo) {
return -1;
}
if (buffer) {
memset(buffer, 0, buffer_size);
}
echo->buffer = buffer;
echo->buffer_size = buffer_size;
echo->echo_expect = echo_expect;
echo->module_task_id = module_task_id;
echo->event_flags = event_flags;
echo->line_num = 0;
echo->status = AT_ECHO_STATUS_NONE;
echo->__w_idx = 0;
return 0;
}
__STATIC_INLINE__ void at_echo_flush(at_echo_t *echo)
{
echo->line_num = 0;
echo->status = AT_ECHO_STATUS_NONE;
echo->__w_idx = 0;
}
__STATIC_INLINE void at_echo_attach(at_echo_t *echo)
{
at_echo_flush(echo);
AT_AGENT->echo = echo;
}
__API__ int tos_at_raw_data_send(at_echo_t *echo, uint32_t timeout, const uint8_t *buf, size_t size)
{
int ret = 0;
if (echo) {
at_echo_attach(echo);
}
ret = at_uart_send(buf, size, 0xFFFF);
return ret;
}
__STATIC__ int at_cmd_do_exec(const char *format, va_list args)
{
size_t cmd_len = 0;
cmd_len = vsnprintf(AT_AGENT->cmd_buf, AT_CMD_BUFFER_SIZE, format, args);
printf("AT CMD:\n%s\n", AT_AGENT->cmd_buf);
at_uart_send((uint8_t *)AT_AGENT->cmd_buf, cmd_len, 0xFFFF);
return 0;
}
__API__ int tos_at_cmd_exec(at_echo_t *echo, uint32_t timeout, const char *cmd, ...)
{
int ret = 0;
va_list args;
if (echo) {
at_echo_attach(echo);
}
va_start(args, cmd);
ret = at_cmd_do_exec(cmd, args);
va_end(args);
if (ret != 0) {
AT_AGENT->echo = K_NULL;
return -1;
}
return 0;
}
__STATIC__ int at_recv_cache_init(void)
{
uint8_t *buffer = K_NULL;
buffer = tos_mmheap_alloc(AT_RECV_CACHE_SIZE);
if (!buffer) {
AT_AGENT->recv_cache.buffer = K_NULL;
return - 1;
}
AT_AGENT->recv_cache.buffer = buffer;
AT_AGENT->recv_cache.buffer_size = AT_RECV_CACHE_SIZE;
AT_AGENT->recv_cache.recv_len = 0;
return 0;
}
__STATIC__ void at_recv_cache_deinit(void)
{
uint8_t *buffer = K_NULL;
buffer = AT_AGENT->recv_cache.buffer;
if (buffer) {
tos_mmheap_free(buffer);
}
AT_AGENT->recv_cache.buffer = K_NULL;
AT_AGENT->recv_cache.buffer_size = 0;
AT_AGENT->recv_cache.recv_len = 0;
}
__STATIC__ at_data_channel_t *at_channel_get(int channel_id, int is_alloc)
{
/*
if is_alloc is K_TRUE, means we are allocating a channel with certain id,
data_channel[channel_id] must be free if return none K_NULL.
otherwise if is_alloc is K_FALSE, means we are trying to get a channel with
certain id, data_channel[channel_id] must be not free if return none K_NULL.
*/
at_data_channel_t *data_channel = K_NULL;
if (channel_id < 0 || channel_id >= AT_DATA_CHANNEL_NUM) {
return K_NULL;
}
data_channel = &AT_AGENT->data_channel[channel_id];
if (is_alloc && data_channel->is_free) {
return data_channel;
}
if (!is_alloc && !data_channel->is_free) {
return data_channel;
}
return K_NULL;
}
__API__ int tos_at_channel_read(int channel_id, uint8_t *buffer, size_t buffer_len)
{
int read_len;
size_t total_read_len = 0;
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
if (!data_channel || data_channel->status == AT_CHANNEL_STATUS_BROKEN) {
return -1;
}
while (K_TRUE) {
read_len = tos_chr_fifo_pop_stream(&data_channel->rx_fifo, buffer, buffer_len);
total_read_len += read_len;
if (total_read_len < buffer_len) {
continue;
} else {
return buffer_len;
}
}
}
__API__ int tos_at_channel_read_timed(int channel_id, uint8_t *buffer, size_t buffer_len, uint32_t timeout)
{
int read_len = 0;
size_t total_read_len = 0;
k_tick_t tick, remain_tick;
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
if (!data_channel || data_channel->status == AT_CHANNEL_STATUS_BROKEN) {
return -1;
}
tick = tos_millisec2tick(timeout);
at_timer_countdown(&AT_AGENT->timer, tick);
while (!at_timer_is_expired(&AT_AGENT->timer)) {
remain_tick = at_timer_remain(&AT_AGENT->timer);
if (remain_tick == (k_tick_t)0u) {
return total_read_len;
}
read_len = tos_chr_fifo_pop_stream(&data_channel->rx_fifo, buffer + read_len, buffer_len - total_read_len);
total_read_len += read_len;
if (total_read_len < buffer_len) {
continue;
} else {
return buffer_len;
}
}
return total_read_len;
}
__API__ int tos_at_channel_write(int channel_id, uint8_t *buffer, size_t buffer_len)
{
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
if (!data_channel) {
return -1;
}
return tos_chr_fifo_push_stream(&data_channel->rx_fifo, buffer, buffer_len);
}
__STATIC_INLINE__ int at_channel_construct(at_data_channel_t *data_channel, const char *ip, const char *port)
{
uint8_t *fifo_buffer = K_NULL;
fifo_buffer = tos_mmheap_alloc(AT_DATA_CHANNEL_FIFO_BUFFER_SIZE);
if (!fifo_buffer) {
return -1;
}
data_channel->rx_fifo_buffer = fifo_buffer;
tos_chr_fifo_create(&data_channel->rx_fifo, fifo_buffer, AT_DATA_CHANNEL_FIFO_BUFFER_SIZE);
data_channel->remote_ip = ip;
data_channel->remote_port = port;
data_channel->is_free = K_FALSE;
data_channel->status = AT_CHANNEL_STATUS_WORKING;
return 0;
}
__API__ int tos_at_channel_alloc_id(int channel_id, const char *ip, const char *port)
{
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_TRUE);
if (!data_channel) {
return -1;
}
if (at_channel_construct(data_channel, ip, port) != 0) {
return -1;
}
return channel_id;
}
__API__ int tos_at_channel_alloc(const char *ip, const char *port)
{
int id = 0;
at_data_channel_t *data_channel = K_NULL;
for (id = 0; id < AT_DATA_CHANNEL_NUM; ++id) {
data_channel = &AT_AGENT->data_channel[id];
if (data_channel->is_free) {
break;
}
}
if (id == AT_DATA_CHANNEL_NUM || !data_channel) {
return -1;
}
if (at_channel_construct(data_channel, ip, port) != 0) {
return -1;
}
return id;
}
__API__ int tos_at_channel_free(int channel_id)
{
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
if (!data_channel) {
return -1;
}
tos_mmheap_free(data_channel->rx_fifo_buffer);
tos_chr_fifo_destroy(&data_channel->rx_fifo);
memset(data_channel, 0, sizeof(at_data_channel_t));
data_channel->is_free = K_TRUE;
data_channel->status = AT_CHANNEL_STATUS_HANGING;
return 0;
}
__API__ int tos_at_channel_set_broken(int channel_id)
{
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
if (!data_channel) {
return -1;
}
data_channel->status = AT_CHANNEL_STATUS_BROKEN;
return 0;
}
__API__ int tos_at_channel_is_working(int channel_id)
{
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
return data_channel && data_channel->status == AT_CHANNEL_STATUS_WORKING;
}
__STATIC__ void at_channel_init(void)
{
int i = 0;
for (i = 0; i < AT_DATA_CHANNEL_NUM; ++i) {
memset(&AT_AGENT->data_channel[i], 0, sizeof(at_data_channel_t));
AT_AGENT->data_channel[i].is_free = K_TRUE;
AT_AGENT->data_channel[i].status = AT_CHANNEL_STATUS_HANGING;
}
}
__STATIC__ void at_channel_deinit(void)
{
int i = 0;
for (i = 0; i < AT_DATA_CHANNEL_NUM; ++i) {
tos_at_channel_free(i);
}
}
__API__ const char *tos_at_channel_ip_get(int channel_id)
{
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
if (!data_channel) {
return K_NULL;
}
return data_channel[channel_id].remote_ip;
}
__API__ const char *tos_at_channel_port_get(int channel_id)
{
at_data_channel_t *data_channel = K_NULL;
data_channel = at_channel_get(channel_id, K_FALSE);
if (!data_channel) {
return K_NULL;
}
return data_channel[channel_id].remote_port;
}
__STATIC__ void at_event_table_set(at_event_t *event_table, size_t event_table_size)
{
AT_AGENT->event_table = event_table;
AT_AGENT->event_table_size = event_table_size;
}
__API__ int tos_at_init(hal_uart_port_t uart_port, evtdrv_task_id_t at_task_id, at_event_t *event_table, size_t event_table_size)
{
void *buffer = K_NULL;
memset(AT_AGENT, 0, sizeof(at_agent_t));
AT_AGENT->at_task_id = at_task_id;
at_event_table_set(event_table, event_table_size);
at_channel_init();
at_timer_init(&AT_AGENT->timer);
buffer = tos_mmheap_alloc(AT_UART_RX_FIFO_BUFFER_SIZE);
if (!buffer) {
return -1;
}
AT_AGENT->uart_rx_fifo_buffer = (uint8_t *)buffer;
tos_chr_fifo_create(&AT_AGENT->uart_rx_fifo, (uint8_t *)buffer, AT_UART_RX_FIFO_BUFFER_SIZE);
buffer = tos_mmheap_alloc(AT_CMD_BUFFER_SIZE);
if (!buffer) {
goto errout0;
}
AT_AGENT->cmd_buf = (char *)buffer;
if (at_recv_cache_init() != 0) {
goto errout1;
}
if (tos_hal_uart_init(&AT_AGENT->uart, uart_port) != 0) {
goto errout2;
}
return 0;
errout2:
at_recv_cache_deinit();
errout1:
tos_mmheap_free(AT_AGENT->cmd_buf);
AT_AGENT->cmd_buf = K_NULL;
errout0:
tos_mmheap_free(AT_AGENT->uart_rx_fifo_buffer);
AT_AGENT->uart_rx_fifo_buffer = K_NULL;
tos_chr_fifo_destroy(&AT_AGENT->uart_rx_fifo);
return -1;
}
__API__ void tos_at_deinit(void)
{
tos_hal_uart_deinit(&AT_AGENT->uart);
at_recv_cache_deinit();
tos_mmheap_free(AT_AGENT->cmd_buf);
AT_AGENT->cmd_buf = K_NULL;
tos_mmheap_free(AT_AGENT->uart_rx_fifo_buffer);
AT_AGENT->uart_rx_fifo_buffer = K_NULL;
tos_chr_fifo_destroy(&AT_AGENT->uart_rx_fifo);
at_channel_deinit();
}
/* To completely decouple the uart intterupt and at agent, we need a more powerful
hal(driver framework), that would be a huge work, we place it in future plans. */
__API__ void tos_at_uart_input_byte(uint8_t data)
{
if (tos_chr_fifo_push(&AT_AGENT->uart_rx_fifo, data) == K_ERR_NONE) {
tos_evtdrv_event_set(AT_AGENT->at_task_id, EVENT_AT_UART_INCOMING);
}
}
__STATIC__ void at_echo_event_emit(at_echo_t *echo)
{
tos_evtdrv_event_set(echo->module_task_id, echo->event_flags);
}
__STATIC__ void at_echo_status_set(at_echo_t *echo)
{
char *buffer;
at_cache_t *at_cache;
at_cache = &AT_AGENT->recv_cache;
buffer = (char *)at_cache->buffer;
if (strstr(buffer, AT_AGENT_ECHO_OK) != K_NULL) {
echo->status = AT_ECHO_STATUS_OK;
} else if (strstr(buffer, AT_AGENT_ECHO_ERROR) != K_NULL) {
echo->status = AT_ECHO_STATUS_ERROR;
} else if (strstr(buffer, AT_AGENT_ECHO_FAIL) != K_NULL) {
echo->status = AT_ECHO_STATUS_FAIL;
}
}
__STATIC__ void at_recv_cache_reset(void)
{
at_cache_t *recv_cache = K_NULL;
recv_cache = &AT_AGENT->recv_cache;
recv_cache->recv_len = 0;
recv_cache->curr_len = 0;
recv_cache->last_data = 0;
memset(recv_cache->buffer, 0, recv_cache->buffer_size);
}
evtdrv_event_flag_t tos_at_evtdrv_task(evtdrv_event_flag_t event)
{
at_echo_t *at_echo = K_NULL;
at_event_t *at_event = K_NULL;
at_cache_t *recv_cache = K_NULL;
recv_cache = &AT_AGENT->recv_cache;
if (event & TOS_EVTDRV_SYS_EVENT_INIT) {
at_recv_cache_reset();
return TOS_EVTDRV_SYS_EVENT_INIT;
}
if (event & TOS_EVTDRV_SYS_EVENT_MSG) {
return TOS_EVTDRV_SYS_EVENT_MSG;
}
if (event & EVENT_AT_PARSE_STATUS_OVERFLOW) {
// TODO: fix me
at_recv_cache_reset();
return EVENT_AT_PARSE_STATUS_OVERFLOW;
}
if (event & EVENT_AT_PARSE_STATUS_EVENT) {
at_event = at_get_event();
if (at_event && at_event->event_callback) {
at_event->event_callback();
}
at_recv_cache_reset();
return EVENT_AT_PARSE_STATUS_EVENT;
}
if (event & EVENT_AT_PARSE_STATUS_EXPECT ||
event & EVENT_AT_PARSE_STATUS_NEWLINE) {
printf("--->%s\n", recv_cache->buffer);
at_echo = AT_AGENT->echo;
if (!at_echo) {
at_recv_cache_reset();
return event & EVENT_AT_PARSE_STATUS_EXPECT ?
EVENT_AT_PARSE_STATUS_EXPECT : EVENT_AT_PARSE_STATUS_NEWLINE;
}
if (at_echo->status == AT_ECHO_STATUS_NONE) {
if (event & EVENT_AT_PARSE_STATUS_EXPECT) {
at_echo->status = AT_ECHO_STATUS_EXPECT;
} else if (event & EVENT_AT_PARSE_STATUS_NEWLINE) {
at_echo_status_set(at_echo);
}
if (at_echo->status != AT_ECHO_STATUS_NONE) {
at_echo_event_emit(at_echo);
}
}
if (at_echo->buffer) {
at_echo_buffer_copy(recv_cache, at_echo);
}
at_recv_cache_reset();
return event & EVENT_AT_PARSE_STATUS_EXPECT ?
EVENT_AT_PARSE_STATUS_EXPECT : EVENT_AT_PARSE_STATUS_NEWLINE;
}
if (event & EVENT_AT_UART_INCOMING) {
uint8_t data;
if (at_uart_getchar(&data, TOS_TIME_FOREVER) != 0) {
return EVENT_AT_UART_INCOMING;
}
if (data == '\0') {
return EVENT_AT_UART_INCOMING;
}
if (recv_cache->curr_len < recv_cache->buffer_size) {
recv_cache->buffer[recv_cache->curr_len++] = data;
recv_cache->recv_len = recv_cache->curr_len;
} else {
recv_cache->buffer[recv_cache->buffer_size - 1] = '\0';
tos_evtdrv_event_set(AT_AGENT->at_task_id, EVENT_AT_PARSE_STATUS_OVERFLOW);
return EVENT_AT_UART_INCOMING;
}
if (at_get_event() != K_NULL) {
tos_evtdrv_event_set(AT_AGENT->at_task_id, EVENT_AT_PARSE_STATUS_EVENT);
return EVENT_AT_UART_INCOMING;
}
if (at_is_echo_expect()) {
tos_evtdrv_event_set(AT_AGENT->at_task_id, EVENT_AT_PARSE_STATUS_EXPECT);
return EVENT_AT_UART_INCOMING;
}
if (data == '\n' && recv_cache->last_data == '\r') { // 0xd 0xa
recv_cache->curr_len -= 1;
recv_cache->buffer[recv_cache->curr_len - 1] = '\n';
recv_cache->recv_len = recv_cache->curr_len;
if (recv_cache->curr_len == 1) { // only a blank newline, ignore
recv_cache->last_data = 0;
recv_cache->curr_len = 0;
recv_cache->recv_len = 0;
tos_evtdrv_event_set(AT_AGENT->at_task_id, EVENT_AT_PARSE_STATUS_NEWLINE);
return EVENT_AT_UART_INCOMING;
}
tos_evtdrv_event_set(AT_AGENT->at_task_id, EVENT_AT_PARSE_STATUS_NEWLINE);
return EVENT_AT_UART_INCOMING;
}
recv_cache->last_data = data;
return EVENT_AT_UART_INCOMING;
}
return TOS_EVTDRV_EVENT_NONE;
}

View File

@@ -1,79 +0,0 @@
#include "tos_evtdrv.h"
#include "tos_at_evtdrv.h"
void at_delay(evtdrv_tick_t tick)
{
evtdrv_tick_t now;
now = tos_evtdrv_systick_get();
while ((tos_evtdrv_systick_get() - now) < tick) {
;
}
}
void at_delay_ms(uint32_t millisec)
{
evtdrv_tick_t tick;
tick = tos_evtdrv_millisec2tick(millisec);
at_delay(tick);
}
int at_timer_is_expired(at_timer_t *tmr)
{
evtdrv_tick_t now;
if (!tmr) {
return -1;
}
now = tos_evtdrv_systick_get();
return now >= tmr->end_time;
}
void at_timer_countdown(at_timer_t *tmr, evtdrv_tick_t tick)
{
evtdrv_tick_t now;
if (!tmr) {
return;
}
now = tos_evtdrv_systick_get();
tmr->end_time = now + tick;
}
void at_timer_countdown_ms(at_timer_t *tmr, uint32_t millisec)
{
evtdrv_tick_t expire;
if (!tmr) {
return;
}
expire = tos_millisec2tick(millisec);
at_timer_countdown(tmr, expire);
}
evtdrv_tick_t at_timer_remain(at_timer_t *tmr)
{
evtdrv_tick_t now;
now = tos_evtdrv_systick_get();
if (at_timer_is_expired(tmr)) {
return (evtdrv_tick_t)0u;
}
return tmr->end_time - now;
}
void at_timer_init(at_timer_t *tmr)
{
if (!tmr) {
return;
}
tmr->end_time = 0;
}

View File

@@ -1,687 +0,0 @@
#include "tos_at_evtdrv.h"
#include "esp8266_evtdrv.h"
#include "sal_module_wrapper.h"
#include "stdio.h"
#include "stdbool.h"
#include "ctype.h"
typedef struct esp8266_send_info_st {
int sockid;
void *buf;
size_t len;
} esp8266_send_info_t;
typedef struct esp8266_domain_parse_info_st {
char *host_ip;
size_t host_ip_len;
} esp8266_domain_parse_info_t;
typedef struct esp8266_context_st {
at_echo_t echo;
char echo_buffer[64];
int try;
evtdrv_task_id_t self_task_id;
int sockid;
evtdrv_task_id_t caller_task_id;
char *ssid;
char *pwd;
esp8266_send_info_t send_info;
esp8266_domain_parse_info_t domain_parse_info;
} esp8266_context_t;
esp8266_context_t esp8266_context;
#define CONTEXT(field) (esp8266_context.##field)
static void esp8266_restore(void)
{
tos_at_echo_create(&CONTEXT(echo), NULL, 0, NULL, CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_RESTORE);
tos_at_cmd_exec(&CONTEXT(echo), 3000, "AT+RESTORE\r\n");
}
static void esp8266_echo_close(void)
{
tos_at_echo_create(&CONTEXT(echo), NULL, 0, NULL, CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_ECHO_CLOSE);
tos_at_cmd_exec(&CONTEXT(echo), 1000, "ATE0\r\n");
}
static void esp8266_net_mode_set(sal_net_mode_t mode)
{
char *cmd = NULL;
switch (mode) {
case SAL_NET_MODE_STA:
cmd = "AT+CWMODE=1\r\n";
break;
case SAL_NET_MODE_AP:
cmd = "AT+CWMODE=2\r\n";
break;
case SAL_NET_MODE_STA_AP:
cmd = "AT+CWMODE=3\r\n";
break;
default:
return;
}
tos_at_echo_create(&CONTEXT(echo), NULL, 0, "no change", CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_NET_MODE_SET);
tos_at_cmd_exec(&CONTEXT(echo), 1000, cmd);
}
static void esp8266_send_mode_set(sal_send_mode_t mode)
{
tos_at_echo_create(&CONTEXT(echo), NULL, 0, NULL, CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_SEND_MODE_SET);
tos_at_cmd_exec(&CONTEXT(echo), 1000, "AT+CIPMODE=%d\r\n", mode == SAL_SEND_MODE_NORMAL ? 0 : 1);
}
static void esp8266_multilink_set(sal_multilink_state_t state)
{
tos_at_echo_create(&CONTEXT(echo), NULL, 0, NULL, CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_MULTILINK_SET);
tos_at_cmd_exec(&CONTEXT(echo), 500, "AT+CIPMUX=%d\r\n", state == SAL_MULTILINK_STATE_ENABLE ? 1 : 0);
}
static void esp8266_do_join_ap(const char *ssid, const char *pwd)
{
tos_at_echo_create(&CONTEXT(echo), NULL, 0, "OK", CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_JOIN_AP);
tos_at_cmd_exec(&CONTEXT(echo), 1000, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, pwd);
}
static int esp8266_do_connect(const char *ip, const char *port, sal_proto_t proto)
{
CONTEXT(sockid) = tos_at_channel_alloc(ip, port);
if (CONTEXT(sockid) == -1) {
return -1;
}
tos_at_echo_create(&CONTEXT(echo), NULL, 0, "OK", CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_CONNECT);
tos_at_cmd_exec(&CONTEXT(echo), 10000,
"AT+CIPSTART=%d,\"%s\",\"%s\",%s\r\n",
CONTEXT(sockid), proto == TOS_SAL_PROTO_UDP ? "UDP" : "TCP", ip, port);
return 0;
}
static int esp8266_recv_timeout(int id, void *buf, size_t len, uint32_t timeout)
{
return tos_at_channel_read_timed(id, buf, len, timeout);
}
static int esp8266_recv(int id, void *buf, size_t len)
{
return esp8266_recv_timeout(id, buf, len, (uint32_t)4000);
}
static int esp8266_is_link_broken(const char *echo_buffer)
{
if (strstr(echo_buffer, "CLOSED") ||
strstr(echo_buffer, "link is not valid")) {
return 1;
}
return 0;
}
static int esp8266_do_send(int id, const void *buf, size_t len)
{
tos_at_echo_create(&CONTEXT(echo), CONTEXT(echo_buffer), sizeof(CONTEXT(echo_buffer)), "SEND OK", CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_SEND);
/*
ATTENTION: we should wait util "SEND OK" is echoed, otherwise the next
time we execute at command, the esp8266 maybe in a "busy s ..." state.
*/
tos_at_raw_data_send(&CONTEXT(echo), 10000, (uint8_t *)buf, len);
return 0;
}
static int esp8266_do_send_ready(int id, const void *buf, size_t len)
{
if (!tos_at_channel_is_working(id)) {
return -1;
}
CONTEXT(sockid) = id;
tos_at_echo_create(&CONTEXT(echo), CONTEXT(echo_buffer), sizeof(CONTEXT(echo_buffer)), ">", CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_SEND_READY);
tos_at_cmd_exec(&CONTEXT(echo), 1000,
"AT+CIPSEND=%d,%d\r\n",
id, len);
return 0;
}
static int esp8266_do_close(int id)
{
tos_at_cmd_exec(NULL, 1000, "AT+CIPCLOSE=%d\r\n", id);
tos_at_channel_free(id);
return 0;
}
static int esp8266_close(int id)
{
esp8266_imsg_close_t *msg_close;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_imsg_close_t));
msg_close = (esp8266_imsg_close_t *)msg_body;
msg_close->header.event = EVENT_IMSG_ESP8266_CLOSE;
msg_close->header.sender_id = tos_evtdrv_task_self();
msg_close->sockid = id;
if (tos_evtdrv_msg_send(CONTEXT(self_task_id), (evtdrv_msg_body_t)msg_close) != EVTDRV_ERR_NONE) {
return -1;
}
return 0;
}
static int esp8266_send(int id, const void *buf, size_t len)
{
esp8266_imsg_send_t *msg_send;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_imsg_send_t));
msg_send = (esp8266_imsg_send_t *)msg_body;
msg_send->header.event = EVENT_IMSG_ESP8266_SEND;
msg_send->header.sender_id = tos_evtdrv_task_self();
msg_send->sockid = id;
msg_send->buf = (void *)buf;
msg_send->len = len;
if (tos_evtdrv_msg_send(CONTEXT(self_task_id), (evtdrv_msg_body_t)msg_send) != EVTDRV_ERR_NONE) {
return -1;
}
return 0;
}
static int esp8266_connect(const char *ip, const char *port, sal_proto_t proto)
{
esp8266_imsg_connect_t *msg_connect;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_imsg_connect_t));
msg_connect = (esp8266_imsg_connect_t *)msg_body;
msg_connect->header.event = EVENT_IMSG_ESP8266_CONNECT;
msg_connect->header.sender_id = tos_evtdrv_task_self();
msg_connect->ip = (char *)ip;
msg_connect->port = (char *)port;
msg_connect->proto = proto;
if (tos_evtdrv_msg_send(CONTEXT(self_task_id), (evtdrv_msg_body_t)msg_connect) != EVTDRV_ERR_NONE) {
return -1;
}
return 0;
}
static int esp8266_do_parse_domain(const char *host_name, char *host_ip, size_t host_ip_len)
{
tos_at_echo_create(&CONTEXT(echo), CONTEXT(echo_buffer), sizeof(CONTEXT(echo_buffer)), NULL, CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_DOMAIN_PARSE);
tos_at_cmd_exec(&CONTEXT(echo), 2000, "AT+CIPDOMAIN=\"%s\"\r\n", host_name);
return 0;
}
static int esp8266_parse_domain(const char *host_name, char *host_ip, size_t host_ip_len)
{
esp8266_imsg_domain_parse_t *msg_domain_parse;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_imsg_domain_parse_t));
msg_domain_parse = (esp8266_imsg_domain_parse_t *)msg_body;
msg_domain_parse->header.event = EVENT_IMSG_ESP8266_DOMAIN_PARSE;
msg_domain_parse->header.sender_id = tos_evtdrv_task_self();
msg_domain_parse->host_name = (char *)host_name;
msg_domain_parse->host_ip = (char *)host_ip;
msg_domain_parse->host_ip_len = host_ip_len;
if (tos_evtdrv_msg_send(CONTEXT(self_task_id), (evtdrv_msg_body_t)msg_domain_parse) != EVTDRV_ERR_NONE) {
return -1;
}
return 0;
}
static int esp8266_init(void)
{
if (tos_evtdrv_event_set(CONTEXT(self_task_id), EVENT_INTERNAL_ESP8266_INIT) != EVTDRV_ERR_NONE) {
return -1;
}
return 0;
}
__STATIC__ uint8_t incoming_data_buffer[512];
__STATIC__ void esp8266_incoming_data_process(void)
{
uint8_t data;
int channel_id = 0, data_len = 0;
/*
+IPD,0,44:1234...
+IPD: prefix
0: link id
44: data length
1234...: data content
*/
while (1) {
if (tos_at_uart_read(&data, 1) != 1) {
return;
}
if (data == ',') {
break;
}
channel_id = channel_id * 10 + (data - '0');
}
while (1) {
if (tos_at_uart_read(&data, 1) != 1) {
return;
}
if (data == ':') {
break;
}
data_len = data_len * 10 + (data - '0');
}
if (data_len > sizeof(incoming_data_buffer)) {
data_len = sizeof(incoming_data_buffer);
}
if (tos_at_uart_read(incoming_data_buffer, data_len) != data_len) {
return;
}
tos_at_channel_write(channel_id, incoming_data_buffer, data_len);
}
at_event_t esp8266_at_event[] = {
{ "+IPD,", esp8266_incoming_data_process },
};
sal_module_t sal_module_esp8266 = {
.init = esp8266_init,
.connect = esp8266_connect,
.send = esp8266_send,
.recv_timeout = esp8266_recv_timeout,
.recv = esp8266_recv,
.close = esp8266_close,
.parse_domain = esp8266_parse_domain,
};
int esp8266_join_ap(const char *ssid, const char *pwd)
{
esp8266_imsg_join_ap_t *msg_join_ap;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_imsg_join_ap_t));
msg_join_ap = (esp8266_imsg_join_ap_t *)msg_body;
msg_join_ap->header.event = EVENT_IMSG_ESP8266_JOIN_AP;
msg_join_ap->header.sender_id = tos_evtdrv_task_self();
msg_join_ap->ssid = (char *)ssid;
msg_join_ap->pwd = (char *)pwd;
if (tos_evtdrv_msg_send(CONTEXT(self_task_id), (evtdrv_msg_body_t)msg_join_ap) != EVTDRV_ERR_NONE) {
return -1;
}
return 0;
}
int esp8266_sal_init(hal_uart_port_t uart_port, evtdrv_task_id_t at_task_id, evtdrv_task_id_t esp8266_task_id)
{
esp8266_imsg_init_t *msg_init;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_imsg_init_t));
msg_init = (esp8266_imsg_init_t *)msg_body;
msg_init->header.event = EVENT_IMSG_ESP8266_INIT;
msg_init->header.sender_id = tos_evtdrv_task_self();
msg_init->uart_port = uart_port;
msg_init->at_task_id = at_task_id;
msg_init->esp8266_task_id = esp8266_task_id;
if (tos_evtdrv_msg_send(esp8266_task_id, (evtdrv_msg_body_t)msg_init) != EVTDRV_ERR_NONE) {
return -1;
}
return 0;
}
static void esp8266_send_msg_reply(int write_len)
{
esp8266_omsg_send_t *omsg_send;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_omsg_send_t));
omsg_send = (esp8266_omsg_send_t *)msg_body;
omsg_send->header.event = EVENT_OMSG_ESP8266_SEND;
omsg_send->header.sender_id = tos_evtdrv_task_self();
omsg_send->write_len = write_len;
tos_evtdrv_msg_send(CONTEXT(caller_task_id), (evtdrv_msg_body_t)omsg_send);
}
static void esp8266_connect_msg_reply(int sockid)
{
esp8266_omsg_connect_t *omsg_connect;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_omsg_connect_t));
omsg_connect = (esp8266_omsg_connect_t *)msg_body;
omsg_connect->header.event = EVENT_OMSG_ESP8266_CONNECT;
omsg_connect->header.sender_id = tos_evtdrv_task_self();
omsg_connect->sockid = sockid;
tos_evtdrv_msg_send(CONTEXT(caller_task_id), (evtdrv_msg_body_t)omsg_connect);
}
static void esp8266_common_msg_reply(evtdrv_event_flag_t event_flag, int return_code)
{
esp8266_omsg_common_t *omsg_common;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(esp8266_omsg_common_t));
omsg_common = (esp8266_omsg_common_t *)msg_body;
omsg_common->header.event = event_flag;
omsg_common->header.sender_id = tos_evtdrv_task_self();
omsg_common->return_code = return_code;
tos_evtdrv_msg_send(CONTEXT(caller_task_id), (evtdrv_msg_body_t)omsg_common);
}
evtdrv_event_flag_t esp8266_task(evtdrv_event_flag_t event)
{
esp8266_event_hdr_t *event_hdr;
esp8266_imsg_init_t *imsg_init;
esp8266_imsg_join_ap_t *imsg_join_ap;
esp8266_imsg_connect_t *imsg_connect;
esp8266_imsg_send_t *imsg_send;
esp8266_imsg_close_t *imsg_close;
esp8266_imsg_domain_parse_t *imsg_domain_parse;
if (event & TOS_EVTDRV_SYS_EVENT_INIT) {
return TOS_EVTDRV_SYS_EVENT_INIT;
}
if (event & TOS_EVTDRV_SYS_EVENT_MSG) {
while (event_hdr = (esp8266_event_hdr_t *)tos_evtdrv_msg_recv()) {
switch (event_hdr->event) {
case EVENT_IMSG_ESP8266_INIT:
imsg_init = (esp8266_imsg_init_t *)event_hdr;
CONTEXT(caller_task_id) = event_hdr->sender_id;
CONTEXT(self_task_id) = imsg_init->esp8266_task_id;
CONTEXT(try) = 0;
if (tos_at_init(imsg_init->uart_port, imsg_init->at_task_id, esp8266_at_event,
sizeof(esp8266_at_event) / sizeof(esp8266_at_event[0])) != 0) {
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, -1);
break;
}
if (tos_sal_module_register(&sal_module_esp8266) != 0) {
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, -1);
break;
}
tos_sal_module_init();
break;
case EVENT_IMSG_ESP8266_JOIN_AP:
imsg_join_ap = (esp8266_imsg_join_ap_t *)event_hdr;
CONTEXT(ssid) = imsg_join_ap->ssid;
CONTEXT(pwd) = imsg_join_ap->pwd;
esp8266_do_join_ap(imsg_join_ap->ssid, imsg_join_ap->pwd);
break;
case EVENT_IMSG_ESP8266_CONNECT:
imsg_connect = (esp8266_imsg_connect_t *)event_hdr;
if (esp8266_do_connect(imsg_connect->ip, imsg_connect->port, imsg_connect->proto) < 0) {
esp8266_connect_msg_reply(-1);
}
break;
case EVENT_IMSG_ESP8266_SEND:
imsg_send = (esp8266_imsg_send_t *)event_hdr;
CONTEXT(send_info).sockid = imsg_send->sockid;
CONTEXT(send_info).buf = imsg_send->buf;
CONTEXT(send_info).len = imsg_send->len;
if (esp8266_do_send_ready(imsg_send->sockid, imsg_send->buf, imsg_send->len) != 0) {
esp8266_send_msg_reply(-1);
}
break;
case EVENT_IMSG_ESP8266_CLOSE:
imsg_close = (esp8266_imsg_close_t *)event_hdr;
esp8266_do_close(imsg_close->sockid);
break;
case EVENT_IMSG_ESP8266_DOMAIN_PARSE:
imsg_domain_parse = (esp8266_imsg_domain_parse_t *)event_hdr;
CONTEXT(domain_parse_info).host_ip = imsg_domain_parse->host_ip;
CONTEXT(domain_parse_info).host_ip_len = imsg_domain_parse->host_ip_len;
esp8266_do_parse_domain(imsg_domain_parse->host_name, imsg_domain_parse->host_ip, imsg_domain_parse->host_ip_len);
break;
}
tos_evtdrv_msg_free((evtdrv_msg_body_t)event_hdr);
}
return TOS_EVTDRV_SYS_EVENT_MSG;
}
if (event & EVENT_INTERNAL_ESP8266_INIT) {
esp8266_restore();
return EVENT_INTERNAL_ESP8266_INIT;
}
if (event & EVENT_INTERNAL_ESP8266_RESTORE) {
at_delay_ms(3000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_OK) {
if (CONTEXT(try)++ < 10) {
esp8266_restore();
} else {
printf("restore failed\n");
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, -1);
}
} else {
esp8266_echo_close();
}
CONTEXT(try) = 0;
return EVENT_INTERNAL_ESP8266_RESTORE;
}
if (event & EVENT_INTERNAL_ESP8266_ECHO_CLOSE) {
at_delay_ms(2000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_OK) {
printf("echo close failed\n");
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, -1);
} else {
esp8266_net_mode_set(SAL_NET_MODE_STA);
}
return EVENT_INTERNAL_ESP8266_ECHO_CLOSE;
}
if (event & EVENT_INTERNAL_ESP8266_NET_MODE_SET) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_OK &&
CONTEXT(echo).status != AT_ECHO_STATUS_EXPECT) {
if (CONTEXT(try)++ < 10) {
esp8266_net_mode_set(SAL_NET_MODE_STA);
} else {
printf("net mode set failed\n");
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, -1);
}
} else {
esp8266_send_mode_set(SAL_SEND_MODE_NORMAL);
}
CONTEXT(try) = 0;
return EVENT_INTERNAL_ESP8266_NET_MODE_SET;
}
if (event & EVENT_INTERNAL_ESP8266_SEND_MODE_SET) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_OK) {
if (CONTEXT(try)++ < 10) {
esp8266_send_mode_set(SAL_SEND_MODE_NORMAL);
} else {
printf("send mode set failed\n");
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, -1);
}
} else {
esp8266_multilink_set(SAL_MULTILINK_STATE_ENABLE);
}
CONTEXT(try) = 0;
return EVENT_INTERNAL_ESP8266_SEND_MODE_SET;
}
if (event & EVENT_INTERNAL_ESP8266_MULTILINK_SET) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_OK) {
if (CONTEXT(try)++ < 10) {
esp8266_multilink_set(SAL_MULTILINK_STATE_ENABLE);
} else {
printf("multilink set failed\n");
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, -1);
}
} else {
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_INIT, 0);
}
CONTEXT(try) = 0;
return EVENT_INTERNAL_ESP8266_MULTILINK_SET;
}
if (event & EVENT_INTERNAL_ESP8266_JOIN_AP) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_EXPECT) {
if (CONTEXT(try)++ < 10) {
esp8266_do_join_ap(CONTEXT(ssid), CONTEXT(pwd));
} else {
printf("esp8266 join ap failed");
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_JOIN_AP, -1);
}
} else {
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_JOIN_AP, 0);
}
CONTEXT(try) = 0;
return EVENT_INTERNAL_ESP8266_JOIN_AP;
}
if (event & EVENT_INTERNAL_ESP8266_CONNECT) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_EXPECT &&
CONTEXT(echo).status != AT_ECHO_STATUS_OK) {
printf("esp8266 connect failed\n");
esp8266_connect_msg_reply(-1);
} else {
esp8266_connect_msg_reply(CONTEXT(sockid));
}
return EVENT_INTERNAL_ESP8266_CONNECT;
}
if (event & EVENT_INTERNAL_ESP8266_SEND_READY) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_OK &&
CONTEXT(echo).status != AT_ECHO_STATUS_EXPECT) {
if (esp8266_is_link_broken((const char *)CONTEXT(echo).buffer)) {
tos_at_channel_set_broken(CONTEXT(sockid));
}
esp8266_send_msg_reply(-1);
} else {
esp8266_do_send(CONTEXT(send_info).sockid, CONTEXT(send_info).buf, CONTEXT(send_info).len);
}
return EVENT_INTERNAL_ESP8266_SEND_READY;
}
if (event & EVENT_INTERNAL_ESP8266_SEND) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_EXPECT) {
if (esp8266_is_link_broken((const char *)CONTEXT(echo).buffer)) {
tos_at_channel_set_broken(CONTEXT(sockid));
}
esp8266_send_msg_reply(-1);
} else {
esp8266_send_msg_reply(CONTEXT(send_info).len);
}
return EVENT_INTERNAL_ESP8266_SEND;
}
if (event & EVENT_INTERNAL_ESP8266_DOMAIN_PARSE) {
at_delay_ms(1000);
if (CONTEXT(echo).status != AT_ECHO_STATUS_OK) {
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_DOMAIN_PARSE, -1);
} else {
/*
+CIPDOMAIN:183.232.231.172
*/
char *str = strstr((const char *)CONTEXT(echo_buffer), "+CIPDOMAIN:");
if (!str) {
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_DOMAIN_PARSE, -1);
} else {
char *host_ip_buffer = CONTEXT(domain_parse_info).host_ip;
size_t host_ip_buffer_len = CONTEXT(domain_parse_info).host_ip_len;
sscanf(str, "+CIPDOMAIN:%s", host_ip_buffer);
host_ip_buffer[host_ip_buffer_len - 1] = '\0';
printf("GOT IP: %s\n", host_ip_buffer);
esp8266_common_msg_reply(EVENT_OMSG_ESP8266_DOMAIN_PARSE, 0);
}
}
return EVENT_INTERNAL_ESP8266_DOMAIN_PARSE;
}
return TOS_EVTDRV_EVENT_NONE;
}

View File

@@ -1,134 +0,0 @@
/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#ifndef __ESP8266_EVTDRV_H__
#define __ESP8266_EVTDRV_H__
#include "tos_evtdrv.h"
#include "tos_hal.h"
#include "sal_module_wrapper.h"
#define EVENT_INTERNAL_ESP8266_INIT (1u << 0)
#define EVENT_INTERNAL_ESP8266_RESTORE (1u << 1)
#define EVENT_INTERNAL_ESP8266_ECHO_CLOSE (1u << 2)
#define EVENT_INTERNAL_ESP8266_NET_MODE_SET (1u << 3)
#define EVENT_INTERNAL_ESP8266_SEND_MODE_SET (1u << 4)
#define EVENT_INTERNAL_ESP8266_MULTILINK_SET (1u << 5)
#define EVENT_INTERNAL_ESP8266_JOIN_AP (1u << 6)
#define EVENT_INTERNAL_ESP8266_CONNECT (1u << 7)
#define EVENT_INTERNAL_ESP8266_SEND_READY (1u << 8)
#define EVENT_INTERNAL_ESP8266_SEND (1u << 9)
#define EVENT_INTERNAL_ESP8266_DOMAIN_PARSE (1u << 10)
#define EVENT_IMSG_ESP8266_INIT (1u << 0)
#define EVENT_IMSG_ESP8266_JOIN_AP (1u << 1)
#define EVENT_IMSG_ESP8266_CONNECT (1u << 2)
#define EVENT_IMSG_ESP8266_SEND (1u << 3)
#define EVENT_IMSG_ESP8266_CLOSE (1u << 4)
#define EVENT_IMSG_ESP8266_DOMAIN_PARSE (1u << 5)
#define EVENT_OMSG_ESP8266_INIT (1u << 0)
#define EVENT_OMSG_ESP8266_JOIN_AP (1u << 1)
#define EVENT_OMSG_ESP8266_CONNECT (1u << 2)
#define EVENT_OMSG_ESP8266_SEND (1u << 3)
#define EVENT_OMSG_ESP8266_DOMAIN_PARSE (1u << 4)
typedef struct esp8266_event_header_st {
evtdrv_event_flag_t event;
evtdrv_task_id_t sender_id;
} esp8266_event_hdr_t;
typedef struct esp8266_in_msg_init_st {
esp8266_event_hdr_t header;
hal_uart_port_t uart_port;
evtdrv_task_id_t at_task_id;
evtdrv_task_id_t esp8266_task_id;
} esp8266_imsg_init_t;
typedef struct esp8266_in_msg_join_ap_st {
esp8266_event_hdr_t header;
char *ssid;
char *pwd;
} esp8266_imsg_join_ap_t;
typedef struct esp8266_in_msg_connect_st {
esp8266_event_hdr_t header;
char *ip;
char *port;
sal_proto_t proto;
} esp8266_imsg_connect_t;
typedef struct esp8266_in_msg_send_st {
esp8266_event_hdr_t header;
int sockid;
void *buf;
size_t len;
} esp8266_imsg_send_t;
typedef struct esp8266_in_msg_close_st {
esp8266_event_hdr_t header;
int sockid;
} esp8266_imsg_close_t;
typedef struct esp8266_in_msg_domain_parse_st {
esp8266_event_hdr_t header;
char *host_name;
char *host_ip;
size_t host_ip_len;
} esp8266_imsg_domain_parse_t;
typedef struct esp8266_out_msg_common_st {
esp8266_event_hdr_t header;
int return_code;
} esp8266_omsg_common_t;
typedef struct esp8266_out_msg_connect_st {
esp8266_event_hdr_t header;
int sockid;
} esp8266_omsg_connect_t;
typedef struct esp8266_out_msg_send_st {
esp8266_event_hdr_t header;
int write_len;
} esp8266_omsg_send_t;
typedef enum sal_net_mode {
SAL_NET_MODE_STA,
SAL_NET_MODE_AP,
SAL_NET_MODE_STA_AP,
} sal_net_mode_t ;
typedef enum sal_send_mode {
SAL_SEND_MODE_NORMAL,
SAL_SEND_MODE_TRANSPARENT,
} sal_send_mode_t;
typedef enum sal_multilink_state {
SAL_MULTILINK_STATE_ENABLE,
SAL_MULTILINK_STATE_DISABLE,
} sal_multilink_state_t;
int esp8266_sal_init(hal_uart_port_t uart_port, evtdrv_task_id_t at_task_id, evtdrv_task_id_t esp8266_task_id);
int esp8266_join_ap(const char *ssid, const char *pwd);
evtdrv_event_flag_t esp8266_task(evtdrv_event_flag_t event);
#endif /* __ESP8266_EVTDRV_H__ */

View File

@@ -1,160 +0,0 @@
#include "esp8266_evtdrv.h"
#include "tos_at_evtdrv.h"
#include "tos_evtdrv.h"
#include "sal_module_wrapper.h"
evtdrv_task_id_t at_task_id = 0;
evtdrv_task_id_t esp8266_task_id = 1;
evtdrv_task_id_t user_task_id = 2;
int socket_id_0 = 0;
#define RECV_LEN 1024
uint8_t recv_data_0[RECV_LEN];
evtdrv_timer_t task0_send_timer;
#define EVENT_USER_INIT (1u << 0)
#define EVENT_USER_SEND (1u << 1)
#define EVENT_USER_CLOSE (1u << 2)
int send_count = 0;
char host_ip[16];
void timer_callback(void *arg)
{
tos_evtdrv_event_set(user_task_id, EVENT_USER_SEND);
}
evtdrv_event_flag_t user_task(evtdrv_event_flag_t event)
{
esp8266_event_hdr_t *event_hdr;
esp8266_omsg_common_t *omsg_common;
esp8266_omsg_connect_t *omsg_connect;
esp8266_omsg_send_t *omsg_send;
if (event & TOS_EVTDRV_SYS_EVENT_INIT) {
tos_evtdrv_event_set(user_task_id, EVENT_USER_INIT);
return TOS_EVTDRV_SYS_EVENT_INIT;
}
if (event & EVENT_USER_INIT) {
esp8266_sal_init(HAL_UART_PORT_0, at_task_id, esp8266_task_id);
return EVENT_USER_INIT;
}
if (event & TOS_EVTDRV_SYS_EVENT_MSG) {
while (event_hdr = (esp8266_event_hdr_t *)tos_evtdrv_msg_recv()) {
if (event_hdr->sender_id == esp8266_task_id) {
switch (event_hdr->event) {
case EVENT_OMSG_ESP8266_INIT:
omsg_common = (esp8266_omsg_common_t *)event_hdr;
if (omsg_common->return_code == 0) {
esp8266_join_ap("SheldonDai", "srnr6x9xbhmb0");
} else {
printf("esp8266 init failed!\n");
}
break;
case EVENT_OMSG_ESP8266_JOIN_AP:
omsg_common = (esp8266_omsg_common_t *)event_hdr;
if (omsg_common->return_code != 0) {
printf("esp8266 join ap failed!\n");
break;
}
tos_sal_module_parse_domain("www.tencent.com", host_ip, sizeof(host_ip));
break;
case EVENT_OMSG_ESP8266_DOMAIN_PARSE:
omsg_common = (esp8266_omsg_common_t *)event_hdr;
if (omsg_common->return_code != 0) {
printf("esp8266 domain parse failed!\n");
} else {
printf("domain parse(www.tencent.com): %s\n", host_ip);
}
tos_sal_module_connect("39.108.190.129", "8080", TOS_SAL_PROTO_TCP);
break;
case EVENT_OMSG_ESP8266_CONNECT:
omsg_connect = (esp8266_omsg_connect_t *)event_hdr;
socket_id_0 = omsg_connect->sockid;
if (socket_id_0 < 0) {
printf("esp8266 connect failed!\n");
break;
}
/* <20><>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD> */
tos_evtdrv_timer_create(&task0_send_timer,
timer_callback, NULL,
EVTDRV_TIMER_OPT_PERIODIC);
tos_evtdrv_timer_start(&task0_send_timer, 6000);
break;
case EVENT_OMSG_ESP8266_SEND:
omsg_send = (esp8266_omsg_send_t *)event_hdr;
int write_len = omsg_send->write_len;
if (write_len < 0) {
printf("write failed! %d\n", write_len);
} else {
printf("task0 write success: %d\n", write_len);
}
break;
}
}
tos_evtdrv_msg_free((evtdrv_msg_body_t)event_hdr);
}
return TOS_EVTDRV_SYS_EVENT_MSG;
}
if (event & EVENT_USER_SEND) {
if (++send_count > 5) {
// after send 5 times, we shutdown the connection
tos_evtdrv_event_set(user_task_id, EVENT_USER_CLOSE);
return EVENT_USER_SEND;
}
tos_sal_module_send(socket_id_0, "hello", 5);
int len = tos_sal_module_recv(socket_id_0, recv_data_0, sizeof(recv_data_0));
if (len > 0) {
printf("task0 receive from server(%d): %s\n", len, recv_data_0);
}
return EVENT_USER_SEND;
}
if (event & EVENT_USER_CLOSE) {
tos_evtdrv_timer_stop(&task0_send_timer);
tos_sal_module_close(socket_id_0);
return EVENT_USER_CLOSE;
}
return TOS_EVTDRV_EVENT_NONE;
}
evtdrv_task_entry_t tasks[] = {
tos_at_evtdrv_task,
esp8266_task,
user_task,
};
int main(void)
{
board_init();
tos_evtdrv_sys_init(tasks, sizeof(tasks) / sizeof(tasks[0]), K_NULL);
tos_evtdrv_sys_start();
}

View File

@@ -1,261 +0,0 @@
#include "tos_evtdrv.h"
typedef struct event_hdr_st {
uint8_t event;
} event_hdr_t;
typedef struct consumer_msg_st {
event_hdr_t hdr;
uint16_t require_len;
} consumer_msg_t;
typedef struct productor_msg_st {
event_hdr_t hdr;
uint16_t payload_len;
char *payload;
} productor_msg_t;
evtdrv_task_id_t productor_id = 0;
evtdrv_task_id_t consumer1_id = 1;
evtdrv_task_id_t consumer2_id = 2;
#define EVENT_CONSUMER1 (1u << 0)
#define EVENT_CONSUMER2 (1u << 1)
#define EVENT_PRODUCTOR (1u << 2)
#define EVENT_CONSUER1_HUNGRY (1u << 3)
#define EVENT_CONSUER2_HUNGRY (1u << 4)
#define CONSUMER1_REQUIRE_LEN 5
#define CONSUMER2_REQUIRE_LEN 9
static void msg_payload_fill(char *payload, uint16_t len)
{
uint16_t i = 0;
for (i = 0; i < len - 1; ++i) {
payload[i] = (i % 10) + 'a';
}
payload[len - 1] = '\0';
}
productor_msg_t *msg4consumer_forge(uint16_t consumer_require_len)
{
productor_msg_t *productor_msg;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(productor_msg_t) + consumer_require_len + 1);
if (!msg_body) {
return K_NULL;
}
productor_msg = (productor_msg_t *)msg_body;
productor_msg->hdr.event = EVENT_PRODUCTOR;
productor_msg->payload_len = consumer_require_len;
productor_msg->payload = (char *)(productor_msg + 1);
msg_payload_fill(productor_msg->payload, consumer_require_len + 1);
return productor_msg;
}
evtdrv_event_flag_t task_productor(evtdrv_event_flag_t event)
{
uint16_t consumer_require_len;
consumer_msg_t *consumer_msg;
productor_msg_t *productor_msg;
if (event & TOS_EVTDRV_SYS_EVENT_INIT) {
printf("init logic for productor\n");
// return event handled
return TOS_EVTDRV_SYS_EVENT_INIT;
}
if (event & TOS_EVTDRV_SYS_EVENT_MSG) {
while (consumer_msg = (consumer_msg_t *)tos_evtdrv_msg_recv()) {
consumer_require_len = consumer_msg->require_len;
switch (consumer_msg->hdr.event) {
case EVENT_CONSUMER1:
printf("msg from consumer1, %d len required\n", consumer_require_len);
productor_msg = msg4consumer_forge(consumer_require_len);
if (productor_msg) {
tos_evtdrv_msg_send(consumer1_id, (evtdrv_msg_body_t)productor_msg);
}
break;
case EVENT_CONSUMER2:
printf("msg from consumer2, %d len required\n", consumer_require_len);
productor_msg = msg4consumer_forge(consumer_require_len);
if (productor_msg) {
tos_evtdrv_msg_send(consumer2_id, (evtdrv_msg_body_t)productor_msg);
}
break;
}
tos_evtdrv_msg_free((evtdrv_msg_body_t)consumer_msg);
}
// return event handled
return TOS_EVTDRV_SYS_EVENT_MSG;
}
if (event & EVENT_CONSUER1_HUNGRY) {
productor_msg = msg4consumer_forge(CONSUMER1_REQUIRE_LEN);
if (productor_msg) {
tos_evtdrv_msg_send(consumer1_id, (evtdrv_msg_body_t)productor_msg);
}
// return event handled
return EVENT_CONSUER1_HUNGRY;
}
if (event & EVENT_CONSUER2_HUNGRY) {
productor_msg = msg4consumer_forge(CONSUMER2_REQUIRE_LEN);
if (productor_msg) {
tos_evtdrv_msg_send(consumer2_id, (evtdrv_msg_body_t)productor_msg);
}
// return event handled
return EVENT_CONSUER2_HUNGRY;
}
return TOS_EVTDRV_EVENT_NONE;
}
consumer_msg_t *msg4productor_forge(uint16_t consumer_event, uint16_t consumer_require_len)
{
consumer_msg_t *consumer_msg;
evtdrv_msg_body_t msg_body;
msg_body = tos_evtdrv_msg_alloc(sizeof(consumer_msg_t));
if (!msg_body) {
return K_NULL;
}
consumer_msg = (consumer_msg_t *)msg_body;
consumer_msg->hdr.event = consumer_event;
consumer_msg->require_len = consumer_require_len;
return consumer_msg;
}
evtdrv_timer_t consumer1_timer;
evtdrv_timer_t consumer2_timer;
void consumer1_timer_callback(void *arg)
{
printf("consumer1_timer_callback\n");
tos_evtdrv_event_set(productor_id, EVENT_CONSUER1_HUNGRY);
}
void consumer2_timer_callback(void *arg)
{
printf("consumer2_timer_callback\n");
tos_evtdrv_event_set(productor_id, EVENT_CONSUER2_HUNGRY);
}
evtdrv_event_flag_t task_consumer1(evtdrv_event_flag_t event)
{
consumer_msg_t *consumer_msg;
productor_msg_t *productor_msg;
if (event & TOS_EVTDRV_SYS_EVENT_INIT) {
printf("init logic for consumer1\n");
tos_evtdrv_timer_create(&consumer1_timer,
consumer1_timer_callback, NULL,
EVTDRV_TIMER_OPT_PERIODIC);
tos_evtdrv_timer_start(&consumer1_timer, 4000);
consumer_msg = msg4productor_forge(EVENT_CONSUMER1, CONSUMER1_REQUIRE_LEN);
if (consumer_msg) {
tos_evtdrv_msg_send(productor_id, (evtdrv_msg_body_t)consumer_msg);
}
// return event handled
return TOS_EVTDRV_SYS_EVENT_INIT;
}
if (event & TOS_EVTDRV_SYS_EVENT_MSG) {
while (productor_msg = (productor_msg_t *)tos_evtdrv_msg_recv()) {
switch (productor_msg->hdr.event) {
case EVENT_PRODUCTOR:
printf("\nconsumer1:\nmsg from productor, payload_len: %d\npayload: %s\n", productor_msg->payload_len, productor_msg->payload);
break;
}
tos_evtdrv_msg_free((evtdrv_msg_body_t)productor_msg);
}
// return event handled
return TOS_EVTDRV_SYS_EVENT_MSG;
}
return TOS_EVTDRV_EVENT_NONE;
}
evtdrv_event_flag_t task_consumer2(evtdrv_event_flag_t event)
{
consumer_msg_t *consumer_msg;
productor_msg_t *productor_msg;
if (event & TOS_EVTDRV_SYS_EVENT_INIT) {
printf("init logic for consumer2\n");
tos_evtdrv_timer_create(&consumer2_timer,
consumer2_timer_callback, NULL,
EVTDRV_TIMER_OPT_PERIODIC);
tos_evtdrv_timer_start(&consumer2_timer, 6000);
consumer_msg = msg4productor_forge(EVENT_CONSUMER2, CONSUMER2_REQUIRE_LEN);
if (consumer_msg) {
tos_evtdrv_msg_send(productor_id, (evtdrv_msg_body_t)consumer_msg);
}
// return event handled
return TOS_EVTDRV_SYS_EVENT_INIT;
}
if (event & TOS_EVTDRV_SYS_EVENT_MSG) {
while (productor_msg = (productor_msg_t *)tos_evtdrv_msg_recv()) {
switch (productor_msg->hdr.event) {
case EVENT_PRODUCTOR:
printf("\nconsumer2:\nmsg from productor, payload_len: %d\npayload: %s\n", productor_msg->payload_len, productor_msg->payload);
break;
}
tos_evtdrv_msg_free((evtdrv_msg_body_t)productor_msg);
}
// return event handled
return TOS_EVTDRV_SYS_EVENT_MSG;
}
return TOS_EVTDRV_EVENT_NONE;
}
evtdrv_task_entry_t tasks[] = {
task_productor,
task_consumer1,
task_consumer2
};
int main(void)
{
board_init();
tos_evtdrv_sys_init(tasks, sizeof(tasks) / sizeof(tasks[0]), K_NULL);
tos_evtdrv_sys_start();
}

View File

@@ -1,102 +0,0 @@
#include "stm32f1xx_hal.h"
#include "bsp_init.h"
#include "tos_k.h"
#include "esp8266.h"
#include "mqttclient.h"
k_task_t task;
k_stack_t task_stack[2048];
static void tos_topic_handler(void* client, message_data_t* msg)
{
(void) client;
MQTT_LOG_I("-----------------------------------------------------------------------------------");
MQTT_LOG_I("%s:%d %s()...\ntopic: %s, qos: %d. \nmessage:\n\t%s\n", __FILE__, __LINE__, __FUNCTION__,
msg->topic_name, msg->message->qos, (char*)msg->message->payload);
MQTT_LOG_I("-----------------------------------------------------------------------------------\n");
}
void mqttclient_task(void *Parameter)
{
int error;
char buf[100] = { 0 };
mqtt_message_t msg;
mqtt_client_t *client = NULL;
memset(&msg, 0, sizeof(msg));
printf("\nwelcome to mqttclient test...\n");
esp8266_sal_init(HAL_UART_PORT_2);
esp8266_join_ap("wifii", "woshijiejie");
mqtt_log_init();
client = mqtt_lease();
mqtt_set_port(client, "1883");
mqtt_set_host(client, "www.jiejie01.top");
mqtt_set_client_id(client, random_string(10));
mqtt_set_user_name(client, random_string(10));
mqtt_set_password(client, random_string(10));
mqtt_set_clean_session(client, 1);
mqtt_set_read_buf_size(client, 256);
mqtt_set_write_buf_size(client, 256);
error = mqtt_connect(client);
MQTT_LOG_D("mqtt connect error is %#x", error);
error = mqtt_connect(client);
MQTT_LOG_D("mqtt connect error is %#x", error);
mqtt_subscribe(client, "tos-topic", QOS0, tos_topic_handler);
MQTT_LOG_D("mqtt subscribe error is %#x", error);
memset(&msg, 0, sizeof(msg));
for (;;) {
sprintf(buf, "welcome to mqttclient, this is a publish test, a rand number: %d ...", random_number());
msg.qos = QOS0;
msg.payload = (void *) buf;
error = mqtt_publish(client, "tos-topic", &msg);
tos_task_delay(4000);
}
}
int main(void)
{
k_err_t err;
bsp_init();
printf("Welcome to TencentOS tiny\r\n");
tos_knl_init(); // TOS Tiny kernel initialize
printf("create mqttclient task\r\n");
err = tos_task_create(&task,
"mqttclient-task",
mqttclient_task,
NULL,
3,
task_stack,
1024,
20);
if(err != K_ERR_NONE)
printf("TencentOS Create mqttclient task fail! code : %d \r\n",err);
tos_knl_start(); // Start TOS Tiny
}

View File

@@ -5,16 +5,14 @@
#include "sal_module_wrapper.h"
#define USE_ESP8266
//#define USE_NB_BC35
//#define USE_BC26
//#define USE_EC200S
//#define USE_EC600S
#if defined(USE_ESP8266)
#include "esp8266.h"
#elif defined(USE_BC26)
#include "bc26.h"
#elif defined(USE_EC200S)
#include "ec200s.h"
#include "ec600s.h"
#endif
#ifdef USE_ESP8266
@@ -102,17 +100,9 @@ void mqttclient_task(void)
esp8266_join_ap("Mculover666", "mculover666");
#endif
#ifdef USE_NB_BC35
int bc35_28_95_sal_init(hal_uart_port_t uart_port);
bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
#ifdef USE_BC26
bc26_sal_init(HAL_UART_PORT_2);
#endif
#ifdef USE_EC200S
ec200s_sal_init(HAL_UART_PORT_2);
ec600s_sal_init(HAL_UART_PORT_2);
#endif
mqtt_log_init();

View File

@@ -1,60 +0,0 @@
#include "bc35_28_95_lwm2m.h"
#include "mcu_init.h"
#include "sal_module_wrapper.h"
#include "cmsis_os.h"
#define NB_IoT_TEST_TASK_STK_SIZE 1024
void nb_iot_demo(void);
osThreadDef(nb_iot_demo, osPriorityNormal, 1, NB_IoT_TEST_TASK_STK_SIZE);
int socket_id=-1;
#define RECV_LEN 1024
uint8_t recv_data[RECV_LEN];
void nb_iot_demo(void)
{
int recv_len = -1;
extern int bc35_28_95_sal_lwm2m_init(hal_uart_port_t uart_port);
bc35_28_95_sal_lwm2m_init(HAL_UART_PORT_0);
socket_id = tos_sal_module_connect("49.4.85.232","5683",TOS_SAL_PROTO_UDP);
if(socket_id !=-1)
{
printf("connect to cloud success! fd: %d\n", socket_id);
}
else
{
printf("connect to cloud failed!\n");
}
while (1)
{
tos_sal_module_send(socket_id, (const void*)"22", strlen("22"));
memset(&recv_data[0], 0, sizeof(recv_data));
recv_len = tos_sal_module_recv(socket_id, recv_data, sizeof(recv_data));
if (recv_len < 0)
{
printf("task receive error\n");
}
else if (recv_len == 0)
{
printf("task receive none\n");
}
else
{
recv_data[recv_len] = 0;
printf("task: receive len: %d\nmsg from remote: %s\n", recv_len, recv_data);
}
tos_sleep_ms(2000);
}
}
void application_entry(void *arg)
{
osThreadCreate(osThread(nb_iot_demo), NULL);
}

View File

@@ -1,40 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _BLEHR_SENS_H_
#define _BLEHR_SENS_H_
#include "nimble/ble.h"
#include "modlog/modlog.h"
#ifdef __cplusplus
extern "C" {
#endif
#define GATT_DEVICE_INFO_UUID 0x180A
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
#define GATT_MODEL_NUMBER_UUID 0x2A24
int gatt_svr_init(void);
#ifdef __cplusplus
}
#endif
#endif //_BLEHR_SENS_H_

View File

@@ -1,280 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "blehr_sens.h"
#include "services/dis/ble_svc_dis.h"
#include "services/bas/ble_svc_bas.h"
/* UUID = 1bce38b3-d137-48ff-a13e-033e14c7a335 */
static const ble_uuid128_t gatt_svr_svc_rw_demo_uuid
= BLE_UUID128_INIT(0x35, 0xa3, 0xc7, 0x14, 0x3e, 0x03, 0x3e, 0xa1, 0xff,
0x48, 0x37, 0xd1, 0xb3, 0x38, 0xce, 0x1b);
/* UUID = 35f28386-3070-4f3b-ba38-27507e991762 */
static const ble_uuid128_t gatt_svr_chr_rw_demo_write_uuid
= BLE_UUID128_INIT(0x62, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba, 0x3b,
0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35);
/* UUID = ccdd113f-40d5-4d68-86ac-a728dd82f4aa */
static const ble_uuid128_t gatt_svr_chr_rw_demo_readonly_uuid
= BLE_UUID128_INIT(0xaa, 0xf4, 0x82, 0xdd, 0x28, 0xa7, 0xac, 0x86, 0x68,
0x4d, 0xd5, 0x40, 0x3f, 0x11, 0xdd, 0xcc);
#define REPLY_BUFFER_SIZE 100
static char reply[REPLY_BUFFER_SIZE];
static char rm_demo_write_data[64] = "This characteristic is readable and writeable!";
static int gatt_svr_chr_access_device_info_manufacturer(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int gatt_svr_chr_access_device_info_model(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int gatt_svr_chr_access_rw_demo(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
/* define several bluetooth services for our device */
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
/*
* access_cb defines a callback for read and write access events on
* given characteristics
*/
{
/* Service: Device Information */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: * Manufacturer name */
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
.access_cb = gatt_svr_chr_access_device_info_manufacturer,
.flags = BLE_GATT_CHR_F_READ,
}, {
/* Characteristic: Model number string */
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
.access_cb = gatt_svr_chr_access_device_info_model,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* No more characteristics in this service */
}, }
},
{
/* Service: Read/Write Demo */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t*) &gatt_svr_svc_rw_demo_uuid.u,
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: Read/Write Demo write */
.uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_write_uuid.u,
.access_cb = gatt_svr_chr_access_rw_demo,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
}, {
/* Characteristic: Read/Write Demo read only */
.uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_readonly_uuid.u,
.access_cb = gatt_svr_chr_access_rw_demo,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* No more characteristics in this service */
}, }
},
{
0, /* No more services */
},
};
static int gatt_svr_chr_access_device_info_manufacturer(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("service 'device info: manufacturer' callback triggered\n");
snprintf(reply, REPLY_BUFFER_SIZE, "This is TencentOS tiny\n");
printf("reply: %s\n", reply);
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
printf("\n");
return rc;
}
static int gatt_svr_chr_access_device_info_model(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("service 'device info: model' callback triggered\n");
snprintf(reply, REPLY_BUFFER_SIZE, "running TencentOS tiny on nordic ble board");
printf("reply: %s\n", reply);
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
printf("\n");
return rc;
}
static int gatt_svr_chr_access_rw_demo(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("service 'rw demo' callback triggered\n");
int rc = 0;
ble_uuid_t* write_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_write_uuid.u;
ble_uuid_t* readonly_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_readonly_uuid.u;
if (ble_uuid_cmp(ctxt->chr->uuid, write_uuid) == 0) {
printf("access to characteristic 'rw demo (write)'\n");
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
printf("read from characteristic\n");
printf("current value of rm_demo_write_data: '%s'\n",
rm_demo_write_data);
/* send given data to the client */
rc = os_mbuf_append(ctxt->om, &rm_demo_write_data, strlen(rm_demo_write_data));
break;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
printf("write to characteristic\n");
printf("old value of rm_demo_write_data: '%s'\n", rm_demo_write_data);
uint16_t om_len;
om_len = OS_MBUF_PKTLEN(ctxt->om);
/* read sent data */
rc = ble_hs_mbuf_to_flat(ctxt->om, &rm_demo_write_data,
sizeof rm_demo_write_data, &om_len);
/* we need to null-terminate the received string */
rm_demo_write_data[om_len] = '\0';
printf("new value of rm_demo_write_data: '%s'\n",
rm_demo_write_data);
break;
case BLE_GATT_ACCESS_OP_READ_DSC:
printf("read from descriptor\n");
break;
case BLE_GATT_ACCESS_OP_WRITE_DSC:
printf("write to descriptor\n");
break;
default:
printf("unhandled operation!\n");
rc = 1;
break;
}
printf("\n");
return rc;
}
else if (ble_uuid_cmp(ctxt->chr->uuid, readonly_uuid) == 0) {
printf("access to characteristic 'rw demo (read-only)'\n");
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
char random_digit;
/* get random char between '0' and '9' */
random_digit = 48 + (rand() % 10);
snprintf(reply, REPLY_BUFFER_SIZE, "new random number: %c", random_digit);
printf("reply: %s\n", reply);
rc = os_mbuf_append(ctxt->om, &reply, strlen(reply));
printf("\n");
return rc;
}
return 0;
}
printf("unhandled uuid!\n");
return 1;
}
void
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
char buf[BLE_UUID_STR_LEN];
switch (ctxt->op) {
case BLE_GATT_REGISTER_OP_SVC:
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
ctxt->svc.handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
"def_handle=%d val_handle=%d\n",
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
ctxt->chr.def_handle,
ctxt->chr.val_handle);
break;
case BLE_GATT_REGISTER_OP_DSC:
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
ctxt->dsc.handle);
break;
default:
assert(0);
break;
}
}
int
gatt_svr_init(void)
{
int rc;
rc = ble_gatts_count_cfg(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
rc = ble_gatts_add_svcs(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
return 0;
}

View File

@@ -1,229 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nimble/nimble_port_tencentos_tiny.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "blehr_sens.h"
static const char device_name[] = "Nimble Gatt";
static uint8_t ble_addr_type;
static void start_advertise(void);
static int blegatt_gap_event(struct ble_gap_event *event, void *arg)
{
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
if (event->connect.status) {
start_advertise();
}
break;
case BLE_GAP_EVENT_DISCONNECT:
start_advertise();
break;
}
return 0;
}
static void start_advertise(void)
{
int rc;
struct ble_gap_adv_params advp;
memset(&advp, 0, sizeof advp);
advp.conn_mode = BLE_GAP_CONN_MODE_UND;
advp.disc_mode = BLE_GAP_DISC_MODE_GEN;
rc = ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER,
&advp, blegatt_gap_event, NULL);
assert(rc == 0);
}
static void
put_ad(uint8_t ad_type, uint8_t ad_len, const void *ad, uint8_t *buf,
uint8_t *len)
{
buf[(*len)++] = ad_len + 1;
buf[(*len)++] = ad_type;
memcpy(&buf[*len], ad, ad_len);
*len += ad_len;
}
static void
update_ad(void)
{
uint8_t ad[BLE_HS_ADV_MAX_SZ];
uint8_t ad_len = 0;
uint8_t ad_flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
put_ad(BLE_HS_ADV_TYPE_FLAGS, 1, &ad_flags, ad, &ad_len);
put_ad(BLE_HS_ADV_TYPE_COMP_NAME, sizeof(device_name), device_name, ad, &ad_len);
ble_gap_adv_set_data(ad, ad_len);
}
#if 0
#if 1
/* UUID = 1bce38b3-d137-48ff-a13e-033e14c7a335 */
static const ble_uuid128_t gatt_svr_svc_rw_demo_uuid
= BLE_UUID128_INIT(0x35, 0xa3, 0xc7, 0x14, 0x3e, 0x03, 0x3e, 0xa1, 0xff,
0x48, 0x37, 0xd1, 0xb3, 0x38, 0xce, 0x1b);
static ble_uuid128_t svc_adv_uuids_128[] =
{
{ BLE_UUID_TYPE_128, { 0x35, 0xa3, 0xc7, 0x14, 0x3e, 0x03, 0x3e, 0xa1, 0xff,
0x48, 0x37, 0xd1, 0xb3, 0x38, 0xce, 0x1b } },
};
#endif
static ble_uuid16_t svc_adv_uuids[] =
{
{ BLE_UUID_TYPE_16, GATT_DEVICE_INFO_UUID },
};
void ble_set_fields(void)
{
struct ble_gap_adv_params adv_params;
struct ble_hs_adv_fields fields;
int rc;
/*
* Set the advertisement data included in our advertisements:
* o Flags (indicates advertisement type and other general info)
* o Advertising tx power
* o Device name
*/
memset(&fields, 0, sizeof(fields));
/*
* Advertise two flags:
* o Discoverability in forthcoming advertisement (general)
* o BLE-only (BR/EDR unsupported)
*/
fields.flags = BLE_HS_ADV_F_DISC_GEN |
BLE_HS_ADV_F_BREDR_UNSUP;
/*
* Indicate that the TX power level field should be included; have the
* stack fill this value automatically. This is done by assigning the
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
*/
fields.tx_pwr_lvl_is_present = 1;
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
fields.name = (uint8_t *)device_name;
fields.name_len = strlen(device_name);
fields.name_is_complete = 1;
/*** 0x02,0x03 - 16-bit service class UUIDs. */
#if 1
fields.num_uuids16 = 1;
fields.uuids16 = svc_adv_uuids;
fields.uuids16_is_complete = 1;
#endif
#if 0
fields.num_uuids128 = 1;
fields.uuids128 = svc_adv_uuids_128;
fields.uuids128_is_complete = 1;
#endif
rc = ble_gap_adv_set_fields(&fields);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
return;
}
/*** 0xff - Manufacturer specific data. */
memset(&fields, 0, sizeof(fields));
fields.mfg_data = (uint8_t*)"GZH:Bluetooth-BLE,177341833";
fields.mfg_data_len = 27;
rc = ble_gap_adv_rsp_set_fields(&fields);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
return;
}
}
#endif
int ble_boot(void)
{
int rc = 0;
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
/* make sure synchronization of host and controller is done */
while (!ble_hs_synced()) {
;
}
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
rc = ble_hs_id_infer_auto(0, &ble_addr_type);
assert(rc == 0);
ble_svc_gap_init();
ble_svc_gatt_init();
/* verify and add our custom services */
rc = gatt_svr_init();
assert(rc == 0);
/* set the device name */
rc = ble_svc_gap_device_name_set(device_name);
assert(rc == 0);
/* reload the GATT server to link our added services */
ble_gatts_start();
update_ad();
#if 0
ble_set_fields();
#endif
start_advertise();
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[2048];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
/*
in this case, ble_boot_task's priority must lower than MYNEWT_VAL_BLE_HOST_TASK_PRIORITY && MYNEWT_VAL_BLE_LL_TASK_PRIORITY,
numerically bigger
to give the host and ll task a chance to run first just after the nimble_port_tencentos_tiny_init.
*/
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
6,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,6 +0,0 @@
# NimBLE心率传感器案例
本案例通过实现一个模拟的BLE心率传感器展示如何通过GATT notification来实现异步的数据传输。
编译工程并烧写后使用手机或任何能支持心率传感器app建议使用Nordic官方的`nRF Toolbox`工具的设备连接开发板创建的Heart Rate Sensor蓝牙设备app界面上可以获取到传感器所在位置以及上传过来的心率信息。

View File

@@ -1,13 +0,0 @@
NimBLE Heart Rate Sensor Example
================================
This example demonstrates how to implement asynchronous data transfer using GATT
notifications by implementing a mock-up BLE heart rate sensor. Once flashed on
a node, you can connect to it using any phone or device capable of using such a
heart rate sensor, e.g. Nordics `nRF Toolbox` for Android
(https://play.google.com/store/apps/details?id=no.nordicsemi.android.nrftoolbox).
The heart rate sensor is simulated by simply providing an up- and down counter
for its BPM value.
On top of the heart rate service, this example implements the device information
as well as the battery service.

View File

@@ -1,46 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLEHR_SENSOR_
#define H_BLEHR_SENSOR_
#include "nimble/ble.h"
#include "modlog/modlog.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Heart-rate configuration */
#define GATT_HRS_UUID 0x180D
#define GATT_HRS_MEASUREMENT_UUID 0x2A37
#define GATT_HRS_BODY_SENSOR_LOC_UUID 0x2A38
#define GATT_DEVICE_INFO_UUID 0x180A
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
#define GATT_MODEL_NUMBER_UUID 0x2A24
extern uint16_t hrs_hrm_handle;
int gatt_svr_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,238 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "blehr_sens.h"
#include "services/dis/ble_svc_dis.h"
#include "services/bas/ble_svc_bas.h"
static const char *manuf_name = "TencentOS tiny";
static const char *model_num = "TOS HR Sensor";
uint16_t hrs_hrm_handle;
static const char *serial_num = "deadbeef-baddad";
static const char *firmware_ver = "1.0.0";
static const char *hardware_ver = "V1.0";
static int
gatt_svr_chr_access_heart_rate(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int
gatt_svr_chr_access_battery_level(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int
gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
/* GATT service definitions */
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
/* Service: Heart-rate */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(GATT_HRS_UUID),
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: Heart-rate measurement */
.uuid = BLE_UUID16_DECLARE(GATT_HRS_MEASUREMENT_UUID),
.access_cb = gatt_svr_chr_access_heart_rate,
.val_handle = &hrs_hrm_handle,
.flags = BLE_GATT_CHR_F_NOTIFY,
}, {
/* Characteristic: Body sensor location */
.uuid = BLE_UUID16_DECLARE(GATT_HRS_BODY_SENSOR_LOC_UUID),
.access_cb = gatt_svr_chr_access_heart_rate,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* No more characteristics in this service */
}, }
},
{
/* Service: Device Information */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: * Manufacturer name */
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
.access_cb = gatt_svr_chr_access_device_info,
.flags = BLE_GATT_CHR_F_READ,
}, {
/* Characteristic: Model number string */
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
.access_cb = gatt_svr_chr_access_device_info,
.flags = BLE_GATT_CHR_F_READ,
}, {
.uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_CHR_UUID16_SERIAL_NUMBER),
.access_cb = gatt_svr_chr_access_device_info,
.flags = BLE_GATT_CHR_F_READ,
}, {
.uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_CHR_UUID16_FIRMWARE_REVISION),
.access_cb = gatt_svr_chr_access_device_info,
.flags = BLE_GATT_CHR_F_READ,
}, {
.uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_CHR_UUID16_HARDWARE_REVISION),
.access_cb = gatt_svr_chr_access_device_info,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* No more characteristics in this service */
}, }
},
{
/* Service: Battery Level */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BLE_SVC_BAS_UUID16),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(BLE_SVC_BAS_CHR_UUID16_BATTERY_LEVEL),
.access_cb = gatt_svr_chr_access_battery_level,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* No more characteristics in this service */
}, }
},
{
0, /* No more services */
},
};
static int
gatt_svr_chr_access_heart_rate(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
/* Sensor location, set to "Chest" */
static uint8_t body_sens_loc = 0x01;
uint16_t uuid;
int rc;
uuid = ble_uuid_u16(ctxt->chr->uuid);
if (uuid == GATT_HRS_BODY_SENSOR_LOC_UUID) {
rc = os_mbuf_append(ctxt->om, &body_sens_loc, sizeof(body_sens_loc));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
assert(0);
return BLE_ATT_ERR_UNLIKELY;
}
static int
gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
uint16_t uuid;
int rc;
uuid = ble_uuid_u16(ctxt->chr->uuid);
if (uuid == GATT_MANUFACTURER_NAME_UUID) {
rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
if (uuid == GATT_MODEL_NUMBER_UUID) {
rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
if (uuid == BLE_SVC_DIS_CHR_UUID16_SERIAL_NUMBER) {
rc = os_mbuf_append(ctxt->om, serial_num, strlen(serial_num));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
if (uuid == BLE_SVC_DIS_CHR_UUID16_FIRMWARE_REVISION) {
rc = os_mbuf_append(ctxt->om, firmware_ver, strlen(firmware_ver));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
if (uuid == BLE_SVC_DIS_CHR_UUID16_HARDWARE_REVISION) {
rc = os_mbuf_append(ctxt->om, hardware_ver, strlen(hardware_ver));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
assert(0);
return BLE_ATT_ERR_UNLIKELY;
}
static int
gatt_svr_chr_access_battery_level(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
MODLOG_DFLT(DEBUG, "[READ] battery level service: battery level value");
uint8_t level = 42;
int res = os_mbuf_append(ctxt->om, &level, sizeof(level));
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
void
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
char buf[BLE_UUID_STR_LEN];
switch (ctxt->op) {
case BLE_GATT_REGISTER_OP_SVC:
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
ctxt->svc.handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
"def_handle=%d val_handle=%d\n",
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
ctxt->chr.def_handle,
ctxt->chr.val_handle);
break;
case BLE_GATT_REGISTER_OP_DSC:
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
ctxt->dsc.handle);
break;
default:
assert(0);
break;
}
}
int
gatt_svr_init(void)
{
int rc;
rc = ble_gatts_count_cfg(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
rc = ble_gatts_add_svcs(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
return 0;
}

View File

@@ -1,294 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "console/console.h"
#include "config/private_syscfg.h"
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "blehr_sens.h"
#include "nimble/nimble_port_tencentos_tiny.h"
static bool notify_state;
/* Connection handle */
static uint16_t conn_handle;
static const char *device_name = "Heart Rate Sensor";
static int blehr_gap_event(struct ble_gap_event *event, void *arg);
static uint8_t ble_addr_type;
/* Sending notify data timer */
static struct ble_npl_callout blehr_tx_timer;
/* Variable to simulate heart beats */
static uint8_t heartrate = 90;
static ble_uuid16_t svc_adv_uuids[] =
{
{ BLE_UUID_TYPE_16, GATT_HRS_UUID }
};
/*
* Enables advertising with parameters:
* o General discoverable mode
* o Undirected connectable mode
*/
static void
blehr_advertise(void)
{
struct ble_gap_adv_params adv_params;
struct ble_hs_adv_fields fields;
int rc;
/*
* Set the advertisement data included in our advertisements:
* o Flags (indicates advertisement type and other general info)
* o Advertising tx power
* o Device name
*/
memset(&fields, 0, sizeof(fields));
/*
* Advertise two flags:
* o Discoverability in forthcoming advertisement (general)
* o BLE-only (BR/EDR unsupported)
*/
fields.flags = BLE_HS_ADV_F_DISC_GEN |
BLE_HS_ADV_F_BREDR_UNSUP;
/*
* Indicate that the TX power level field should be included; have the
* stack fill this value automatically. This is done by assigning the
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
*/
fields.tx_pwr_lvl_is_present = 1;
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
fields.name = (uint8_t *)device_name;
fields.name_len = strlen(device_name);
fields.name_is_complete = 1;
/*** 0x02,0x03 - 16-bit service class UUIDs. */
fields.num_uuids16 = 1;
fields.uuids16 = svc_adv_uuids;
fields.uuids16_is_complete = 1;
rc = ble_gap_adv_set_fields(&fields);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
return;
}
/*** 0xff - Manufacturer specific data. */
memset(&fields, 0, sizeof(fields));
fields.mfg_data = (uint8_t*)"GZH:Bluetooth-BLE,177341833";
fields.mfg_data_len = 27;
rc = ble_gap_adv_rsp_set_fields(&fields);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
return;
}
/* Begin advertising */
memset(&adv_params, 0, sizeof(adv_params));
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
rc = ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER,
&adv_params, blehr_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
return;
}
}
static void
blehr_tx_hrate_stop(void)
{
ble_npl_callout_stop(&blehr_tx_timer);
}
/* Reset heartrate measurment */
static void
blehr_tx_hrate_reset(void)
{
int rc;
rc = ble_npl_callout_reset(&blehr_tx_timer, OS_TICKS_PER_SEC);
assert(rc == 0);
}
/* This functions simulates heart beat and notifies it to the client */
static void
blehr_tx_hrate(struct os_event *ev)
{
static uint8_t hrm[2];
int rc;
struct os_mbuf *om;
if (!notify_state) {
blehr_tx_hrate_stop();
heartrate = 90;
return;
}
hrm[0] = 0x06; /* contact of a sensor */
hrm[1] = heartrate; /* storing dummy data */
/* Simulation of heart beats */
heartrate++;
if (heartrate == 160) {
heartrate = 90;
}
om = ble_hs_mbuf_from_flat(hrm, sizeof(hrm));
rc = ble_gattc_notify_custom(conn_handle, hrs_hrm_handle, om);
assert(rc == 0);
blehr_tx_hrate_reset();
}
static int
blehr_gap_event(struct ble_gap_event *event, void *arg)
{
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
/* A new connection was established or a connection attempt failed */
MODLOG_DFLT(INFO, "connection %s; status=%d\n",
event->connect.status == 0 ? "established" : "failed",
event->connect.status);
if (event->connect.status != 0) {
/* Connection failed; resume advertising */
blehr_advertise();
conn_handle = 0;
}
else {
conn_handle = event->connect.conn_handle;
}
break;
case BLE_GAP_EVENT_DISCONNECT:
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
conn_handle = BLE_HS_CONN_HANDLE_NONE; /* reset conn_handle */
/* Connection terminated; resume advertising */
blehr_advertise();
break;
case BLE_GAP_EVENT_ADV_COMPLETE:
MODLOG_DFLT(INFO, "adv complete\n");
blehr_advertise();
break;
case BLE_GAP_EVENT_SUBSCRIBE:
MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d\n value handle; "
"val_handle=%d\n",
event->subscribe.cur_notify, hrs_hrm_handle);
if (event->subscribe.attr_handle == hrs_hrm_handle) {
notify_state = event->subscribe.cur_notify;
blehr_tx_hrate_reset();
} else if (event->subscribe.attr_handle != hrs_hrm_handle) {
notify_state = event->subscribe.cur_notify;
blehr_tx_hrate_stop();
}
break;
case BLE_GAP_EVENT_MTU:
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
event->mtu.conn_handle,
event->mtu.value);
break;
}
return 0;
}
static void
blehr_on_sync(void)
{
int rc;
/* Use privacy */
rc = ble_hs_id_infer_auto(0, &ble_addr_type);
assert(rc == 0);
/* Begin advertising */
blehr_advertise();
}
int ble_boot(void)
{
int rc = 0;
/* Initialize the NimBLE host configuration */
ble_hs_cfg.sync_cb = blehr_on_sync;
ble_npl_callout_init(&blehr_tx_timer, nimble_port_get_dflt_eventq(),
blehr_tx_hrate, NULL);
/* verify and add our custom services */
rc = gatt_svr_init();
assert(rc == 0);
/* Set the default device name */
rc = ble_svc_gap_device_name_set(device_name);
assert(rc == 0);
/* run an event loop for handling the heart rate update events */
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[512];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
4,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_BLE_QIOT_CONFIG_H
#define QCLOUD_BLE_QIOT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#define BLE_QIOT_SDK_VERSION "1.2.0" // sdk version
#define BLE_QIOT_SDK_DEBUG 0 // sdk debug switch
// the device broadcast is controlled by the user, but we provide a mechanism to help the device save more power.
// if you want broadcast is triggered by something like press a button instead of all the time, and the broadcast
// stopped automatically in a few minutes if the device is not bind, define BLE_QIOT_BUTTON_BROADCAST is 1 and
// BLE_QIOT_BIND_TIMEOUT is the period that broadcast stopped.
// if the device in the bound state, broadcast dose not stop automatically.
#define BLE_QIOT_BUTTON_BROADCAST 0
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
#define BLE_QIOT_BIND_TIMEOUT (2 * 60 * 1000) // unit: ms
#endif
// some data like integer need to be transmitted in a certain byte order, defined it according to your device
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __ORDER_BIG_ENDIAN__ 4321
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
// in some BLE stack ble_qiot_log_hex() maybe not work, user can use there own hexdump function
#define BLE_QIOT_USER_DEFINE_HEDUMP 0
#if (1 == BLE_QIOT_USER_DEFINE_HEDUMP)
// add your code here like this
// #define ble_qiot_log_hex(level, hex_name, data, data_len) \
// do { \
// MY_RAW_LOG("\r\nble qiot dump: %s, length: %d\r\n", hex_name, data_len); \
// MY_RAW_HEXDUMP_(data, data_len); \
// } while(0)
// or use your own hexdump function with same definition
// void ble_qiot_log_hex(e_ble_qiot_log_level level, const char *hex_name, const char *data, uint32_t data_len);
#endif // BLE_QIOT_USER_DEFINE_HEDUMP
// Macro for logging a formatted string, the function must printf raw string without any color, prefix, newline or
// timestamp
#define BLE_QIOT_LOG_PRINT(...) printf(__VA_ARGS__)
// nrf52832xxAA Flash size is 512KB, nrf52832xxAB Flash size is 512KB, be carefol of the address!
#define BLE_QIOT_RECORD_FLASH_ADDR 0x7e000 // qiot data storage address
#define BLE_QIOT_RECORD_FLASH_PAGESIZE 4096 // flash page size, see chip datasheet
#define BLE_QIOT_RECORD_FLASH_PAGENUM 2 // how many pages qiot use
// the following definition will affect the stack that LLSync used, the minimum value tested is
// 2048 (BLE_QIOT_EVENT_MAX_SIZE is 128, BLE_QIOT_EVENT_BUF_SIZE is 23) the max length that llsync event data, depends
// on the length of user data reported to Tencent Lianlian at a time
#define BLE_QIOT_EVENT_MAX_SIZE (128)
// the minimum between BLE_QIOT_EVENT_MAX_SIZE and mtu
#define BLE_QIOT_EVENT_BUF_SIZE (23)
#define BLE_QIOT_INCLUDE_PROPERTY
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_QIOT_CONFIG_H

View File

@@ -1,424 +0,0 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// #include "nrf52832_xxaa_service.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "ble_qiot_import.h"
// #include "host/ble_hs.h"
// #include "host/ble_uuid.h"
#include "host/ble_gap.h"
#include "host/ble_gatt.h"
#include "flash_storage.h"
#include "ble_qiot_log.h"
// divece configs
// this only for reference, please create your own device and replace it!
// https://cloud.tencent.com/product/iotexplorer
// #define PRODUCT_ID "PRODUCT_ID" // 10 Bytes
// #define DEVICE_NAME "YOUR_DEVICE_NAME" // equal or lesser than 48 Bytes
// #define SECRET_KEY "YOUR_PRODUCT_SECRET_KEY_" // 24 Bytes
#define ADV_DEVICE_NAME "tos_llsync"
#define IOT_BLE_UUID_BASE96 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, \
0x20, 0x4e, 0xd0, 0x65
#define UINT16_TO_BYTES(n) ((uint8_t) (n)), ((uint8_t)((n) >> 8))
#define UINT32_TO_BYTES(n) ((uint8_t) (n)), ((uint8_t)((n) >> 8)), ((uint8_t)((n) >> 16)), ((uint8_t)((n) >> 24))
#define UINT16_TO_UUID32(n) ((uint8_t) (n)), ((uint8_t)((n) >> 8)), ((uint8_t)((n) >> 16)), ((uint8_t)((n) >> 24))
#define IOT_BLE_UUID128_BUILD(uuid) IOT_BLE_UUID_BASE96, UINT16_TO_UUID32(uuid)
#define IOT_BLE_UUID128_SERVICE IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_SERVICE)
#define IOT_BLE_UUID128_DEVICE_INFO IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_DEVICE_INFO)
#define IOT_BLE_UUID128_DATA IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_DATA)
#define IOT_BLE_UUID128_EVENT IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_EVENT)
static ble_uuid128_t ble_uuid128_t_service = BLE_UUID128_INIT(IOT_BLE_UUID128_SERVICE);
static ble_uuid128_t ble_uuid128_t_device_info = BLE_UUID128_INIT(IOT_BLE_UUID128_DEVICE_INFO);
static ble_uuid128_t ble_uuid128_t_data = BLE_UUID128_INIT(IOT_BLE_UUID128_DATA);
static ble_uuid128_t ble_uuid128_t_event = BLE_UUID128_INIT(IOT_BLE_UUID128_EVENT);
static uint16_t qiot_gap_connect_handle;
static uint16_t qiot_device_info_handle;
static uint16_t qiot_data_handle;
static uint16_t qiot_event_handle;
static int ble_svc_qiot_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
// LLsync BLE services and characteristics
static const struct ble_gatt_svc_def ble_svc_qiot_defs[] = {
{
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &ble_uuid128_t_service.u,
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_SERVICE),
.characteristics = (struct ble_gatt_chr_def[]) {
{
.uuid = &ble_uuid128_t_device_info.u,
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_DEVICE_INFO),
.access_cb = ble_svc_qiot_access,
// .val_handle = &qiot_device_info_handle,
// .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
// .flags = 0xFFF,
},
{
.uuid = &ble_uuid128_t_data.u,
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_DATA),
.access_cb = ble_svc_qiot_access,
// .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP,
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
},
{
.uuid = &ble_uuid128_t_event.u,
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_EVENT),
.access_cb = ble_svc_qiot_access,
.val_handle = &qiot_event_handle,
.flags = BLE_GATT_CHR_F_NOTIFY,
},
// end of characteristics
{.uuid = 0},
},
},
// end of services
{.type = 0},
};
static int ble_svc_qiot_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
const ble_uuid_t *uuid;
// int rand_num;
int rc, ret;
uint16_t len = 0;
uint8_t buf[256] = {0};
uuid = ctxt->chr->uuid;
if(ble_uuid_cmp(uuid, &ble_uuid128_t_device_info.u) == 0)
{
switch (ctxt->op)
{
case BLE_GATT_ACCESS_OP_WRITE_CHR:
rc = ble_hs_mbuf_to_flat(ctxt->om, buf, sizeof(buf), &len);
if (rc != 0)
{
ble_qiot_log_e("ble att err, ret: %d", ret);
return BLE_ATT_ERR_UNLIKELY;
}
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_DEBUG, "device info raw", (char *)buf, len);
ble_device_info_write_cb(buf, len);
default:
return BLE_ATT_ERR_UNLIKELY;
}
}
else if(ble_uuid_cmp(uuid, &ble_uuid128_t_data.u) == 0)
{
switch (ctxt->op)
{
case BLE_GATT_ACCESS_OP_WRITE_CHR:
rc = ble_hs_mbuf_to_flat(ctxt->om, buf, sizeof(buf), &len);
if (rc != 0)
{
ble_qiot_log_e("ble att err, ret: %d", ret);
return BLE_ATT_ERR_UNLIKELY;
}
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_DEBUG, "lldata raw", (char *)buf, len);
ble_lldata_write_cb(buf, len);
default:
return BLE_ATT_ERR_UNLIKELY;
}
}
else if(ble_uuid_cmp(uuid, &ble_uuid128_t_event.u) == 0)
{
// this characteristic not have read or write attribute
}
else
{
ble_qiot_log_e("unknown service or characteristic");
}
return 0;
}
// add services and characteristic
void ble_services_add(const qiot_service_init_s *p_service)
{
int ret = 0;
ret = ble_gatts_count_cfg(ble_svc_qiot_defs);
if(ret != 0)
{
ble_qiot_log_e("ble_gatts_count_cfg() err, ret: %d", ret);
}
ret = ble_gatts_add_svcs(ble_svc_qiot_defs);
if(ret != 0)
{
ble_qiot_log_e("ble_gatts_add_svcs() err, ret: %d", ret);
}
return;
}
int ble_get_product_id(char *product_id)
{
memcpy(product_id, PRODUCT_ID, strlen(PRODUCT_ID));
return 0;
}
int ble_get_device_name(char *device_name)
{
memcpy(device_name, DEVICE_NAME, strlen(DEVICE_NAME));
return strlen(DEVICE_NAME);
}
int ble_get_psk(char *psk)
{
memcpy(psk, SECRET_KEY, strlen(SECRET_KEY));
return 0;
}
int ble_get_mac(char *mac)
{
memcpy(mac, MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR, sizeof(MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR));
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_DEBUG, "mac_addr", mac, 6);
return 0;
}
int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
{
return fstorage_write(flash_addr, write_len, write_buf);
}
int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len)
{
return fstorage_read(flash_addr, read_len, read_buf);
}
int ble_qiot_gap_event_fn(struct ble_gap_event *event, void *arg)
{
ble_qiot_log_d("get event, type: %d", event->type);
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
/* A new connection was established or a connection attempt failed */
MODLOG_DFLT(INFO, "connection %s; status=%d\n",
event->connect.status == 0 ? "established" : "failed",
event->connect.status);
if (event->connect.status != 0) {
/* Connection failed; resume advertising */
ble_qiot_advertising_start();
qiot_gap_connect_handle = 0;
}
else
{
qiot_gap_connect_handle = event->connect.conn_handle;
}
break;
case BLE_GAP_EVENT_DISCONNECT:
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
/* Connection terminated; resume advertising */
ble_qiot_advertising_start();
qiot_gap_connect_handle = 0;
break;
case BLE_GAP_EVENT_ADV_COMPLETE:
MODLOG_DFLT(INFO, "adv complete\n");
ble_qiot_advertising_start();
break;
// case BLE_GAP_EVENT_SUBSCRIBE:
// MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d\n value handle; "
// "val_handle=%d\n",
// event->subscribe.cur_notify, hrs_hrm_handle);
// if (event->subscribe.attr_handle == hrs_hrm_handle) {
// notify_state = event->subscribe.cur_notify;
// notify_conn_handle = event->subscribe.conn_handle;
// blehr_tx_hrate_reset();
// } else if (event->subscribe.attr_handle != hrs_hrm_handle) {
// notify_state = event->subscribe.cur_notify;
// notify_conn_handle = 0;
// blehr_tx_hrate_stop();
// }
// break;
case BLE_GAP_EVENT_MTU:
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
event->mtu.conn_handle,
event->mtu.value);
break;
}
return 0;
}
#define ADV_MAX_UUID16_NUM 15
static uint8_t ble_addr_type;
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
{
int ret = 0, i = 0;
struct ble_gap_adv_params adv_params;
struct ble_hs_adv_fields fields;
struct ble_hs_adv_fields rsp_fields;
uint8_t adv_manufacture_data[32] = {0};
ble_uuid16_t adv_uuids16_list[ADV_MAX_UUID16_NUM];
memset(&fields, 0, sizeof(fields));
memset(&rsp_fields, 0, sizeof(rsp_fields));
// set advertising data
/* Advertise two flags:
* o Discoverability in forthcoming advertisement (general)
* o BLE-only (BR/EDR unsupported).
*/
fields.flags = BLE_HS_ADV_F_DISC_GEN |
BLE_HS_ADV_F_BREDR_UNSUP;
// fields.uuids16 = (ble_uuid16_t)adv->uuid_info.uuids;??
if (adv->uuid_info.uuid_num > ADV_MAX_UUID16_NUM)
{
printf("err: too many uuids16 in adv data! (uuids num %d)\r\n", adv->uuid_info.uuid_num);
return BLE_QIOT_RS_ERR;
}
for (i=0; i<adv->uuid_info.uuid_num; i++)
{
adv_uuids16_list[i].u.type = BLE_UUID_TYPE_16;
adv_uuids16_list[i].value = adv->uuid_info.uuids[i];
}
fields.uuids16 = adv_uuids16_list;
fields.num_uuids16 = adv->uuid_info.uuid_num;
fields.uuids16_is_complete = 1;
memcpy(&adv_manufacture_data[0], (uint8_t *)&adv->manufacturer_info.company_identifier, 2);
memcpy(&adv_manufacture_data[2], adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
fields.mfg_data = adv_manufacture_data;
fields.mfg_data_len = adv->manufacturer_info.adv_data_len + 2;
ret = ble_gap_adv_set_fields(&fields);
if (ret != 0)
{
ble_qiot_log_e("ble_gap_adv_set_fields() err, ret: %d", ret);
return BLE_QIOT_RS_ERR;
}
// set advertising respond data
rsp_fields.name = ADV_DEVICE_NAME;
rsp_fields.name_len = strlen(ADV_DEVICE_NAME);
rsp_fields.name_is_complete = 1;
ret = ble_gap_adv_rsp_set_fields(&rsp_fields);
if(ret != 0)
{
ble_qiot_log_e("ble_gap_adv_rsp_set_fields() err, ret: %d", ret);
return BLE_QIOT_RS_ERR;
}
ret = ble_hs_id_infer_auto(0, &ble_addr_type);
if (ret != 0)
{
ble_qiot_log_e("ble_hs_id_infer_auto() err, ret: %d", ret);
return BLE_QIOT_RS_ERR;
}
memset(&adv_params, 0, sizeof adv_params);
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
ret = ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER,
&adv_params, ble_qiot_gap_event_fn, NULL);
if (ret != 0)
{
ble_qiot_log_e("ble_gap_adv_start() err, ret: %d", ret);
return BLE_QIOT_RS_ERR;
}
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_advertising_stop(void)
{
int ret = 0;
ble_gap_adv_stop();
if(ret != 0)
{
ble_qiot_log_e("ble_gap_adv_stop() err, ret: %d", ret);
return BLE_QIOT_RS_ERR;
}
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
{
struct os_mbuf *om;
int rc = 0;
om = ble_hs_mbuf_from_flat(buf, len);
rc = ble_gattc_notify_custom(qiot_gap_connect_handle, qiot_event_handle, om);
if(rc)
{
ble_qiot_log_e("send notify err, return %d", rc);
return BLE_QIOT_RS_ERR;
}
return BLE_QIOT_RS_OK;
}
ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle)
{
return (ble_timer_t)NULL;
}
ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period)
{
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id)
{
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id)
{
return BLE_QIOT_RS_OK;
}
// should return ATT_MTU - 3
uint16_t ble_get_user_data_mtu_size(void)
{
// this is an example, the default mtu is 23, user should get real mtu and return it
int mtu = 23;
return mtu - 3;
}

View File

@@ -1,541 +0,0 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "ble_qiot_template.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "ble_qiot_export.h"
#include "ble_qiot_common.h"
#include "ble_qiot_param_check.h"
extern void property_power_switch(const char *data, uint16_t len);
extern void action_led_blink(int ms);
extern void report_reply_blink(void);
static uint8_t sg_test_power_switch = false;
static int ble_property_power_switch_set(const char *data, uint16_t len)
{
ble_qiot_log_d("set property power_switch %d", *(uint8_t *)data);
property_power_switch(data, len);
sg_test_power_switch = data[0];
return 0;
}
static int ble_property_power_switch_get(char *data, uint16_t buf_len)
{
ble_qiot_log_d("get property power_switch %d", sg_test_power_switch);
data[0] = sg_test_power_switch;
return sizeof(uint8_t);
}
static uint16_t sg_test_color = 0;
static int ble_property_color_set(const char *data, uint16_t len)
{
uint16_t color_value = 0;
memcpy(&color_value, data, sizeof(uint16_t));
color_value = NTOHS(color_value);
ble_qiot_log_d("set property color %d", color_value);
sg_test_color = color_value;
return 0;
}
static int ble_property_color_get(char *data, uint16_t buf_len)
{
uint16_t color_value = 0;
ble_qiot_log_d("get property color %d", color_value);
color_value = HTONS(sg_test_color);
memcpy(data, &color_value, sizeof(uint16_t));
return sizeof(uint16_t);
}
static int sg_test_brightness = 0;
static int ble_property_brightness_set(const char *data, uint16_t len)
{
int brightness_value = 0;
memcpy(&brightness_value, data, sizeof(int));
brightness_value = NTOHL(brightness_value);
if ((brightness_value < BLE_QIOT_PROPERTY_BRIGHTNESS_MIN) ||
(brightness_value > BLE_QIOT_PROPERTY_BRIGHTNESS_MAX)) {
ble_qiot_log_e("invalid brightness value %d", brightness_value);
return -1;
}
ble_qiot_log_d("set property brightness %d", brightness_value);
sg_test_brightness = brightness_value;
return 0;
}
static int ble_property_brightness_get(char *data, uint16_t buf_len)
{
int brightness_value = 0;
ble_qiot_log_d("get property brightness %d", sg_test_brightness);
brightness_value = HTONL(sg_test_brightness);
memcpy(data, &brightness_value, sizeof(int));
return sizeof(uint32_t);
}
static char sg_test_name[100 + 1] = "default name";
static int ble_property_name_set(const char *data, uint16_t len)
{
ble_qiot_log_d("set property name %.*s", len, data);
if (len > sizeof(sg_test_name) - 1) {
ble_qiot_log_d("too long name");
return -1;
}
memset(sg_test_name, 0, sizeof(sg_test_name));
memcpy(sg_test_name, data, len);
return 0;
}
static int ble_property_name_get(char *data, uint16_t buf_len)
{
int i = 0;
ble_qiot_log_d("get property name %s", sg_test_name);
if (0 == strncmp("default name", sg_test_name, sizeof("default name") - 1)) {
for (i = 0; i < 26 * 3; i++) {
data[i] = 'a' + (i % 26);
}
return i;
} else {
memcpy(data, sg_test_name, strlen(sg_test_name));
return strlen(sg_test_name);
}
}
static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {
{ble_property_power_switch_set, ble_property_power_switch_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_BOOL},
{ble_property_color_set, ble_property_color_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_ENUM},
{ble_property_brightness_set, ble_property_brightness_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_INT},
{ble_property_name_set, ble_property_name_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_STRING},
};
static bool ble_check_space_enough_by_type(uint8_t type, uint16_t left_size)
{
switch (type) {
case BLE_QIOT_DATA_TYPE_BOOL:
return left_size >= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return left_size >= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return left_size >= sizeof(uint16_t);
default:
// string length is unknow, default true
return true;
}
}
static uint16_t ble_check_ret_value_by_type(uint8_t type, uint16_t buf_len, uint16_t ret_val)
{
switch (type) {
case BLE_QIOT_DATA_TYPE_BOOL:
return ret_val <= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return ret_val <= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return ret_val <= sizeof(uint16_t);
default:
// string length is unknow, default true
return ret_val <= buf_len;
}
}
uint8_t ble_get_property_type_by_id(uint8_t id)
{
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_property_array[id].type;
}
int ble_user_property_set_data(const e_ble_tlv *tlv)
{
POINTER_SANITY_CHECK(tlv, BLE_QIOT_RS_ERR_PARA);
if (tlv->id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
if (NULL != sg_ble_property_array[tlv->id].set_cb) {
if (0 != sg_ble_property_array[tlv->id].set_cb(tlv->val, tlv->len)) {
ble_qiot_log_e("set property id %d failed", tlv->id);
return BLE_QIOT_RS_ERR;
} else {
return BLE_QIOT_RS_OK;
}
}
ble_qiot_log_e("invalid set callback, id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len)
{
int ret_len = 0;
POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return -1;
}
if (NULL != sg_ble_property_array[id].get_cb) {
if (!ble_check_space_enough_by_type(sg_ble_property_array[id].type, buf_len)) {
ble_qiot_log_e("not enough space get property id %d data", id);
return -1;
}
ret_len = sg_ble_property_array[id].get_cb(buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get property id %d data failed", id);
return -1;
} else {
if (ble_check_ret_value_by_type(sg_ble_property_array[id].type, buf_len, ret_len)) {
return ret_len;
} else {
ble_qiot_log_e("property id %d length invalid, type %d", id, sg_ble_property_array[id].type);
return -1;
}
}
}
ble_qiot_log_e("invalid callback, property id %d", id);
return 0;
}
int ble_user_property_report_reply_handle(uint8_t result)
{
ble_qiot_log_d("report reply result %d", result);
if (0 == result) {
report_reply_blink();
}
return BLE_QIOT_RS_OK;
}
static int ble_event_get_status_report_status(char *buf, uint16_t buf_len)
{
buf[0] = 1;
return 1;
}
static int ble_event_get_status_report_message(char *buf, uint16_t buf_len)
{
int i = 0;
for (i = 0; i < 26 * 3; i++) {
buf[i] = 'a' + (i % 26);
}
return i;
}
static ble_event_param sg_ble_event_status_report_array[BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_BUTT] = {
{ble_event_get_status_report_status, BLE_QIOT_DATA_TYPE_BOOL},
{ble_event_get_status_report_message, BLE_QIOT_DATA_TYPE_STRING},
};
static int ble_event_get_low_voltage_voltage(char *data, uint16_t buf_len)
{
float tmp = 1.0;
memcpy(data, &tmp, sizeof(float));
return sizeof(float);
}
static ble_event_param sg_ble_event_low_voltage_array[BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_BUTT] = {
{ble_event_get_low_voltage_voltage, BLE_QIOT_DATA_TYPE_FLOAT},
};
static int ble_event_get_hardware_fault_name(char *data, uint16_t buf_len)
{
memcpy(data, "hardware_fault", sizeof("hardware_fault") - 1);
return sizeof("hardware_fault") - 1;
}
static int ble_event_get_hardware_fault_error_code(char *data, uint16_t buf_len)
{
int error_code = HTONL(1024);
memcpy(data, &error_code, sizeof(int));
return sizeof(int);
}
static ble_event_param sg_ble_event_hardware_fault_array[BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_BUTT] = {
{ble_event_get_hardware_fault_name, BLE_QIOT_DATA_TYPE_STRING},
{ble_event_get_hardware_fault_error_code, BLE_QIOT_DATA_TYPE_INT},
};
static ble_event_t sg_ble_event_array[BLE_QIOT_EVENT_ID_BUTT] = {
{sg_ble_event_status_report_array, sizeof(sg_ble_event_status_report_array) / sizeof(ble_event_param)},
{sg_ble_event_low_voltage_array, sizeof(sg_ble_event_low_voltage_array) / sizeof(ble_event_param)},
{sg_ble_event_hardware_fault_array, sizeof(sg_ble_event_hardware_fault_array) / sizeof(ble_event_param)},
};
int ble_event_get_id_array_size(uint8_t event_id)
{
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
ble_qiot_log_e("invalid event id %d", event_id);
return -1;
}
return sg_ble_event_array[event_id].array_size;
}
uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id)
{
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
ble_qiot_log_e("invalid event id %d", event_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
if (param_id >= sg_ble_event_array[event_id].array_size) {
ble_qiot_log_e("invalid param id %d", param_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_event_array[event_id].event_array[param_id].type;
}
int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len)
{
int ret_len = 0;
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
ble_qiot_log_e("invalid event id %d", event_id);
return -1;
}
if (param_id >= sg_ble_event_array[event_id].array_size) {
ble_qiot_log_e("invalid param id %d", param_id);
return -1;
}
if (NULL == sg_ble_event_array[event_id].event_array[param_id].get_cb) {
ble_qiot_log_e("invalid callback, event id %d, param id %d", event_id, param_id);
return 0;
}
if (!ble_check_space_enough_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len)) {
ble_qiot_log_e("not enough space get data, event id %d, param id %d", event_id, param_id);
return -1;
}
ret_len = sg_ble_event_array[event_id].event_array[param_id].get_cb(out_buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get event data failed, event id %d, param id %d", event_id, param_id);
return -1;
} else {
if (ble_check_ret_value_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len, ret_len)) {
return ret_len;
} else {
ble_qiot_log_e("evnet data length invalid, event id %d, param id %d, type %d", event_id, param_id,
sg_ble_event_array[event_id].event_array[param_id].type);
return -1;
}
}
}
int ble_user_event_reply_handle(uint8_t event_id, uint8_t result)
{
ble_qiot_log_d("event id %d, reply result %d", event_id, result);
return BLE_QIOT_RS_OK;
}
static int ble_action_handle_loop_input_cb(e_ble_tlv *input_param_array, uint8_t input_array_size,
uint8_t *output_id_array)
{
int result = 0;
if (NULL == input_param_array || NULL == output_id_array) {
ble_qiot_log_e("invalid param");
return -1;
}
report_reply_blink();
for (int i = 0; i < input_array_size; i++) {
ble_qiot_log_d("id %d", input_param_array[i].id);
}
memcpy(&result, input_param_array[0].val, sizeof(int));
result = NTOHL(result);
ble_qiot_log_d("id %d, val %d", input_param_array[0].id, result);
action_led_blink(result);
output_id_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT] = true;
return 0;
}
static int ble_action_handle_loop_output_cb(uint8_t output_id, char *buf, uint16_t buf_len)
{
int data_len = 0;
int i = 0;
switch (output_id) {
case BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT:
for (i = 0; i < 26 * 3; i++) {
buf[i] = 'a' + (i % 26);
}
data_len = i;
break;
default:
break;
}
return data_len;
}
static uint8_t sg_ble_action_loop_input_type_array[BLE_QIOT_ACTION_LOOP_INPUT_ID_BUTT] = {
BLE_QIOT_DATA_TYPE_INT,
};
static uint8_t sg_ble_action_loop_output_type_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_BUTT] = {
BLE_QIOT_DATA_TYPE_STRING,
};
static ble_action_t sg_ble_action_array[BLE_QIOT_ACTION_ID_BUTT] = {
{ble_action_handle_loop_input_cb, ble_action_handle_loop_output_cb, sg_ble_action_loop_input_type_array,
sg_ble_action_loop_output_type_array, sizeof(sg_ble_action_loop_input_type_array) / sizeof(uint8_t),
sizeof(sg_ble_action_loop_output_type_array) / sizeof(uint8_t)},
};
uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
if (input_id >= sg_ble_event_array[action_id].array_size) {
ble_qiot_log_e("invalid input id %d", input_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_action_array[action_id].input_type_array[input_id];
}
uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
if (output_id >= sg_ble_event_array[action_id].array_size) {
ble_qiot_log_e("invalid output id %d", output_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_action_array[action_id].output_type_array[output_id];
}
int ble_action_get_input_id_size(uint8_t action_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
return sg_ble_action_array[action_id].input_id_size;
}
int ble_action_get_output_id_size(uint8_t action_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
return sg_ble_action_array[action_id].output_id_size;
}
int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
uint8_t *output_id_array)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
if (NULL != sg_ble_action_array[action_id].input_cb) {
if (0 != sg_ble_action_array[action_id].input_cb(input_param_array, input_array_size, output_id_array)) {
ble_qiot_log_e("input handle error");
return -1;
}
}
return 0;
}
int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len)
{
int ret_len = 0;
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
if (NULL == sg_ble_action_array[action_id].output_cb) {
ble_qiot_log_e("invalid callback, action id %d", action_id);
return 0;
}
if (!ble_check_space_enough_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len)) {
ble_qiot_log_e("not enough space get data, action id %d, output id %d", action_id, output_id);
return -1;
}
ret_len = sg_ble_action_array[action_id].output_cb(output_id, buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get action data failed, action id %d, output id %d", action_id, output_id);
return -1;
} else {
if (ble_check_ret_value_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len,
ret_len)) {
return ret_len;
} else {
ble_qiot_log_e("action data length invalid, action id %d, output id %d", action_id, output_id);
return -1;
}
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,285 +0,0 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef BLE_QIOT_TEMPLATE_H_
#define BLE_QIOT_TEMPLATE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
// data type in template, corresponding to type in json file
enum {
BLE_QIOT_DATA_TYPE_BOOL = 0,
BLE_QIOT_DATA_TYPE_INT,
BLE_QIOT_DATA_TYPE_STRING,
BLE_QIOT_DATA_TYPE_FLOAT,
BLE_QIOT_DATA_TYPE_ENUM,
BLE_QIOT_DATA_TYPE_TIME,
BLE_QIOT_DATA_TYPE_BUTT,
};
// message type, reference data template
enum {
BLE_QIOT_MSG_TYPE_PROPERTY = 0,
BLE_QIOT_MSG_TYPE_EVENT,
BLE_QIOT_MSG_TYPE_ACTION,
BLE_QIOT_MSG_TYPE_BUTT,
};
// define property authority, not used
enum {
BLE_QIOT_PROPERTY_AUTH_RW = 0,
BLE_QIOT_PROPERTY_AUTH_READ,
BLE_QIOT_PROPERTY_AUTH_BUTT,
};
// define reply result
enum {
BLE_QIOT_REPLY_SUCCESS = 0,
BLE_QIOT_REPLY_FAIL,
BLE_QIOT_REPLY_DATA_ERR,
BLE_QIOT_REPLY_BUTT,
};
// define message flow direction
enum {
BLE_QIOT_EFFECT_REQUEST = 0,
BLE_QIOT_EFFECT_REPLY,
BLE_QIOT_EFFECT_BUTT,
};
// define message type that from server to device
enum {
BLE_QIOT_DATA_DOWN_REPORT_REPLY = 0,
BLE_QIOT_DATA_DOWN_CONTROL,
BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY,
BLE_QIOT_DATA_DOWN_ACTION,
BLE_QIOT_DATA_DOWN_EVENT_REPLY,
};
// define message type that from device to server
enum {
BLE_QIOT_EVENT_UP_PROPERTY_REPORT = 0,
BLE_QIOT_EVENT_UP_CONTROL_REPLY,
BLE_QIOT_EVENT_UP_GET_STATUS,
BLE_QIOT_EVENT_UP_EVENT_POST,
BLE_QIOT_EVENT_UP_ACTION_REPLY,
BLE_QIOT_EVENT_UP_BIND_SIGN_RET,
BLE_QIOT_EVENT_UP_CONN_SIGN_RET,
BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET,
BLE_QIOT_EVENT_UP_REPORT_MTU,
BLE_QIOT_EVENT_UP_BUTT,
};
// msg header define, bit 7-6 is msg type, bit 5 means request or reply, bit 4 - 0 is id
#define BLE_QIOT_PARSE_MSG_HEAD_TYPE(_C) (((_C)&0XFF) >> 6)
#define BLE_QIOT_PARSE_MSG_HEAD_EFFECT(_C) ((((_C)&0XFF) & 0X20) ? BLE_QIOT_EFFECT_REPLY : BLE_QIOT_EFFECT_REQUEST)
#define BLE_QIOT_PARSE_MSG_HEAD_ID(_C) ((_C)&0X1F)
#define BLE_QIOT_PACKAGE_MSG_HEAD(_TYPE, _REPLY, _ID) \
(((_TYPE) << 6) | (((_REPLY) == BLE_QIOT_EFFECT_REPLY) << 5) | ((_ID)&0X1F))
// tlv header define, bit 7 - 5 is type, bit 4 - 0 depends on type of data template
#define BLE_QIOT_PARSE_TLV_HEAD_TYPE(_C) (((_C)&0XFF) >> 5)
#define BLE_QIOT_PARSE_TLV_HEAD_ID(_C) ((_C)&0X1F)
#define BLE_QIOT_PACKAGE_TLV_HEAD(_TYPE, _ID) (((_TYPE) << 5) | ((_ID)&0X1F))
// define property id
enum {
BLE_QIOT_PROPERTY_ID_POWER_SWITCH = 0,
BLE_QIOT_PROPERTY_ID_COLOR,
BLE_QIOT_PROPERTY_ID_BRIGHTNESS,
BLE_QIOT_PROPERTY_ID_NAME,
BLE_QIOT_PROPERTY_ID_BUTT,
};
// define property color enum
enum {
BLE_QIOT_PROPERTY_COLOR_RED = 0,
BLE_QIOT_PROPERTY_COLOR_GREEN = 1,
BLE_QIOT_PROPERTY_COLOR_BLUE = 2,
BLE_QIOT_PROPERTY_COLOR_BUTT = 3,
};
// define brightness attributes
#define BLE_QIOT_PROPERTY_BRIGHTNESS_STEP (1)
#define BLE_QIOT_PROPERTY_BRIGHTNESS_MIN (0)
#define BLE_QIOT_PROPERTY_BRIGHTNESS_MAX (100)
#define BLE_QIOT_PROPERTY_BRIGHTNESS_START (1)
// define name length limit
#define BLE_QIOT_PROPERTY_NAME_LEN_MIN (0)
#define BLE_QIOT_PROPERTY_NAME_LEN_MAX (640)
// define property set handle return 0 if success, other is error
// sdk call the function that inform the server data to the device
typedef int (*property_set_cb)(const char *data, uint16_t len);
// define property get handle. return the data length obtained, -1 is error, 0 is no data
// sdk call the function fetch user data and send to the server, the data should wrapped by user adn skd just transmit
typedef int (*property_get_cb)(char *buf, uint16_t buf_len);
// each property have a struct ble_property_t, make up a array named sg_ble_property_array
typedef struct {
property_set_cb set_cb; // set callback
property_get_cb get_cb; // get callback
uint8_t authority; // property authority
uint8_t type; // data type
} ble_property_t;
// define event id
enum {
BLE_QIOT_EVENT_ID_STATUS_REPORT = 0,
BLE_QIOT_EVENT_ID_LOW_VOLTAGE,
BLE_QIOT_EVENT_ID_HARDWARE_FAULT,
BLE_QIOT_EVENT_ID_BUTT,
};
// define param id for event status_report
enum {
BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_STATUS = 0,
BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_MESSAGE,
BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_BUTT,
};
// define range for param message
#define BLE_QIOT_EVENT_STATUS_REPORT_MESSAGE_LEN_MIN (0)
#define BLE_QIOT_EVENT_STATUS_REPORT_MESSAGE_LEN_MAX (64)
// define param id for event low_voltage
enum {
BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_VOLTAGE = 0,
BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_BUTT,
};
// define param voltage attributes
#define BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_STEP (1)
#define BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_MIN (0.0)
#define BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_MAX (24.0)
#define BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_START (1)
// define param id for event hardware_fault
enum {
BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_NAME = 0,
BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_ERROR_CODE,
BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_BUTT,
};
// define range for param name
#define BLE_QIOT_EVENT_HARDWARE_FAULT_NAME_LEN_MIN (0)
#define BLE_QIOT_EVENT_HARDWARE_FAULT_NAME_LEN_MAX (64)
// define param error_code attributes
#define BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_STEP (1)
#define BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_MIN (0)
#define BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_MAX (2000)
#define BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_START (1)
// define event get handle. return the data length obtained, -1 is error, 0 is no data
// sdk call the function fetch user data and send to the server, the data should wrapped by user adn skd just transmit
typedef int (*event_get_cb)(char *buf, uint16_t buf_len);
// each param have a struct ble_event_param, make up a array for the event
typedef struct {
event_get_cb get_cb; // get param data callback
uint8_t type; // param type
} ble_event_param;
// a array named sg_ble_event_array is composed by all the event array
typedef struct {
ble_event_param *event_array; // array of params data
uint8_t array_size; // array size
} ble_event_t;
// define action id
enum {
BLE_QIOT_ACTION_ID_LOOP = 0,
BLE_QIOT_ACTION_ID_BUTT,
};
// define input id for action loop
enum {
BLE_QIOT_ACTION_LOOP_INPUT_ID_INTERVAL = 0,
BLE_QIOT_ACTION_LOOP_INPUT_ID_BUTT,
};
// define output id for action loop
enum {
BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT = 0,
BLE_QIOT_ACTION_LOOP_OUTPUT_ID_BUTT,
};
#define BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_MIN (0)
#define BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_MAX (100)
#define BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_START (0)
#define BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_STEP (1)
// define output id result attributes
#define BLE_QIOT_ACTION_OUTPUT_LOOP_RESULT_LEN_MIN (0)
#define BLE_QIOT_ACTION_OUTPUT_LOOP_RESULT_LEN_MAX (320)
// define max input id and output id in all of input id and output id above
#define BLE_QIOT_ACTION_INPUT_ID_BUTT 1
#define BLE_QIOT_ACTION_OUTPUT_ID_BUTT 1
// define tlv struct
typedef struct {
uint8_t type;
uint8_t id;
uint16_t len;
char * val;
} e_ble_tlv;
// define action input handle, return 0 is success, other is error.
// input_param_array carry the data from server, include input id, data length ,data val
// input_array_size means how many input id
// output_id_array filling with output id numbers that need obtained, sdk will traverse it and call the
// action_output_handle to obtained data
typedef int (*action_input_handle)(e_ble_tlv *input_param_array, uint8_t input_array_size, uint8_t *output_id_array);
// define action output handle, return length of the data, 0 is no data, -1 is error
// output_id means which id data should be obtained
typedef int (*action_output_handle)(uint8_t output_id, char *buf, uint16_t buf_len);
// each action have a struct ble_action_t, make up a array named sg_ble_action_array
typedef struct {
action_input_handle input_cb; // handle input data
action_output_handle output_cb; // get output data in the callback
uint8_t * input_type_array; // type array for input id
uint8_t * output_type_array; // type array for output id
uint8_t input_id_size; // numbers of input id
uint8_t output_id_size; // numbers of output id
} ble_action_t;
// property module
uint8_t ble_get_property_type_by_id(uint8_t id);
int ble_user_property_set_data(const e_ble_tlv *tlv);
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len);
int ble_user_property_report_reply_handle(uint8_t result);
// event module
int ble_event_get_id_array_size(uint8_t event_id);
uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id);
int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len);
int ble_user_event_reply_handle(uint8_t event_id, uint8_t result);
// action module
uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id);
uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id);
int ble_action_get_input_id_size(uint8_t action_id);
int ble_action_get_output_id_size(uint8_t action_id);
int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
uint8_t *output_id_array);
int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len);
#ifdef __cplusplus
}
#endif
#endif // BLE_QIOT_TEMPLATE_H_

View File

@@ -1,183 +0,0 @@
{
"version": "1.0",
"profile": {
"ProductId": "DHZX03IQAZ",
"CategoryId": "141"
},
"properties": [
{
"id": "power_switch",
"name": "电灯开关",
"desc": "控制电灯开灭",
"required": true,
"mode": "rw",
"define": {
"type": "bool",
"mapping": {
"0": "关",
"1": "开"
}
}
},
{
"id": "color",
"name": "颜色",
"desc": "灯光颜色",
"mode": "rw",
"define": {
"type": "enum",
"mapping": {
"0": "Red",
"1": "Green",
"2": "Blue"
}
}
},
{
"id": "brightness",
"name": "亮度",
"desc": "灯光亮度",
"mode": "rw",
"define": {
"type": "int",
"unit": "%",
"step": "1",
"min": "0",
"max": "100",
"start": "1"
}
},
{
"id": "name",
"name": "灯位置名称",
"desc": "灯位置名称:书房、客厅等",
"mode": "rw",
"define": {
"type": "string",
"min": "0",
"max": "640"
},
"required": false
}
],
"events": [
{
"id": "status_report",
"name": "DeviceStatus",
"desc": "Report the device status",
"type": "info",
"required": false,
"params": [
{
"id": "status",
"name": "running_state",
"desc": "Report current device running state",
"define": {
"type": "bool",
"mapping": {
"0": "normal",
"1": "fault"
}
}
},
{
"id": "message",
"name": "Message",
"desc": "Some extra message",
"define": {
"type": "string",
"min": "0",
"max": "64"
}
}
]
},
{
"id": "low_voltage",
"name": "LowVoltage",
"desc": "Alert for device voltage is low",
"type": "alert",
"required": false,
"params": [
{
"id": "voltage",
"name": "Voltage",
"desc": "Current voltage",
"define": {
"type": "float",
"unit": "V",
"step": "1",
"min": "0.0",
"max": "24.0",
"start": "1"
}
}
]
},
{
"id": "hardware_fault",
"name": "Hardware_fault",
"desc": "Report hardware fault",
"type": "fault",
"required": false,
"params": [
{
"id": "name",
"name": "Name",
"desc": "Name like: memory,tf card, censors ...",
"define": {
"type": "string",
"min": "0",
"max": "64"
}
},
{
"id": "error_code",
"name": "Error_Code",
"desc": "Error code for fault",
"define": {
"type": "int",
"unit": "",
"step": "1",
"min": "0",
"max": "2000",
"start": "1"
}
}
]
}
],
"actions": [
{
"id": "loop",
"name": "loop",
"desc": "",
"input": [
{
"id": "interval",
"name": "interval",
"define": {
"type": "int",
"min": "0",
"max": "100",
"start": "0",
"step": "1",
"unit": ""
}
}
],
"output": [
{
"id": "result",
"name": "result",
"define": {
"type": "string",
"min": "0",
"max": "320"
}
}
],
"required": false
}
]
}

View File

@@ -1,209 +0,0 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "flash_storage.h"
#include "ble_qiot_config.h"
#include "nrf_fstorage.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_fstorage_nvmc.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include <stdlib.h>
#ifdef SOFTDEVICE_PRESENT
#include "nrf_fstorage_sd.h"
#else
#include "nrf_fstorage_nvmc.h"
#endif
static void fstorage_evt_handler(nrf_fstorage_evt_t *p_evt);
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) = {
/* Set a handler for fstorage events. */
.evt_handler = fstorage_evt_handler,
/* These below are the boundaries of the flash space assigned to this instance of fstorage.
* You must set these manually, even at runtime, before nrf_fstorage_init() is called.
* The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
* last page of flash available to write data. */
.start_addr = 0x7e000,
.end_addr = 0x7ffff,
};
static void *p_write_buf = NULL;
void fstorage_init(void)
{
nrf_fstorage_api_t *p_fs_api;
ret_code_t rc;
#ifdef SOFTDEVICE_PRESENT
NRF_LOG_INFO("SoftDevice is present.");
NRF_LOG_INFO("Initializing nrf_fstorage_sd implementation...");
/* Initialize an fstorage instance using the nrf_fstorage_sd backend.
* nrf_fstorage_sd uses the SoftDevice to write to flash. This implementation can safely be
* used whenever there is a SoftDevice, regardless of its status (enabled/disabled). */
p_fs_api = &nrf_fstorage_sd;
#else
NRF_LOG_INFO("SoftDevice not present.");
NRF_LOG_INFO("Initializing nrf_fstorage_nvmc implementation...");
/* Initialize an fstorage instance using the nrf_fstorage_nvmc backend.
* nrf_fstorage_nvmc uses the NVMC peripheral. This implementation can be used when the
* SoftDevice is disabled or not present.
*
* Using this implementation when the SoftDevice is enabled results in a hardfault. */
p_fs_api = &nrf_fstorage_nvmc;
#endif
p_write_buf = NULL;
rc = nrf_fstorage_init(&fstorage, p_fs_api, NULL);
APP_ERROR_CHECK(rc);
}
/**@brief Helper function to obtain the last address on the last page of the on-chip flash that
* can be used to write user data.
* It is possible to set the start and end addresses of an fstorage instance at runtime.
* They can be set multiple times, should it be needed. The helper function below can
* be used to determine the last address on the last page of flash memory available to
* store data.
*/
/*
static uint32_t nrf5_flash_end_addr_get()
{
uint32_t const bootloader_addr = NRF_UICR->NRFFW[0];
uint32_t const page_sz = NRF_FICR->CODEPAGESIZE;
uint32_t const code_sz = NRF_FICR->CODESIZE;
return (bootloader_addr != 0xFFFFFFFF ?
bootloader_addr : (code_sz * page_sz));
}
*/
/**@brief Sleep until an event is received. */
static void power_manage(void)
{
#ifdef SOFTDEVICE_PRESENT
(void)sd_app_evt_wait();
#else
__WFE();
#endif
}
int fstorage_read(uint32_t addr, uint32_t read_len, void *p_data)
{
ret_code_t rc;
/* Read data. */
rc = nrf_fstorage_read(&fstorage, addr, p_data, read_len);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_read() returned: %s\n", nrf_strerror_get(rc));
return 0;
}
return read_len;
}
static uint32_t round_up_u32(uint32_t len)
{
if (len % sizeof(uint32_t)) {
return (len + sizeof(uint32_t) - (len % sizeof(uint32_t)));
}
return len;
}
int fstorage_erase(uint32_t addr)
{
ret_code_t rc;
rc = nrf_fstorage_erase(&fstorage, addr, BLE_QIOT_RECORD_FLASH_PAGENUM, NULL);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_erase() returned: %s\n", nrf_strerror_get(rc));
return rc;
}
return 0;
}
int fstorage_write(uint32_t addr, uint32_t write_len, void const *p_data)
{
/* The following code snippet make sure that the length of the data we are writing to flash
* is a multiple of the program unit of the flash peripheral (4 bytes).
*/
uint32_t len = round_up_u32(write_len);
ret_code_t rc;
rc = nrf_fstorage_erase(&fstorage, addr, BLE_QIOT_RECORD_FLASH_PAGENUM, NULL);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_erase() returned: %s\n", nrf_strerror_get(rc));
}
/* Copy the data to write in flash.
* Because the fstorage interface is asynchrounous, the data must be kept in memory before get
* the NRF_FSTORAGE_EVT_WRITE_RESULT event. This memory will be free in fstorage_evt_handler().
*/
p_write_buf = (void *)malloc(len);
if (NULL == p_write_buf) {
NRF_LOG_ERROR("fstorage_write() malloc size %d error", len);
return 0;
}
memset(p_write_buf, 0, len);
memcpy(p_write_buf, p_data, write_len);
rc = nrf_fstorage_write(&fstorage, addr, p_write_buf, len, NULL);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_write() returned: %s\n", nrf_strerror_get(rc));
return 0;
}
return write_len;
}
static void fstorage_evt_handler(nrf_fstorage_evt_t *p_evt)
{
if (p_evt->result != NRF_SUCCESS) {
NRF_LOG_INFO("fstorage event received: ERROR while executing an fstorage operation.");
return;
}
switch (p_evt->id) {
case NRF_FSTORAGE_EVT_WRITE_RESULT: {
free(p_write_buf);
p_write_buf = NULL;
NRF_LOG_INFO("fstorage event received: wrote %d bytes at address 0x%x.", p_evt->len, p_evt->addr);
} break;
case NRF_FSTORAGE_EVT_ERASE_RESULT: {
NRF_LOG_INFO("fstorage event received: erased %d page from address 0x%x.", p_evt->len, p_evt->addr);
} break;
default:
break;
}
}
/**
* @brief While fstorage is busy, sleep and wait for an event.
*
* @param p_fstorage nrf_fstorage_t obj
*/
void wait_for_flash_ready(nrf_fstorage_t const *p_fstorage)
{
/* While fstorage is busy, sleep and wait for an event. */
while (nrf_fstorage_is_busy(p_fstorage)) {
power_manage();
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdint.h>
/**
* @brief initialize of flash storage
*
*/
void fstorage_init(void);
/**
* @brief read data from flash
*
* @param addr read address from flash
* @param read_len length of data to read
* @param p_data point to read buf
* @return read length is success, other is error
*/
int fstorage_read(uint32_t addr, uint32_t read_len, void *p_data);
/**
* @brief write data to flash, must erase before write
*
* @param addr write address in flash
* @param write_len length of data to write
* @param p_data point to write buf
* @return write length is success, other is error
*/
int fstorage_write(uint32_t addr, uint32_t write_len, void const *p_data);
/**
* @brief erase one page
*
* @param addr address must align to page. For example, one page is 4096 bytes,
* you want to erase address 0x1020, you should set address 0x1000
* @return 0 is succcess, other is error
*/
int fstorage_erase(uint32_t addr);

View File

@@ -1,85 +0,0 @@
/**
* Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_FPRINTF)
#include <stdarg.h>
#include "nrf_assert.h"
#include "nrf_fprintf_format.h"
void nrf_fprintf_buffer_flush(nrf_fprintf_ctx_t * const p_ctx)
{
ASSERT(p_ctx != NULL);
if (p_ctx->io_buffer_cnt == 0)
{
return;
}
p_ctx->fwrite(p_ctx->p_user_ctx,
p_ctx->p_io_buffer,
p_ctx->io_buffer_cnt);
p_ctx->io_buffer_cnt = 0;
}
void nrf_fprintf(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
...)
{
ASSERT(p_ctx != NULL);
ASSERT(p_ctx->fwrite != NULL);
ASSERT(p_ctx->p_io_buffer != NULL);
ASSERT(p_ctx->io_buffer_size > 0);
if (p_fmt == NULL)
{
return;
}
va_list args = {0};
va_start(args, p_fmt);
nrf_fprintf_fmt(p_ctx, p_fmt, &args);
va_end(args);
}
#endif // NRF_MODULE_ENABLED(NRF_FPRINTF)

View File

@@ -1,114 +0,0 @@
/**
* Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_FPRINTF_H__
#define NRF_FPRINTF_H__
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (* nrf_fprintf_fwrite)(void const * p_user_ctx, char const * p_str, size_t length);
/**
* @brief fprintf context
*/
typedef struct nrf_fprintf_ctx
{
char * const p_io_buffer; ///< Pointer to IO buffer.
size_t const io_buffer_size; ///< IO buffer size.
size_t io_buffer_cnt; ///< IO buffer usage.
bool auto_flush; ///< Auto flush configurator.
void const * const p_user_ctx; ///< Pointer to user data to be passed to the fwrite funciton.
nrf_fprintf_fwrite fwrite; ///< Pointer to function sending data stream.
} nrf_fprintf_ctx_t;
/**
* @brief Macro for defining nrf_fprintf instance.
*
* @param name Instance name.
* @param _p_user_ctx Pointer to user data.
* @param _p_io_buffer Pointer to IO buffer
* @param _io_buffer_size Size of IO buffer.
* @param _auto_flush Indicator if IO buffer shall be automatically flush.
* @param _fwrite Pointer to function sending data stream.
* */
#define NRF_FPRINTF_DEF(name, _p_user_ctx, _p_io_buffer, _io_buffer_size, _auto_flush, _fwrite) \
static nrf_fprintf_ctx_t name = \
{ \
.p_io_buffer = _p_io_buffer, \
.io_buffer_size = _io_buffer_size, \
.io_buffer_cnt = 0, \
.auto_flush = _auto_flush, \
.p_user_ctx = _p_user_ctx, \
.fwrite = _fwrite \
}
/**
* @brief fprintf like function which send formated data stream to output specified by user
* @ref nrf_fprintf_ctx_t
*
* @param p_ctx fprintf context.
* @param p_fmt Format string.
* @param ... List of parameters to print.
* */
void nrf_fprintf(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
...);
/**
* @brief function flushing data stored in io_buffer @ref nrf_fprintf_ctx_t
*
* @param p_ctx fprintf context
*/
void nrf_fprintf_buffer_flush(nrf_fprintf_ctx_t * const p_ctx);
#ifdef __cplusplus
}
#endif
#endif /* NRF_FPRINTF_H__ */

View File

@@ -1,516 +0,0 @@
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* The Embedded Experts *
**********************************************************************
* *
* (c) 2014 - 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* conditions are met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* o Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the following *
* disclaimer in the documentation and/or other materials provided *
* with the distribution. *
* *
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
* nor the names of its contributors may be used to endorse or *
* promote products derived from this software without specific *
* prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
* *
* RTT version: 6.14d *
* *
*********************************************************************/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_FPRINTF)
#include <stdarg.h>
#include "nrf_assert.h"
#include "nrf_fprintf.h"
#include "nrf_fprintf_format.h"
#define NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
#define NRF_CLI_FORMAT_FLAG_PAD_ZERO (1u << 1)
#define NRF_CLI_FORMAT_FLAG_PRINT_SIGN (1u << 2)
static void buffer_add(nrf_fprintf_ctx_t * const p_ctx, char c)
{
#if NRF_MODULE_ENABLED(NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF)
if (c == '\n')
{
buffer_add(p_ctx, '\r');
}
#endif
p_ctx->p_io_buffer[p_ctx->io_buffer_cnt++] = c;
if (p_ctx->io_buffer_cnt >= p_ctx->io_buffer_size)
{
nrf_fprintf_buffer_flush(p_ctx);
}
}
static void string_print(nrf_fprintf_ctx_t * const p_ctx,
char const * p_str,
uint32_t FieldWidth,
uint32_t FormatFlags)
{
uint32_t Width = 0;
char c;
if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
{
while ((c = *p_str) != '\0')
{
p_str++;
Width++;
buffer_add(p_ctx, c);
}
while ((FieldWidth > Width) && (FieldWidth > 0))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
}
else
{
if (p_str != 0)
{
Width = strlen(p_str);
}
while ((FieldWidth > Width) && (FieldWidth > 0))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
while ((c = *p_str) != '\0')
{
p_str++;
Width++;
buffer_add(p_ctx, c);
}
}
}
static void unsigned_print(nrf_fprintf_ctx_t * const p_ctx,
uint32_t v,
uint32_t Base,
uint32_t NumDigits,
uint32_t FieldWidth,
uint32_t FormatFlags)
{
static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' };
uint32_t Div;
uint32_t Value;
uint32_t Width;
char c;
Value = v;
//
// Get actual field width
//
Width = 1u;
while (Value >= Base)
{
Value = (Value / Base);
Width++;
}
if (NumDigits > Width)
{
Width = NumDigits;
}
//
// Print leading chars if necessary
//
if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u)
{
if (FieldWidth != 0u)
{
if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
(NumDigits == 0u))
{
c = '0';
}
else
{
c = ' ';
}
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, c);
}
}
}
Value = 1;
/*
* Compute Digit.
* Loop until Digit has the value of the highest digit required.
* Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
*/
while (1)
{
/* User specified a min number of digits to print? => Make sure we loop at least that
* often, before checking anything else (> 1 check avoids problems with NumDigits
* being signed / unsigned)
*/
if (NumDigits > 1u)
{
NumDigits--;
}
else
{
Div = v / Value;
// Is our divider big enough to extract the highest digit from value? => Done
if (Div < Base)
{
break;
}
}
Value *= Base;
}
//
// Output digits
//
do
{
Div = v / Value;
v -= Div * Value;
buffer_add(p_ctx, _aV2C[Div]);
Value /= Base;
} while (Value);
//
// Print trailing spaces if necessary
//
if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
{
if (FieldWidth != 0u)
{
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
}
}
}
static void int_print(nrf_fprintf_ctx_t * const p_ctx,
int32_t v,
uint32_t Base,
uint32_t NumDigits,
uint32_t FieldWidth,
uint32_t FormatFlags)
{
uint32_t Width;
int32_t Number;
Number = (v < 0) ? -v : v;
//
// Get actual field width
//
Width = 1u;
while (Number >= (int32_t)Base)
{
Number = (Number / (int32_t)Base);
Width++;
}
if (NumDigits > Width)
{
Width = NumDigits;
}
if ((FieldWidth > 0u) && ((v < 0) ||
((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)))
{
FieldWidth--;
}
//
// Print leading spaces if necessary
//
if ((((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) &&
((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u))
{
if (FieldWidth != 0u)
{
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
}
}
//
// Print sign if necessary
//
if (v < 0)
{
v = -v;
buffer_add(p_ctx, '-');
}
else if ((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)
{
buffer_add(p_ctx, '+');
}
else
{
/* do nothing */
}
//
// Print leading zeros if necessary
//
if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u))
{
if (FieldWidth != 0u)
{
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, '0');
}
}
}
//
// Print number without sign
//
unsigned_print(p_ctx, (uint32_t)v, Base, NumDigits, FieldWidth, FormatFlags);
}
void nrf_fprintf_fmt(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
va_list * p_args)
{
ASSERT(p_ctx != NULL);
ASSERT(p_ctx->fwrite != NULL);
ASSERT(p_ctx->p_io_buffer != NULL);
ASSERT(p_ctx->io_buffer_size > 0);
if (p_fmt == NULL)
{
return;
}
char c;
int32_t v;
uint32_t NumDigits;
uint32_t FormatFlags;
uint32_t FieldWidth;
do
{
c = *p_fmt;
p_fmt++;
if (c == 0u)
{
break;
}
if (c == '%')
{
//
// Filter out flags
//
FormatFlags = 0u;
v = 1;
do
{
c = *p_fmt;
switch (c)
{
case '-':
FormatFlags |= NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY;
p_fmt++;
break;
case '0':
FormatFlags |= NRF_CLI_FORMAT_FLAG_PAD_ZERO;
p_fmt++;
break;
case '+':
FormatFlags |= NRF_CLI_FORMAT_FLAG_PRINT_SIGN;
p_fmt++;
break;
default:
v = 0;
break;
}
} while (v);
//
// filter out field width
//
FieldWidth = 0u;
do
{
if (c == '*')
{
/*lint -save -e64 -e56*/
FieldWidth += va_arg(*p_args, unsigned);
/*lint -restore*/
p_fmt++;
break;
}
c = *p_fmt;
if ((c < '0') || (c > '9'))
{
break;
}
p_fmt++;
FieldWidth = (FieldWidth * 10u) + (c - '0');
} while (1);
//
// Filter out precision (number of digits to display)
//
NumDigits = 0u;
c = *p_fmt;
if (c == '.')
{
p_fmt++;
do
{
c = *p_fmt;
if ((c < '0') || (c > '9'))
{
break;
}
p_fmt++;
NumDigits = NumDigits * 10u + (c - '0');
} while (1);
}
//
// Filter out length modifier
//
c = *p_fmt;
do
{
if ((c == 'l') || (c == 'h'))
{
p_fmt++;
c = *p_fmt;
}
else
{
break;
}
} while (1);
//
// Handle specifiers
//
/*lint -save -e64*/
switch (c)
{
case 'c':
{
char c0;
v = va_arg(*p_args, int32_t);
c0 = (char)v;
buffer_add(p_ctx, c0);
break;
}
case 'd':
case 'i':
v = va_arg(*p_args, int32_t);
int_print(p_ctx,
v,
10u,
NumDigits,
FieldWidth,
FormatFlags);
break;
case 'u':
v = va_arg(*p_args, int32_t);
unsigned_print(p_ctx,
(uint32_t)v,
10u,
NumDigits,
FieldWidth,
FormatFlags);
break;
case 'x':
case 'X':
v = va_arg(*p_args, int32_t);
unsigned_print(p_ctx,
(uint32_t)v,
16u,
NumDigits,
FieldWidth,
FormatFlags);
break;
case 's':
{
char const * p_s = va_arg(*p_args, const char *);
string_print(p_ctx, p_s, FieldWidth, FormatFlags);
break;
}
case 'p':
v = va_arg(*p_args, int32_t);
buffer_add(p_ctx, '0');
buffer_add(p_ctx, 'x');
unsigned_print(p_ctx, (uint32_t)v, 16u, 8u, 8u, 0);
break;
case '%':
buffer_add(p_ctx, '%');
break;
default:
break;
}
/*lint -restore*/
p_fmt++;
}
else
{
buffer_add(p_ctx, c);
}
} while (*p_fmt != '\0');
if (p_ctx->auto_flush)
{
nrf_fprintf_buffer_flush(p_ctx);
}
}
#endif // NRF_MODULE_ENABLED(NRF_FPRINTF)

View File

@@ -1,86 +0,0 @@
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* The Embedded Experts *
**********************************************************************
* *
* (c) 2014 - 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* conditions are met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* o Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the following *
* disclaimer in the documentation and/or other materials provided *
* with the distribution. *
* *
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
* nor the names of its contributors may be used to endorse or *
* promote products derived from this software without specific *
* prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
* *
* RTT version: 6.14d *
* *
*********************************************************************/
#ifndef NRF_FPRINTF_FORMAT_H__
#define NRF_FPRINTF_FORMAT_H__
#include <stdarg.h>
#include "nrf_fprintf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Printf like function which sends formated data stream to output.
*
* @param nrf_fprintf_ctx_t Print context.
* @param p_fmt Format string.
* @param p_args List of parameters to print.
* */
void nrf_fprintf_fmt(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
va_list * p_args);
#ifdef __cplusplus
}
#endif
#endif /* NRF_FPRINTF_FORMAT_H__ */

View File

@@ -1,155 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
// #include "blehr_sens.h"
#include "services/dis/ble_svc_dis.h"
#include "services/bas/ble_svc_bas.h"
#define GATT_DEVICE_INFO_UUID 0x180A
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
#define GATT_MODEL_NUMBER_UUID 0x2A24
#define REPLY_BUFFER_SIZE 100
static char reply[REPLY_BUFFER_SIZE];
static int gatt_svr_chr_access_device_info_manufacturer(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int gatt_svr_chr_access_device_info_model(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
/* define several bluetooth services for our device */
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
/*
* access_cb defines a callback for read and write access events on
* given characteristics
*/
{
/* Service: Device Information */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: * Manufacturer name */
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
.access_cb = gatt_svr_chr_access_device_info_manufacturer,
.flags = BLE_GATT_CHR_F_READ,
}, {
/* Characteristic: Model number string */
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
.access_cb = gatt_svr_chr_access_device_info_model,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* No more characteristics in this service */
}, }
},
{
0, /* No more services */
},
};
static int gatt_svr_chr_access_device_info_manufacturer(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("service 'device info: manufacturer' callback triggered\n");
snprintf(reply, REPLY_BUFFER_SIZE, "This is TencentOS tiny\n");
printf("reply: %s\n", reply);
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
printf("\n");
return rc;
}
static int gatt_svr_chr_access_device_info_model(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("service 'device info: model' callback triggered\n");
snprintf(reply, REPLY_BUFFER_SIZE, "running TencentOS tiny on nordic ble board");
printf("reply: %s\n", reply);
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
printf("\n");
return rc;
}
void
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
char buf[BLE_UUID_STR_LEN];
switch (ctxt->op) {
case BLE_GATT_REGISTER_OP_SVC:
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
ctxt->svc.handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
"def_handle=%d val_handle=%d\n",
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
ctxt->chr.def_handle,
ctxt->chr.val_handle);
break;
case BLE_GATT_REGISTER_OP_DSC:
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
ctxt->dsc.handle);
break;
default:
assert(0);
break;
}
}
int
gatt_svr_init(void)
{
int rc;
rc = ble_gatts_count_cfg(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
rc = ble_gatts_add_svcs(gatt_svr_svcs);
if (rc != 0) {
return rc;
}
return 0;
}

View File

@@ -1,142 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nimble/nimble_port_tencentos_tiny.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "boards.h"
#include "ble_qiot_config.h"
#include "flash_storage.h"
#include "ble_qiot_export.h"
#include "ble_qiot_import.h"
extern int gatt_svr_init(void);
extern void board_init(void);
extern void nimble_port_init(void);
static const char device_name[] = "TOS LLSync";
static uint8_t ble_addr_type;
void ble_boot(void *arg)
{
int rc = 0;
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
/* make sure synchronization of host and controller is done */
while (!ble_hs_synced()) {
;
}
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
rc = ble_hs_id_infer_auto(0, &ble_addr_type);
assert(rc == 0);
ble_svc_gap_init();
ble_svc_gatt_init();
/* verify and add our custom services */
rc = gatt_svr_init();
assert(rc == 0);
/* init llsync, add llsync services */
ble_qiot_explorer_init();
/* set the device name */
rc = ble_svc_gap_device_name_set(device_name);
assert(rc == 0);
/* reload the GATT server to link our added services */
ble_gatts_start();
/* llsync start advertising */
ble_qiot_advertising_start();
return;
}
static void leds_init(void)
{
bsp_board_init(BSP_INIT_LEDS);
}
void property_power_switch(const char *data, uint16_t len)
{
if (data[0]) {
bsp_board_led_on(BSP_BOARD_LED_0);
printf("Received LED ON!");
} else {
bsp_board_led_off(BSP_BOARD_LED_0);
printf("Received LED OFF!");
}
return;
}
void action_led_blink(int ms)
{
bsp_board_led_on(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_on(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_on(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
}
void report_reply_blink(void)
{
bsp_board_led_on(BSP_BOARD_LED_2);
tos_sleep_ms(200);
bsp_board_led_off(BSP_BOARD_LED_2);
tos_sleep_ms(200);
bsp_board_led_on(BSP_BOARD_LED_2);
tos_sleep_ms(200);
bsp_board_led_off(BSP_BOARD_LED_2);
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[2048];
int main(void)
{
board_init();
// other devices init
leds_init();
/* init flash that llsync need to save some device info */
fstorage_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
/*
in this case, ble_boot_task's priority must lower than MYNEWT_VAL_BLE_HOST_TASK_PRIORITY && MYNEWT_VAL_BLE_LL_TASK_PRIORITY,
numerically bigger
to give the host and ll task a chance to run first just after the nimble_port_tencentos_tiny_init.
*/
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
6,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,564 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include "mesh/mesh.h"
#include "console/console.h"
#if 0
#include "hal/hal_system.h"
#include "hal/hal_gpio.h"
#include "bsp/bsp.h"
#include "shell/shell.h"
#endif
///////////////////////
// stub-s
#define LED_1 17
#define LED_2 18
#define LED_3 19
#define LED_4 20
void hal_gpio_init_out(int led, int s)
{
}
void hal_gpio_write(int led, int s)
{
}
int __atomic_load_4(int *p)
{
return *p;
}
int __atomic_fetch_and_4(int *p, int v)
{
return *p & v;
}
int __atomic_fetch_or_4(int *p, int v)
{
return *p | v;
}
int __atomic_exchange_4(int *p, int v)
{
int old = *p;
*p = v;
return old;
}
void unreachable(void)
{
while (1) {
;
}
}
//////////////////////
/* BLE */
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "services/gap/ble_svc_gap.h"
#include "mesh/glue.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG))
/* Company ID */
#define CID_VENDOR 0x05C3
#define STANDARD_TEST_ID 0x00
#define TEST_ID 0x01
static int recent_test_id = STANDARD_TEST_ID;
#define FAULT_ARR_SIZE 2
static bool has_reg_fault = true;
static struct bt_mesh_cfg_srv cfg_srv = {
.relay = BT_MESH_RELAY_DISABLED,
.beacon = BT_MESH_BEACON_ENABLED,
#if MYNEWT_VAL(BLE_MESH_FRIEND)
.frnd = BT_MESH_FRIEND_ENABLED,
#else
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
#if MYNEWT_VAL(BLE_MESH_GATT_PROXY)
.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
#else
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
.default_ttl = 7,
/* 3 transmissions with 20ms interval */
.net_transmit = BT_MESH_TRANSMIT(2, 20),
.relay_retransmit = BT_MESH_TRANSMIT(2, 20),
};
static int
fault_get_cur(struct bt_mesh_model *model,
uint8_t *test_id,
uint16_t *company_id,
uint8_t *faults,
uint8_t *fault_count)
{
uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff };
console_printf("fault_get_cur() has_reg_fault %u\n", has_reg_fault);
*test_id = recent_test_id;
*company_id = CID_VENDOR;
*fault_count = min(*fault_count, sizeof(reg_faults));
memcpy(faults, reg_faults, *fault_count);
return 0;
}
static int
fault_get_reg(struct bt_mesh_model *model,
uint16_t company_id,
uint8_t *test_id,
uint8_t *faults,
uint8_t *fault_count)
{
if (company_id != CID_VENDOR) {
return -BLE_HS_EINVAL;
}
console_printf("fault_get_reg() has_reg_fault %u\n", has_reg_fault);
*test_id = recent_test_id;
if (has_reg_fault) {
uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff };
*fault_count = min(*fault_count, sizeof(reg_faults));
memcpy(faults, reg_faults, *fault_count);
} else {
*fault_count = 0;
}
return 0;
}
static int
fault_clear(struct bt_mesh_model *model, uint16_t company_id)
{
if (company_id != CID_VENDOR) {
return -BLE_HS_EINVAL;
}
has_reg_fault = false;
return 0;
}
static int
fault_test(struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id)
{
if (company_id != CID_VENDOR) {
return -BLE_HS_EINVAL;
}
if (test_id != STANDARD_TEST_ID && test_id != TEST_ID) {
return -BLE_HS_EINVAL;
}
recent_test_id = test_id;
has_reg_fault = true;
bt_mesh_fault_update(bt_mesh_model_elem(model));
return 0;
}
static const struct bt_mesh_health_srv_cb health_srv_cb = {
.fault_get_cur = &fault_get_cur,
.fault_get_reg = &fault_get_reg,
.fault_clear = &fault_clear,
.fault_test = &fault_test,
};
static struct bt_mesh_health_srv health_srv = {
.cb = &health_srv_cb,
};
static struct bt_mesh_model_pub health_pub;
static void
health_pub_init(void)
{
health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(0);
}
static struct bt_mesh_model_pub gen_level_pub;
static struct bt_mesh_model_pub gen_onoff_pub;
static uint8_t gen_on_off_state;
static int16_t gen_level_state;
static void gen_onoff_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
uint8_t *status;
console_printf("#mesh-onoff STATUS\n");
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
status = net_buf_simple_add(msg, 1);
*status = gen_on_off_state;
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
console_printf("#mesh-onoff STATUS: send status failed\n");
}
os_mbuf_free_chain(msg);
}
static void gen_onoff_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
console_printf("#mesh-onoff GET\n");
gen_onoff_status(model, ctx);
}
static void gen_onoff_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
console_printf("#mesh-onoff SET\n");
gen_on_off_state = buf->om_data[0];
hal_gpio_write(LED_2, !gen_on_off_state);
gen_onoff_status(model, ctx);
}
static void gen_onoff_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
console_printf("#mesh-onoff SET-UNACK\n");
gen_on_off_state = buf->om_data[0];
hal_gpio_write(LED_2, !gen_on_off_state);
}
static const struct bt_mesh_model_op gen_onoff_op[] = {
{ BT_MESH_MODEL_OP_2(0x82, 0x01), 0, gen_onoff_get },
{ BT_MESH_MODEL_OP_2(0x82, 0x02), 2, gen_onoff_set },
{ BT_MESH_MODEL_OP_2(0x82, 0x03), 2, gen_onoff_set_unack },
BT_MESH_MODEL_OP_END,
};
static void gen_level_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
console_printf("#mesh-level STATUS\n");
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x08));
net_buf_simple_add_le16(msg, gen_level_state);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
console_printf("#mesh-level STATUS: send status failed\n");
}
os_mbuf_free_chain(msg);
}
static void gen_level_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
console_printf("#mesh-level GET\n");
gen_level_status(model, ctx);
}
static void gen_level_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
int16_t level;
level = (int16_t) net_buf_simple_pull_le16(buf);
console_printf("#mesh-level SET: level=%d\n", level);
gen_level_status(model, ctx);
gen_level_state = level;
console_printf("#mesh-level: level=%d\n", gen_level_state);
}
static void gen_level_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
int16_t level;
level = (int16_t) net_buf_simple_pull_le16(buf);
console_printf("#mesh-level SET-UNACK: level=%d\n", level);
gen_level_state = level;
console_printf("#mesh-level: level=%d\n", gen_level_state);
}
static void gen_delta_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
int16_t delta_level;
delta_level = (int16_t) net_buf_simple_pull_le16(buf);
console_printf("#mesh-level DELTA-SET: delta_level=%d\n", delta_level);
gen_level_status(model, ctx);
gen_level_state += delta_level;
console_printf("#mesh-level: level=%d\n", gen_level_state);
}
static void gen_delta_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
int16_t delta_level;
delta_level = (int16_t) net_buf_simple_pull_le16(buf);
console_printf("#mesh-level DELTA-SET-UNACK: delta_level=%d\n", delta_level);
gen_level_state += delta_level;
console_printf("#mesh-level: level=%d\n", gen_level_state);
}
static void gen_move_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
}
static void gen_move_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
}
static const struct bt_mesh_model_op gen_level_op[] = {
{ BT_MESH_MODEL_OP_2(0x82, 0x05), 0, gen_level_get },
{ BT_MESH_MODEL_OP_2(0x82, 0x06), 3, gen_level_set },
{ BT_MESH_MODEL_OP_2(0x82, 0x07), 3, gen_level_set_unack },
{ BT_MESH_MODEL_OP_2(0x82, 0x09), 5, gen_delta_set },
{ BT_MESH_MODEL_OP_2(0x82, 0x0a), 5, gen_delta_set_unack },
{ BT_MESH_MODEL_OP_2(0x82, 0x0b), 3, gen_move_set },
{ BT_MESH_MODEL_OP_2(0x82, 0x0c), 3, gen_move_set_unack },
BT_MESH_MODEL_OP_END,
};
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_op,
&gen_onoff_pub, NULL),
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, gen_level_op,
&gen_level_pub, NULL),
};
static struct bt_mesh_model_pub vnd_model_pub;
static void vnd_model_recv(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
console_printf("#vendor-model-recv\n");
console_printf("data:%s len:%d\n", bt_hex(buf->om_data, buf->om_len),
buf->om_len);
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR));
os_mbuf_append(msg, buf->om_data, buf->om_len);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
console_printf("#vendor-model-recv: send rsp failed\n");
}
os_mbuf_free_chain(msg);
}
static const struct bt_mesh_model_op vnd_model_op[] = {
{ BT_MESH_MODEL_OP_3(0x01, CID_VENDOR), 0, vnd_model_recv },
BT_MESH_MODEL_OP_END,
};
static struct bt_mesh_model vnd_models[] = {
BT_MESH_MODEL_VND(CID_VENDOR, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, vnd_model_op,
&vnd_model_pub, NULL),
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, vnd_models),
};
static const struct bt_mesh_comp comp = {
.cid = CID_VENDOR,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
static int output_number(bt_mesh_output_action_t action, uint32_t number)
{
console_printf("OOB Number: %lu\n", number);
return 0;
}
static void prov_complete(u16_t net_idx, u16_t addr)
{
console_printf("Local node provisioned, primary address 0x%04x\n", addr);
}
static const uint8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
.output_size = 4,
.output_actions = BT_MESH_DISPLAY_NUMBER | BT_MESH_BEEP | BT_MESH_VIBRATE | BT_MESH_BLINK,
.output_number = output_number,
.complete = prov_complete,
};
static void
blemesh_on_reset(int reason)
{
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
}
void mesh_initialized(void);
static void
blemesh_on_sync(void)
{
int err;
ble_addr_t addr;
console_printf("Bluetooth initialized\n");
/* Use NRPA */
err = ble_hs_id_gen_rnd(1, &addr);
assert(err == 0);
err = ble_hs_id_set_rnd(addr.val);
assert(err == 0);
err = bt_mesh_init(addr.type, &prov, &comp);
if (err) {
console_printf("Initializing mesh failed (err %d)\n", err);
return;
}
#if (MYNEWT_VAL(BLE_MESH_SHELL))
shell_register_default_module("mesh");
#endif
console_printf("Mesh initialized\n");
/* THIS IS VERY IMPORTANT */
/* the official sample doesnot do this, the meshctl cannot discover the mesh device */
mesh_initialized();
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
if (bt_mesh_is_provisioned()) {
printk("Mesh network restored from flash\n");
}
}
void *ble_mesh_adv_task(void *param)
{
mesh_adv_thread(param);
return NULL;
}
k_stack_t ble_mesh_adv_stack[1024];
static struct ble_npl_task s_task_mesh_adv;
void mesh_initialized(void)
{
ble_npl_task_init(&s_task_mesh_adv, "ble_mesh_adv", ble_mesh_adv_task,
NULL, 4, BLE_NPL_TIME_FOREVER,
ble_mesh_adv_stack, sizeof(ble_mesh_adv_stack));
}
int ble_boot(void)
{
#ifdef ARCH_sim
mcu_sim_parse_args(argc, argv);
#endif
ble_svc_gap_init();
ble_svc_gatt_init();
bt_mesh_register_gatt();
/* XXX Need to have template for store */
ble_store_ram_init();
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = blemesh_on_reset;
ble_hs_cfg.sync_cb = blemesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
hal_gpio_init_out(LED_2, 0);
health_pub_init();
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[512];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
4,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,244 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
#include "mesh/mesh.h"
#if 0
#include "bsp.h"
#include "pwm/pwm.h"
#endif
#include "light_model.h"
#include "ws2812.h"
#if (!MYNEWT_VAL(USE_NEOPIXEL))
#if MYNEWT_VAL(PWM_0)
struct pwm_dev *pwm0;
#endif
#if MYNEWT_VAL(PWM_1)
struct pwm_dev *pwm1;
#endif
#if MYNEWT_VAL(PWM_2)
struct pwm_dev *pwm2;
#endif
#if MYNEWT_VAL(PWM_3)
struct pwm_dev *pwm3;
#endif
static uint16_t top_val;
#endif
#if (MYNEWT_VAL(USE_NEOPIXEL))
static uint32_t neopixel[WS2812_NUM_LED];
#endif
static u8_t gen_onoff_state;
static s16_t gen_level_state;
static void light_set_lightness(u8_t percentage)
{
#if (!MYNEWT_VAL(USE_NEOPIXEL))
int rc;
uint16_t pwm_val = (uint16_t) (percentage * top_val / 100);
#if MYNEWT_VAL(PWM_0)
rc = pwm_set_duty_cycle(pwm0, 0, pwm_val);
assert(rc == 0);
#endif
#if MYNEWT_VAL(PWM_1)
rc = pwm_set_duty_cycle(pwm1, 0, pwm_val);
assert(rc == 0);
#endif
#if MYNEWT_VAL(PWM_2)
rc = pwm_set_duty_cycle(pwm2, 0, pwm_val);
assert(rc == 0);
#endif
#if MYNEWT_VAL(PWM_3)
rc = pwm_set_duty_cycle(pwm3, 0, pwm_val);
assert(rc == 0);
#endif
#else
int i;
u32_t lightness;
u8_t max_lightness = 0x1f;
lightness = (u8_t) (percentage * max_lightness / 100);
for (i = 0; i < WS2812_NUM_LED; i++) {
neopixel[i] = (lightness | lightness << 8 | lightness << 16);
}
ws2812_write(neopixel);
#endif
}
static void update_light_state(void)
{
u16_t level = (u16_t)gen_level_state;
int percent = 100 * level / 0xffff;
if (gen_onoff_state == 0) {
percent = 0;
}
light_set_lightness((uint8_t) percent);
}
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state)
{
*state = gen_onoff_state;
return 0;
}
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state)
{
gen_onoff_state = state;
update_light_state();
return 0;
}
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level)
{
*level = gen_level_state;
return 0;
}
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level)
{
gen_level_state = level;
if ((u16_t)gen_level_state > 0x0000) {
gen_onoff_state = 1;
}
if ((u16_t)gen_level_state == 0x0000) {
gen_onoff_state = 0;
}
update_light_state();
return 0;
}
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness)
{
return light_model_gen_level_get(model, lightness);
}
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness)
{
return light_model_gen_level_set(model, lightness);
}
#if (!MYNEWT_VAL(USE_NEOPIXEL))
struct pwm_dev_cfg dev_conf = {
.n_cycles = 0,
.int_prio = 3,
};
#if MYNEWT_VAL(PWM_0)
static struct pwm_chan_cfg led1_conf = {
.pin = LED_1,
.inverted = true,
};
#endif
#if MYNEWT_VAL(PWM_1)
static struct pwm_chan_cfg led2_conf = {
.pin = LED_2,
.inverted = true,
};
#endif
#if MYNEWT_VAL(PWM_2)
static struct pwm_chan_cfg led3_conf = {
.pin = LED_3,
.inverted = true,
};
#endif
#endif
#if MYNEWT_VAL(PWM_3)
static struct pwm_chan_cfg led4_conf = {
.pin = LED_4,
.inverted = true,
};
#endif
#if (!MYNEWT_VAL(USE_NEOPIXEL))
void init_pwm_dev(struct pwm_dev **pwm, char *dev_name, struct pwm_chan_cfg *chan_cfg)
{
int rc = 0;
*pwm = (struct pwm_dev *) os_dev_open(dev_name, 0, NULL);
assert(pwm);
rc = pwm_configure_device(*pwm, &dev_conf);
assert(rc == 0);
rc = pwm_configure_channel(*pwm, 0, chan_cfg);
assert(rc == 0);
rc = pwm_enable(*pwm);
assert(rc == 0);
}
int pwm_init(void)
{
#if MYNEWT_VAL(PWM_0)
init_pwm_dev(&pwm0, "pwm0", &led1_conf);
#endif
#if MYNEWT_VAL(PWM_1)
init_pwm_dev(&pwm1, "pwm1", &led2_conf);
#endif
#if MYNEWT_VAL(PWM_2)
init_pwm_dev(&pwm2, "pwm2", &led3_conf);
#endif
#if MYNEWT_VAL(PWM_3)
init_pwm_dev(&pwm3, "pwm3", &led4_conf);
#endif
if (!pwm0) {
return 0;
}
top_val = (uint16_t) pwm_get_top_value(pwm0);
update_light_state();
return 0;
}
#endif
#endif
int light_model_init(void)
{
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
int rc;
#if (!MYNEWT_VAL(USE_NEOPIXEL))
rc = pwm_init();
assert(rc == 0);
#else
rc = ws2812_init();
assert(rc == 0);
update_light_state();
#endif
return rc;
#else
return 0;
#endif
}

View File

@@ -1,37 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* Copyright (c) 2017 Intel Corporation
*
*/
#ifndef __BT_MESH_LIGHT_MODEL_H
#define __BT_MESH_LIGHT_MODEL_H
#include "syscfg/syscfg.h"
#include "mesh/mesh.h"
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state);
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state);
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level);
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level);
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness);
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness);
int light_model_init(void);
#endif

View File

@@ -1,207 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include "sysinit/sysinit.h"
#include "os/os.h"
#include "mesh/mesh.h"
#include "console/console.h"
#if 0
#include "hal/hal_system.h"
#include "hal/hal_gpio.h"
#include "bsp/bsp.h"
#endif
#include "shell.h"
/* BLE */
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "services/gap/ble_svc_gap.h"
#include "mesh/glue.h"
#include "mesh/testing.h"
#include "mesh/model_srv.h"
#include "light_model.h"
///////////////////////
// stub-s
int __atomic_load_4(int *p)
{
return *p;
}
int __atomic_fetch_and_4(int *p, int v)
{
return *p & v;
}
int __atomic_fetch_or_4(int *p, int v)
{
return *p | v;
}
int __atomic_exchange_4(int *p, int v)
{
int old = *p;
*p = v;
return old;
}
void unreachable(void)
{
while (1) {
;
}
}
void shell_register_default_module(char *module)
{
}
void shell_evq_set(struct ble_npl_eventq *evq)
{
}
int shell_register(const char *module_name, const struct shell_cmd *commands)
{
return 0;
}
//////////////////////
static void model_bound_cb(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx)
{
int rc;
console_printf("Model bound: remote addr 0x%04x key_idx 0x%04x model %p\n",
addr, key_idx, model);
if (model->id != BT_MESH_MODEL_ID_GEN_LEVEL_SRV) {
return;
}
/* Hack for demo purposes */
rc = bt_test_bind_app_key_to_model(model, key_idx,
BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV);
if (rc) {
console_printf("Failed to bind light lightness srv model to app_key");
} else {
console_printf("Successfuly bound light lightness srv model to app_key");
}
}
static struct bt_test_cb bt_test_cb = {
.mesh_model_bound = model_bound_cb,
};
static void
blemesh_on_reset(int reason)
{
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
}
static struct bt_mesh_gen_onoff_srv_cb gen_onoff_srv_cb = {
.get = light_model_gen_onoff_get,
.set = light_model_gen_onoff_set,
};
static struct bt_mesh_gen_level_srv_cb gen_level_srv_cb = {
.get = light_model_gen_level_get,
.set = light_model_gen_level_set,
};
static struct bt_mesh_light_lightness_srv_cb light_lightness_srv_cb = {
.get = light_model_light_lightness_get,
.set = light_model_light_lightness_set,
};
static void
blemesh_on_sync(void)
{
console_printf("Bluetooth initialized\n");
shell_register_default_module("mesh");
bt_test_cb_register(&bt_test_cb);
light_model_init();
bt_mesh_set_gen_onoff_srv_cb(&gen_onoff_srv_cb);
bt_mesh_set_gen_level_srv_cb(&gen_level_srv_cb);
bt_mesh_set_light_lightness_srv_cb(&light_lightness_srv_cb);
console_printf("Mesh initialized\n");
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
if (bt_mesh_is_provisioned()) {
printk("Mesh network restored from flash\n");
}
/* Hack for demo purposes */
bt_test_shell_init();
#if 1 // we donnot have a shell yet, trigger the command by code...
if (bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV)) {
console_printf("Failed to enable PB-ADV & PB-GATT\n");
} else {
console_printf("PB-ADV & PB-GATT enabled\n");
}
#endif
}
int ble_boot(void)
{
ble_svc_gap_init();
ble_svc_gatt_init();
bt_mesh_register_gatt();
/* XXX Need to have template for store */
ble_store_ram_init();
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = blemesh_on_reset;
ble_hs_cfg.sync_cb = blemesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[512];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
4,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,143 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "syscfg/syscfg.h"
#if (MYNEWT_VAL(USE_NEOPIXEL))
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "sysinit/sysinit.h"
#include "os/os.h"
#if 0
#include "bsp/bsp.h"
#include "pwm/pwm.h"
#endif
#include "nrfx.h"
#include "nrfx_pwm.h"
#include "ws2812.h"
#define BITS_PER_SEQ (24)
#define BIT0 (0x8000 | 6)
#define BIT1 (0x8000 | 11)
static const nrfx_pwm_t pwm = NRFX_PWM_INSTANCE(WS2812_PWM);
static const nrfx_pwm_config_t pwm_config = {
.output_pins = { WS2812_GPIO, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED },
.irq_priority = 3,
.base_clock = NRF_PWM_CLK_16MHz,
.count_mode = NRF_PWM_MODE_UP,
.top_value = 20,
.load_mode = NRF_PWM_LOAD_COMMON,
.step_mode = NRF_PWM_STEP_AUTO,
};
static uint16_t pwm_seq_values[2][BITS_PER_SEQ];
static const nrf_pwm_sequence_t pwm_seq[2] = {
{
.values.p_raw = pwm_seq_values[0],
.length = BITS_PER_SEQ,
.repeats = 0,
.end_delay = 0,
}, {
.values.p_raw = pwm_seq_values[1],
.length = BITS_PER_SEQ,
.repeats = 0,
.end_delay = 0,
},
};
static uint32_t led_color[WS2812_NUM_LED];
static int led_idx;
static void
load_pixel(void)
{
uint16_t *seq_values;
uint32_t grb;
int i;
seq_values = pwm_seq_values[led_idx & 1];
grb = led_color[led_idx];
for (i = 0; i < BITS_PER_SEQ; i++) {
*seq_values = grb & 0x800000 ? BIT1 : BIT0;
grb <<= 1;
seq_values++;
}
led_idx++;
}
static void
pwm_handler_func(nrfx_pwm_evt_type_t event_type)
{
switch (event_type) {
case NRFX_PWM_EVT_END_SEQ0:
case NRFX_PWM_EVT_END_SEQ1:
load_pixel();
break;
default:
break;
}
}
int
ws2812_init(void)
{
#if 0
nrfx_err_t err;
err = nrfx_pwm_init(&pwm, &pwm_config, pwm_handler_func);
return err != NRFX_SUCCESS;
#endif
return 0;
}
int
ws2812_write(const uint32_t *rgb)
{
uint32_t grb;
int i;
for (i = 0; i < WS2812_NUM_LED; i++) {
grb = 0;
grb |= (rgb[i] & 0x00FF00) << 8;
grb |= (rgb[i] & 0xFF0000) >> 8;
grb |= (rgb[i] & 0x0000FF);
led_color[i] = grb;
}
led_idx = 0;
load_pixel();
load_pixel();
nrfx_pwm_complex_playback(&pwm, &pwm_seq[0], &pwm_seq[1], WS2812_NUM_LED,
NRFX_PWM_FLAG_SIGNAL_END_SEQ0 |
NRFX_PWM_FLAG_SIGNAL_END_SEQ1 |
NRFX_PWM_FLAG_STOP);
return 0;
}
#endif

View File

@@ -1,42 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef __WS2812_H__
#define __WS2812_H__
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define WS2812_PWM 0
#define WS2812_GPIO 30
#define WS2812_NUM_LED 32
int ws2812_init(void);
int ws2812_write(const uint32_t *rgb);
#ifdef __cplusplus
}
#endif
#endif /* __WS2812_H__ */

View File

@@ -1,79 +0,0 @@
### Bluetooth: Mesh OnOff Model
#### Overview
This is a simple application demonstrating a Bluetooth mesh multi-element node.
Each element has a mesh onoff client and server
model which controls one of the 4 sets of buttons and LEDs .
Prior to provisioning, an unprovisioned beacon is broadcast that contains
a UUID. Each button controls the state of its
corresponding LED and does not initiate any mesh activity.
The models for button 1 and LED 1 are in the node's root element.
The 3 remaining button/LED pairs are in elements 1 through 3.
Assuming the provisioner assigns 0x100 to the root element,
the secondary elements will appear at 0x101, 0x102 and 0x103.
After provisioning, the button clients must
be configured to publish and the LED servers to subscribe.
If a LED server is provided with a publish address, it will
also publish its status on an onoff state change.
If a button is pressed only once within a 1 second interval, it sends an
"on" message. If it is pressed more than once, it
sends an "off" message. The buttons are quite noisy and are debounced in
the button_pressed() interrupt handler. An interrupt within 250ms of the
previous is discarded. This might seem a little clumsy, but the alternative of
using one button for "on" and another for "off" would reduce the number
of onoff clients from 4 to 2.
#### Requirements
************
This sample has been tested on the Nordic nRF52840-PDK board, but would
likely also run on the nrf52_pca10040 board.
#### Building and Running
********************
Prior to provisioning, each button controls its corresponding LED as one
would expect with an actual switch.
Provisioning is done using the BlueZ meshctl utility. Below is an example that
binds button 2 and LED 1 to application key 1. It then configures button 2
to publish to group 0xc000 and LED 1 to subscribe to that group.
```
discover-unprovisioned on
provision <discovered UUID>
menu config
target 0100
appkey-add 1
bind 0 1 1000 # bind appkey 1 to LED server on element 0 (unicast 0100)
sub-add 0100 c000 1000 # add subscription to group address c000 to the LED server
bind 1 1 1001 # bind appkey 1 to button 2 on element 1 (unicast 0101)
pub-set 0101 c000 1 0 0 1001 # publish button 2 to group address c000
```
The meshctl utility maintains a persistent JSON database containing
the mesh configuration. As additional nodes (boards) are provisioned, it
assigns sequential unicast addresses based on the number of elements
supported by the node. This example supports 4 elements per node.
The first or root element of the node contains models for configuration,
health, and onoff. The secondary elements only
have models for onoff. The meshctl target for configuration must be the
root element's unicast address as it is the only one that has a
configuration server model.
If meshctl is gracefully exited, it can be restarted and reconnected to
network 0x0.
The meshctl utility also supports a onoff model client that can be used to
change the state of any LED that is bound to application key 0x1.
This is done by setting the target to the unicast address of the element
that has that LED's model and issuing the onoff command.
Group addresses are not supported.

View File

@@ -1,817 +0,0 @@
/* main.c - Application main entry point */
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This application is specific to the Nordic nRF52840-PDK board.
*
* It supports the 4 buttons and 4 LEDs as mesh clients and servers.
*
* Prior to provisioning, a button inverts the state of the
* corresponding LED.
*
* Button and LED 1 are in the root node.
* The 3 remaining button/LED pairs are in element 1 through 3.
* Assuming the provisioner assigns 0x100 to the root node,
* the secondary elements will appear at 0x101, 0x102 and 0x103.
*
* It's anticipated that after provisioning, the button clients would
* be configured to publish and the LED servers to subscribe.
*
* If a LED server is provided with a publish address, it will
* also publish its status on a state change.
*
* Messages from a button to its corresponding LED are ignored as
* the LED's state has already been changed locally by the button client.
*
* The buttons are debounced at a nominal 250ms. That value can be
* changed as needed.
*
*/
#include "bsp/bsp.h"
#include "console/console.h"
#include "host/ble_hs.h"
#include "mesh/glue.h"
#include "mesh/mesh.h"
///////////////////////
// stub-s
/*
* The "pull" of the gpio. This is either an input or an output.
*/
enum hal_gpio_pull {
/** Pull-up/down not enabled */
HAL_GPIO_PULL_NONE = 0,
/** Pull-up enabled */
HAL_GPIO_PULL_UP = 1,
/** Pull-down enabled */
HAL_GPIO_PULL_DOWN = 2
};
typedef enum hal_gpio_pull hal_gpio_pull_t;
/*
* IRQ trigger type.
*/
enum hal_gpio_irq_trigger {
HAL_GPIO_TRIG_NONE = 0,
/** IRQ occurs on rising edge */
HAL_GPIO_TRIG_RISING = 1,
/** IRQ occurs on falling edge */
HAL_GPIO_TRIG_FALLING = 2,
/** IRQ occurs on either edge */
HAL_GPIO_TRIG_BOTH = 3,
/** IRQ occurs when line is low */
HAL_GPIO_TRIG_LOW = 4,
/** IRQ occurs when line is high */
HAL_GPIO_TRIG_HIGH = 5
};
typedef enum hal_gpio_irq_trigger hal_gpio_irq_trig_t;
/* Function proto for GPIO irq handler functions */
typedef void (*hal_gpio_irq_handler_t)(void *arg);
int hal_gpio_irq_init(int pin, hal_gpio_irq_handler_t handler, void *arg,
hal_gpio_irq_trig_t trig, hal_gpio_pull_t pull)
{
// printf("gpio irq init\n");
return 0;
}
void hal_gpio_irq_enable(int pin)
{
// printf("gpio irq enable\n");
}
void hal_gpio_init_out(int led, int s)
{
// printf("gpio init out\n");
}
void hal_gpio_write(int led, int s)
{
// printf("led[%d]: %s\n", s == 0 ? "OFF" : "ON");
}
int __atomic_load_4(int *p)
{
return *p;
}
int __atomic_fetch_and_4(int *p, int v)
{
return *p & v;
}
int __atomic_fetch_or_4(int *p, int v)
{
return *p | v;
}
int __atomic_exchange_4(int *p, int v)
{
int old = *p;
*p = v;
return old;
}
void unreachable(void)
{
while (1) {
;
}
}
///////////////////////
#define CID_RUNTIME 0x05C3
/* Model Operation Codes */
#define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03)
#define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04)
static void gen_onoff_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf);
static void gen_onoff_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf);
static void gen_onoff_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf);
static void gen_onoff_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf);
/*
* Server Configuration Declaration
*/
static struct bt_mesh_cfg_srv cfg_srv = {
.relay = BT_MESH_RELAY_DISABLED,
.beacon = BT_MESH_BEACON_ENABLED,
#if defined(CONFIG_BT_MESH_FRIEND)
.frnd = BT_MESH_FRIEND_ENABLED,
#else
.frnd = BT_MESH_FRIEND_NOT_SUPPORTED,
#endif
#if defined(CONFIG_BT_MESH_GATT_PROXY)
.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
#else
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
.default_ttl = 7,
/* 3 transmissions with 20ms interval */
.net_transmit = BT_MESH_TRANSMIT(2, 20),
.relay_retransmit = BT_MESH_TRANSMIT(2, 20),
};
/*
* Client Configuration Declaration
*/
static struct bt_mesh_cfg_cli cfg_cli = {
};
/*
* Health Server Declaration
*/
static struct bt_mesh_health_srv health_srv = {
};
/*
* Publication Declarations
*
* The publication messages are initialized to the
* the size of the opcode + content
*
* For publication, the message must be in static or global as
* it is re-transmitted several times. This occurs
* after the function that called bt_mesh_model_publish() has
* exited and the stack is no longer valid.
*
* Note that the additional 4 bytes for the AppMIC is not needed
* because it is added to a stack variable at the time a
* transmission occurs.
*
*/
static struct bt_mesh_model_pub health_pub;
static struct bt_mesh_model_pub gen_onoff_pub_srv;
static struct bt_mesh_model_pub gen_onoff_pub_cli;
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_0;
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_0;
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_1;
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_1;
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_2;
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_2;
static struct os_mbuf *bt_mesh_pub_msg_health_pub;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
void init_pub(void)
{
bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(1 + 3 + 0);
bt_mesh_pub_msg_gen_onoff_pub_srv = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_onoff_pub_cli = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_onoff_pub_srv_s_0 = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_onoff_pub_cli_s_0 = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_onoff_pub_srv_s_1 = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_onoff_pub_cli_s_1 = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_onoff_pub_srv_s_2 = NET_BUF_SIMPLE(2 + 2);
bt_mesh_pub_msg_gen_onoff_pub_cli_s_2 = NET_BUF_SIMPLE(2 + 2);
health_pub.msg = bt_mesh_pub_msg_health_pub;
gen_onoff_pub_srv.msg = bt_mesh_pub_msg_gen_onoff_pub_srv;
gen_onoff_pub_cli.msg = bt_mesh_pub_msg_gen_onoff_pub_cli;
gen_onoff_pub_srv_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
gen_onoff_pub_cli_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
gen_onoff_pub_srv_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
gen_onoff_pub_cli_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
gen_onoff_pub_srv_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
gen_onoff_pub_cli_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
}
/*
* Models in an element must have unique op codes.
*
* The mesh stack dispatches a message to the first model in an element
* that is also bound to an app key and supports the op code in the
* received message.
*
*/
/*
* OnOff Model Server Op Dispatch Table
*
*/
static const struct bt_mesh_model_op gen_onoff_srv_op[] = {
{ BT_MESH_MODEL_OP_GEN_ONOFF_GET, 0, gen_onoff_get },
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET, 2, gen_onoff_set },
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack },
BT_MESH_MODEL_OP_END,
};
/*
* OnOff Model Client Op Dispatch Table
*/
static const struct bt_mesh_model_op gen_onoff_cli_op[] = {
{ BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, gen_onoff_status },
BT_MESH_MODEL_OP_END,
};
struct onoff_state {
u8_t current;
u8_t previous;
u8_t led_gpio_pin;
};
/*
* Declare and Initialize Element Contexts
* Change to select different GPIO output pins
*/
static struct onoff_state onoff_state_arr[] = {
{ .led_gpio_pin = LED_1 },
{ .led_gpio_pin = LED_2 },
{ .led_gpio_pin = LED_3 },
{ .led_gpio_pin = LED_4 },
};
/*
*
* Element Model Declarations
*
* Element 0 Root Models
*/
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
&gen_onoff_pub_srv, &onoff_state_arr[0]),
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
&gen_onoff_pub_cli, &onoff_state_arr[0]),
};
/*
* Element 1 Models
*/
static struct bt_mesh_model secondary_0_models[] = {
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
&gen_onoff_pub_srv_s_0, &onoff_state_arr[1]),
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
&gen_onoff_pub_cli_s_0, &onoff_state_arr[1]),
};
/*
* Element 2 Models
*/
static struct bt_mesh_model secondary_1_models[] = {
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
&gen_onoff_pub_srv_s_1, &onoff_state_arr[2]),
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
&gen_onoff_pub_cli_s_1, &onoff_state_arr[2]),
};
/*
* Element 3 Models
*/
static struct bt_mesh_model secondary_2_models[] = {
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
&gen_onoff_pub_srv_s_2, &onoff_state_arr[3]),
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
&gen_onoff_pub_cli_s_2, &onoff_state_arr[3]),
};
/*
* Button to Client Model Assignments
*/
struct bt_mesh_model *mod_cli_sw[] = {
&root_models[4],
&secondary_0_models[1],
&secondary_1_models[1],
&secondary_2_models[1],
};
/*
* LED to Server Model Assigmnents
*/
struct bt_mesh_model *mod_srv_sw[] = {
&root_models[3],
&secondary_0_models[0],
&secondary_1_models[0],
&secondary_2_models[0],
};
/*
* Root and Secondary Element Declarations
*/
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
BT_MESH_ELEM(0, secondary_0_models, BT_MESH_MODEL_NONE),
BT_MESH_ELEM(0, secondary_1_models, BT_MESH_MODEL_NONE),
BT_MESH_ELEM(0, secondary_2_models, BT_MESH_MODEL_NONE),
};
static const struct bt_mesh_comp comp = {
.cid = CID_RUNTIME,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
struct sw {
u8_t sw_num;
u8_t onoff_state;
struct ble_npl_callout button_work;
struct ble_npl_callout button_timer;
};
static u8_t button_press_cnt;
static struct sw sw;
static u8_t trans_id;
static u32_t time, last_time;
static u16_t primary_addr;
static u16_t primary_net_idx;
/*
* Generic OnOff Model Server Message Handlers
*
* Mesh Model Specification 3.1.1
*
*/
static void gen_onoff_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct onoff_state *state = model->user_data;
BT_INFO("addr 0x%04x onoff 0x%02x",
bt_mesh_model_elem(model)->addr, state->current);
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
net_buf_simple_add_u8(msg, state->current);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
BT_ERR("Unable to send On Off Status response");
}
os_mbuf_free_chain(msg);
}
static void gen_onoff_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = model->pub->msg;
struct onoff_state *state = model->user_data;
int err;
state->current = net_buf_simple_pull_u8(buf);
BT_INFO("addr 0x%02x state 0x%02x",
bt_mesh_model_elem(model)->addr, state->current);
/* Pin set low turns on LED's on the nrf52840-pca10056 board */
hal_gpio_write(state->led_gpio_pin,
state->current ? 0 : 1);
/*
* If a server has a publish address, it is required to
* publish status on a state change
*
* See Mesh Profile Specification 3.7.6.1.2
*
* Only publish if there is an assigned address
*/
if (state->previous != state->current &&
model->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
BT_INFO("publish last 0x%02x cur 0x%02x",
state->previous,
state->current);
state->previous = state->current;
bt_mesh_model_msg_init(msg,
BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
net_buf_simple_add_u8(msg, state->current);
err = bt_mesh_model_publish(model);
if (err) {
BT_ERR("bt_mesh_model_publish err %d", err);
}
}
}
static void gen_onoff_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
BT_INFO("");
gen_onoff_set_unack(model, ctx, buf);
gen_onoff_get(model, ctx, buf);
}
static void gen_onoff_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
u8_t state;
state = net_buf_simple_pull_u8(buf);
BT_INFO("Node 0x%04x OnOff status from 0x%04x with state 0x%02x",
bt_mesh_model_elem(model)->addr, ctx->addr, state);
}
static int output_number(bt_mesh_output_action_t action, u32_t number)
{
BT_INFO("OOB Number %u", number);
return 0;
}
static int output_string(const char *str)
{
BT_INFO("OOB String %s", str);
return 0;
}
static void prov_complete(u16_t net_idx, u16_t addr)
{
BT_INFO("provisioning complete for net_idx 0x%04x addr 0x%04x",
net_idx, addr);
primary_addr = addr;
primary_net_idx = net_idx;
}
static void prov_reset(void)
{
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
}
static u8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
#define BUTTON_DEBOUNCE_DELAY_MS 250
/*
* Map GPIO pins to button number
* Change to select different GPIO input pins
*/
static uint8_t pin_to_sw(int pin_pos)
{
switch (pin_pos) {
case BUTTON_1: return 0;
case BUTTON_2: return 1;
case BUTTON_3: return 2;
case BUTTON_4: return 3;
default:break;
}
BT_ERR("No match for GPIO pin 0x%08x", pin_pos);
return 0;
}
static void button_pressed(struct ble_npl_event *ev)
{
int pin_pos = (int ) ev->arg;
/*
* One button press within a 1 second interval sends an on message
* More than one button press sends an off message
*/
time = k_uptime_get_32();
/* debounce the switch */
if (time < last_time + BUTTON_DEBOUNCE_DELAY_MS) {
last_time = time;
return;
}
if (button_press_cnt == 0) {
ble_npl_callout_reset(&sw.button_timer, ble_npl_time_ms_to_ticks32(K_SECONDS(1)));
}
BT_INFO("button_press_cnt 0x%02x", button_press_cnt);
button_press_cnt++;
/* The variable pin_pos is the pin position in the GPIO register,
* not the pin number. It's assumed that only one bit is set.
*/
sw.sw_num = pin_to_sw(pin_pos);
last_time = time;
}
/*
* Button Count Timer Worker
*/
static void button_cnt_timer(struct ble_npl_event *work)
{
struct sw *button_sw = work->arg;
button_sw->onoff_state = button_press_cnt == 1 ? 1 : 0;
BT_INFO("button_press_cnt 0x%02x onoff_state 0x%02x",
button_press_cnt, button_sw->onoff_state);
button_press_cnt = 0;
ble_npl_callout_reset(&sw.button_work, 0);
}
/*
* Button Pressed Worker Task
*/
static void button_pressed_worker(struct ble_npl_event *work)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(1);
struct bt_mesh_model *mod_cli, *mod_srv;
struct bt_mesh_model_pub *pub_cli, *pub_srv;
struct sw *sw = work->arg;
u8_t sw_idx = sw->sw_num;
int err;
mod_cli = mod_cli_sw[sw_idx];
pub_cli = mod_cli->pub;
mod_srv = mod_srv_sw[sw_idx];
pub_srv = mod_srv->pub;
(void)pub_srv;
/* If unprovisioned, just call the set function.
* The intent is to have switch-like behavior
* prior to provisioning. Once provisioned,
* the button and its corresponding led are no longer
* associated and act independently. So, if a button is to
* control its associated led after provisioning, the button
* must be configured to either publish to the led's unicast
* address or a group to which the led is subscribed.
*/
if (primary_addr == BT_MESH_ADDR_UNASSIGNED) {
struct bt_mesh_msg_ctx ctx = {
.addr = sw_idx + primary_addr,
};
/* This is a dummy message sufficient
* for the led server
*/
net_buf_simple_add_u8(msg, sw->onoff_state);
gen_onoff_set_unack(mod_srv, &ctx, msg);
goto done;
}
if (pub_cli->addr == BT_MESH_ADDR_UNASSIGNED) {
goto done;
}
BT_INFO("publish to 0x%04x onoff 0x%04x sw_idx 0x%04x",
pub_cli->addr, sw->onoff_state, sw_idx);
bt_mesh_model_msg_init(pub_cli->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET);
net_buf_simple_add_u8(pub_cli->msg, sw->onoff_state);
net_buf_simple_add_u8(pub_cli->msg, trans_id++);
err = bt_mesh_model_publish(mod_cli);
if (err) {
BT_ERR("bt_mesh_model_publish err %d", err);
}
done:
os_mbuf_free_chain(msg);
}
/* Disable OOB security for SILabs Android app */
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
#if 1
.output_size = 6,
.output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING),
.output_number = output_number,
.output_string = output_string,
#else
.output_size = 0,
.output_actions = 0,
.output_number = 0,
#endif
.complete = prov_complete,
.reset = prov_reset,
};
void init_led(u8_t dev)
{
hal_gpio_init_out(onoff_state_arr[dev].led_gpio_pin, 1);
}
static struct ble_npl_event button_event;
static void
gpio_irq_handler(void *arg)
{
button_event.arg = arg;
ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &button_event);
}
void init_button(int button)
{
button_event.fn = button_pressed;
hal_gpio_irq_init(button, gpio_irq_handler, (void *)button,
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
hal_gpio_irq_enable(button);
}
static void
blemesh_on_reset(int reason)
{
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
}
static void
blemesh_on_sync(void)
{
int err;
ble_addr_t addr;
console_printf("Bluetooth initialized\n");
/* Use NRPA */
err = ble_hs_id_gen_rnd(1, &addr);
assert(err == 0);
err = ble_hs_id_set_rnd(addr.val);
assert(err == 0);
err = bt_mesh_init(addr.type, &prov, &comp);
if (err) {
console_printf("Initializing mesh failed (err %d)\n", err);
return;
}
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
if (bt_mesh_is_provisioned()) {
console_printf("Mesh network restored from flash\n");
}
bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
console_printf("Mesh initialized\n");
}
int ble_boot(void)
{
#ifdef ARCH_sim
mcu_sim_parse_args(argc, argv);
#endif
BT_INFO("Initializing...");
/* Initialize the button debouncer */
last_time = k_uptime_get_32();
/* Initialize button worker task*/
ble_npl_callout_init(&sw.button_work, nimble_port_get_dflt_eventq(),
button_pressed_worker, &sw);
/* Initialize button count timer */
ble_npl_callout_init(&sw.button_timer, nimble_port_get_dflt_eventq(),
button_cnt_timer, &sw);
/* Initialize LED's */
init_led(0);
init_led(1);
init_led(2);
init_led(3);
init_button(BUTTON_1);
init_button(BUTTON_2);
init_button(BUTTON_3);
init_button(BUTTON_4);
init_pub();
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = blemesh_on_reset;
ble_hs_cfg.sync_cb = blemesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
bt_mesh_register_gatt();
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[512];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
4,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,101 +0,0 @@
#### Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
##### Overview
********
This is a application demonstrating a Bluetooth mesh node in
which Root element has following models
- Generic OnOff Server
- Generic OnOff Client
- Generic Level Server
- Generic Level Client
- Generic Default Transition Time Server
- Generic Default Transition Time Client
- Generic Power OnOff Server
- Generic Power OnOff Setup Server
- Generic Power OnOff Client
- Light Lightness Server
- Light Lightness Setup Server
- Light Lightness Client
- Light CTL Server
- Light CTL Setup Server
- Light CTL Client
- Vendor Model
And Secondary element has following models
- Generic Level Server
- Generic Level Client
- Light CTL Temperature Server
Prior to provisioning, an unprovisioned beacon is broadcast that contains
a unique UUID. Each button controls the state of its
corresponding LED and does not initiate any mesh activity
##### Associations of Models with hardware
************************************
For the nRF52840-PDK board, these are the model associations:
* LED1 is associated with generic OnOff Server's state which is part of Root element
* LED2 is associated with Vendor Model which is part of Root element
* LED3 is associated with generic Level (ROOT) / Light Lightness Actual value
* LED4 is associated with generic Level (Secondary) / Light CTL Temperature value
* Button1 and Button2 are associated with gen. OnOff Client or Vendor Model which is part of Root element
* Button3 and Button4 are associated with gen. Level Client / Light Lightness Client / Light CTL Client which is part of Root element
States of Servers are bounded as per Bluetooth SIG Mesh Model Specification v1.0
After provisioning, the button clients must
be configured to publish and the LED servers to subscribe.
If a server is provided with a publish address, it will
also publish its relevant status.
##### Requirements
************
This sample has been tested on the Nordic nRF52840-PDK board, but would
likely also run on the nrf52_pca10040 board.
##### Running
************
Provisioning is done using the BlueZ meshctl utility. In this example, we'll use meshctl commands to bind:
- Button1, Button2, and LED1 to application key 1. It then configures Button1 and Button2
to publish to group 0xC000 and LED1 to subscribe to that group.
- Button3, Button4, and LED3 to application key 1. It then configures Button3 and Button4
to publish to group 0xC000 and LED3 to subscribe to that group.
```
discover-unprovisioned on
provision <discovered UUID>
menu config
target 0100
appkey-add 1
bind 0 1 1000
bind 0 1 1001
bind 0 1 1002
bind 0 1 1003
sub-add 0100 c000 1000
sub-add 0100 c000 1002
pub-set 0100 c000 1 0 5 1001
pub-set 0100 c000 1 0 5 1003
```
The meshctl utility maintains a persistent JSON database containing
the mesh configuration. As additional nodes (boards) are provisioned, it
assigns sequential unicast addresses based on the number of elements
supported by the node. This example supports 2 elements per node.
The meshctl target for configuration must be the root element's unicast
address as it is the only one that has a configuration server model. If
meshctl is gracefully exited, it can be restarted and reconnected to
network 0x0.
The meshctl utility also supports a onoff model client that can be used to
change the state of any LED that is bound to application key 0x1.
This is done by setting the target to the unicast address of the element
that has that LED's model and issuing the onoff command.
Group addresses are not supported.

View File

@@ -1,96 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "bsp/bsp.h"
#include "console/console.h"
#include "mesh/mesh.h"
#include "app_gpio.h"
#include "publisher.h"
int button_device[] = {
BUTTON_1,
BUTTON_2,
BUTTON_3,
BUTTON_4,
};
int led_device[] = {
LED_1,
LED_2,
LED_3,
LED_4,
};
static struct ble_npl_callout button_work;
static void button_pressed(struct ble_npl_event *ev)
{
ble_npl_callout_reset(&button_work, 0);
}
static struct ble_npl_event button_event;
static void gpio_irq_handler(void *arg)
{
button_event.arg = arg;
ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &button_event);
}
void app_gpio_init(void)
{
/* LEDs configiuratin & setting */
#if 0
hal_gpio_init_out(led_device[0], 1);
hal_gpio_init_out(led_device[1], 1);
hal_gpio_init_out(led_device[2], 1);
hal_gpio_init_out(led_device[3], 1);
/* Buttons configiuratin & setting */
ble_npl_callout_init(&button_work, nimble_port_get_dflt_eventq(), publish, NULL);
button_event.ev_cb = button_pressed;
hal_gpio_irq_init(button_device[0], gpio_irq_handler, NULL,
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
hal_gpio_irq_enable(button_device[0]);
hal_gpio_irq_init(button_device[1], gpio_irq_handler, NULL,
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
hal_gpio_irq_enable(button_device[1]);
hal_gpio_irq_init(button_device[2], gpio_irq_handler, NULL,
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
hal_gpio_irq_enable(button_device[2]);
hal_gpio_irq_init(button_device[3], gpio_irq_handler, NULL,
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
hal_gpio_irq_enable(button_device[3]);
#endif
}

View File

@@ -1,36 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _APP_GPIO_H
#define _APP_GPIO_H
/* GPIO */
extern int button_device[];
extern int led_device[];
void app_gpio_init(void);
#endif

View File

@@ -1,116 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "console/console.h"
#include "common.h"
#include "ble_mesh.h"
#include "device_composition.h"
#define OOB_AUTH_ENABLE 1
#ifdef OOB_AUTH_ENABLE
static int output_number(bt_mesh_output_action_t action, u32_t number)
{
printk("OOB Number: %lu\n", number);
return 0;
}
static int output_string(const char *str)
{
printk("OOB String: %s\n", str);
return 0;
}
#endif
static void prov_complete(u16_t net_idx, u16_t addr)
{
printk("Local node provisioned, primary address 0x%04x\n", addr);
}
static void prov_reset(void)
{
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
}
static u8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
#ifdef OOB_AUTH_ENABLE
.output_size = 6,
.output_actions = BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING,
.output_number = output_number,
.output_string = output_string,
#endif
.complete = prov_complete,
.reset = prov_reset,
};
void blemesh_on_reset(int reason)
{
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
}
void blemesh_on_sync(void)
{
int err;
ble_addr_t addr;
console_printf("Bluetooth initialized\n");
/* Use NRPA */
err = ble_hs_id_gen_rnd(1, &addr);
assert(err == 0);
err = ble_hs_id_set_rnd(addr.val);
assert(err == 0);
err = bt_mesh_init(addr.type, &prov, &comp);
if (err) {
console_printf("Initializing mesh failed (err %d)\n", err);
return;
}
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
if (bt_mesh_is_provisioned()) {
console_printf("Mesh network restored from flash\n");
}
bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
console_printf("Mesh initialized\n");
bt_initialized();
}

View File

@@ -1,73 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLE_MESH_H
#define _BLE_MESH_H
#include "mesh/mesh.h"
#include "mesh/glue.h"
/* Model Operation Codes */
#define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03)
#define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04)
#define BT_MESH_MODEL_OP_GEN_LEVEL_GET BT_MESH_MODEL_OP_2(0x82, 0x05)
#define BT_MESH_MODEL_OP_GEN_LEVEL_SET BT_MESH_MODEL_OP_2(0x82, 0x06)
#define BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x07)
#define BT_MESH_MODEL_OP_GEN_LEVEL_STATUS BT_MESH_MODEL_OP_2(0x82, 0x08)
#define BT_MESH_MODEL_OP_GEN_DELTA_SET BT_MESH_MODEL_OP_2(0x82, 0x09)
#define BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0A)
#define BT_MESH_MODEL_OP_GEN_MOVE_SET BT_MESH_MODEL_OP_2(0x82, 0x0B)
#define BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0C)
#define BT_MESH_MODEL_GEN_DEF_TRANS_TIME_STATUS BT_MESH_MODEL_OP_2(0x82, 0x10)
#define BT_MESH_MODEL_GEN_ONPOWERUP_STATUS BT_MESH_MODEL_OP_2(0x82, 0x12)
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_STATUS BT_MESH_MODEL_OP_2(0x82, 0x4E)
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_LINEAR_STATUS \
BT_MESH_MODEL_OP_2(0x82, 0x52)
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_LAST_STATUS \
BT_MESH_MODEL_OP_2(0x82, 0x54)
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_DEFAULT_STATUS \
BT_MESH_MODEL_OP_2(0x82, 0x56)
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_RANGE_STATUS \
BT_MESH_MODEL_OP_2(0x82, 0x58)
#define BT_MESH_MODEL_LIGHT_CTL_STATUS BT_MESH_MODEL_OP_2(0x82, 0x60)
#define BT_MESH_MODEL_LIGHT_CTL_TEMP_RANGE_STATUS \
BT_MESH_MODEL_OP_2(0x82, 0x63)
#define BT_MESH_MODEL_LIGHT_CTL_TEMP_STATUS BT_MESH_MODEL_OP_2(0x82, 0x66)
#define BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS BT_MESH_MODEL_OP_2(0x82, 0x68)
void blemesh_on_reset(int reason);
void blemesh_on_sync(void);
void init_pub(void);
#endif

View File

@@ -1,33 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _COMMON_H
#define _COMMON_H
void update_light_state(void);
void bt_initialized(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,177 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _DEVICE_COMPOSITION_H
#define _DEVICE_COMPOSITION_H
#define CID_RUNTIME 0x05C3
#define STATE_OFF 0x00
#define STATE_ON 0x01
#define STATE_DEFAULT 0x01
#define STATE_RESTORE 0x02
/* Following 4 values are as per Mesh Model specification */
#define LIGHTNESS_MIN 0x0001
#define LIGHTNESS_MAX 0xFFFF
#define TEMP_MIN 0x0320
#define TEMP_MAX 0x4E20
/* Refer 7.2 of Mesh Model Specification */
#define RANGE_SUCCESSFULLY_UPDATED 0x00
#define CANNOT_SET_RANGE_MIN 0x01
#define CANNOT_SET_RANGE_MAX 0x02
struct generic_onoff_state {
u8_t onoff;
u8_t target_onoff;
u8_t last_tid;
u16_t last_src_addr;
u16_t last_dst_addr;
s64_t last_msg_timestamp;
s32_t tt_delta;
struct transition *transition;
};
struct generic_level_state {
s16_t level;
s16_t target_level;
s16_t last_level;
s32_t last_delta;
u8_t last_tid;
u16_t last_src_addr;
u16_t last_dst_addr;
s64_t last_msg_timestamp;
s32_t tt_delta;
struct transition *transition;
};
struct generic_onpowerup_state {
u8_t onpowerup;
};
struct gen_def_trans_time_state {
u8_t tt;
};
struct vendor_state {
int current;
u32_t response;
u8_t last_tid;
u16_t last_src_addr;
u16_t last_dst_addr;
s64_t last_msg_timestamp;
};
struct light_lightness_state {
u16_t linear;
u16_t target_linear;
u16_t actual;
u16_t target_actual;
u16_t last;
u16_t def;
u8_t status_code;
u16_t light_range_min;
u16_t light_range_max;
u32_t lightness_range;
u8_t last_tid;
u16_t last_src_addr;
u16_t last_dst_addr;
s64_t last_msg_timestamp;
s32_t tt_delta_actual;
s32_t tt_delta_linear;
struct transition *transition;
};
struct light_ctl_state {
u16_t lightness;
u16_t target_lightness;
u16_t temp;
u16_t target_temp;
s16_t delta_uv;
s16_t target_delta_uv;
u8_t status_code;
u16_t temp_range_min;
u16_t temp_range_max;
u32_t temperature_range;
u16_t lightness_def;
u16_t temp_def;
u32_t lightness_temp_def;
s16_t delta_uv_def;
u32_t lightness_temp_last;
u8_t last_tid;
u16_t last_src_addr;
u16_t last_dst_addr;
s64_t last_msg_timestamp;
s32_t tt_delta_lightness;
s32_t tt_delta_temp;
s32_t tt_delta_duv;
struct transition *transition;
};
extern struct generic_onoff_state gen_onoff_srv_root_user_data;
extern struct generic_level_state gen_level_srv_root_user_data;
extern struct gen_def_trans_time_state gen_def_trans_time_srv_user_data;
extern struct generic_onpowerup_state gen_power_onoff_srv_user_data;
extern struct light_lightness_state light_lightness_srv_user_data;
extern struct light_ctl_state light_ctl_srv_user_data;
extern struct generic_level_state gen_level_srv_s0_user_data;
extern struct bt_mesh_model root_models[];
extern struct bt_mesh_model vnd_models[];
extern struct bt_mesh_model s0_models[];
extern const struct bt_mesh_comp comp;
void gen_onoff_publish(struct bt_mesh_model *model);
void gen_level_publish(struct bt_mesh_model *model);
void light_lightness_publish(struct bt_mesh_model *model);
void light_lightness_linear_publish(struct bt_mesh_model *model);
void light_ctl_publish(struct bt_mesh_model *model);
void light_ctl_temp_publish(struct bt_mesh_model *model);
#endif

View File

@@ -1,365 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "console/console.h"
#include "mesh/mesh.h"
#include "app_gpio.h"
#include "storage.h"
#include "ble_mesh.h"
#include "device_composition.h"
#include "no_transition_work_handler.h"
#include "publisher.h"
#include "state_binding.h"
#include "transition.h"
static bool reset;
///////////////////////
// stub-s
/*
* The "pull" of the gpio. This is either an input or an output.
*/
enum hal_gpio_pull {
/** Pull-up/down not enabled */
HAL_GPIO_PULL_NONE = 0,
/** Pull-up enabled */
HAL_GPIO_PULL_UP = 1,
/** Pull-down enabled */
HAL_GPIO_PULL_DOWN = 2
};
typedef enum hal_gpio_pull hal_gpio_pull_t;
/*
* IRQ trigger type.
*/
enum hal_gpio_irq_trigger {
HAL_GPIO_TRIG_NONE = 0,
/** IRQ occurs on rising edge */
HAL_GPIO_TRIG_RISING = 1,
/** IRQ occurs on falling edge */
HAL_GPIO_TRIG_FALLING = 2,
/** IRQ occurs on either edge */
HAL_GPIO_TRIG_BOTH = 3,
/** IRQ occurs when line is low */
HAL_GPIO_TRIG_LOW = 4,
/** IRQ occurs when line is high */
HAL_GPIO_TRIG_HIGH = 5
};
typedef enum hal_gpio_irq_trigger hal_gpio_irq_trig_t;
/* Function proto for GPIO irq handler functions */
typedef void (*hal_gpio_irq_handler_t)(void *arg);
int hal_gpio_irq_init(int pin, hal_gpio_irq_handler_t handler, void *arg,
hal_gpio_irq_trig_t trig, hal_gpio_pull_t pull)
{
// printf("gpio irq init\n");
return 0;
}
void hal_gpio_irq_enable(int pin)
{
// printf("gpio irq enable\n");
}
void hal_gpio_init_out(int led, int s)
{
// printf("gpio init out\n");
}
void hal_gpio_write(int led, int s)
{
// printf("led[%d]: %s\n", s == 0 ? "OFF" : "ON");
}
int hal_gpio_read(int pin)
{
}
int __atomic_load_4(int *p)
{
return *p;
}
int __atomic_fetch_and_4(int *p, int v)
{
return *p & v;
}
int __atomic_fetch_or_4(int *p, int v)
{
return *p | v;
}
int __atomic_exchange_4(int *p, int v)
{
int old = *p;
*p = v;
return old;
}
void unreachable(void)
{
while (1) {
;
}
}
///////////////////////
static void light_default_var_init(void)
{
gen_def_trans_time_srv_user_data.tt = 0x00;
gen_power_onoff_srv_user_data.onpowerup = STATE_DEFAULT;
light_lightness_srv_user_data.light_range_min = LIGHTNESS_MIN;
light_lightness_srv_user_data.light_range_max = LIGHTNESS_MAX;
light_lightness_srv_user_data.last = LIGHTNESS_MAX;
light_lightness_srv_user_data.def = LIGHTNESS_MAX;
/* Following 2 values are as per specification */
light_ctl_srv_user_data.temp_range_min = TEMP_MIN;
light_ctl_srv_user_data.temp_range_max = TEMP_MAX;
light_ctl_srv_user_data.temp_def = TEMP_MIN;
light_ctl_srv_user_data.lightness_temp_last =
(u32_t) ((LIGHTNESS_MAX << 16) | TEMP_MIN);
}
static void light_default_status_init(void)
{
u16_t lightness;
lightness = (u16_t) (light_ctl_srv_user_data.lightness_temp_last >> 16);
if (lightness) {
gen_onoff_srv_root_user_data.onoff = STATE_ON;
} else {
gen_onoff_srv_root_user_data.onoff = STATE_OFF;
}
/* Retrieve Default Lightness & Temperature Values */
if (light_ctl_srv_user_data.lightness_temp_def) {
light_ctl_srv_user_data.lightness_def = (u16_t)
(light_ctl_srv_user_data.lightness_temp_def >> 16);
light_ctl_srv_user_data.temp_def = (u16_t)
(light_ctl_srv_user_data.lightness_temp_def);
}
light_lightness_srv_user_data.def =
light_ctl_srv_user_data.lightness_def;
light_ctl_srv_user_data.temp = light_ctl_srv_user_data.temp_def;
/* Retrieve Range of Lightness & Temperature */
if (light_lightness_srv_user_data.lightness_range) {
light_lightness_srv_user_data.light_range_max = (u16_t)
(light_lightness_srv_user_data.lightness_range >> 16);
light_lightness_srv_user_data.light_range_min = (u16_t)
(light_lightness_srv_user_data.lightness_range);
}
if (light_ctl_srv_user_data.temperature_range) {
light_ctl_srv_user_data.temp_range_max = (u16_t)
(light_ctl_srv_user_data.temperature_range >> 16);
light_ctl_srv_user_data.temp_range_min = (u16_t)
(light_ctl_srv_user_data.temperature_range);
}
switch (gen_power_onoff_srv_user_data.onpowerup) {
case STATE_OFF:
gen_onoff_srv_root_user_data.onoff = STATE_OFF;
state_binding(ONOFF, ONOFF_TEMP);
break;
case STATE_DEFAULT:
gen_onoff_srv_root_user_data.onoff = STATE_ON;
state_binding(ONOFF, ONOFF_TEMP);
break;
case STATE_RESTORE:
light_lightness_srv_user_data.last = (u16_t)
(light_ctl_srv_user_data.lightness_temp_last >> 16);
light_ctl_srv_user_data.temp =
(u16_t) (light_ctl_srv_user_data.lightness_temp_last);
state_binding(ONPOWERUP, ONOFF_TEMP);
break;
}
default_tt = gen_def_trans_time_srv_user_data.tt;
}
void update_light_state(void)
{
u8_t power, color;
power = 100 * ((float) lightness / 65535);
color = 100 * ((float) (temperature + 32768) / 65535);
printk("power-> %d, color-> %d\n", power, color);
if (lightness) {
/* LED1 On */
hal_gpio_write(led_device[0], 0);
} else {
/* LED1 Off */
hal_gpio_write(led_device[0], 1);
}
if (power < 50) {
/* LED3 On */
hal_gpio_write(led_device[2], 0);
} else {
/* LED3 Off */
hal_gpio_write(led_device[2], 1);
}
if (color < 50) {
/* LED4 On */
hal_gpio_write(led_device[3], 0);
} else {
/* LED4 Off */
hal_gpio_write(led_device[3], 1);
}
if (*ptr_counter == 0 || reset == false) {
reset = true;
ble_npl_callout_reset(&no_transition_work, 0);
}
}
static void short_time_multireset_bt_mesh_unprovisioning(void)
{
if (reset_counter >= 4) {
reset_counter = 0;
printk("BT Mesh reset\n");
bt_mesh_reset();
} else {
printk("Reset Counter -> %d\n", reset_counter);
reset_counter++;
}
save_on_flash(RESET_COUNTER);
}
static void reset_counter_timer_handler(struct ble_npl_event *dummy)
{
reset_counter = 0;
save_on_flash(RESET_COUNTER);
printk("Reset Counter set to Zero\n");
}
struct ble_npl_callout reset_counter_timer;
static void init_timers(void)
{
ble_npl_callout_init(&reset_counter_timer, nimble_port_get_dflt_eventq(),
reset_counter_timer_handler, NULL);
ble_npl_callout_reset(&reset_counter_timer,
ble_npl_time_ms_to_ticks32(K_MSEC(7000)));
no_transition_work_init();
}
void bt_initialized(void)
{
light_default_status_init();
update_light_state();
randomize_publishers_TID();
short_time_multireset_bt_mesh_unprovisioning();
}
int ble_boot(void)
{
#ifdef ARCH_sim
mcu_sim_parse_args(argc, argv);
#endif
light_default_var_init();
app_gpio_init();
init_timers();
transition_timers_init();
init_pub();
#if 0 // disable this...
ps_settings_init();
#endif
printk("Initializing...\n");
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = blemesh_on_reset;
ble_hs_cfg.sync_cb = blemesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[512];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
4,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,89 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ble_mesh.h"
#include "device_composition.h"
#include "storage.h"
static void unsolicitedly_publish_states_work_handler(struct ble_npl_event *work)
{
gen_onoff_publish(&root_models[2]);
gen_level_publish(&root_models[4]);
light_lightness_publish(&root_models[11]);
light_lightness_linear_publish(&root_models[11]);
light_ctl_publish(&root_models[14]);
gen_level_publish(&s0_models[0]);
light_ctl_temp_publish(&s0_models[2]);
}
struct ble_npl_callout unsolicitedly_publish_states_work;
static void unsolicitedly_publish_states_timer_handler(struct ble_npl_event *dummy)
{
ble_npl_callout_reset(&unsolicitedly_publish_states_work, 0);
}
struct ble_npl_callout unsolicitedly_publish_states_timer;
static void save_lightness_temp_last_values_timer_handler(struct ble_npl_event *dummy)
{
save_on_flash(LIGHTNESS_TEMP_LAST_STATE);
}
struct ble_npl_callout save_lightness_temp_last_values_timer;
static void no_transition_work_handler(struct ble_npl_event *work)
{
ble_npl_callout_reset(&unsolicitedly_publish_states_timer,
ble_npl_time_ms_to_ticks32(K_MSEC(5000)));
/* If Lightness & Temperature values remains stable for
* 10 Seconds then & then only get stored on SoC flash.
*/
if (gen_power_onoff_srv_user_data.onpowerup == STATE_RESTORE) {
ble_npl_callout_reset(&save_lightness_temp_last_values_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(10000)));
}
}
struct ble_npl_callout no_transition_work;
void no_transition_work_init(void)
{
ble_npl_callout_init(&no_transition_work, nimble_port_get_dflt_eventq(),
no_transition_work_handler, NULL);
ble_npl_callout_init(&save_lightness_temp_last_values_timer,
nimble_port_get_dflt_eventq(),
save_lightness_temp_last_values_timer_handler,
NULL);
ble_npl_callout_init(&unsolicitedly_publish_states_work, nimble_port_get_dflt_eventq(),
unsolicitedly_publish_states_work_handler, NULL);
ble_npl_callout_init(&unsolicitedly_publish_states_timer, nimble_port_get_dflt_eventq(),
unsolicitedly_publish_states_timer_handler, NULL);
}

View File

@@ -1,34 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _NO_TRANSITION_WORK_HANDLER_H
#define _NO_TRANSITION_WORK_HANDLER_H
extern struct os_callout no_transition_work;
void no_transition_work_init(void);
#endif

View File

@@ -1,265 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "console/console.h"
#include "app_gpio.h"
#include "ble_mesh.h"
#include "device_composition.h"
#include "publisher.h"
#define ONOFF
#define GENERIC_LEVEL
/* #define LIGHT_CTL */
/* #define LIGHT_CTL_TEMP */
static bool is_randomization_of_TIDs_done;
#if (defined(ONOFF) || defined(ONOFF_TT))
static u8_t tid_onoff;
#elif defined(VND_MODEL_TEST)
static u8_t tid_vnd;
#endif
static u8_t tid_level;
void randomize_publishers_TID(void)
{
#if (defined(ONOFF) || defined(ONOFF_TT))
bt_rand(&tid_onoff, sizeof(tid_onoff));
#elif defined(VND_MODEL_TEST)
bt_rand(&tid_vnd, sizeof(tid_vnd));
#endif
bt_rand(&tid_level, sizeof(tid_level));
is_randomization_of_TIDs_done = true;
}
static u32_t button_read(int button)
{
return (uint32_t) hal_gpio_read(button);
}
void publish(struct ble_npl_event *work)
{
int err = 0;
if (is_randomization_of_TIDs_done == false) {
return;
}
if (button_read(button_device[0]) == 0) {
#if defined(ONOFF)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
err = bt_mesh_model_publish(&root_models[3]);
#elif defined(ONOFF_TT)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x28);
err = bt_mesh_model_publish(&root_models[3]);
#elif defined(VND_MODEL_TEST)
bt_mesh_model_msg_init(vnd_models[0].pub->msg,
BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME));
net_buf_simple_add_le16(vnd_models[0].pub->msg, 0x0001);
net_buf_simple_add_u8(vnd_models[0].pub->msg, tid_vnd++);
err = bt_mesh_model_publish(&vnd_models[0]);
#endif
} else if (button_read(button_device[1]) == 0) {
#if defined(ONOFF)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x00);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
err = bt_mesh_model_publish(&root_models[3]);
#elif defined(ONOFF_TT)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x00);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x28);
err = bt_mesh_model_publish(&root_models[3]);
#elif defined(VND_MODEL_TEST)
bt_mesh_model_msg_init(vnd_models[0].pub->msg,
BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME));
net_buf_simple_add_le16(vnd_models[0].pub->msg, 0x0000);
net_buf_simple_add_u8(vnd_models[0].pub->msg, tid_vnd++);
err = bt_mesh_model_publish(&vnd_models[0]);
#endif
} else if (button_read(button_device[2]) == 0) {
#if defined(GENERIC_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK);
net_buf_simple_add_le16(root_models[5].pub->msg, LEVEL_S25);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(ONOFF_GET)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_GET);
err = bt_mesh_model_publish(&root_models[3]);
#elif defined(GENERIC_DELTA_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK);
net_buf_simple_add_le32(root_models[5].pub->msg, 100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(GENERIC_MOVE_LEVEL_TT)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK);
net_buf_simple_add_le16(root_models[5].pub->msg, 13100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(LIGHT_LIGHTNESS_TT)
bt_mesh_model_msg_init(root_models[13].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x4D));
net_buf_simple_add_le16(root_models[13].pub->msg, LEVEL_U25);
net_buf_simple_add_u8(root_models[13].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x28);
err = bt_mesh_model_publish(&root_models[13]);
#elif defined(LIGHT_CTL)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U25);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TT)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U25);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TEMP)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x65));
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#endif
} else if (button_read(button_device[3]) == 0) {
#if defined(GENERIC_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK);
net_buf_simple_add_le16(root_models[5].pub->msg, LEVEL_S100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(GENERIC_DELTA_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK);
net_buf_simple_add_le32(root_models[5].pub->msg, -100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(GENERIC_MOVE_LEVEL_TT)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK);
net_buf_simple_add_le16(root_models[5].pub->msg, -13100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(LIGHT_LIGHTNESS_TT)
bt_mesh_model_msg_init(root_models[13].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x4D));
net_buf_simple_add_le16(root_models[13].pub->msg, LEVEL_U100);
net_buf_simple_add_u8(root_models[13].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x28);
err = bt_mesh_model_publish(&root_models[13]);
#elif defined(LIGHT_CTL)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U100);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TT)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U100);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TEMP)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x65));
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#endif
}
if (err) {
printk("bt_mesh_model_publish: err: %d\n", err);
}
}

View File

@@ -1,46 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _PUBLISHER_H
#define _PUBLISHER_H
/* Others */
#define LEVEL_S0 -32768
#define LEVEL_S25 -16384
#define LEVEL_S50 0
#define LEVEL_S75 16384
#define LEVEL_S100 32767
#define LEVEL_U0 0
#define LEVEL_U25 16384
#define LEVEL_U50 32768
#define LEVEL_U75 49152
#define LEVEL_U100 65535
void randomize_publishers_TID(void);
void publish(struct ble_npl_event *work);
#endif

View File

@@ -1,308 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <math.h>
#include "ble_mesh.h"
#include "device_composition.h"
#include "state_binding.h"
#include "transition.h"
u16_t lightness, target_lightness;
s16_t temperature, target_temperature;
static s32_t ceiling(float num)
{
s32_t inum;
inum = (s32_t) num;
if (num == (float) inum) {
return inum;
}
return inum + 1;
}
u16_t actual_to_linear(u16_t val)
{
float tmp;
tmp = ((float) val / 65535);
return (u16_t) ceiling(65535 * tmp * tmp);
}
u16_t linear_to_actual(u16_t val)
{
return (u16_t) (65535 * sqrt(((float) val / 65535)));
}
static void constrain_lightness(u16_t var)
{
if (var > 0 && var < light_lightness_srv_user_data.light_range_min) {
var = light_lightness_srv_user_data.light_range_min;
} else if (var > light_lightness_srv_user_data.light_range_max) {
var = light_lightness_srv_user_data.light_range_max;
}
lightness = var;
}
static void constrain_lightness2(u16_t var)
{
/* This is as per Mesh Model Specification 3.3.2.2.3 */
if (var > 0 && var < light_lightness_srv_user_data.light_range_min) {
if (gen_level_srv_root_user_data.last_delta < 0) {
var = 0U;
} else {
var = light_lightness_srv_user_data.light_range_min;
}
} else if (var > light_lightness_srv_user_data.light_range_max) {
var = light_lightness_srv_user_data.light_range_max;
}
lightness = var;
}
static void constrain_target_lightness(u16_t var)
{
if (var > 0 &&
var < light_lightness_srv_user_data.light_range_min) {
var = light_lightness_srv_user_data.light_range_min;
} else if (var > light_lightness_srv_user_data.light_range_max) {
var = light_lightness_srv_user_data.light_range_max;
}
target_lightness = var;
}
static s16_t light_ctl_temp_to_level(u16_t temp)
{
float tmp;
/* Mesh Model Specification 6.1.3.1.1 2nd formula start */
tmp = (temp - light_ctl_srv_user_data.temp_range_min) * 65535;
tmp = tmp / (light_ctl_srv_user_data.temp_range_max -
light_ctl_srv_user_data.temp_range_min);
return (s16_t) (tmp - 32768);
/* 6.1.3.1.1 2nd formula end */
}
static u16_t level_to_light_ctl_temp(s16_t level)
{
u16_t tmp;
float diff;
/* Mesh Model Specification 6.1.3.1.1 1st formula start */
diff = (float) (light_ctl_srv_user_data.temp_range_max -
light_ctl_srv_user_data.temp_range_min) / 65535;
tmp = (u16_t) ((level + 32768) * diff);
return (light_ctl_srv_user_data.temp_range_min + tmp);
/* 6.1.3.1.1 1st formula end */
}
void state_binding(u8_t light, u8_t temp)
{
switch (temp) {
case ONOFF_TEMP:
case CTL_TEMP:
temperature =
light_ctl_temp_to_level(light_ctl_srv_user_data.temp);
gen_level_srv_s0_user_data.level = temperature;
break;
case LEVEL_TEMP:
temperature = gen_level_srv_s0_user_data.level;
light_ctl_srv_user_data.temp =
level_to_light_ctl_temp(temperature);
break;
default:
break;
}
switch (light) {
case ONPOWERUP:
if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) {
lightness = 0U;
} else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
lightness = light_lightness_srv_user_data.last;
}
break;
case ONOFF:
if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) {
lightness = 0U;
} else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
if (light_lightness_srv_user_data.def == 0) {
lightness = light_lightness_srv_user_data.last;
} else {
lightness = light_lightness_srv_user_data.def;
}
}
break;
case LEVEL:
lightness = gen_level_srv_root_user_data.level + 32768;
break;
case DELTA_LEVEL:
lightness = gen_level_srv_root_user_data.level + 32768;
constrain_lightness2(lightness);
goto jump;
case ACTUAL:
lightness = light_lightness_srv_user_data.actual;
break;
case LINEAR:
lightness =
linear_to_actual(light_lightness_srv_user_data.linear);
break;
case CTL:
lightness = light_ctl_srv_user_data.lightness;
break;
default:
break;
}
constrain_lightness(lightness);
jump:
if (lightness != 0) {
light_lightness_srv_user_data.last = lightness;
}
if (lightness) {
gen_onoff_srv_root_user_data.onoff = STATE_ON;
} else {
gen_onoff_srv_root_user_data.onoff = STATE_OFF;
}
gen_level_srv_root_user_data.level = lightness - 32768;
light_lightness_srv_user_data.actual = lightness;
light_lightness_srv_user_data.linear = actual_to_linear(lightness);
light_ctl_srv_user_data.lightness = lightness;
}
void calculate_lightness_target_values(u8_t type)
{
bool set_light_ctl_temp_target_value;
u16_t tmp;
set_light_ctl_temp_target_value = true;
switch (type) {
case ONOFF:
if (gen_onoff_srv_root_user_data.target_onoff == 0) {
tmp = 0U;
} else {
if (light_lightness_srv_user_data.def == 0) {
tmp = light_lightness_srv_user_data.last;
} else {
tmp = light_lightness_srv_user_data.def;
}
}
break;
case LEVEL:
tmp = gen_level_srv_root_user_data.target_level + 32768;
break;
case ACTUAL:
tmp = light_lightness_srv_user_data.target_actual;
break;
case LINEAR:
tmp = linear_to_actual(light_lightness_srv_user_data.target_linear);
break;
case CTL:
set_light_ctl_temp_target_value = false;
tmp = light_ctl_srv_user_data.target_lightness;
target_temperature = light_ctl_temp_to_level(light_ctl_srv_user_data.target_temp);
gen_level_srv_s0_user_data.target_level = target_temperature;
break;
default:
return;
}
constrain_target_lightness(tmp);
if (target_lightness) {
gen_onoff_srv_root_user_data.target_onoff = STATE_ON;
} else {
gen_onoff_srv_root_user_data.target_onoff = STATE_OFF;
}
gen_level_srv_root_user_data.target_level = target_lightness - 32768;
light_lightness_srv_user_data.target_actual = target_lightness;
light_lightness_srv_user_data.target_linear =
actual_to_linear(target_lightness);
light_ctl_srv_user_data.target_lightness = target_lightness;
if (set_light_ctl_temp_target_value) {
target_temperature = light_ctl_srv_user_data.temp;
light_ctl_srv_user_data.target_temp = target_temperature;
}
}
void calculate_temp_target_values(u8_t type)
{
bool set_light_ctl_delta_uv_target_value;
set_light_ctl_delta_uv_target_value = true;
switch (type) {
case LEVEL_TEMP:
target_temperature = gen_level_srv_s0_user_data.target_level;
light_ctl_srv_user_data.target_temp =
level_to_light_ctl_temp(target_temperature);
break;
case CTL_TEMP:
set_light_ctl_delta_uv_target_value = false;
target_temperature = light_ctl_temp_to_level(light_ctl_srv_user_data.target_temp);
gen_level_srv_s0_user_data.target_level = target_temperature;
break;
default:
return;
}
target_lightness = light_ctl_srv_user_data.lightness;
light_ctl_srv_user_data.target_lightness = target_lightness;
if (set_light_ctl_delta_uv_target_value) {
light_ctl_srv_user_data.target_delta_uv =
light_ctl_srv_user_data.delta_uv;
}
}

View File

@@ -1,53 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _STATE_BINDING_H
#define _STATE_BINDING_H
enum state_binding {
ONPOWERUP = 0x01,
ONOFF,
LEVEL,
DELTA_LEVEL,
ACTUAL,
LINEAR,
CTL,
IGNORE,
ONOFF_TEMP,
LEVEL_TEMP,
CTL_TEMP,
IGNORE_TEMP
};
extern u16_t lightness, target_lightness;
extern s16_t temperature, target_temperature;
void state_binding(u8_t lightness, u8_t temperature);
void calculate_lightness_target_values(u8_t type);
void calculate_temp_target_values(u8_t type);
#endif

View File

@@ -1,266 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "base64/base64.h"
#include "console/console.h"
#include "mesh/mesh.h"
#include "ble_mesh.h"
#include "device_composition.h"
#include "storage.h"
static u8_t storage_id;
u8_t reset_counter;
#if 0
static void save_reset_counter(void)
{
char buf[5];
settings_str_from_bytes(&reset_counter, sizeof(reset_counter), buf,
sizeof(buf));
settings_save_one("ps/rc", buf);
}
static void save_gen_def_trans_time_state(void)
{
char buf[5];
settings_str_from_bytes(&gen_def_trans_time_srv_user_data.tt,
sizeof(gen_def_trans_time_srv_user_data.tt),
buf, sizeof(buf));
settings_save_one("ps/gdtt", buf);
}
static void save_gen_onpowerup_state(void)
{
char buf[5];
settings_str_from_bytes(&gen_power_onoff_srv_user_data.onpowerup,
sizeof(gen_power_onoff_srv_user_data.onpowerup),
buf, sizeof(buf));
settings_save_one("ps/gpo", buf);
if (gen_power_onoff_srv_user_data.onpowerup == 0x02) {
save_on_flash(LIGHTNESS_TEMP_LAST_STATE);
}
}
static void save_lightness_temp_def_state(void)
{
char buf[12];
light_ctl_srv_user_data.lightness_temp_def =
(u32_t) ((light_ctl_srv_user_data.lightness_def << 16) |
light_ctl_srv_user_data.temp_def);
settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_def,
sizeof(light_ctl_srv_user_data.lightness_temp_def),
buf, sizeof(buf));
settings_save_one("ps/ltd", buf);
}
static void save_lightness_temp_last_state(void)
{
char buf[12];
light_ctl_srv_user_data.lightness_temp_last =
(u32_t) ((light_ctl_srv_user_data.lightness << 16) |
light_ctl_srv_user_data.temp);
settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_last,
sizeof(light_ctl_srv_user_data.lightness_temp_last),
buf, sizeof(buf));
settings_save_one("ps/ltl", buf);
printk("Light CTL Last values have beed saved !!\n");
}
static void save_lightness_range(void)
{
char buf[12];
light_lightness_srv_user_data.lightness_range =
(u32_t) ((light_lightness_srv_user_data.light_range_max << 16) |
light_lightness_srv_user_data.light_range_min);
settings_str_from_bytes(&light_lightness_srv_user_data.lightness_range,
sizeof(light_lightness_srv_user_data.lightness_range),
buf, sizeof(buf));
settings_save_one("ps/lr", buf);
}
static void save_temperature_range(void)
{
char buf[12];
light_ctl_srv_user_data.temperature_range =
(u32_t) ((light_ctl_srv_user_data.temp_range_max << 16) |
light_ctl_srv_user_data.temp_range_min);
settings_str_from_bytes(&light_ctl_srv_user_data.temperature_range,
sizeof(light_ctl_srv_user_data.temperature_range),
buf, sizeof(buf));
settings_save_one("ps/tr", buf);
}
static void storage_work_handler(struct ble_npl_event *work)
{
switch (storage_id) {
case RESET_COUNTER:
save_reset_counter();
break;
case GEN_DEF_TRANS_TIME_STATE:
save_gen_def_trans_time_state();
break;
case GEN_ONPOWERUP_STATE:
save_gen_onpowerup_state();
break;
case LIGHTNESS_TEMP_DEF_STATE:
save_lightness_temp_def_state();
break;
case LIGHTNESS_TEMP_LAST_STATE:
save_lightness_temp_last_state();
break;
case LIGHTNESS_RANGE:
save_lightness_range();
break;
case TEMPERATURE_RANGE:
save_temperature_range();
break;
}
}
struct ble_npl_callout storage_work;
void save_on_flash(u8_t id)
{
storage_id = id;
ble_npl_callout_reset(&storage_work, 0);
}
static int ps_set(int argc, char **argv, char *val)
{
int len;
if (argc == 1) {
if (!strcmp(argv[0], "rc")) {
len = sizeof(reset_counter);
return settings_bytes_from_str(val, &reset_counter,
&len);
}
if (!strcmp(argv[0], "gdtt")) {
len = sizeof(gen_def_trans_time_srv_user_data.tt);
return settings_bytes_from_str(val,
&gen_def_trans_time_srv_user_data.tt, &len);
}
if (!strcmp(argv[0], "gpo")) {
len = sizeof(gen_power_onoff_srv_user_data.onpowerup);
return settings_bytes_from_str(val,
&gen_power_onoff_srv_user_data.onpowerup, &len);
}
if (!strcmp(argv[0], "ltd")) {
len = sizeof(light_ctl_srv_user_data.lightness_temp_def);
return settings_bytes_from_str(val,
&light_ctl_srv_user_data.lightness_temp_def,
&len);
}
if (!strcmp(argv[0], "ltl")) {
len = sizeof(light_ctl_srv_user_data.
lightness_temp_last);
return settings_bytes_from_str(val,
&light_ctl_srv_user_data.lightness_temp_last,
&len);
}
if (!strcmp(argv[0], "lr")) {
len = sizeof(light_lightness_srv_user_data.
lightness_range);
return settings_bytes_from_str(val,
&light_lightness_srv_user_data.lightness_range,
&len);
}
if (!strcmp(argv[0], "tr")) {
len = sizeof(light_ctl_srv_user_data.
temperature_range);
return settings_bytes_from_str(val,
&light_ctl_srv_user_data. temperature_range,
&len);
}
}
return -ENOENT;
}
static struct conf_handler ps_settings = {
.ch_name = "ps",
.ch_set = ps_set,
};
int ps_settings_init(void)
{
int err;
ble_npl_callout_init(&storage_work, nimble_port_get_dflt_eventq(),
storage_work_handler, NULL);
err = conf_register(&ps_settings);
if (err) {
printk("ps_settings_register failed (err %d)", err);
return err;
}
return 0;
}
#else
void save_on_flash(u8_t id)
{
}
#endif

View File

@@ -1,47 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _STORAGE_H
#define _STORAGE_H
enum ps_variables_id {
RESET_COUNTER = 0x01,
GEN_DEF_TRANS_TIME_STATE,
GEN_ONPOWERUP_STATE,
LIGHTNESS_TEMP_DEF_STATE,
LIGHTNESS_TEMP_LAST_STATE,
LIGHTNESS_RANGE,
TEMPERATURE_RANGE
};
extern u8_t reset_counter;
extern struct ble_npl_callout storage_work;
int ps_settings_init(void);
void save_on_flash(u8_t id);
#endif

View File

@@ -1,792 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ble_mesh.h"
#include "common.h"
#include "device_composition.h"
#include "state_binding.h"
#include "transition.h"
struct ble_npl_callout onoff_work;
struct ble_npl_callout level_lightness_work;
struct ble_npl_callout level_temp_work;
struct ble_npl_callout light_lightness_actual_work;
struct ble_npl_callout light_lightness_linear_work;
struct ble_npl_callout light_ctl_work;
struct ble_npl_callout light_ctl_temp_work;
struct ble_npl_callout dummy_timer;
u8_t transition_type, default_tt;
u32_t *ptr_counter;
struct ble_npl_callout *ptr_timer = &dummy_timer;
struct transition lightness_transition, temp_transition;
/* Function to calculate Remaining Time (Start) */
void calculate_rt(struct transition *transition)
{
u8_t steps, resolution;
s32_t duration_remainder;
s64_t now;
if (transition->just_started) {
transition->rt = transition->tt;
} else {
now = k_uptime_get();
duration_remainder = transition->total_duration -
(now - transition->start_timestamp);
if (duration_remainder > 620000) {
/* > 620 seconds -> resolution = 0b11 [10 minutes] */
resolution = 0x03;
steps = duration_remainder / 600000;
} else if (duration_remainder > 62000) {
/* > 62 seconds -> resolution = 0b10 [10 seconds] */
resolution = 0x02;
steps = duration_remainder / 10000;
} else if (duration_remainder > 6200) {
/* > 6.2 seconds -> resolution = 0b01 [1 seconds] */
resolution = 0x01;
steps = duration_remainder / 1000;
} else if (duration_remainder > 0) {
/* <= 6.2 seconds -> resolution = 0b00 [100 ms] */
resolution = 0x00;
steps = duration_remainder / 100;
} else {
resolution = 0x00;
steps = 0x00;
}
transition->rt = (resolution << 6) | steps;
}
}
/* Function to calculate Remaining Time (End) */
static void bound_states_transition_type_reassignment(u8_t type)
{
switch (type) {
case ONOFF:
case LEVEL:
case ACTUAL:
case LINEAR:
light_ctl_srv_user_data.transition = &lightness_transition;
break;
case CTL:
light_ctl_srv_user_data.transition = &lightness_transition;
gen_level_srv_s0_user_data.transition = &lightness_transition;
break;
case LEVEL_TEMP:
case CTL_TEMP:
gen_level_srv_s0_user_data.transition = &temp_transition;
light_ctl_srv_user_data.transition = &temp_transition;
break;
default:
break;
}
}
static void tt_values_calculator(struct transition *transition)
{
u8_t steps_multiplier, resolution;
resolution = (transition->tt >> 6);
steps_multiplier = (transition->tt & 0x3F);
switch (resolution) {
case 0: /* 100ms */
transition->total_duration = steps_multiplier * 100;
break;
case 1: /* 1 second */
transition->total_duration = steps_multiplier * 1000;
break;
case 2: /* 10 seconds */
transition->total_duration = steps_multiplier * 10000;
break;
case 3: /* 10 minutes */
transition->total_duration = steps_multiplier * 600000;
break;
}
transition->counter = ((float) transition->total_duration / 100);
if (transition->counter > DEVICE_SPECIFIC_RESOLUTION) {
transition->counter = DEVICE_SPECIFIC_RESOLUTION;
}
ptr_counter = &transition->counter;
}
void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay)
{
bound_states_transition_type_reassignment(ONOFF);
calculate_lightness_target_values(ONOFF);
state->transition->tt = tt;
state->transition->delay = delay;
if (tt != 0) {
tt_values_calculator(state->transition);
} else {
return;
}
state->transition->quo_tt = state->transition->total_duration /
state->transition->counter;
state->tt_delta = ((float) (lightness - target_lightness) /
state->transition->counter);
}
void level_tt_values(struct generic_level_state *state, u8_t tt, u8_t delay)
{
if (state == &gen_level_srv_root_user_data) {
bound_states_transition_type_reassignment(LEVEL);
calculate_lightness_target_values(LEVEL);
} else if (state == &gen_level_srv_s0_user_data) {
bound_states_transition_type_reassignment(LEVEL_TEMP);
calculate_temp_target_values(LEVEL_TEMP);
}
state->transition->tt = tt;
state->transition->delay = delay;
if (tt != 0) {
tt_values_calculator(state->transition);
} else {
return;
}
state->transition->quo_tt = state->transition->total_duration /
state->transition->counter;
state->tt_delta = ((float) (state->level - state->target_level) /
state->transition->counter);
}
void light_lightness_actual_tt_values(struct light_lightness_state *state,
u8_t tt, u8_t delay)
{
bound_states_transition_type_reassignment(ACTUAL);
calculate_lightness_target_values(ACTUAL);
state->transition->tt = tt;
state->transition->delay = delay;
if (tt != 0) {
tt_values_calculator(state->transition);
} else {
return;
}
state->transition->quo_tt = state->transition->total_duration /
state->transition->counter;
state->tt_delta_actual =
((float) (state->actual - state->target_actual) /
state->transition->counter);
}
void light_lightness_linear_tt_values(struct light_lightness_state *state,
u8_t tt, u8_t delay)
{
bound_states_transition_type_reassignment(LINEAR);
calculate_lightness_target_values(LINEAR);
state->transition->tt = tt;
state->transition->delay = delay;
if (tt != 0) {
tt_values_calculator(state->transition);
} else {
return;
}
state->transition->quo_tt = state->transition->total_duration /
state->transition->counter;
state->tt_delta_linear =
((float) (state->linear - state->target_linear) /
state->transition->counter);
}
void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay)
{
bound_states_transition_type_reassignment(CTL);
calculate_lightness_target_values(CTL);
state->transition->tt = tt;
state->transition->delay = delay;
if (tt != 0) {
tt_values_calculator(state->transition);
} else {
return;
}
state->transition->quo_tt = state->transition->total_duration /
state->transition->counter;
state->tt_delta_lightness =
((float) (state->lightness - state->target_lightness) /
state->transition->counter);
state->tt_delta_temp =
((float) (state->temp - state->target_temp) /
state->transition->counter);
state->tt_delta_duv =
((float) (state->delta_uv - state->target_delta_uv) /
state->transition->counter);
}
void light_ctl_temp_tt_values(struct light_ctl_state *state,
u8_t tt, u8_t delay)
{
bound_states_transition_type_reassignment(CTL_TEMP);
calculate_temp_target_values(CTL_TEMP);
state->transition->tt = tt;
state->transition->delay = delay;
if (tt != 0) {
tt_values_calculator(state->transition);
} else {
return;
}
state->transition->quo_tt = state->transition->total_duration /
state->transition->counter;
state->tt_delta_temp = ((float) (state->temp - state->target_temp) /
state->transition->counter);
state->tt_delta_duv =
((float) (state->delta_uv - state->target_delta_uv) /
state->transition->counter);
}
/* Timers related handlers & threads (Start) */
static void onoff_work_handler(struct ble_npl_event *work)
{
struct generic_onoff_state *state = &gen_onoff_srv_root_user_data;
if (state->transition->just_started) {
state->transition->just_started = false;
if (state->transition->counter == 0) {
state_binding(ONOFF, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
} else {
state->transition->start_timestamp = k_uptime_get();
if (state->target_onoff == STATE_ON) {
state->onoff = STATE_ON;
}
}
return;
}
if (state->transition->counter != 0) {
state->transition->counter--;
lightness -= state->tt_delta;
state_binding(IGNORE, IGNORE_TEMP);
update_light_state();
}
if (state->transition->counter == 0) {
state->onoff = state->target_onoff;
lightness = target_lightness;
state_binding(IGNORE, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
}
}
static void level_lightness_work_handler(struct ble_npl_event *work)
{
u8_t level;
struct generic_level_state *state = &gen_level_srv_root_user_data;
switch (transition_type) {
case LEVEL_TT:
level = LEVEL;
break;
case LEVEL_TT_DELTA:
level = DELTA_LEVEL;
break;
case LEVEL_TT_MOVE:
level = LEVEL;
break;
default:
return;
}
if (state->transition->just_started) {
state->transition->just_started = false;
if (state->transition->counter == 0) {
state_binding(level, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
} else {
state->transition->start_timestamp = k_uptime_get();
}
return;
}
if (state->transition->counter != 0) {
state->transition->counter--;
state->level -= state->tt_delta;
state_binding(level, IGNORE_TEMP);
update_light_state();
}
if (state->transition->counter == 0) {
state->level = state->target_level;
state_binding(level, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
}
}
static void level_temp_work_handler(struct ble_npl_event *work)
{
struct generic_level_state *state = &gen_level_srv_s0_user_data;
switch (transition_type) {
case LEVEL_TEMP_TT:
break;
case LEVEL_TEMP_TT_DELTA:
break;
case LEVEL_TEMP_TT_MOVE:
break;
default:
return;
}
if (state->transition->just_started) {
state->transition->just_started = false;
if (state->transition->counter == 0) {
state_binding(IGNORE, LEVEL_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
} else {
state->transition->start_timestamp = k_uptime_get();
}
return;
}
if (state->transition->counter != 0) {
state->transition->counter--;
state->level -= state->tt_delta;
state_binding(IGNORE, LEVEL_TEMP);
update_light_state();
}
if (state->transition->counter == 0) {
state->level = state->target_level;
state_binding(IGNORE, LEVEL_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
}
}
static void light_lightness_actual_work_handler(struct ble_npl_event *work)
{
struct light_lightness_state *state = &light_lightness_srv_user_data;
if (state->transition->just_started) {
state->transition->just_started = false;
if (state->transition->counter == 0) {
state_binding(ACTUAL, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
} else {
state->transition->start_timestamp = k_uptime_get();
}
return;
}
if (state->transition->counter != 0) {
state->transition->counter--;
state->actual -= state->tt_delta_actual;
state_binding(ACTUAL, IGNORE_TEMP);
update_light_state();
}
if (state->transition->counter == 0) {
state->actual = state->target_actual;
state_binding(ACTUAL, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
}
}
static void light_lightness_linear_work_handler(struct ble_npl_event *work)
{
struct light_lightness_state *state = &light_lightness_srv_user_data;
if (state->transition->just_started) {
state->transition->just_started = false;
if (state->transition->counter == 0) {
state_binding(LINEAR, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
} else {
state->transition->start_timestamp = k_uptime_get();
}
return;
}
if (state->transition->counter != 0) {
state->transition->counter--;
state->linear -= state->tt_delta_linear;
state_binding(LINEAR, IGNORE_TEMP);
update_light_state();
}
if (state->transition->counter == 0) {
state->linear = state->target_linear;
state_binding(LINEAR, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
}
}
static void light_ctl_work_handler(struct ble_npl_event *work)
{
struct light_ctl_state *state = &light_ctl_srv_user_data;
if (state->transition->just_started) {
state->transition->just_started = false;
if (state->transition->counter == 0) {
state_binding(CTL, CTL_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
} else {
state->transition->start_timestamp = k_uptime_get();
}
return;
}
if (state->transition->counter != 0) {
state->transition->counter--;
/* Lightness */
state->lightness -= state->tt_delta_lightness;
/* Temperature */
state->temp -= state->tt_delta_temp;
/* Delta_UV */
state->delta_uv -= state->tt_delta_duv;
state_binding(CTL, CTL_TEMP);
update_light_state();
}
if (state->transition->counter == 0) {
state->lightness = state->target_lightness;
state->temp = state->target_temp;
state->delta_uv = state->target_delta_uv;
state_binding(CTL, CTL_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
}
}
static void light_ctl_temp_work_handler(struct ble_npl_event *work)
{
struct light_ctl_state *state = &light_ctl_srv_user_data;
if (state->transition->just_started) {
state->transition->just_started = false;
if (state->transition->counter == 0) {
state_binding(IGNORE, CTL_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
} else {
state->transition->start_timestamp = k_uptime_get();
}
return;
}
if (state->transition->counter != 0) {
state->transition->counter--;
/* Temperature */
state->temp -= state->tt_delta_temp;
/* Delta UV */
state->delta_uv -= state->tt_delta_duv;
state_binding(IGNORE, CTL_TEMP);
update_light_state();
}
if (state->transition->counter == 0) {
state->temp = state->target_temp;
state->delta_uv = state->target_delta_uv;
state_binding(IGNORE, CTL_TEMP);
update_light_state();
ble_npl_callout_stop(ptr_timer);
}
}
static void dummy_timer_handler(struct ble_npl_event *ev)
{ }
static void onoff_tt_handler(struct ble_npl_event *ev)
{
struct generic_onoff_state *state = ev->arg;
assert(state != NULL);
ble_npl_callout_reset(&onoff_work, 0);
ble_npl_callout_reset(&state->transition->timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(state->transition->quo_tt)));
}
static void level_lightness_tt_handler(struct ble_npl_event *ev)
{
struct generic_level_state *state = ev->arg;
assert(state != NULL);
ble_npl_callout_reset(&level_lightness_work, 0);
ble_npl_callout_reset(&state->transition->timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(state->transition->quo_tt)));
}
static void level_temp_tt_handler(struct ble_npl_event *ev)
{
struct generic_level_state *state = ev->arg;
assert(state != NULL);
ble_npl_callout_reset(&level_temp_work, 0);
ble_npl_callout_reset(&state->transition->timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(state->transition->quo_tt)));
}
static void light_lightness_actual_tt_handler(struct ble_npl_event *ev)
{
struct light_lightness_state *state = ev->arg;
assert(state != NULL);
ble_npl_callout_reset(&light_lightness_actual_work, 0);
ble_npl_callout_reset(&state->transition->timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(state->transition->quo_tt)));
}
static void light_lightness_linear_tt_handler(struct ble_npl_event *ev)
{
struct light_lightness_state *state = ev->arg;
assert(state != NULL);
ble_npl_callout_reset(&light_lightness_linear_work, 0);
ble_npl_callout_reset(&state->transition->timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(state->transition->quo_tt)));
}
static void light_ctl_tt_handler(struct ble_npl_event *ev)
{
struct light_ctl_state *state = ev->arg;
assert(state != NULL);
ble_npl_callout_reset(&light_ctl_work, 0);
ble_npl_callout_reset(&state->transition->timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(state->transition->quo_tt)));
}
static void light_ctl_temp_tt_handler(struct ble_npl_event *ev)
{
struct light_ctl_state *state = ev->arg;
assert(state != NULL);
ble_npl_callout_reset(&light_ctl_temp_work, 0);
ble_npl_callout_reset(&state->transition->timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(state->transition->quo_tt)));
}
/* Timers related handlers & threads (End) */
/* Messages handlers (Start) */
void onoff_handler(struct generic_onoff_state *state)
{
ptr_timer = &state->transition->timer;
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
onoff_tt_handler, NULL);
ptr_timer->ev.arg = state;
ble_npl_callout_reset(ptr_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(5 * state->transition->delay)));
}
void level_lightness_handler(struct generic_level_state *state)
{
ptr_timer = &state->transition->timer;
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
level_lightness_tt_handler, NULL);
ptr_timer->ev.arg = state;
ble_npl_callout_reset(ptr_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(5 * state->transition->delay)));
}
void level_temp_handler(struct generic_level_state *state)
{
ptr_timer = &state->transition->timer;
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
level_temp_tt_handler, NULL);
ptr_timer->ev.arg = state;
ble_npl_callout_reset(ptr_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(5 * state->transition->delay)));
}
void light_lightness_actual_handler(struct light_lightness_state *state)
{
ptr_timer = &state->transition->timer;
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
light_lightness_actual_tt_handler, NULL);
ptr_timer->ev.arg = state;
ble_npl_callout_reset(ptr_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(5 * state->transition->delay)));
}
void light_lightness_linear_handler(struct light_lightness_state *state)
{
ptr_timer = &state->transition->timer;
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
light_lightness_linear_tt_handler, NULL);
ptr_timer->ev.arg = state;
ble_npl_callout_reset(ptr_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(5 * state->transition->delay)));
}
void light_ctl_handler(struct light_ctl_state *state)
{
ptr_timer = &state->transition->timer;
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
light_ctl_tt_handler, NULL);
ptr_timer->ev.arg = state;
ble_npl_callout_reset(ptr_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(5 * state->transition->delay)));
}
void light_ctl_temp_handler(struct light_ctl_state *state)
{
ptr_timer = &state->transition->timer;
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
light_ctl_temp_tt_handler, NULL);
ptr_timer->ev.arg = state;
ble_npl_callout_reset(ptr_timer,
ble_npl_time_ms_to_ticks32(
K_MSEC(5 * state->transition->delay)));
}
/* Messages handlers (End) */
void transition_timers_init(void)
{
ble_npl_callout_init(&onoff_work, nimble_port_get_dflt_eventq(),
onoff_work_handler, NULL);
ble_npl_callout_init(&level_lightness_work, nimble_port_get_dflt_eventq(),
level_lightness_work_handler, NULL);
ble_npl_callout_init(&level_temp_work, nimble_port_get_dflt_eventq(),
level_temp_work_handler, NULL);
ble_npl_callout_init(&light_lightness_actual_work,
nimble_port_get_dflt_eventq(),
light_lightness_actual_work_handler, NULL);
ble_npl_callout_init(&light_lightness_linear_work,
nimble_port_get_dflt_eventq(),
light_lightness_linear_work_handler, NULL);
ble_npl_callout_init(&light_ctl_work, nimble_port_get_dflt_eventq(),
light_ctl_work_handler, NULL);
ble_npl_callout_init(&light_ctl_temp_work, nimble_port_get_dflt_eventq(),
light_ctl_temp_work_handler, NULL);
ble_npl_callout_init(&dummy_timer, nimble_port_get_dflt_eventq(),
dummy_timer_handler, NULL);
}

View File

@@ -1,87 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _TRANSITION_H
#define _TRANSITION_H
#define UNKNOWN_VALUE 0x3F
#define DEVICE_SPECIFIC_RESOLUTION 10
enum level_transition_types {
LEVEL_TT,
LEVEL_TT_DELTA,
LEVEL_TT_MOVE,
LEVEL_TEMP_TT,
LEVEL_TEMP_TT_DELTA,
LEVEL_TEMP_TT_MOVE,
};
struct transition {
bool just_started;
u8_t tt;
u8_t rt;
u8_t delay;
u32_t quo_tt;
u32_t counter;
u32_t total_duration;
s64_t start_timestamp;
struct ble_npl_callout timer;
};
extern u8_t transition_type, default_tt;
extern u32_t *ptr_counter;
extern struct ble_npl_callout *ptr_timer;
extern struct transition lightness_transition, temp_transition;
extern struct ble_npl_callout dummy_timer;
void calculate_rt(struct transition *transition);
void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay);
void level_tt_values(struct generic_level_state *state, u8_t tt, u8_t delay);
void light_lightness_actual_tt_values(struct light_lightness_state *state,
u8_t tt, u8_t delay);
void light_lightness_linear_tt_values(struct light_lightness_state *state,
u8_t tt, u8_t delay);
void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay);
void light_ctl_temp_tt_values(struct light_ctl_state *state,
u8_t tt, u8_t delay);
void onoff_handler(struct generic_onoff_state *state);
void level_lightness_handler(struct generic_level_state *state);
void level_temp_handler(struct generic_level_state *state);
void light_lightness_actual_handler(struct light_lightness_state *state);
void light_lightness_linear_handler(struct light_lightness_state *state);
void light_ctl_handler(struct light_ctl_state *state);
void light_ctl_temp_handler(struct light_ctl_state *state);
void transition_timers_init(void);
#endif

View File

@@ -1,313 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nimble/nimble_port_tencentos_tiny.h"
#include "nimble/ble.h"
#include "host/ble_gap.h"
#define BLE_RAW_ADV_DATA_LEN (31U)
typedef enum nimble_scan_status_en {
NIMBLE_SCAN_STATUS_STOPPED = 0,
NIMBLE_SCAN_STATUS_SCANNING = 1,
} nimble_scan_status_t;
typedef struct nimble_scan_item_st {
k_list_t list;
ble_addr_t addr; /* ble address */
uint8_t adv_data[BLE_RAW_ADV_DATA_LEN]; /* advertising data received */
uint8_t adv_data_len; /* length of the advertising data */
int8_t rssi; /* last RSSI of a scanned node */
uint8_t type; /* advertising packet type */
} nimble_scan_item_t;
/*
type: type of advertising packet, e.g BLE_HCI_ADV_TYPE_ADV_IND
disc_addr: advertising address of the source node
disc_rssi: RSSI value for the received packet
disc_adv_data: received advertising data
disc_adv_data_len: length of disc_adv_data in bytes
*/
typedef void(*nimble_scan_cb_t)(uint8_t type,
const ble_addr_t *disc_addr, int8_t disc_rssi,
const uint8_t *disc_adv_data, size_t disc_adv_data_len);
static uint8_t ble_addr_type;
static nimble_scan_cb_t scan_disc_cb = NULL;
static struct ble_gap_disc_params scan_params = { 0 };
static nimble_scan_item_t entry_pool[200];
TOS_LIST_DEFINE(free_entry);
TOS_LIST_DEFINE(scan_entry);
void nimble_scan_info_list_init(void)
{
int i = 0;
for (i = 0; i < sizeof(entry_pool) / sizeof(entry_pool[0]); ++i) {
tos_list_init(&entry_pool[i].list);
tos_list_add(&entry_pool[i].list, &free_entry);
}
}
void nimble_scan_item_addr_display(ble_addr_t *addr)
{
int i = 0;
printf("%02x", (int)addr->val[5]);
for (i = 4; i >=0; --i) {
printf(":%02x", addr->val[i]);
}
switch (addr->type) {
case BLE_ADDR_PUBLIC:
printf(" (PUBLIC)");
break;
case BLE_ADDR_RANDOM:
printf(" (RANDOM)");
break;
case BLE_ADDR_PUBLIC_ID:
printf(" (PUB_ID)");
break;
case BLE_ADDR_RANDOM_ID:
printf(" (RAND_ID)");
break;
default:
printf(" (UNKNOWN)");
break;
}
}
void nimble_scan_item_type_display(uint8_t type)
{
switch (type) {
case BLE_HCI_ADV_TYPE_ADV_IND:
printf(" [IND]");
break;
case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD:
printf(" [DIRECT_IND_HD]");
break;
case BLE_HCI_ADV_TYPE_ADV_SCAN_IND:
printf(" [SCAN_IND]");
break;
case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND:
printf(" [NONCONN_IND]");
break;
case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD:
printf(" [DIRECT_IND_LD]");
break;
default:
printf(" [INVALID]");
break;
}
}
void nimble_scan_item_display(nimble_scan_item_t *item)
{
nimble_scan_item_addr_display(&item->addr);
nimble_scan_item_type_display(item->type);
printf(", rssi: %d\n", item->rssi);
printf("\n");
}
void nimble_scan_info_list_display(void)
{
nimble_scan_item_t *iter;
TOS_LIST_FOR_EACH_ENTRY(iter, nimble_scan_item_t, list, &scan_entry) {
nimble_scan_item_display(iter);
}
}
nimble_scan_item_t *nimble_scan_item_alloc(void)
{
return TOS_LIST_FIRST_ENTRY_OR_NULL(&free_entry, nimble_scan_item_t, list);
}
int nimble_scan_item_is_exist(ble_addr_t *addr)
{
nimble_scan_item_t *iter;
TOS_LIST_FOR_EACH_ENTRY(iter, nimble_scan_item_t, list, &free_entry) {
if (ble_addr_cmp(&addr, &iter->addr) == 0) {
return K_TRUE;
}
}
return K_FALSE;
}
void nimble_scan_info_save(uint8_t type, const ble_addr_t *disc_addr, int8_t disc_rssi,
const uint8_t *disc_adv_data, size_t disc_adv_data_len)
{
int i = 0;
nimble_scan_item_t *item;
if (nimble_scan_item_is_exist(disc_addr)) {
return;
}
item = nimble_scan_item_alloc();
if (!item) {
return;
}
memcpy(&item->addr, disc_addr, sizeof(ble_addr_t));
if (disc_adv_data) {
memcpy(&item->adv_data, disc_adv_data, disc_adv_data_len);
}
item->adv_data_len = disc_adv_data_len;
item->rssi = disc_rssi;
item->type = type;
tos_list_del(&item->list);
tos_list_add(&item->list, &scan_entry);
}
static int blescan_gap_event(struct ble_gap_event *event, void *arg)
{
/* only interested in the DISC event */
switch (event->type) {
case BLE_GAP_EVENT_DISC:
scan_disc_cb(event->disc.event_type, &event->disc.addr, event->disc.rssi,
event->disc.data, (size_t)event->disc.length_data);
break;
default:
/* should never happen */
MODLOG_DFLT(DEBUG, "unexpected event: (%d)\n", (int)event->type);
assert(0);
break;
}
return 0;
}
int nimble_scan_start(void)
{
int rc;
if (ble_gap_disc_active() != NIMBLE_SCAN_STATUS_STOPPED) {
return 0;
}
rc = ble_gap_disc(ble_addr_type, BLE_HS_FOREVER,
&scan_params, blescan_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(DEBUG, "[scanner] err: start failed (%i)\n", rc);
return -1;
}
return 0;
}
void nimble_scan_stop(void)
{
int rc;
if (ble_gap_disc_active() != NIMBLE_SCAN_STATUS_SCANNING) {
return;
}
rc = ble_gap_disc_cancel();
assert(rc == 0);
}
nimble_scan_status_t nimble_scan_status(void)
{
return ble_gap_disc_active() == 1 ? NIMBLE_SCAN_STATUS_SCANNING : NIMBLE_SCAN_STATUS_STOPPED;
}
int nimble_scan_init(const struct ble_gap_disc_params *params, nimble_scan_cb_t disc_cb)
{
assert(disc_cb);
if (params) {
memcpy(&scan_params, params, sizeof(scan_params));
} else {
memset(&scan_params, 0, sizeof(scan_params));
}
scan_disc_cb = disc_cb;
return 0;
}
int ble_boot(void)
{
int rc;
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
/* make sure synchronization of host and controller is done */
while (!ble_hs_synced()) {
;
}
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
rc = ble_hs_id_infer_auto(0, &ble_addr_type);
assert(rc == 0);
/* do a 'full time' scan, set the window equal the interval */
struct ble_gap_disc_params scan_params = {
.itvl = BLE_GAP_LIM_DISC_SCAN_INT,
.window = BLE_GAP_LIM_DISC_SCAN_WINDOW,
.filter_policy = 0, /* dummy */
.limited = 0, /* no limited discovery */
.passive = 0, /* no passive scanning */
.filter_duplicates = 0, /* no duplicate filtering */
};
nimble_scan_info_list_init();
/* initialize the nimble scanner */
nimble_scan_init(&scan_params, nimble_scan_info_save);
rc = nimble_scan_start();
assert(rc == 0);
tos_task_delay(2000);
nimble_scan_stop();
nimble_scan_info_list_display();
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[2048];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
/*
in this case, ble_boot_task's priority must lower than MYNEWT_VAL_BLE_HOST_TASK_PRIORITY && MYNEWT_VAL_BLE_LL_TASK_PRIORITY,
numerically bigger
to give the host and ll task a chance to run first just after the nimble_port_tencentos_tiny_init.
*/
tos_task_create(&ble_boot_task, "ble_boot", ble_boot, NULL,
6,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,258 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
/* BLE */
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "host/ble_hs_adv.h"
#include "host/ble_uuid.h"
#include "host/ble_att.h"
#include "host/ble_gap.h"
#include "host/ble_gatt.h"
#include "host/ble_l2cap.h"
#include "host/ble_sm.h"
#include "controller/ble_ll.h"
/* RAM HCI transport. */
#include "transport/ram/ble_hci_ram.h"
/* Mandatory services. */
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "bleuart/bleuart.h"
#include "nimble/nimble_port_tencentos_tiny.h"
static const char device_name[] = "Nimble Uart";
static int bleuart_gap_event(struct ble_gap_event *event, void *arg);
/**
* Enables advertising with the following parameters:
* o General discoverable mode.
* o Undirected connectable mode.
*/
static void
bleuart_advertise(void)
{
struct ble_gap_adv_params adv_params;
struct ble_hs_adv_fields fields;
int rc;
/*
* Set the advertisement data included in our advertisements:
* o Flags (indicates advertisement type and other general info).
* o Advertising tx power.
* o 128 bit UUID
*/
memset(&fields, 0, sizeof fields);
/* Advertise two flags:
* o Discoverability in forthcoming advertisement (general)
* o BLE-only (BR/EDR unsupported).
*/
fields.flags = BLE_HS_ADV_F_DISC_GEN |
BLE_HS_ADV_F_BREDR_UNSUP;
/* Indicate that the TX power level field should be included; have the
* stack fill this value automatically. This is done by assiging the
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
*/
fields.tx_pwr_lvl_is_present = 1;
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
fields.uuids128 = BLE_UUID128(&gatt_svr_svc_uart_uuid.u);
fields.num_uuids128 = 1;
fields.uuids128_is_complete = 1;
rc = ble_gap_adv_set_fields(&fields);
if (rc != 0) {
return;
}
memset(&fields, 0, sizeof fields);
fields.name = (uint8_t *)ble_svc_gap_device_name();
fields.name_len = strlen((char *)fields.name);
fields.name_is_complete = 1;
rc = ble_gap_adv_rsp_set_fields(&fields);
if (rc != 0) {
return;
}
/* Begin advertising. */
memset(&adv_params, 0, sizeof adv_params);
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
&adv_params, bleuart_gap_event, NULL);
if (rc != 0) {
return;
}
}
/**
* The nimble host executes this callback when a GAP event occurs. The
* application associates a GAP event callback with each connection that forms.
* bleuart uses the same callback for all connections.
*
* @param event The type of event being signalled.
* @param ctxt Various information pertaining to the event.
* @param arg Application-specified argument; unuesd by
* bleuart.
*
* @return 0 if the application successfully handled the
* event; nonzero on failure. The semantics
* of the return code is specific to the
* particular GAP event being signalled.
*/
static int
bleuart_gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_conn_desc desc;
int rc;
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
/* A new connection was established or a connection attempt failed. */
if (event->connect.status == 0) {
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
assert(rc == 0);
bleuart_set_conn_handle(event->connect.conn_handle);
}
if (event->connect.status != 0) {
/* Connection failed; resume advertising. */
bleuart_advertise();
}
return 0;
case BLE_GAP_EVENT_DISCONNECT:
/* Connection terminated; resume advertising. */
bleuart_advertise();
return 0;
case BLE_GAP_EVENT_ADV_COMPLETE:
/* Advertising terminated; resume advertising. */
bleuart_advertise();
return 0;
case BLE_GAP_EVENT_REPEAT_PAIRING:
/* We already have a bond with the peer, but it is attempting to
* establish a new secure link. This app sacrifices security for
* convenience: just throw away the old bond and accept the new link.
*/
/* Delete the old bond. */
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
assert(rc == 0);
ble_store_util_delete_peer(&desc.peer_id_addr);
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
* continue with the pairing operation.
*/
return BLE_GAP_REPEAT_PAIRING_RETRY;
}
return 0;
}
static void
bleuart_on_sync(void)
{
/* Begin advertising. */
bleuart_advertise();
}
static void
put_ad(uint8_t ad_type, uint8_t ad_len, const void *ad, uint8_t *buf,
uint8_t *len)
{
buf[(*len)++] = ad_len + 1;
buf[(*len)++] = ad_type;
memcpy(&buf[*len], ad, ad_len);
*len += ad_len;
}
static void
update_ad(void)
{
uint8_t ad[BLE_HS_ADV_MAX_SZ];
uint8_t ad_len = 0;
uint8_t ad_flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
put_ad(BLE_HS_ADV_TYPE_FLAGS, 1, &ad_flags, ad, &ad_len);
put_ad(BLE_HS_ADV_TYPE_COMP_NAME, sizeof(device_name), device_name, ad, &ad_len);
ble_gap_adv_set_data(ad, ad_len);
}
int ble_boot(void)
{
int rc = 0;
/* Initialize the BLE host. */
ble_hs_cfg.sync_cb = bleuart_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
rc = bleuart_gatt_svr_init();
assert(rc == 0);
/* Set the default device name */
rc = ble_svc_gap_device_name_set(device_name);
assert(rc == 0);
update_ad();
/* run an event loop for handling the heart rate update events */
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
return 0;
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[512];
int main(void)
{
board_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
4,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}

View File

@@ -1,33 +0,0 @@
#ifdef ACTION_ENABLED
#define TOTAL_ACTION_COUNTS (1)
static TYPE_DEF_TEMPLATE_INT sg_light_blink_in_time = 0;
static TYPE_DEF_TEMPLATE_BOOL sg_light_blink_in_color = 0;
static TYPE_DEF_TEMPLATE_INT sg_light_blink_in_total_time = 0;
static DeviceProperty g_actionInput_light_blink[] = {
{.key = "time", .data = &sg_light_blink_in_time, .type = TYPE_TEMPLATE_INT},
{.key = "color", .data = &sg_light_blink_in_color, .type = TYPE_TEMPLATE_BOOL},
{.key = "total_time", .data = &sg_light_blink_in_total_time, .type = TYPE_TEMPLATE_INT},
};
static TYPE_DEF_TEMPLATE_BOOL sg_light_blink_out_err_code = 0;
static DeviceProperty g_actionOutput_light_blink[] = {
{.key = "err_code", .data = &sg_light_blink_out_err_code, .type = TYPE_TEMPLATE_BOOL},
};
static DeviceAction g_actions[]={
{
.pActionId = "light_blink",
.timestamp = 0,
.input_num = sizeof(g_actionInput_light_blink)/sizeof(g_actionInput_light_blink[0]),
.output_num = sizeof(g_actionOutput_light_blink)/sizeof(g_actionOutput_light_blink[0]),
.pInput = g_actionInput_light_blink,
.pOutput = g_actionOutput_light_blink,
},
};
#endif

View File

@@ -1,39 +0,0 @@
/*-----------------data config start -------------------*/
#define TOTAL_PROPERTY_COUNT 4
static sDataPoint sg_DataTemplate[TOTAL_PROPERTY_COUNT];
typedef struct _ProductDataDefine {
TYPE_DEF_TEMPLATE_BOOL m_power_switch;
TYPE_DEF_TEMPLATE_ENUM m_color;
TYPE_DEF_TEMPLATE_INT m_brightness;
TYPE_DEF_TEMPLATE_STRING m_name[64+1];
} ProductDataDefine;
static ProductDataDefine sg_ProductData;
static void _init_data_template(void)
{
sg_ProductData.m_power_switch = 0;
sg_DataTemplate[0].data_property.data = &sg_ProductData.m_power_switch;
sg_DataTemplate[0].data_property.key = "power_switch";
sg_DataTemplate[0].data_property.type = TYPE_TEMPLATE_BOOL;
sg_ProductData.m_color = 0;
sg_DataTemplate[1].data_property.data = &sg_ProductData.m_color;
sg_DataTemplate[1].data_property.key = "color";
sg_DataTemplate[1].data_property.type = TYPE_TEMPLATE_ENUM;
sg_ProductData.m_brightness = 1;
sg_DataTemplate[2].data_property.data = &sg_ProductData.m_brightness;
sg_DataTemplate[2].data_property.key = "brightness";
sg_DataTemplate[2].data_property.type = TYPE_TEMPLATE_INT;
sg_ProductData.m_name[0] = '\0';
sg_DataTemplate[3].data_property.data = sg_ProductData.m_name;
sg_DataTemplate[3].data_property.data_buff_len = sizeof(sg_ProductData.m_name)/sizeof(sg_ProductData.m_name[3]);
sg_DataTemplate[3].data_property.key = "name";
sg_DataTemplate[3].data_property.type = TYPE_TEMPLATE_STRING;
};

View File

@@ -1,590 +0,0 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "lite-utils.h"
#include "data_config.c"
#ifdef AUTH_MODE_CERT
static char sg_cert_file[PATH_MAX + 1]; // full path of device cert file
static char sg_key_file[PATH_MAX + 1]; // full path of device key file
#endif
static DeviceInfo sg_devInfo;
static MQTTEventType sg_subscribe_event_result = MQTT_EVENT_UNDEF;
static bool sg_control_msg_arrived = false;
static char sg_data_report_buffer[2048];
size_t sg_data_report_buffersize = sizeof(sg_data_report_buffer) / sizeof(sg_data_report_buffer[0]);
#ifdef EVENT_POST_ENABLED
#if defined(EVENT_TIMESTAMP_USED)
#undef EVENT_TIMESTAMP_USED
#endif
#include "events_config.c"
static void update_events_timestamp(sEvent *pEvents, int count)
{
int i;
for(i = 0; i < count; i++){
if (NULL == (&pEvents[i])) {
Log_e("null event pointer");
return;
}
#ifdef EVENT_TIMESTAMP_USED
pEvents[i].timestamp = time(NULL); //should be UTC and accurate
#else
pEvents[i].timestamp = 0;
#endif
}
}
static void event_post_cb(void *pClient, MQTTMessage *msg)
{
Log_d("Reply:%.*s", msg->payload_len, msg->payload);
IOT_Event_clearFlag(pClient, FLAG_EVENT0|FLAG_EVENT1|FLAG_EVENT2);
}
//event check and post
static void eventPostCheck(void *client)
{
int i;
int rc;
uint32_t eflag;
uint8_t event_count;
sEvent *pEventList[EVENT_COUNTS];
IOT_Event_setFlag(client, FLAG_EVENT0|FLAG_EVENT1|FLAG_EVENT2);
eflag = IOT_Event_getFlag(client);
if((EVENT_COUNTS > 0 )&& (eflag > 0)){
event_count = 0;
for(i = 0; i < EVENT_COUNTS; i++){
if((eflag&(1<<i))&ALL_EVENTS_MASK){
pEventList[event_count++] = &(g_events[i]);
update_events_timestamp(&g_events[i], 1);
IOT_Event_clearFlag(client, 1<<i);
}
}
rc = IOT_Post_Event(client, sg_data_report_buffer, sg_data_report_buffersize, \
event_count, pEventList, event_post_cb);
if(rc < 0){
Log_e("events post failed: %d", rc);
}
}
}
#endif
#ifdef ACTION_ENABLED
#include "action_config.c"
// action : regist action and set the action handle callback, add your aciton logic here
static void OnActionCallback(void *pClient, const char *pClientToken, DeviceAction *pAction)
{
int i;
sReplyPara replyPara;
//do something base on input, just print as an sample
DeviceProperty *pActionInput = pAction->pInput;
for (i = 0; i < pAction->input_num; i++) {
if (JSTRING == pActionInput[i].type) {
Log_d("Input:[%s], data:[%s]", pActionInput[i].key, pActionInput[i].data);
HAL_Free(pActionInput[i].data);
} else {
if(JINT32 == pActionInput[i].type) {
Log_d("Input:[%s], data:[%d]", pActionInput[i].key, *((int*)pActionInput[i].data));
} else if( JFLOAT == pActionInput[i].type) {
Log_d("Input:[%s], data:[%f]", pActionInput[i].key, *((float*)pActionInput[i].data));
} else if( JUINT32 == pActionInput[i].type) {
Log_d("Input:[%s], data:[%u]", pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
}
}
}
// construct output
memset((char *)&replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
strcpy(replyPara.status_msg, "action execute success!"); //add the message about the action resault
DeviceProperty *pActionOutnput = pAction->pOutput;
(void)pActionOutnput; //elimate warning
//TO DO: add your aciont logic here and set output properties which will be reported by action_reply
IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &replyPara);
}
static int _register_data_template_action(void *pTemplate_client)
{
int i,rc;
for (i = 0; i < TOTAL_ACTION_COUNTS; i++) {
rc = IOT_Template_Register_Action(pTemplate_client, &g_actions[i], OnActionCallback);
if (rc != QCLOUD_RET_SUCCESS) {
rc = IOT_Template_Destroy(pTemplate_client);
Log_e("register device data template action failed, err: %d", rc);
return rc;
} else {
Log_i("data template action=%s registered.", g_actions[i].pActionId);
}
}
return QCLOUD_RET_SUCCESS;
}
#endif
static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
switch(msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe success, packet-id=%u", packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe wait ack timeout, packet-id=%u", packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe nack, packet-id=%u", packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
// Setup MQTT construct parameters
static int _setup_connect_init_params(TemplateInitParams* initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if(QCLOUD_RET_SUCCESS != ret){
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
/* TLS with certs*/
char certs_dir[PATH_MAX + 1] = "certs";
char current_path[PATH_MAX + 1];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL)
{
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);
initParams->cert_file = sg_cert_file;
initParams->key_file = sg_key_file;
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = event_handler;
return QCLOUD_RET_SUCCESS;
}
static void OnControlMsgCallback(void *pClient, const char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty)
{
int i = 0;
for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) {
/* handle self defined string/json here. Other properties are dealed in _handle_delta()*/
if (strcmp(sg_DataTemplate[i].data_property.key, pProperty->key) == 0) {
sg_DataTemplate[i].state = eCHANGED;
Log_i("Property=%s changed", pProperty->key);
sg_control_msg_arrived = true;
return;
}
}
Log_e("Property=%s changed no match", pProperty->key);
}
static void OnReportReplyCallback(void *pClient, Method method, ReplyAck replyAck, const char *pJsonDocument, void *pUserdata) {
Log_i("recv report reply response, reply ack: %d", replyAck);
}
// register data template properties
static int _register_data_template_property(void *pTemplate_client)
{
int i,rc;
for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) {
rc = IOT_Template_Register_Property(pTemplate_client, &sg_DataTemplate[i].data_property, OnControlMsgCallback);
if (rc != QCLOUD_RET_SUCCESS) {
rc = IOT_Template_Destroy(pTemplate_client);
Log_e("register device data template property failed, err: %d", rc);
return rc;
} else {
Log_i("data template property=%s registered.", sg_DataTemplate[i].data_property.key);
}
}
return QCLOUD_RET_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////
__weak void OLED_Clear(void)
{
printf("OLED Clear\n");
}
__weak void OLED_ShowString(int x, int y, uint8_t *str, int bold)
{
printf("OLED ShowString: %s\n", (char *)str);
}
// handle the light(simulated)
static void light_change_color(const char *color)
{
// 作为demo这里用oled屏字符显示来模拟灯颜色的切换
// 这里应该由用户实现硬件操作代码,来改变智能灯的颜色
// 此处demo在开发板显示屏上显示具体的颜色
OLED_ShowString(0, 0, (uint8_t *)color, 8);
}
static void light_change_brightness(TYPE_DEF_TEMPLATE_INT brightness)
{
// 作为demo这里用oled屏字符显示来模拟灯颜色的切换
// 这里应该由用户实现硬件操作代码,来改变智能灯的颜色
// 此处demo在开发板显示屏上显示具体的颜色
char brightness_str[12];
snprintf(brightness_str, sizeof(brightness_str), "%d", brightness);
brightness_str[sizeof(brightness_str) - 1] = '\0';
OLED_ShowString(0, 2, (uint8_t *)brightness_str, 8);
}
static void light_power_on(void)
{
// 作为demo这里用oled屏字符显示来模拟灯颜色的切换
OLED_Clear();
}
static void light_power_off(void)
{
// 作为demo这里用oled屏字符显示来模拟灯颜色的切换
char *info = "light off";
OLED_Clear();
OLED_ShowString(0, 0, (uint8_t *)info, 16);
}
/////////////////////////////////////////////////////////////////////////////////////
// when control msg received, data_template's properties has been parsed in pData
// you should add your logic how to use pData
void deal_down_stream_user_logic(void *client, ProductDataDefine * pData)
{
Log_d("someting about your own product logic wait to be done");
/////////////////////////////////////////////////////////////////////////////////////
char *color_name;
/* 灯光颜色 */
switch (sg_ProductData.m_color) {
case 0:
color_name = " RED ";
break;
case 1:
color_name = "GREEN";
break;
case 2:
color_name = "BLUE";
break;
}
if (sg_ProductData.m_power_switch == 1) {
/* 灯光开启式,按照控制参数展示 */
light_power_on();
light_change_color(color_name);
light_change_brightness(sg_ProductData.m_brightness);
} else {
/* 灯光关闭展示 */
light_power_off();
}
}
void first_time_report_construct(DeviceProperty *pReportDataList[], int *pCount)
{
int i, j;
for (i = 0, j = 0; i < TOTAL_PROPERTY_COUNT; i++) {
pReportDataList[j++] = &(sg_DataTemplate[i].data_property);
}
*pCount = j;
}
/////////////////////////////////////////////////////////////////////////////////////
// demo for up-stream
// add changed properties to pReportDataList, then the changed properties would be reported
// you should add your own logic for how to get the changed properties
int deal_up_stream_user_logic(DeviceProperty *pReportDataList[], int *pCount)
{
int i, j;
for (i = 0, j = 0; i < TOTAL_PROPERTY_COUNT; i++) {
if(eCHANGED == sg_DataTemplate[i].state) {
pReportDataList[j++] = &(sg_DataTemplate[i].data_property);
sg_DataTemplate[i].state = eNOCHANGE;
}
}
*pCount = j;
return (*pCount > 0)?QCLOUD_RET_SUCCESS:QCLOUD_ERR_FAILURE;
}
/*You should get the real info for your device, here just for example*/
static int _get_sys_info(void *handle, char *pJsonDoc, size_t sizeOfBuffer)
{
/*platform info has at least one of module_hardinfo/module_softinfo/fw_ver property*/
DeviceProperty plat_info[] = {
{.key = "module_hardinfo", .type = TYPE_TEMPLATE_STRING, .data = "ESP8266"},
{.key = "module_softinfo", .type = TYPE_TEMPLATE_STRING, .data = "V1.0"},
{.key = "fw_ver", .type = TYPE_TEMPLATE_STRING, .data = QCLOUD_IOT_DEVICE_SDK_VERSION},
{.key = "imei", .type = TYPE_TEMPLATE_STRING, .data = "11-22-33-44"},
{.key = "lat", .type = TYPE_TEMPLATE_STRING, .data = "22.546015"},
{.key = "lon", .type = TYPE_TEMPLATE_STRING, .data = "113.941125"},
{NULL, NULL, 0} //end
};
/*self define info*/
DeviceProperty self_info[] = {
{.key = "append_info", .type = TYPE_TEMPLATE_STRING, .data = "your self define info"},
{NULL, NULL, 0} //end
};
return IOT_Template_JSON_ConstructSysInfo(handle, pJsonDoc, sizeOfBuffer, plat_info, self_info);
}
int data_template_light_thread(void) {
int rc;
sReplyPara replyPara;
DeviceProperty *pReportDataList[TOTAL_PROPERTY_COUNT];
int ReportCont;
//init log level
IOT_Log_Set_Level(eLOG_DEBUG);
//init connection
TemplateInitParams init_params = DEFAULT_TEMPLATE_INIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *client = IOT_Template_Construct(&init_params, NULL);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
///////////////////////////////////
int first_time_report = 1;
light_power_off();
///////////////////////////////////
//init data template
_init_data_template();
//register data template propertys here
rc = _register_data_template_property(client);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("Register data template propertys Success");
} else {
Log_e("Register data template propertys Failed: %d", rc);
return rc;
}
//register data template actions here
#ifdef ACTION_ENABLED
rc = _register_data_template_action(client);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("Register data template actions Success");
} else {
Log_e("Register data template actions Failed: %d", rc);
return rc;
}
#endif
//report device info, then you can manager your product by these info, like position
rc = _get_sys_info(client, sg_data_report_buffer, sg_data_report_buffersize);
if(QCLOUD_RET_SUCCESS == rc){
rc = IOT_Template_Report_SysInfo_Sync(client, sg_data_report_buffer, sg_data_report_buffersize, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Report system info fail, err: %d", rc);
goto exit;
}
}else {
Log_e("Get system info fail, err: %d", rc);
}
//get the property changed during offline
rc = IOT_Template_GetStatus_sync(client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Get data status fail, err: %d", rc);
//goto exit;
}else {
Log_d("Get data status success");
}
while (IOT_Template_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT
|| rc == QCLOUD_RET_MQTT_RECONNECTED || QCLOUD_RET_SUCCESS == rc) {
rc = IOT_Template_Yield(client, 200);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
}
else if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Exit loop caused of errCode: %d", rc);
}
/* handle control msg from server */
if (sg_control_msg_arrived) {
deal_down_stream_user_logic(client, &sg_ProductData);
/* control msg should reply, otherwise server treat device didn't receive and retain the msg which would be get by get status*/
memset((char *)&replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
replyPara.status_msg[0] = '\0'; //add extra info to replyPara.status_msg when error occured
rc = IOT_Template_ControlReply(client, sg_data_report_buffer, sg_data_report_buffersize, &replyPara);
if (rc == QCLOUD_RET_SUCCESS) {
Log_d("Contol msg reply success");
sg_control_msg_arrived = false;
} else {
Log_e("Contol msg reply failed, err: %d", rc);
}
}else {
Log_d("No control msg received...");
}
///////////////////////////////////
// some mistake(kind of bug) in this official sample, must do the first time report
// the cloud take the light switch state as ON by default
if (first_time_report) {
/*report msg to server*/
/*report the lastest properties's status*/
first_time_report_construct(pReportDataList, &ReportCont);
rc = IOT_Template_JSON_ConstructReportArray(client, sg_data_report_buffer, sg_data_report_buffersize, ReportCont, pReportDataList);
if (rc == QCLOUD_RET_SUCCESS) {
rc = IOT_Template_Report(client, sg_data_report_buffer, sg_data_report_buffersize,
OnReportReplyCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("data template reporte success");
} else {
Log_e("data template reporte failed, err: %d", rc);
}
} else {
Log_e("construct reporte data failed, err: %d", rc);
}
first_time_report = 0;
} else {
///////////////////////////////////
/*report msg to server*/
/*report the lastest properties's status*/
if(QCLOUD_RET_SUCCESS == deal_up_stream_user_logic(pReportDataList, &ReportCont)){
rc = IOT_Template_JSON_ConstructReportArray(client, sg_data_report_buffer, sg_data_report_buffersize, ReportCont, pReportDataList);
if (rc == QCLOUD_RET_SUCCESS) {
rc = IOT_Template_Report(client, sg_data_report_buffer, sg_data_report_buffersize,
OnReportReplyCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("data template reporte success");
} else {
Log_e("data template reporte failed, err: %d", rc);
}
} else {
Log_e("construct reporte data failed, err: %d", rc);
}
}else {
//Log_d("no data need to be reported or someting goes wrong");
}
///////////////////////////////////
}
///////////////////////////////////
#ifdef EVENT_POST_ENABLED
eventPostCheck(client);
#endif
HAL_SleepMs(3000);
}/*end of while*/
exit:
rc = IOT_Template_Destroy(client);
return rc;
}

View File

@@ -1,46 +0,0 @@
#include "tos_k.h"
/* 用户根据自己的底层通信链路来配置此宏
* 如果是基于以太网lwip的链路这里应该定义 USE_LWIP
* 如果是基于模组的通信链路这里应该定义相应的模组宏如使用ESP8266则定义 USE_ESP8266
* */
#define USE_ESP8266
#ifdef USE_LWIP
#include "lwip/api.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#endif
#ifdef USE_ESP8266
#include "esp8266.h"
#endif
void application_entry(void *arg)
{
#ifdef USE_LWIP
dns_init();
MX_LWIP_Init();
#endif
#ifdef USE_ESP8266
extern int esp8266_sal_init(hal_uart_port_t uart_port);
extern int esp8266_join_ap(const char *ssid, const char *pwd);
esp8266_sal_init(HAL_UART_PORT_0);
esp8266_join_ap("SheldonDai", "srnr6x9xbhmb0");
#endif
#ifdef USE_NB_BC35
extern int bc35_28_95_sal_init(hal_uart_port_t uart_port);
bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
data_template_light_thread();
while (1) {
printf("This is a qcloud explorer sdk data template demo!\r\n");
tos_task_delay(1000);
}
}

View File

@@ -1,53 +0,0 @@
#ifdef EVENT_POST_ENABLED
#define EVENT_COUNTS (3)
static TYPE_DEF_TEMPLATE_BOOL sg_status_report_status = 0;
static TYPE_DEF_TEMPLATE_STRING sg_status_report_message[64+1]={0};
static DeviceProperty g_propertyEvent_status_report[] = {
{.key = "status", .data = &sg_status_report_status, .type = TYPE_TEMPLATE_BOOL},
{.key = "message", .data = sg_status_report_message, .type = TYPE_TEMPLATE_STRING},
};
static TYPE_DEF_TEMPLATE_FLOAT sg_low_voltage_voltage = 1;
static DeviceProperty g_propertyEvent_low_voltage[] = {
{.key = "voltage", .data = &sg_low_voltage_voltage, .type = TYPE_TEMPLATE_FLOAT},
};
static TYPE_DEF_TEMPLATE_STRING sg_hardware_fault_name[64+1]={0};
static TYPE_DEF_TEMPLATE_INT sg_hardware_fault_error_code = 1;
static DeviceProperty g_propertyEvent_hardware_fault[] = {
{.key = "name", .data = sg_hardware_fault_name, .type = TYPE_TEMPLATE_STRING},
{.key = "error_code", .data = &sg_hardware_fault_error_code, .type = TYPE_TEMPLATE_INT},
};
static sEvent g_events[]={
{
.event_name = "status_report",
.type = "info",
.timestamp = 0,
.eventDataNum = sizeof(g_propertyEvent_status_report)/sizeof(g_propertyEvent_status_report[0]),
.pEventData = g_propertyEvent_status_report,
},
{
.event_name = "low_voltage",
.type = "alert",
.timestamp = 0,
.eventDataNum = sizeof(g_propertyEvent_low_voltage)/sizeof(g_propertyEvent_low_voltage[0]),
.pEventData = g_propertyEvent_low_voltage,
},
{
.event_name = "hardware_fault",
.type = "fault",
.timestamp = 0,
.eventDataNum = sizeof(g_propertyEvent_hardware_fault)/sizeof(g_propertyEvent_hardware_fault[0]),
.pEventData = g_propertyEvent_hardware_fault,
},
};
#endif

View File

@@ -1,46 +0,0 @@
#include "tos_k.h"
/* 用户根据自己的底层通信链路来配置此宏
* 如果是基于以太网lwip的链路这里应该定义 USE_LWIP
* 如果是基于模组的通信链路这里应该定义相应的模组宏如使用ESP8266则定义 USE_ESP8266
* */
#define USE_ESP8266
#ifdef USE_LWIP
#include "lwip/api.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#endif
#ifdef USE_ESP8266
#include "esp8266.h"
#endif
void application_entry(void *arg)
{
#ifdef USE_LWIP
dns_init();
MX_LWIP_Init();
#endif
#ifdef USE_ESP8266
extern int esp8266_sal_init(hal_uart_port_t uart_port);
extern int esp8266_join_ap(const char *ssid, const char *pwd);
esp8266_sal_init(HAL_UART_PORT_0);
esp8266_join_ap("SheldonDai", "srnr6x9xbhmb0");
#endif
#ifdef USE_NB_BC35
extern int bc35_28_95_sal_init(hal_uart_port_t uart_port);
bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
ota_thread();
while (1) {
printf("This is a qcloud explorer sdk ota demo!\r\n");
tos_task_delay(1000);
}
}

View File

@@ -1,522 +0,0 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "lite-utils.h"
#ifdef AUTH_MODE_CERT
static char sg_cert_file[PATH_MAX + 1]; // full path of device cert file
static char sg_key_file[PATH_MAX + 1]; // full path of device key file
#endif
static DeviceInfo sg_devInfo;
#define OTA_BUF_LEN (5000)
static bool sg_pub_ack = false;
static int sg_packet_id = 0;
static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
if (sg_packet_id == packet_id)
sg_pub_ack = true;
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
/* demo of firmware info management in device side for resuming download from break point */
#define VERSION_FILE_PATH "./local_fw_info.json"
#define KEY_VER "version"
#define KEY_MD5 "md5"
#define KEY_SIZE "downloadSize"
#define KEY_STATE "state"
#define KEY_PREVER "running_version"
static char * get_local_fw_version(char **ver, char **md5, char **size)
{
#define INFO_FILE_MAX_LEN 256
FILE *fp;
int len;
int rlen;
char *preVer;
char *reportVer = NULL;
fp = fopen(VERSION_FILE_PATH, "r");
if (NULL == fp) {
Log_e("open file %s failed", VERSION_FILE_PATH);
goto exit;
}
fseek(fp, 0L, SEEK_END);
len = ftell(fp);
if (len > INFO_FILE_MAX_LEN) {
Log_e("%s is too big, pls check", VERSION_FILE_PATH);
goto exit;
}
char *JsonDoc = (char *)HAL_Malloc(len + 10);
if (NULL == JsonDoc) {
Log_e("malloc buffer for json file read fail");
goto exit;
}
rewind(fp);
rlen = fread(JsonDoc, 1, len, fp);
if (len != rlen) {
Log_e("read data len (%d) less than needed (%d), %s", rlen, len, JsonDoc);
}
*ver = LITE_json_value_of(KEY_VER, JsonDoc);
*md5 = LITE_json_value_of(KEY_MD5, JsonDoc);
*size = LITE_json_value_of(KEY_SIZE, JsonDoc);
preVer = LITE_json_value_of(KEY_PREVER, JsonDoc);
if ((NULL != *ver) && (NULL != preVer) && (0 == strcmp(*ver, preVer))) {
reportVer = *ver;
HAL_Free(preVer);
} else {
reportVer = preVer;
}
exit:
if (NULL != fp) {
fclose(fp);
}
return reportVer;
#undef INFO_FILE_MAX_LEN
}
/* update local firmware info for resuming download from break point */
static int update_local_fw_info(const char *version, const char *preVer, const char *md5, uint32_t downloadedSize)
{
#define INFO_FILE_MAX_LEN 256
FILE *fp;
int wlen;
int ret = QCLOUD_RET_SUCCESS;
static char dataBuff[INFO_FILE_MAX_LEN];
memset(dataBuff, 0, INFO_FILE_MAX_LEN);
HAL_Snprintf(dataBuff, INFO_FILE_MAX_LEN, "{\"%s\":\"%s\", \"%s\":\"%s\",\"%s\":%d,\"%s\":\"%s\"}", \
KEY_VER, version, KEY_MD5, md5, KEY_SIZE, downloadedSize, \
KEY_PREVER, (NULL == preVer) ? "1.0.0" : preVer);
fp = fopen(VERSION_FILE_PATH, "w");
if (NULL == fp) {
Log_e("open file %s failed", VERSION_FILE_PATH);
ret = QCLOUD_ERR_FAILURE;
goto exit;
}
wlen = fwrite(dataBuff, 1, strlen(dataBuff), fp);
if (wlen != strlen(dataBuff)) {
Log_e("save version to file err");
ret = QCLOUD_ERR_FAILURE;
}
exit:
if (NULL != fp) {
fclose(fp);
}
return ret;
#undef INFO_FILE_MAX_LEN
}
/* get local firmware offset for resuming download from break point */
static int getFwOffset(void *h_ota, char *local_ver, char *local_md5, char *local_size, uint32_t *offset, uint32_t *size_file)
{
static char version[128], md5sum[33];
uint32_t local_len;
int Ret;
Ret = IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
Ret |= IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
Ret |= IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, size_file, 4);
local_len = (NULL == local_size) ? 0 : atoi(local_size);
if ((NULL == local_ver) || (NULL == local_md5) || (NULL == local_size)) {
*offset = 0;
} else if ((0 != strcmp(local_ver, version)) || (0 != strcmp(local_md5, md5sum)) || (local_len > *size_file)) {
*offset = 0;
} else {
*offset = local_len;
}
return Ret;
}
/* calculate left MD5 for resuming download from break point */
static int cal_exist_fw_md5(void *h_ota, FILE *fp, size_t size)
{
#define BUFF_LEN 1024
static char buff[BUFF_LEN];
size_t rlen;
int Ret = QCLOUD_RET_SUCCESS;
while ((size > 0) && (!feof(fp))) {
rlen = (size > BUFF_LEN) ? BUFF_LEN : size;
if (rlen != fread(buff, 1, rlen, fp)) {
Log_e("read data len not expected");
Ret = QCLOUD_ERR_FAILURE;
break;
}
IOT_OTA_UpdateClientMd5(h_ota, buff, rlen);
size -= rlen;
}
return Ret;
#undef BUFF_LEN
}
static int _setup_connect_init_params(MQTTInitParams* initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if (QCLOUD_RET_SUCCESS != ret) {
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[PATH_MAX + 1] = "certs";
char current_path[PATH_MAX + 1];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);
initParams->cert_file = sg_cert_file;
initParams->key_file = sg_key_file;
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = event_handler;
return QCLOUD_RET_SUCCESS;
}
int ota_thread(void)
{
IOT_Log_Set_Level(eLOG_DEBUG);
int rc;
uint32_t firmware_valid;
static char version[128], md5sum[33];
uint32_t len, size_downloaded, size_file;
int ota_over = 0;
bool upgrade_fetch_success = true;
static char buf_ota[OTA_BUF_LEN];
FILE *fp = NULL;
uint32_t offset = 0;
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *client = IOT_MQTT_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
void *h_ota = IOT_OTA_Init(sg_devInfo.product_id, sg_devInfo.device_name, client);
if (NULL == h_ota) {
Log_e("initialize OTA failed");
return QCLOUD_ERR_FAILURE;
}
IOT_MQTT_Yield(client, 1000); //make sure subscribe success
char *local_ver = NULL, *local_md5 = NULL, *local_size = NULL, *reportVer = NULL;
reportVer = get_local_fw_version(&local_ver, &local_md5, &local_size);
Log_d("local_ver:%s local_md5:%s, local_size:%s", local_ver, local_md5, local_size);
/* Must report version first */
if (0 > IOT_OTA_ReportVersion(h_ota, (NULL == reportVer) ? "1.0.0" : reportVer)) {
Log_e("report OTA version failed");
goto exit;
}
do {
Log_i("wait for ota upgrade command...");
IOT_MQTT_Yield(client, 200);
if (IOT_OTA_IsFetching(h_ota)) {
/*check pre-download finished or not*/
/*if version & MD5 is the same,then pre-download not finished,get breakpoint continue download.otherwise the version is new*/
rc = getFwOffset(h_ota, local_ver, local_md5, local_size, &offset, &size_file);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("get fw offset err,rc:%d", rc);
upgrade_fetch_success = false;
break;
}
//finish download but not report state
if(offset == size_file) {
Log_d("download success last time without report!");
upgrade_fetch_success = true;
/* get fw information */
IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
size_downloaded = size_file;
break;
}
/*start http connect*/
rc = IOT_OTA_StartDownload(h_ota, offset, size_file);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("OTA download start err,rc:%d", rc);
upgrade_fetch_success = false;
break;
}
/*cal file md5*/
//Log_d("Get offset:%d(%x)", offset, offset);
if (offset > 0) {
if (NULL == (fp = fopen("ota.bin", "ab+"))) {
Log_e("open file failed");
upgrade_fetch_success = false;
break;
}
if (QCLOUD_RET_SUCCESS != cal_exist_fw_md5(h_ota, fp, offset)) {
Log_e("cal exist fw md5 failed");
upgrade_fetch_success = false;
break;
}
/*set offset*/
fseek(fp, offset, SEEK_SET);
} else {
if (NULL == (fp = fopen("ota.bin", "wb+"))) {
Log_e("open file failed");
upgrade_fetch_success = false;
break;
}
}
do {
len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
if (len > 0) {
if (1 != fwrite(buf_ota, len, 1, fp)) {
Log_e("write data to file failed");
upgrade_fetch_success = false;
break;
}
} else if (len < 0) {
Log_e("download fail rc=%d", len);
upgrade_fetch_success = false;
break;
}
fflush(fp);
/* get OTA information and update local info */
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &size_downloaded, 4);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
rc = update_local_fw_info(version, reportVer, md5sum, size_downloaded);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("update local fw info err,rc:%d", rc);
}
IOT_MQTT_Yield(client, 100);
} while (!IOT_OTA_IsFetchFinish(h_ota));
fclose(fp);
fp = NULL;
/* Must check MD5 match or not */
if (upgrade_fetch_success) {
IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
if (0 == firmware_valid) {
Log_e("The firmware is invalid");
upgrade_fetch_success = false;
rc = update_local_fw_info(NULL, reportVer, NULL, 0);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("update local fw info err,rc:%d", rc);
}
} else {
Log_i("The firmware is valid");
upgrade_fetch_success = true;
}
}
ota_over = 1;
}
HAL_SleepMs(2000);
} while (!ota_over);
if (upgrade_fetch_success) {
/* begin execute OTA files, should report upgrade begin */
sg_packet_id = IOT_OTA_ReportUpgradeBegin(h_ota);
if (0 > sg_packet_id) {
Log_e("report OTA begin failed error:%d", sg_packet_id);
return QCLOUD_ERR_FAILURE;
}
while (!sg_pub_ack) {
HAL_SleepMs(1000);
IOT_MQTT_Yield(client, 200);
}
sg_pub_ack = false;
//* add your own upgrade logic here*//
//* fw_upgrade.....
if (QCLOUD_RET_SUCCESS == rc) {
/* if upgrade success */
/* after execute OTA files, should report upgrade result */
sg_packet_id = IOT_OTA_ReportUpgradeSuccess(h_ota, NULL);
if (0 > sg_packet_id) {
Log_e("report OTA result failed error:%d", sg_packet_id);
return QCLOUD_ERR_FAILURE;
}
while (!sg_pub_ack) {
HAL_SleepMs(1000);
IOT_MQTT_Yield(client, 200);
}
rc = update_local_fw_info(version, version, md5sum, size_downloaded); // just for example, add your own logic
sg_pub_ack = false;
} else {
/* if upgrade fail */
sg_packet_id = IOT_OTA_ReportUpgradeFail(h_ota, NULL);
if (0 > sg_packet_id) {
Log_e("report OTA result failed error:%d", sg_packet_id);
return QCLOUD_ERR_FAILURE;
}
while (!sg_pub_ack) {
HAL_SleepMs(1000);
IOT_MQTT_Yield(client, 200);
}
rc = update_local_fw_info(NULL, reportVer, NULL, 0); // just for example, add your own logic
sg_pub_ack = false;
}
}
exit:
if (NULL != fp) {
fclose(fp);
fp = NULL;
}
if (NULL != local_ver) {
reportVer = (reportVer == local_ver) ? NULL : reportVer;
HAL_Free(local_ver);
local_ver = NULL;
}
if (NULL != local_md5) {
HAL_Free(local_md5);
local_md5 = NULL;
}
if (NULL != local_size) {
HAL_Free(local_size);
local_size = NULL;
}
if (NULL != reportVer) {
HAL_Free(reportVer);
reportVer = NULL;
}
IOT_OTA_Destroy(h_ota);
IOT_MQTT_Destroy(&client);
return 0;
}

View File

@@ -1,191 +0,0 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#ifdef AUTH_MODE_CERT
static char sg_cert_file[PATH_MAX + 1]; // full path of device cert file
static char sg_key_file[PATH_MAX + 1]; // full path of device key file
#endif
static DeviceInfo sg_devInfo;
void response_message_callback(void* coap_message, void* userContext)
{
int ret_code = IOT_COAP_GetMessageCode(coap_message);
switch (ret_code) {
case COAP_EVENT_RECEIVE_ACK:
Log_i("message received ACK, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_RECEIVE_RESPCONTENT:
{
char* payload = NULL;
int payload_len = 0;
int ret = -1;
ret = IOT_COAP_GetMessagePayload(coap_message, &payload, &payload_len);
if (ret == QCLOUD_RET_SUCCESS) {
Log_i("message received response, content: %s", payload);
}
else {
Log_e("message received response, content error.");
}
}
break;
case COAP_EVENT_UNAUTHORIZED:
Log_i("coap client auth token expired or invalid, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_FORBIDDEN:
Log_i("coap URI is invalid for this device, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_INTERNAL_SERVER_ERROR:
Log_i("coap server internal error, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_ACK_TIMEOUT:
Log_i("message receive ACK timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_SEPRESP_TIMEOUT:
Log_i("message received ACK but receive response timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
default:
break;
}
}
void event_handler(void *pcontext, CoAPEventMessage *message)
{
switch (message->event_type) {
case COAP_EVENT_RECEIVE_ACK:
Log_i("message received ACK, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_RECEIVE_RESPCONTENT:
Log_i("message received response, content: %s", IOT_COAP_GetMessageId(message->message));
break;
case COAP_EVENT_UNAUTHORIZED:
Log_i("coap client auth token expired or invalid, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_FORBIDDEN:
Log_i("coap URI is invalid for this device, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_INTERNAL_SERVER_ERROR:
Log_i("coap server internal error, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_ACK_TIMEOUT:
Log_i("message receive ACK timeout, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_SEPRESP_TIMEOUT:
Log_i("message received ACK but receive response timeout, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
default:
Log_e("unrecogonized event type: %d", message->event_type);
break;
}
}
static int _setup_connect_init_params(CoAPInitParams* initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if(QCLOUD_RET_SUCCESS != ret){
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[PATH_MAX + 1] = "certs";
char current_path[PATH_MAX + 1];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL)
{
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);
initParams->cert_file = sg_cert_file;
initParams->key_file = sg_key_file;
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->event_handle.h_fp = event_handler;
initParams->max_retry_count = 3;
return QCLOUD_RET_SUCCESS;
}
int coap_basic_thread(void)
{
int rc = QCLOUD_RET_SUCCESS;
IOT_Log_Set_Level(eLOG_DEBUG);
CoAPInitParams init_params = DEFAULT_COAPINIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *coap_client = IOT_COAP_Construct(&init_params);
if (coap_client == NULL) {
Log_e("COAP Client construct failed.");
return QCLOUD_ERR_FAILURE;
}
do {
SendMsgParams send_params = DEFAULT_SENDMSG_PARAMS;
send_params.pay_load = "{\"name\":\"hello world\"}";
send_params.pay_load_len = strlen("{\"name\":\"hello world\"}");
send_params.resp_callback = response_message_callback;
char topicName[128] = "";
sprintf(topicName, "%s/%s/data", sg_devInfo.product_id, sg_devInfo.device_name);
Log_i("topic name is %s", topicName);
rc = IOT_COAP_SendMessage(coap_client, topicName, &send_params);
if (rc < 0) {
Log_e("client publish topic failed :%d.", rc);
}
else {
Log_d("client topic has been sent, msg_id: %d", rc);
}
rc = IOT_COAP_Yield(coap_client, 200);
if (rc != QCLOUD_RET_SUCCESS){
Log_e("exit with error: %d", rc);
break;
}
} while (1);
IOT_COAP_Destroy(&coap_client);
return QCLOUD_RET_SUCCESS;
}

View File

@@ -1,48 +0,0 @@
#include "tos_k.h"
/* 用户根据自己的底层通信链路来配置此宏
* 如果是基于以太网lwip的链路这里应该定义 USE_LWIP
* 如果是基于模组的通信链路这里应该定义相应的模组宏如使用ESP8266则定义 USE_ESP8266
* */
#define USE_ESP8266
#ifdef USE_LWIP
#include "lwip/api.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#endif
#ifdef USE_ESP8266
#include "esp8266.h"
#endif
void application_entry(void *arg)
{
extern void mqtt_basic_thread(void);
#ifdef USE_LWIP
dns_init();
MX_LWIP_Init();
#endif
#ifdef USE_ESP8266
extern int esp8266_sal_init(hal_uart_port_t uart_port);
extern int esp8266_join_ap(const char *ssid, const char *pwd);
esp8266_sal_init(HAL_UART_PORT_0);
esp8266_join_ap("SheldonDai", "srnr6x9xbhmb0");
#endif
#ifdef USE_NB_BC35
extern int bc35_28_95_sal_init(hal_uart_port_t uart_port);
bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
coap_basic_thread();
while (1) {
printf("This is a coap demo!\r\n");
tos_task_delay(1000);
}
}

View File

@@ -1,322 +0,0 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <signal.h>
#include "utils_getopt.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#ifdef AUTH_MODE_CERT
static char sg_cert_file[PATH_MAX + 1]; // full path of device cert file
static char sg_key_file[PATH_MAX + 1]; // full path of device key file
#endif
static DeviceInfo sg_devInfo;
static int sg_count = 0;
static int sg_sub_packet_id = -1;
// user's log print callback
static bool log_handler(const char* message)
{
// return true if print success
return false;
}
// MQTT event callback
static void _mqtt_event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
MQTTMessage* mqtt_messge = (MQTTMessage*)msg->msg;
uintptr_t packet_id = (uintptr_t)msg->msg;
switch(msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_PUBLISH_RECVEIVED:
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
mqtt_messge->topic_len,
mqtt_messge->ptopic,
mqtt_messge->payload_len,
mqtt_messge->payload);
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
sg_sub_packet_id = packet_id;
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
sg_sub_packet_id = packet_id;
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
sg_sub_packet_id = packet_id;
break;
case MQTT_EVENT_UNSUBCRIBE_SUCCESS:
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_TIMEOUT:
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_NACK:
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
// Setup MQTT construct parameters
static int _setup_connect_init_params(MQTTInitParams* initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if(QCLOUD_RET_SUCCESS != ret){
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[PATH_MAX + 1] = "certs";
char current_path[PATH_MAX + 1];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL)
{
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
sprintf(sg_cert_file, "%s\\%s\\%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
sprintf(sg_key_file, "%s\\%s\\%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);
#else
sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);
#endif
initParams->cert_file = sg_cert_file;
initParams->key_file = sg_key_file;
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = _mqtt_event_handler;
initParams->event_handle.context = NULL;
return QCLOUD_RET_SUCCESS;
}
#define MAX_SIZE_OF_TOPIC_CONTENT 100
// publish MQTT msg
static int _publish_test_msg(void *client, char *topic_keyword, QoS qos)
{
char topicName[128] = {0};
sprintf(topicName,"%s/%s/%s", sg_devInfo.product_id, sg_devInfo.device_name, topic_keyword);
PublishParams pub_params = DEFAULT_PUB_PARAMS;
pub_params.qos = qos;
char topic_content[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
int size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"action\": \"publish_test\", \"count\": \"%d\"}", sg_count++);
if (size < 0 || size > sizeof(topic_content) - 1) {
Log_e("payload content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_content));
return -3;
}
pub_params.payload = topic_content;
pub_params.payload_len = strlen(topic_content);
return IOT_MQTT_Publish(client, topicName, &pub_params);
}
// callback when MQTT msg arrives
static void on_message_callback(void *pClient, MQTTMessage *message, void *userData)
{
if (message == NULL) {
return;
}
Log_i("Receive Message With topicName:%.*s, payload:%.*s",
(int) message->topic_len, message->ptopic, (int) message->payload_len, (char *) message->payload);
}
// subscrib MQTT topic
static int _subscribe_topic(void *client, char *topic_keyword, QoS qos)
{
static char topic_name[128] = {0};
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", sg_devInfo.product_id, sg_devInfo.device_name, topic_keyword);
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.qos = qos;
sub_params.on_message_handler = on_message_callback;
return IOT_MQTT_Subscribe(client, topic_name, &sub_params);
}
#ifdef LOG_UPLOAD
// init log upload module
static int _init_log_upload(void)
{
LogUploadInitParams log_init_params;
memset(&log_init_params, 0, sizeof(LogUploadInitParams));
log_init_params.product_id = sg_devInfo.product_id;
log_init_params.device_name = sg_devInfo.device_name;
#ifdef AUTH_MODE_CERT
log_init_params.sign_key = sg_cert_file;
#else
log_init_params.sign_key = sg_devInfo.device_secret;
#endif
#if defined(__linux__) || defined(WIN32)
log_init_params.read_func = HAL_Log_Read;
log_init_params.save_func = HAL_Log_Save;
log_init_params.del_func = HAL_Log_Del;
log_init_params.get_size_func = HAL_Log_Get_Size;
#endif
return IOT_Log_Init_Uploader(&log_init_params);
}
#endif
int mqtt_basic_thread(void)
{
int rc;
//init log level
IOT_Log_Set_Level(eLOG_DEBUG);
IOT_Log_Set_MessageHandler(log_handler);
//init connection
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params error, rc = %d", rc);
return rc;
}
#ifdef LOG_UPLOAD
// _init_log_upload should be done after _setup_connect_init_params and before IOT_MQTT_Construct
rc = _init_log_upload();
if (rc != QCLOUD_RET_SUCCESS)
Log_e("init log upload error, rc = %d", rc);
#endif
// create MQTT client and connect with server
void *client = IOT_MQTT_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
rc = IOT_MQTT_GetErrCode();
Log_e("MQTT Construct failed, rc = %d", rc);
IOT_Log_Upload(true);
return QCLOUD_ERR_FAILURE;
}
#ifdef SYSTEM_COMM
long time = 0;
// get system timestamp from server
rc = IOT_Get_SysTime(client, &time);
if (QCLOUD_RET_SUCCESS == rc){
Log_i("system time is %ld", time);
} else {
Log_e("get system time failed!");
}
#endif
//subscribe normal topics here
rc = _subscribe_topic(client, "data", QOS0);
if (rc < 0) {
Log_e("Client Subscribe Topic Failed: %d", rc);
IOT_Log_Upload(true);
return rc;
}
// wait for subscription result
IOT_MQTT_Yield(client, 500);
do {
if (sg_sub_packet_id > 0) {
rc = _publish_test_msg(client, "data", QOS1);
if (rc < 0) {
Log_e("client publish topic failed :%d.", rc);
}
}
rc = IOT_MQTT_Yield(client, 500);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED){
Log_e("exit with error: %d", rc);
break;
}
} while (1);
rc = IOT_MQTT_Destroy(&client);
IOT_Log_Upload(true);
return rc;
}

View File

@@ -1,48 +0,0 @@
#include "tos_k.h"
/* 用户根据自己的底层通信链路来配置此宏
* 如果是基于以太网lwip的链路这里应该定义 USE_LWIP
* 如果是基于模组的通信链路这里应该定义相应的模组宏如使用ESP8266则定义 USE_ESP8266
* */
#define USE_ESP8266
#ifdef USE_LWIP
#include "lwip/api.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#endif
#ifdef USE_ESP8266
#include "esp8266.h"
#endif
void application_entry(void *arg)
{
extern void mqtt_basic_thread(void);
#ifdef USE_LWIP
dns_init();
MX_LWIP_Init();
#endif
#ifdef USE_ESP8266
extern int esp8266_sal_init(hal_uart_port_t uart_port);
extern int esp8266_join_ap(const char *ssid, const char *pwd);
esp8266_sal_init(HAL_UART_PORT_0);
esp8266_join_ap("SheldonDai", "srnr6x9xbhmb0");
#endif
#ifdef USE_NB_BC35
extern int bc35_28_95_sal_init(hal_uart_port_t uart_port);
bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
mqtt_basic_thread();
while (1) {
printf("This is a mqtt demo!\r\n");
tos_task_delay(1000);
}
}

View File

@@ -3,41 +3,20 @@
#include "cmsis_os.h"
#define USE_ESP8266
//#define USE_SIM800A
//#define USE_BC26
//#define USE_EC20
//#define USE_EC200S
//#define USE_AIR724
//#define USE_L610
//#define USE_EC600S
#ifdef USE_ESP8266
#include "esp8266.h"
#endif
#ifdef USE_SIM800A
#include "sim800a.h"
#endif
#ifdef USE_BC26
#include "bc26.h"
#endif
#ifdef USE_EC20
#include "ec20.h"
#endif
#ifdef USE_EC200S
#include "ec200s.h"
#endif
#ifdef USE_AIR724
#include "air724.h"
#endif
#ifdef USE_L610
#include "l610.h"
#endif
#ifdef USE_EC600S
#include "ec600s.h"
@@ -106,19 +85,8 @@ void application_entry(void *arg)
#if defined(USE_ESP8266)
esp8266_sal_init(HAL_UART_PORT_0);
esp8266_join_ap("Mculover666", "mculover666");
#elif defined(USE_SIM800A)
sim800a_power_on();
sim800a_sal_init(HAL_UART_PORT_2);
#elif defined(USE_BC26)
bc26_sal_init(HAL_UART_PORT_2);
#elif defined(USE_EC20)
ec20_sal_init(HAL_UART_PORT_0);
#elif defined(USE_EC200S)
ec200s_sal_init(HAL_UART_PORT_0);
#elif defined(USE_AIR724)
air724_sal_init(HAL_UART_PORT_0);
#elif defined(USE_L610)
l610_sal_init(HAL_UART_PORT_0);
#elif defined(USE_EC600S)
ec600s_sal_init(HAL_UART_PORT_0);
#endif

View File

@@ -76,10 +76,6 @@ void application_entry(void *arg)
esp8266_join_ap("SheldonDai", "srnr6x9xbhmb0");
#endif
#ifdef USE_SIM800A
sim800a_power_on();
sim800a_sal_init(HAL_UART_PORT_2);
#endif
#ifdef USE_AIR724
air724_sal_init(HAL_UART_PORT_0);

View File

@@ -1,162 +0,0 @@
#include "cmsis_os.h"
#include "tcp_client_echo.h"
#include "utils/debug/art_assert.h"
#include "utils/debug/log.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/netifapi.h"
#define TCP_CLI_ECHO_STK_SIZE 512*3
void tcp_client_echo_task_entry(void *arg);
osThreadDef(tcp_client_echo_task_entry, osPriorityNormal, 1, TCP_CLI_ECHO_STK_SIZE);
#define BUFSZ 1500
static char recv_data[BUFSZ];
void tcp_client_echo_task_entry(void *arg)
{
int ret;
int conn;
static uint64_t cli_recv_count = 0;
struct sockaddr_in target_sockaddr;
ip4_addr_t target_ser_ip;
int optval = 0;
int len = sizeof(int);
struct timeval tv;
target_ser_t target_ser = *(target_ser_t*)arg;
if(!ipaddr_aton((const char *)target_ser.ip, &target_ser_ip))
{
LOG(LOG_LVL_ERROR, "[%s, %d]Convert target server ip addr failed.\r\n", __func__, __LINE__);
return;
}
if ((conn = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
LOG(LOG_LVL_ERROR, "[%s, %d]Socket creat error.\r\n", __func__, __LINE__);
return;
}
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(conn, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(struct timeval));
target_sockaddr.sin_family = AF_INET;
target_sockaddr.sin_port = htons(target_ser.port);
target_sockaddr.sin_addr.s_addr = target_ser_ip.addr;
memset(&(target_sockaddr.sin_zero), 0, sizeof(target_sockaddr.sin_zero));
while (1)
{
if(connect(conn, (struct sockaddr *)&target_sockaddr, sizeof(struct sockaddr)) == -1)
{
LOG(LOG_LVL_ERROR, "[%s, %d]Connect target tcp server faild!\r\n", __func__, __LINE__);
OS_MsDelay(3000);
continue;
}
LOG(LOG_LVL_ERROR, "[%s, %d]Connect target tcp server successful!\r\n", __func__, __LINE__);
while (1)
{
ret = send(conn, "hello", strlen("hello"), 0);
//---------------recv data-----------------------//
memset(recv_data,0,sizeof(recv_data));
ret = recv(conn, recv_data, BUFSZ-1, 0);
getsockopt(conn, SOL_SOCKET, SO_ERROR, &optval, (socklen_t *)&len);
if (ret < 0)
{
if(optval == EWOULDBLOCK){
LOG(LOG_LVL_ERROR, "[%s, %d] recv < 0 (recv timeout)\r\n", __func__, __LINE__ );
continue;
} else if(optval == ECONNABORTED) {
LOG(LOG_LVL_ERROR, "[%s, %d] recv < 0 (conn abort)\r\n", __func__, __LINE__ );
closesocket(conn);
break;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] recv < 0 (err optval = %d)\r\n", __func__, __LINE__,optval);
closesocket(conn);
break;
}
}
else if(ret == 0)
{
if(optval == ERR_OK){
LOG(LOG_LVL_ERROR, "[%s, %d] recv = 0 ERR_OK\r\n", __func__, __LINE__);
continue;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] recv = 0 (err optval = %d)\r\n", __func__, __LINE__, optval);
closesocket(conn);
break;
}
}
else
{
cli_recv_count += ret;
LOG(LOG_LVL_ERROR, "client_recv_count = %u\r\n", cli_recv_count);
}
//---------------send data-----------------------//
LOG(LOG_LVL_INFO, "received: %s\r\n", recv_data);
getsockopt(conn, SOL_SOCKET, SO_ERROR, &optval, (socklen_t *)&len);
if (ret < 0)
{
if(optval == EWOULDBLOCK){
LOG(LOG_LVL_ERROR, "[%s, %d] send < 0 (send timeout)\r\n", __func__, __LINE__);
continue;
} else if(optval == ECONNABORTED) {
LOG(LOG_LVL_ERROR, "[%s, %d] send < 0 (conn abort)\r\n", __func__, __LINE__);
closesocket(conn);
break;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] send < 0 (err optval = %d)\r\n", __func__, __LINE__, optval);
closesocket(conn);
break;
}
}
else if(ret == 0)
{
if(optval == ERR_OK){
LOG(LOG_LVL_ERROR, "[%s, %d] send = 0 ERR_OK\r\n", __func__, __LINE__);
continue;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] send = 0 (err optval = %d)\r\n", __func__, __LINE__, optval);
closesocket(conn);
break;
}
}
OS_MsDelay(3000);
}
}
closesocket(conn);
LOG(LOG_LVL_ERROR, "[%s, %d]tcp client sock closed.\r\n", __func__, __LINE__);
}
void tcp_client_echo_task_creat(uint8_t * ser_ip, uint32_t port)
{
static target_ser_t ser = {0};
ser.ip = ser_ip;
ser.port = port;
osThreadCreate(osThread(tcp_client_echo_task_entry), &ser);
}

View File

@@ -1,16 +0,0 @@
#ifndef __TCP_CLIENT_ECHO_H__
#define __TCP_CLIENT_ECHO_H__
#include "stdint.h"
typedef struct{
uint8_t * ip;
uint32_t port;
}target_ser_t;
void tcp_client_echo_task_creat(uint8_t * ser_ip, uint32_t port);
#endif /* __TCP_CLIENT_ECHO_H__ */

View File

@@ -1,165 +0,0 @@
#include "cmsis_os.h"
#include "tcp_server_echo.h"
#include "utils/debug/art_assert.h"
#include "utils/debug/log.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/netifapi.h"
#define TCP_SER_ECHO_STK_SIZE 512*3
void tcp_server_echo_task_entry(void *arg);
osThreadDef(tcp_server_echo_task_entry, osPriorityNormal, 1, TCP_SER_ECHO_STK_SIZE);
#define BUFSZ 1500
static char recv_data[BUFSZ];
void tcp_server_echo_task_entry(void *arg)
{
socklen_t sin_size;
int server_sock, conn;
struct sockaddr_in server_addr, client_addr;
bool stop = false;
int ret;
static uint64_t ser_recv_count = 0;
static int optval = 0;
int len = sizeof(int);
struct timeval tv;
uint32_t ser_port = *(uint32_t *)arg;
if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1){
LOG(LOG_LVL_ERROR, "[%s, %d]create server_sock failed.\r\n", __func__, __LINE__);
return;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(ser_port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){
LOG(LOG_LVL_ERROR, "[%s, %d]bind error.\r\n", __func__, __LINE__);
closesocket(server_sock);
return;
}
if (listen(server_sock, 5) == -1){
getsockopt(server_sock, SOL_SOCKET, SO_ERROR, &optval, (socklen_t *)&len);
LOG(LOG_LVL_ERROR, "[%s, %d]listen error.optval=%d\r\n", __func__, __LINE__, optval);
closesocket(server_sock);
return;
}
LOG(LOG_LVL_ERROR, "[%s, %d]listening on port %d\r\n", __func__, __LINE__, ser_port);
while (stop != true)
{
ser_recv_count = 0;
sin_size = sizeof(struct sockaddr_in);
if ((conn = accept(server_sock, (struct sockaddr *)&client_addr, &sin_size)) < 0)
{
getsockopt(server_sock, SOL_SOCKET, SO_ERROR, &optval, (socklen_t *)&len);
LOG(LOG_LVL_ERROR, "[%s, %d]accept failed.optval=%d\r\n", __func__, __LINE__, optval);
break;
}
LOG(LOG_LVL_ERROR, "[%s, %d]got a conn from (%s , %d)\r\n", __func__, __LINE__, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
tv.tv_sec = 3;
tv.tv_usec = 0;
setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
tv.tv_sec = 3;
tv.tv_usec = 0;
setsockopt(conn, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(struct timeval));
while (1)
{
//---------------recv data-----------------------//
memset(recv_data,0,sizeof(recv_data));
ret = recv(conn, recv_data, BUFSZ-1, 0);
getsockopt(conn, SOL_SOCKET, SO_ERROR, &optval, (socklen_t *)&len);
if (ret < 0)
{
if(optval == EWOULDBLOCK){
LOG(LOG_LVL_ERROR, "[%s, %d] recv < 0 (recv timeout)\r\n", __func__, __LINE__ );
continue;
} else if(optval == ECONNABORTED) {
LOG(LOG_LVL_ERROR, "[%s, %d] recv < 0 (conn abort)\r\n", __func__, __LINE__ );
closesocket(conn);
break;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] recv < 0 (err optval = %d)\r\n", __func__, __LINE__,optval);
closesocket(conn);
break;
}
}
else if(ret == 0)
{
if(optval == ERR_OK){
LOG(LOG_LVL_ERROR, "[%s, %d] recv = 0 ERR_OK\r\n", __func__, __LINE__);
continue;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] recv = 0 (err optval = %d)\r\n", __func__, __LINE__, optval);
closesocket(conn);
break;
}
}
else
{
ser_recv_count += ret;
LOG(LOG_LVL_ERROR, "server_recv_count = %u\r\n", ser_recv_count);
}
//---------------send data-----------------------//
ret = send(conn, recv_data, ret, 0);
getsockopt(conn, SOL_SOCKET, SO_ERROR, &optval, (socklen_t *)&len);
if (ret < 0)
{
if(optval == EWOULDBLOCK){
LOG(LOG_LVL_ERROR, "[%s, %d] send < 0 (send timeout)\r\n", __func__, __LINE__);
continue;
} else if(optval == ECONNABORTED) {
LOG(LOG_LVL_ERROR, "[%s, %d] send < 0 (conn abort)\r\n", __func__, __LINE__);
closesocket(conn);
break;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] send < 0 (err optval = %d)\r\n", __func__, __LINE__, optval);
closesocket(conn);
break;
}
}
else if(ret == 0)
{
if(optval == ERR_OK){
LOG(LOG_LVL_ERROR, "[%s, %d] send = 0 ERR_OK\r\n", __func__, __LINE__);
continue;
} else {
LOG(LOG_LVL_ERROR, "[%s, %d] send = 0 (err optval = %d)\r\n", __func__, __LINE__, optval);
closesocket(conn);
break;
}
}
}
}
closesocket(server_sock);
LOG(LOG_LVL_ERROR, "[%s, %d]server_sock closed.\r\n", __func__, __LINE__);
}
void tcp_server_echo_task_creat(uint32_t port)
{
static uint32_t server_port;
server_port = port;
osThreadCreate(osThread(tcp_server_echo_task_entry), &server_port);
}

View File

@@ -1,12 +0,0 @@
#ifndef __TCP_SERVER_ECHO_H__
#define __TCP_SERVER_ECHO_H__
#include "stdint.h"
void tcp_server_echo_task_creat(uint32_t port);
#endif /* __TCP_SERVER_ECHO_H__ */

View File

@@ -1,210 +0,0 @@
#include "cmsis_os.h"
#include "osal/osal.h"
#include "utils/debug/log.h"
#include "utils/debug/art_assert.h"
#include "utils/art_string.h"
#include "wifi/wifi.h"
#include "ping/ping.h"
#include "netif/ethernetif.h"
#include "wifi_manager/wifi_manager.h"
#include "lwip/tcpip.h"
#include "drv_adc_measure.h"
#include "utils/system_parameter.h"
#include "hal/hal_adc.h"
#include "tcp_server_echo.h"
#include "tcp_client_echo.h"
static OS_Thread_t g_temp_cal_thread;
#define TEMP_APP_TASK_STACK_SIZE 4*256 //Byte
volatile uint8_t dhcp_get_ip = 0;
void wifi_init_sta(void)
{
uint8_t macaddr[6] = {0}, macaddr_default[6] = {0};
wifi_config_t wifi_config = {
.sta = {
.ssid = "SheldonDai",
.password = "srnr6x9xbhmb0",
0,
},
};
wifi_config_t temp_config = {0};
wifi_init_type_t init_param = {
.wifi_mode = WIFI_MODE_STATION,
.sta_ps_mode = WIFI_NO_POWERSAVE,
#if 1
.dhcp_mode = WLAN_DHCP_CLIENT,
#else
.dhcp_mode = WLAN_STATIC_IP,
.local_ip_addr = "192.168.1.110",
.net_mask = "255.255.255.0",
.gateway_ip_addr = "192.168.1.1",
#endif
//In station mode, define the length of the AP list scanned.
.scanned_ap_list_size = SCANNED_AP_LIST_SIZE,
};
//Set wifi mode
wifi_set_mode(init_param.wifi_mode);
//Check mac address
system_parameter_get_wifi_macaddr_default(STATION_IF, macaddr_default);
wifi_get_macaddr(STATION_IF, macaddr);
if(is_valid_mac((const char *)macaddr) && memcmp(macaddr, macaddr_default, 6) != 0){
//If there is a valid MAC in flash, use it
wifi_set_macaddr_current(STATION_IF, macaddr);
}else{
//generate random macaddr
generate_mac_randomly(macaddr);
wifi_set_macaddr(STATION_IF, macaddr);
}
//Check config
wifi_get_config(STATION_IF, &temp_config);
if(strlen((const char *)temp_config.sta.ssid) > 0){
//If there is a valid config in flash, use it;
wifi_set_config_current(STATION_IF, &temp_config);
}else{
//else, use the prev wifi_config and save it to flash.
wifi_set_config(STATION_IF, &wifi_config);
}
//Startup WiFi.
if(!wifi_start(&init_param)){//WIFI_MAX_POWERSAVE
LOG(LOG_LVL_ERROR, "[%s, %d]wifi_start() fail.\r\n", __func__, __LINE__);
}
}
void wifi_init_ap(void)
{
uint8_t macaddr[6] = {0}, macaddr_default[6] = {0};
wifi_config_t wifi_config = {
.ap = {
.ssid = "ln882x-softap",
.ssid_len = strlen("ln882x-softap"),
.password = "12345678",
.channel = 1,
.authmode = WIFI_AUTH_OPEN,
.ssid_hidden = 0,
.max_connection = 4,
.beacon_interval = 100,
.reserved = 0,
},
};
wifi_config_t temp_config = {0};
wifi_init_type_t init_param = {
.wifi_mode = WIFI_MODE_AP,
.sta_ps_mode = WIFI_NO_POWERSAVE,
.dhcp_mode = WLAN_DHCP_SERVER,
};
//Set wifi mode
wifi_set_mode(init_param.wifi_mode);
//Check mac address
system_parameter_get_wifi_macaddr_default(SOFT_AP_IF, macaddr_default);
wifi_get_macaddr(SOFT_AP_IF, macaddr);
if(is_valid_mac((const char *)macaddr) && memcmp(macaddr, macaddr_default, 6) != 0){
//If there is a valid MAC in flash, use it
wifi_set_macaddr_current(SOFT_AP_IF, macaddr);
}else{
//generate random macaddr
generate_mac_randomly(macaddr);
wifi_set_macaddr(SOFT_AP_IF, macaddr);
}
//Check config
wifi_get_config(SOFT_AP_IF, &temp_config);
if(strlen((const char *)temp_config.sta.ssid) > 0){
//If there is a valid config in flash, use it;
wifi_set_config_current(SOFT_AP_IF, &temp_config);
}else{
//else, use the prev wifi_config and save it to flash.
wifi_set_config(SOFT_AP_IF, &wifi_config);
}
//Startup WiFi.
if(!wifi_start(&init_param)){
LOG(LOG_LVL_ERROR, "[%s, %d]wifi_start() fail.\r\n", __func__, __LINE__);
}
}
void temp_cal_app_task_entry(void *params)
{
drv_adc_init();
OS_MsDelay(1);
wifi_temp_cal_init(drv_adc_read(ADC_CHAN_0));
while(1)
{
OS_MsDelay(1);
wifi_do_temp_cal_period(drv_adc_read(ADC_CHAN_0));
OS_MsDelay(1000);
}
}
void wifi_event_sta_got_ip_cb(wifi_msg_t * msg)
{
dhcp_get_ip = 1;
};
void application_entry(void *arg)
{
//wifi chip temperature calibration.
if(OS_OK != OS_ThreadCreate(&g_temp_cal_thread, "TempAPP", temp_cal_app_task_entry, NULL, OS_PRIORITY_BELOW_NORMAL, TEMP_APP_TASK_STACK_SIZE)) {
ART_ASSERT(1);
}
reg_wifi_msg_callbcak(WIFI_MSG_ID_STA_DHCP_GOT_IP,wifi_event_sta_got_ip_cb);
wifi_mode_enum_t wifi_mode = WIFI_MODE_STATION;
tcpip_ip_info_t ip_info = {0};
wifi_interface_enum_t if_index;
if(wifi_mode == WIFI_MODE_STATION){
if_index = STATION_IF;
wifi_init_sta();
}else if(wifi_mode == WIFI_MODE_AP){
if_index = SOFT_AP_IF;
wifi_init_ap();
}else if(wifi_mode == WIFI_MODE_MONITOR){
if_index = MONITOR_IF;
}else{
LOG(LOG_LVL_ERROR, "wifi interface error!\r\n");
}
if((wifi_mode == WIFI_MODE_STATION)||(wifi_mode == WIFI_MODE_AP)) {
//Wait for network link up
while(LINK_UP != ethernetif_get_link_state()){
OS_MsDelay(1000);
}
ethernetif_get_ip_info(if_index, &ip_info);
}
while(!dhcp_get_ip){
OS_MsDelay(1000);
};
tcp_server_echo_task_creat(8087);
// tcp_client_echo_task_creat((uint8_t *)"39.108.190.129", 8000);//ͨ<><CDA8>è<EFBFBD><C3A8><EFBFBD><EFBFBD>(IP:120.76.100.197) 10002<30>˿<EFBFBD>
while(1)
{
tos_task_delay(1*1000);
}
}