更新时间:2023-09-06 10:41:15下载pdf
本文详细介绍 SDK 上蓝牙配网功能,实现网关设备接入到涂鸦生态。
配网流程的业务逻辑已经在 SDK 内部实现,SDK 定义一套 TuyaOS Kernel Layer(简称 TKL)接口来屏蔽硬件和系统差异。TKL 接口由开发者实现,在 TKL 接口完成底层硬件的操作。本文档将提供 TKL 接口开发指导。
蓝牙配网是将网关通过蓝牙接收手机发来的配网信息(路由热点的 SSID 和 PW),收到配网信息后网关走激活流程直至配网成功。
蓝牙配网主要适用场景如下:
网关设备把其设备信息加密后定期发送蓝牙广播数据包,手机 App 打开蓝牙并接收蓝牙广播数据包。如果广播数据包中包含涂鸦服务,则发起扫描响应请求进一步获取设备的详细信息。成功获取到设备信息后,会在 自动发现 页面显示待配网设备。
用户在手机 App 上单击 添加 激活待配网设备时,手机 App 与设备建立蓝牙连接,把配网信息发送给设备。设备收到配网信息后走激活流程,直到配网完成。
涂鸦蓝牙配网用的是私有服务和私有数据,所有数据均由 SDK 解析和封装,开发者无需关心数据内容,直接透传处理。
蓝牙配网的流程图如下图所示:
tkl_ble_stack_init
OPERATE_RET tkl_ble_stack_init(UCHAR_T role);
SDK 初始化时,会调用该接口,应用可以在该接口中实现初始化蓝牙协议栈的功能。如果不需要初始化蓝牙相关业务,该接口为空实现即可。
tkl_ble_gap_callback_register
OPERATE_RET tkl_ble_gap_callback_register(CONST TKL_BLE_GAP_EVT_FUNC_CB gap_evt);
注册蓝牙低功耗 Generic Access Profile(GAP)层的事件回调接口,应用需要把 gap_evt
函数指针保存到全局变量。当应用收到蓝牙低功耗 GAP 数据时,通过函数指针把 GAP 数据传递给 SDK 处理。
蓝牙配网过程中,主要关注的 GAP 是 TKL_BLE_GAP_EVT_CONNECT
事件。当应用检测到手机与网关设备建立蓝牙连接时,应用通过函数指针把 GAP 数据传递给 SDK。
tkl_ble_gatt_callback_register
OPERATE_RET tkl_ble_gatt_callback_register(CONST TKL_BLE_GATT_EVT_FUNC_CB gatt_evt);
注册蓝牙低功耗 Generic Attribute Protocol(GATT)层的事件回调接口,应用需要把 gatt_evt
函数指针保存到全局变量。当应用收到蓝牙低功耗 GATT 数据时,通过函数指针把 GATT 数据传递给 SDK 处理。
蓝牙配网过程中,主要关注的 GATT 是 TKL_BLE_GATT_EVT_WRITE_REQ
事件。当应用收到手机发送到 Service UUID = 0x1910
的 Write Request 时,应用通过函数指针把 GATT 数据传递给 SDK。
tkl_ble_gap_adv_rsp_data_set
OPERATE_RET tkl_ble_gap_addr_set(TKL_BLE_GAP_ADDR_T CONST *p_peer_addr);
SDK 设置广播以及扫描响应数据的接口,应用需要在接口中实现把广播数据以及扫描响应数据缓存起来。广播时广播使用广播数据,回复扫描响应请求时使用扫描响应数据。
tkl_ble_gap_adv_start
OPERATE_RET tkl_ble_gap_adv_start(TKL_BLE_GAP_ADV_PARAMS_T CONST *p_adv_params);
SDK 通知应用开启蓝牙低功耗广播的接口,应用需要在接口中实现开启蓝牙低功耗广播的功能,广播和扫描响应数据由 tkl_ble_gap_adv_rsp_data_set
接口设置。
tkl_ble_gap_adv_stop
OPERATE_RET tkl_ble_gap_adv_stop(VOID);
SDK 通知应用停止蓝牙低功耗广播的接口,应用需要在接口中实现关闭广播功能。
tkl_ble_gatts_value_notify
OPERATE_RET tkl_ble_gatts_value_notify(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length);
SDK 需要发送蓝牙低功耗 GATT 数据给手机时,会调用该接口。应用需要在接口中实现把 GATT 数据通过蓝牙发送给手机。
蓝牙广播和扫描响应的数据格式:
蓝牙广播和扫描响应遵循蓝牙规范,SDK 把广播数据和扫描响应数据封装成 AD Structure 格式,应用无需解析处理,直接完成透传。
蓝牙传输的数据格式:
App 和网关建立蓝牙连接后,通过蓝牙 The Attribute Protocol(ATT)协议来传输数据,SDK 封装和解析的数据都属于 ATT Payload。
Service 和 Characteristic 定义如下:
Service UUID: 0x1910
。
Characteristic | UUID | 属性 | 说明 |
---|---|---|---|
Write Characteristic | 0x2B11 | Write Without Response | App 向蓝牙低功耗设备发送数据 |
Notify Characteristic | 0x2B10 | Notify | 蓝牙低功耗设备向 App 发送通知信息 |
本文档演示了 Linux 通用平台 TKL 接口的实现,以供参考。
#include <unistd.h>
#include "uni_log.h"
#include "base_os_adapter.h"
#include "tuya_iot_base_api.h"
#include "tuya_iot_com_api.h"
#include "tuya_iot_sdk_api.h"
#include "tuya_iot_sdk_defs.h"
#if defined(TY_BT_MOD) && (TY_BT_MOD == 1)
#include "tuya_os_adapt_bt.h"
#endif
#define PID "fljmamufiym5fktz" // 替换成自己的产品 ID
#define UUID "tuya461dbc63aeeb991f" // 替换成自己的 UUID
#define AUTHKEY "c8X4PR4wx1gMFaQlaZu5dfgVvVRwB8Ug" // 替换成自己的 AUTHKEY
STATIC VOID __gw_reset_cb(GW_RESET_TYPE_E type)
{
PR_DEBUG("gw reset callback, type: %d", type);
if (GW_RESET_DATA_FACTORY != type) {
exit(0);
}
return;
}
STATIC VOID __gw_upgrade_cb(CONST FW_UG_S *fw)
{
PR_DEBUG("gw upgrade callback");
if (fw == NULL) {
PR_ERR("invalid param");
return;
}
PR_DEBUG(" tp: %d", fw->tp);
PR_DEBUG(" fw_url: %s", fw->fw_url);
PR_DEBUG(" sw_ver: %s", fw->sw_ver);
PR_DEBUG(" fw_hmac: %s", fw->fw_hmac);
PR_DEBUG(" file_size: %u", fw->file_size);
return;
}
STATIC VOID __gw_active_stat_cb(GW_STATUS_E status)
{
PR_DEBUG("gw active stat callback, status: %d", status);
return;
}
STATIC VOID __gw_reboot_cb(VOID)
{
PR_DEBUG("gw reboot callback");
exit(0);
return;
}
STATIC VOID __nw_stat_cb(IN CONST SDK_NW_STAT_T stat)
{
PR_DEBUG("network stat: %d", stat);
return;
}
STATIC VOID __wired_stat_cb(IN CONST SDK_WIRED_NW_STAT_T stat)
{
PR_DEBUG("wired stat: %d", stat);
return;
}
int main(int argc, char **argv)
{
OPERATE_RET rt = OPRT_OK;
GW_PROD_INFO_S prod_info = {0};
/* gw base callback */
TY_GW_INFRA_CBS_S gw_cbs = {
.gw_reset_cb = __gw_reset_cb,
.gw_upgrade_cb = __gw_upgrade_cb,
.gw_active_stat_cb = __gw_active_stat_cb,
.gw_reboot_cb = __gw_reboot_cb,
};
#if defined(TY_BT_MOD) && (TY_BT_MOD == 1)
tuya_os_adapt_reg_bt_intf();
#endif
/* initiate os-layer service*/
tuya_os_intf_init();
/* initiate iot-layer service */
TUYA_CALL_ERR_RETURN(tuya_iot_init("./"));
/* set the logging level to debug */
SET_PR_DEBUG_LEVEL(TY_LOG_LEVEL_DEBUG);
PR_DEBUG("SDK INFO: %s", tuya_iot_get_sdk_info());
/* set uuid and authkey */
prod_info.uuid = UUID;
prod_info.auth_key = AUTHKEY;
TUYA_CALL_ERR_RETURN(tuya_iot_set_gw_prod_info(&prod_info));
/* pre-initiate sdk service */
TUYA_CALL_ERR_RETURN(tuya_iot_sdk_pre_init(TRUE));
/* initiate application service, more service in here */
TUYA_CALL_ERR_RETURN(tuya_user_svc_init(&gw_cbs));
/* initiate sdk service */
#if defined(GW_SUPPORT_WIRED_WIFI) && (GW_SUPPORT_WIRED_WIFI==1)
TUYA_CALL_ERR_RETURN(tuya_iot_wr_wf_sdk_init(IOT_GW_NET_WIRED_WIFI, GWCM_OLD, WF_START_AP_ONLY, PID, USER_SW_VER, NULL, 0));
#elif defined(WIFI_GW) && (WIFI_GW==1)
TUYA_CALL_ERR_RETURN(tuya_iot_wf_sdk_init(GWCM_OLD, WF_START_AP_ONLY, PID, USER_SW_VER, NULL, 0));
#else
TUYA_CALL_ERR_RETURN(tuya_iot_sdk_init(PID, USER_SW_VER, NULL, 0));
return OPRT_COM_ERROR;
#endif
/* register net stat notification callback */
TUYA_CALL_ERR_RETURN(tuya_iot_sdk_reg_netstat_cb(__nw_stat_cb, __wired_stat_cb, NULL));
/* start application service, more service in here */
TUYA_CALL_ERR_RETURN(tuya_user_svc_start(NULL));
while (1) {
sleep(10);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <net/if.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include "uni_log.h"
#include "tkl_wired.h"
#define WIRED_NAME "eth0"
TKL_WIRED_STATUS_CHANGE_CB g_link_status_change_cb;
STATIC VOID *link_status_thread(VOID *arg)
{
INT_T old_status = -1;
TKL_WIRED_STAT_E new_status;
while (1) {
tkl_wired_get_status(&new_status);
if (old_status != new_status) {
g_link_status_change_cb(new_status);
old_status = new_status;
}
sleep(1);
}
}
/**
* 获取网口 IP 地址接口
*/
OPERATE_RET tkl_wired_get_ip(OUT NW_IP_S *ip)
{
int sock = 0;
char ipaddr[50] = {0};
struct sockaddr_in *sin;
struct ifreq ifr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
PR_ERR("socket create failed");
return OPRT_COM_ERROR;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, WIRED_NAME, sizeof(ifr.ifr_name) - 1);
if (ioctl(sock, SIOCGIFADDR, &ifr) < 0 ) {
PR_ERR("ioctl failed");
close(sock);
return OPRT_COM_ERROR;
}
sin = (struct sockaddr_in *)&ifr.ifr_addr;
strcpy(ip->ip, inet_ntoa(sin->sin_addr));
close(sock);
return OPRT_OK;
}
/**
* 获取网线连接状态接口
*/
OPERATE_RET tkl_wired_get_status(TKL_WIRED_STAT_E *status)
{
int sock;
struct sockaddr_in *sin;
struct ifreq ifr;
NW_IP_S ip;
*status = TKL_WIRED_LINK_DOWN;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
PR_ERR("socket failed");
return OPRT_COM_ERROR;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, WIRED_NAME, sizeof(ifr.ifr_name) - 1);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
PR_ERR("ioctl failed");
close(sock);
return OPRT_COM_ERROR;
}
close(sock);
if ((ifr.ifr_flags & IFF_UP) == 0) {
return OPRT_OK;
}
if (tkl_wired_get_ip(&ip) != OPRT_OK) {
return OPRT_OK;
}
*status = TKL_WIRED_LINK_UP;
return OPRT_OK;
}
/* 设置有线状态回调 */
OPERATE_RET tkl_wired_set_status_cb(TKL_WIRED_STATUS_CHANGE_CB cb)
{
pthread_t tid;
g_link_status_change_cb = cb;
return pthread_create(&tid, NULL, link_status_thread, NULL);
}
OPERATE_RET tkl_wired_get_mac(NW_MAC_S *mac)
{
int i;
int sock = -1;
struct ifreq ifr;
struct sockaddr *addr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
PR_ERR("socket failed");
return OPRT_SOCK_ERR;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, WIRED_NAME, sizeof(ifr.ifr_name) - 1);
addr = (struct sockaddr *)&ifr.ifr_hwaddr;
addr->sa_family = 1;
/* get mac addr */
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
PR_ERR("ioctl failed");
close(sock);
return OPRT_COM_ERROR;
}
memcpy(mac->mac, addr->sa_data, MAC_ADDR_LEN);
close(sock);
return OPRT_OK;
}
/* 无需实现 */
OPERATE_RET tkl_wired_set_mac(CONST NW_MAC_S *mac)
{
return OPRT_OK;
}
#include "tuya_iot_config.h"
#if defined(WIFI_GW) && (WIFI_GW==1)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include "tuya_os_adapter.h"
#include "tkl_wifi.h"
#include "tkl_system.h"
#include "uni_log.h"
#define WLAN_DEV "wlan0"
#define UDHCPD_CONF "/etc/udhcpd.conf"
#define HOSTAPD_CONF "/etc/hostapd/hostapd.conf"
#define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant/wpa_supplicant.conf"
STATIC NW_IP_S g_ap_ip = {0};
STATIC WF_WK_MD_E g_wifi_mode = WWM_STATION;
STATIC WIFI_EVENT_CB __wifi_event_cb = NULL;
STATIC OPERATE_RET save_conf(CONST CHAR_T *filename, VOID *data, UINT32_T len)
{
OPERATE_RET wbyte = 0;
FILE *fp = NULL;
fp = fopen(filename, "w");
if (fp == NULL) {
PR_ERR("open %s failed", filename);
return OPRT_OPEN_FILE_FAILED;
}
wbyte = fwrite(data, 1, len, fp);
if (wbyte != len) {
PR_ERR("write error");
fclose(fp);
return OPRT_WRITE_FILE_FAILED;
}
fflush(fp);
fsync(fileno(fp));
fclose(fp);
return OPRT_OK;
}
STATIC OPERATE_RET exec_command(CONST CHAR_T *cmd, CHAR_T *data, INT_T len)
{
FILE *fp = NULL;
fp = popen(cmd, "r");
if (fp == NULL) {
return OPRT_COM_ERROR;
}
if (data != NULL) {
memset(data, 0, len);
fread(data, len, 1, fp);
len = strlen(data);
if (data[len - 1] == '\n') {
data[len - 1] = '\0';
}
}
pclose(fp);
return OPRT_OK;
}
STATIC BOOL_T __wifi_status(VOID)
{
FILE *fp = NULL;
CHAR_T buf[512] = {0};
WF_STATION_STAT_E stat = 0;
fp = popen("wpa_cli -i " WLAN_DEV " status", "r");
if (fp == NULL) {
return FALSE;
}
while (fgets(buf, SIZEOF(buf), fp)) {
if (!strstr(buf, "wpa_state"))
continue;
char *k = strtok(buf, "=");
char *v = strtok(NULL, "=");
if (v && !strncmp(v, "COMPLETED", strlen("COMPLETED"))) {
tkl_wifi_station_get_status(&stat);
if (stat == WSS_GOT_IP) {
return TRUE;
}
}
}
pclose(fp);
return FALSE;
}
STATIC VOID *__wifi_status_thread(VOID *arg)
{
BOOL_T cur_status = FALSE, lst_status = FALSE;
while (1) {
if (g_wifi_mode != WWM_STATION) {
tkl_system_sleep(500);
continue;
}
cur_status = __wifi_status();
if (cur_status != lst_status) {
PR_DEBUG("wifi connection status changed, %d -> %d", lst_status, cur_status);
if (__wifi_event_cb) {
__wifi_event_cb(cur_status ? WFE_CONNECTED : WFE_DISCONNECTED, NULL);
}
lst_status = cur_status;
}
tkl_system_sleep(1000);
}
}
OPERATE_RET tkl_wifi_init(WIFI_EVENT_CB cb)
{
pthread_t tid;
__wifi_event_cb = cb;
pthread_create(&tid, NULL, __wifi_status_thread, NULL);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_get_ip(CONST WF_IF_E wf, NW_IP_S *ip)
{
struct ifreq ifr;
int sock = 0;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
PR_ERR("create socket failed");
return OPRT_COM_ERROR;
}
strncpy(ifr.ifr_name, WLAN_DEV, strlen(WLAN_DEV) + 1);
if (ioctl(sock, SIOCGIFADDR, &ifr) == 0)
strncpy(ip->ip, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), sizeof(ip->ip));
if (ioctl(sock, SIOCGIFBRDADDR, &ifr) == 0)
strncpy(ip->gw, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr), sizeof(ip->gw));
if (ioctl(sock, SIOCGIFNETMASK, &ifr) == 0)
strncpy(ip->mask, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), sizeof(ip->mask));
close(sock);
PR_DEBUG("WiFi ip->ip: %s", ip->ip);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_station_get_status(WF_STATION_STAT_E *stat)
{
OPERATE_RET op_ret = OPRT_OK;
NW_IP_S ip = {0};
*stat = WSS_IDLE;
op_ret = tkl_wifi_get_ip(WF_STATION, &ip);
if (op_ret != OPRT_OK) {
return op_ret;
}
if ((strlen(ip.ip) > 0) && (strncmp(g_ap_ip.ip, ip.ip, strlen(ip.ip)) != 0)) {
*stat = WSS_GOT_IP;
}
return OPRT_OK;
}
OPERATE_RET tkl_wifi_get_mac(CONST WF_IF_E wf, NW_MAC_S *mac)
{
int i;
int fd = -1;
struct ifreq ifr;
struct sockaddr *addr;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
PR_ERR("socket failed");
return OPRT_SOCK_ERR;
}
memset(&ifr, 0, SIZEOF(ifr));
strncpy(ifr.ifr_name, WLAN_DEV, SIZEOF(ifr.ifr_name) - 1);
addr = (struct sockaddr *)&ifr.ifr_hwaddr;
addr->sa_family = 1;
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
PR_ERR("ioctl failed");
close(fd);
return OPRT_COM_ERROR;
}
memcpy(mac->mac, addr->sa_data, MAC_ADDR_LEN);
PR_DEBUG("WiFi mac->mac: %02X-%02X-%02X-%02X-%02X-%02X", mac->mac[0], mac->mac[1], mac->mac[2], \
mac->mac[3],mac->mac[4],mac->mac[5]);
close(fd);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_set_work_mode(CONST WF_WK_MD_E mode)
{
PR_DEBUG("WiFi set mode: %d", mode);
g_wifi_mode = mode;
switch (mode) {
case WWM_STATION:
exec_command("iwconfig " WLAN_DEV " mode managed", NULL, 0);
break;
case WWM_SOFTAP:
// exec_command("iwconfig " WLAN_DEV " mode master", NULL, 0);
break;
default:
break;
}
return OPRT_OK;
}
OPERATE_RET tkl_wifi_get_work_mode(WF_WK_MD_E *mode)
{
#if 0
CHAR_T buf[256] = {0};
CHAR_T *pstart = NULL;
CHAR_T mode_buf[16] = {0};
FILE *fp = NULL;
fp = popen("iwconfig " WLAN_DEV, "r");
if (fp == NULL) {
return OPRT_COM_ERROR;
}
while (fgets(buf, SIZEOF(buf), fp) != NULL) {
pstart = strstr(buf, "Mode:");
if (pstart != NULL) {
sscanf(pstart + strlen("Mode:"), "%s ", mode_buf);
break;
}
}
pclose(fp);
if (!strncasecmp(mode_buf, "Managed", strlen("Managed"))) {
*mode = WWM_STATION;
} else if (!strncasecmp(mode_buf, "Master", strlen("Master"))) {
*mode = WWM_SOFTAP;
}
#endif
*mode = g_wifi_mode;
PR_DEBUG("WiFi got mode: %d", *mode);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_start_ap(CONST WF_AP_CFG_IF_S *cfg)
{
OPERATE_RET op_ret = OPRT_OK;
INT_T len = 0;
CHAR_T buf[512] = {0};
CHAR_T cmd[128] = {0};
CHAR_T *ap_conf_fmt =
"interface=%s\n"
"ssid=%s\n"
"country_code=CN\n"
"channel=%d\n"
"beacon_int=100\n"
"max_num_sta=%d\n"
"auth_algs=3\n"
"wpa=%d\n"
"wpa_key_mgmt=WPA-PSK\n"
"wpa_pairwise=TKIP CCMP\n"
"rsn_pairwise=CCMP\n";
CHAR_T *udhcpd_conf_fmt =
"interface %s\n"
"start %s.100\n"
"end %s.200\n"
"opt subnet %s\n"
"opt lease 28800\n"
"opt router %s\n"
"opt dns %s\n"
"opt domain SmartLift\n";
INT_T seg1 = 0, seg2 = 0, seg3 = 0, seg4 = 0;
CHAR_T ip_prefix[12] = {0};
tkl_wifi_station_disconnect();
PR_DEBUG("start ap, ssid: %s, ip: %s", cfg->ssid, cfg->ip.ip);
memcpy(&g_ap_ip, &(cfg->ip), SIZEOF(NW_IP_S));
sscanf(cfg->ip.ip, "%d.%d.%d.%d", &seg1, &seg2, &seg3, &seg4);
snprintf(ip_prefix, SIZEOF(ip_prefix), "%d.%d.%d", seg1, seg2, seg3);
if (cfg->p_len > 0) {
len = snprintf(buf, SIZEOF(buf), ap_conf_fmt, WLAN_DEV, cfg->ssid, cfg->chan, cfg->max_conn, 2);
len += snprintf(buf + len, SIZEOF(buf) - len, "wpa_passphrase=%s\n", cfg->passwd);
} else {
len = snprintf(buf, SIZEOF(buf), ap_conf_fmt, WLAN_DEV, cfg->ssid, cfg->chan, cfg->max_conn, 0);
}
op_ret = save_conf(HOSTAPD_CONF, buf, len);
if (op_ret != OPRT_OK) {
PR_ERR("fail to write %s", HOSTAPD_CONF);
}
len = snprintf(buf, SIZEOF(buf), udhcpd_conf_fmt, WLAN_DEV, ip_prefix, ip_prefix, cfg->ip.mask, cfg->ip.gw, cfg->ip.gw);
op_ret = save_conf(UDHCPD_CONF, buf, len);
if (op_ret != OPRT_OK) {
PR_ERR("fail to write %s", UDHCPD_CONF);
}
snprintf(cmd, SIZEOF(cmd), "ifconfig %s %s netmask %s", WLAN_DEV, cfg->ip.ip, cfg->ip.mask);
exec_command(cmd, NULL, 0);
exec_command("ifconfig " WLAN_DEV " up", NULL, 0);
tkl_system_sleep(1000);
exec_command("hostapd -B -P /run/hostapd.pid " HOSTAPD_CONF, NULL, 0);
exec_command("killall udhcpd", NULL, 0);
exec_command("udhcpd " UDHCPD_CONF, NULL, 0);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_stop_ap(VOID_T)
{
exec_command("killall udhcpd", NULL, 0);
exec_command("killall hostapd", NULL, 0);
exec_command("ifconfig " WLAN_DEV " down", NULL, 0);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_station_connect(CONST SCHAR_T *ssid, CONST SCHAR_T *passwd)
{
OPERATE_RET op_ret = OPRT_OK;
INT_T len = 0;
CHAR_T buf[512] = {0};
CHAR_T *wpa_conf_fmt =
"ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\n"
"update_config=1\n"
"country=CN\n"
"\n"
"network={\n"
"\tssid=\"%s\"\n"
"\tpairwise=CCMP TKIP\n"
"\tkey_mgmt=WPA-PSK\n"
"\tgroup=CCMP TKIP\n"
"\tpsk=\"%s\"\n"
"}\n";
if (!ssid || !passwd) {
PR_WARN("ssid or passwd is null");
return OPRT_INVALID_PARM;
}
tkl_wifi_stop_ap();
PR_DEBUG("ssid: %s, passwd: %s", ssid, passwd);
len = snprintf(buf, SIZEOF(buf), wpa_conf_fmt, ssid, passwd);
op_ret = save_conf(WPA_SUPPLICANT_CONF, buf, len);
if (op_ret != OPRT_OK) {
PR_ERR("fail to write %s", UDHCPD_CONF);
}
exec_command("wpa_supplicant -B -Dnl80211 -i" WLAN_DEV " -c" WPA_SUPPLICANT_CONF, NULL, 0);
exec_command("udhcpc -i " WLAN_DEV " -s /etc/udhcpc/default.script -p /run/udhcpc_wlan0.pid -b", NULL, 0);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_station_disconnect(VOID_T)
{
exec_command("wpa_cli -i " WLAN_DEV " terminate", NULL, 0);
exec_command("[ -f /run/udhcpc_wlan0.pid ] && (cat /run/udhcpc_wlan0.pid | xargs sudo kill)", NULL, 0);
exec_command("ifconfig " WLAN_DEV " down", NULL, 0);
return OPRT_OK;
}
OPERATE_RET tkl_wifi_set_mac(CONST WF_IF_E wf, CONST NW_MAC_S *mac)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_scan_ap(CONST SCHAR_T *ssid, AP_IF_S **aps, UINT_T *num)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_release_ap(AP_IF_S *ap)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_set_cur_channel(CONST UCHAR_T chan)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_get_cur_channel(UCHAR_T *chan)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_set_sniffer(CONST BOOL_T en, CONST SNIFFER_CALLBACK cb)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_station_get_conn_ap_rssi(SCHAR_T *rssi)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_get_bssid(UCHAR_T *mac)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_set_country_code(CONST COUNTRY_CODE_E ccode)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_send_mgnt(CONST UCHAR_T *buf, CONST UINT_T len)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_register_recv_mgnt_callback(CONST BOOL_T enable, CONST WIFI_REV_MGNT_CB recv_cb)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_set_lp_mode(CONST BOOL_T enable, CONST UCHAR_T dtim)
{
return OPRT_OK;
}
OPERATE_RET tkl_wifi_get_connected_ap_info(FAST_WF_CONNECTED_AP_INFO_T **fast_ap_info)
{
return OPRT_COM_ERROR;
}
OPERATE_RET tkl_wifi_station_fast_connect(CONST FAST_WF_CONNECTED_AP_INFO_T *fast_ap_info)
{
return OPRT_COM_ERROR;
}
OPERATE_RET tkl_wifi_set_rf_calibrated(VOID_T)
{
return OPRT_OK;
}
OPERATE_RET tkl_hostap_ioctl_inet(INT_T dev, INT_T vif_index, UINT_T cmd, ULONG_T arg)
{
return OPRT_OK;
}
#endif
#include "tkl_bluetooth.h"
OPERATE_RET tkl_ble_stack_init(UCHAR_T role)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_stack_deinit(UCHAR_T role)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_callback_register(CONST TKL_BLE_GAP_EVT_FUNC_CB gap_evt)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gatt_callback_register(CONST TKL_BLE_GATT_EVT_FUNC_CB gatt_evt)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_adv_start(TKL_BLE_GAP_ADV_PARAMS_T CONST *p_adv_params)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_adv_stop(VOID)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_adv_rsp_data_set(TKL_BLE_DATA_T CONST *p_adv, TKL_BLE_DATA_T CONST *p_scan_rsp)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_adv_rsp_data_update(TKL_BLE_DATA_T CONST *p_adv, TKL_BLE_DATA_T CONST *p_scan_rsp)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gatts_value_notify(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_stack_gatt_link(USHORT_T *p_link)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_addr_set(TKL_BLE_GAP_ADDR_T CONST *p_peer_addr)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_address_get(TKL_BLE_GAP_ADDR_T *p_peer_addr)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_scan_start(TKL_BLE_GAP_SCAN_PARAMS_T CONST *p_scan_params)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_scan_stop(VOID)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_connect(TKL_BLE_GAP_ADDR_T CONST *p_peer_addr, TKL_BLE_GAP_SCAN_PARAMS_T CONST *p_scan_params, TKL_BLE_GAP_CONN_PARAMS_T CONST *p_conn_params)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_disconnect(USHORT_T conn_handle, UCHAR_T hci_reason)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_conn_param_update(USHORT_T conn_handle, TKL_BLE_GAP_CONN_PARAMS_T CONST *p_conn_params)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_tx_power_set(UCHAR_T role, INT_T tx_power)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gap_rssi_get(USHORT_T conn_handle)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gatts_service_add(TKL_BLE_GATTS_PARAMS_T *p_service)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gatts_value_set(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gatts_value_get(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gatts_value_indicate(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gatts_exchange_mtu_reply(USHORT_T conn_handle, USHORT_T server_rx_mtu)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gattc_all_service_discovery(USHORT_T conn_handle)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gattc_all_char_discovery(USHORT_T conn_handle, USHORT_T start_handle, USHORT_T end_handle)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gattc_char_desc_discovery(USHORT_T conn_handle, USHORT_T start_handle, USHORT_T end_handle)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gattc_write_without_rsp(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gattc_write(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gattc_read(USHORT_T conn_handle, USHORT_T char_handle)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_gattc_exchange_mtu_request(USHORT_T conn_handle, USHORT_T client_rx_mtu)
{
return OPRT_OK;
}
OPERATE_RET tkl_ble_vendor_command_control(USHORT_T opcode, VOID_T *user_data, USHORT_T data_len)
{
return OPRT_NOT_SUPPORTED;
}
TKL 接口不允许阻塞,耗时的任务建议做异步处理。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈