一、簡介
本demo基于OpenHarmony3.1Beta版本開發(fā),該樣例能夠接入數字管家應用,通過數字管家應用監(jiān)測體重秤上報數據,獲得當前測量到的體重,身高,并在應用端形成一段時間內記錄的體重值,以折線圖的形式表現出來,根據計算的BMI值來提醒當前身體健康狀態(tài),推送健康小知識。
1.交互流程
如上圖所示,智能體重稱整體方案原理圖可以大致分成:智能體重稱設備、數字管家應用、云平臺三部分。智能體重稱通過MQTT協(xié)議連接華為IOT物聯(lián)網平臺,從而實現命令的接收和屬性上報。
2.實物簡介
如上圖示,左邊為xr806模組,右邊為超聲波測距模塊,echo腳連接PA19,Triq腳連接PA20,Vcc腳連接5V電源,Gnd腳接地,
如上圖示,右邊為稱重模塊,clk腳接PB15,dt腳接PB14,vcc腳接5V,gnd腳接地,稱重傳感器紅色線接E+,黑色線接E-,白色線接A-,綠色線接A+
左邊xr806模塊左下角k1按鍵,長按k1按鍵不放,同時上電,4-5秒后松開按鍵,可以清除已保存得配網信息
xr806模塊,在設備正常工作后,按k1按鍵,可以初始化當前得重量為0,高度為0
3.實物操作體驗
####二、 快速上手
1.硬件準備
2、環(huán)境準備
參照文檔: [XR806快速上手指導文檔]
3、編譯前準備
鴻蒙開發(fā)文檔參考:[qr23.cn/AKFP8k
]
設備側代碼下載
下載方式:使用git 命令下載,指令如下(用戶也可以根據需要將該倉庫fork到自己的目錄下后進行下載)
cd ~
git clone git@gitee.com:openharmony-sig/knowledge_demo_smart_home.git
代碼拷貝
cp -rfa ~/knowledge_demo_smart_home/dev/team_x ~/openharmony/vendor/
cp -rfa ~/knowledge_demo_smart_home/dev/third_party/iot_link ~/openharmony/third_party/
SOC代碼下載替換
當前官方soc代碼由于DHCP暫未適配,所以暫時不支持AP模式,這時需要下載并替換之前SOC代碼。如果官方soc代碼已修復該問題,可忽略此步驟。
git clone https://gitee.com/moldy-potato-chips/xr806_-ap_mode.git
mv ~/openharmony/device/soc/allwinner ~/allwinner.org // 不建議直接刪除,
cp -raf xr806_-ap_mode ~/openharmony/device/soc/allwinner
整合并修改完成后的目錄結構如下圖
修改文件
- 修改編譯依賴
打開 device/soc/allwinner/xradio/xr806/BUILD.gn,添加應用依賴(deps字段):
module_group(module_name) {
modules = [
"src",
"project",
"include",
]
configs = [
":SdkLdCconfig",
]
deps = [ "http://vendor/team_x/smart_weight_scale/demo_smart_weight_scale:smart_weight_scale" ]
}
- 修改編譯方式
將demo依賴的庫編譯方式(static_library)修改為(source_set):
具體依賴查看demo_smart_weight_scale目錄下的BUILD.gn:
deps = [
"../../common/iot_wifi_xradio:iot_wifi",
"../../common/iot_cloud:iot_cloud",
"http://third_party/cJSON:cjson",
"../../common/iot_boardbutton_xradio:iot_boardbutton",
"../../common/iot_boardled_xradio:iot_boardled_xradio",
]
其中//third_party/cJSON目錄下的BUILD.gn建議參照下面的修改:
source_set("cJSON") {
sources = [
"cJSON.c",
"cJSON_Utils.c",
]
ldflags = [ "-lm" ]
}
third_party/iot_link目錄下的各級使用到的BUILD.gn也需要將編譯方式修改為source_set,或者將所有需要編譯的文件放在iot_link目錄的BUILD.gn中,如下:
source_set("iot_link") {
sources = [
"link_log/link_log.c",
"link_misc/link_random.c",
"link_misc/link_ring_buffer.c",
"link_misc/link_string.c",
"network/dtls/dtls_al/dtls_al.c",
"network/dtls/mbedtls/mbedtls_port/dtls_interface.c",
"network/dtls/mbedtls/mbedtls_port/mbed_port.c",
"network/dtls/mbedtls/mbedtls_port/timing_alt.c",
"network/mqtt/mqtt_al/mqtt_al.c",
"network/mqtt/paho_mqtt/port/paho_mqtt_port.c",
"network/mqtt/paho_mqtt/port/paho_osdepends.c",
"network/mqtt/paho_mqtt/paho/MQTTClient-C/src/MQTTClient.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTConnectClient.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTConnectServer.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTDeserializePublish.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTFormat.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTPacket.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSerializePublish.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSubscribeClient.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSubscribeServer.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTUnsubscribeClient.c",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTUnsubscribeServer.c",
"oc_mqtt/oc_mqtt_al/oc_mqtt_al.c",
"oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_profile.c",
"oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_profile_package.c",
"oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_event.c",
"oc_mqtt/oc_mqtt_tiny_v5/oc_mqtt_tiny.c",
"oc_mqtt/oc_mqtt_tiny_v5/hmac.c",
"queue/queue.c",
]
cflags = [ "-Wno-unused-variable" ]
cflags += [ "-Wno-unused-but-set-variable" ]
cflags += [ "-Wno-sign-compare" ]
cflags += [ "-Wno-unused-parameter" ]
cflags += [ "-Wno-unused-function" ]
ldflags = [ "-Wl,-rpath-link=//device/xradio/xr806/xr_skylark/lib" ]
ldflags += [ "-lmbedtls" ]
include_dirs = [
"inc",
"link_log",
"link_misc",
"queue",
"oc_mqtt/oc_mqtt_tiny_v5",
"oc_mqtt/oc_mqtt_profile_v5",
"oc_mqtt/oc_mqtt_al",
"network/dtls/mbedtls/mbedtls_port",
"network/mqtt/paho_mqtt/port",
"network/mqtt/paho_mqtt/paho/MQTTClient-C/src",
"network/mqtt/paho_mqtt/paho/MQTTPacket/src",
"http://third_party/mbedtls/include/",
"http://third_party/mbedtls/include/",
"http://third_party/cJSON",
"http://kernel/liteos_m/components/cmsis/2.0",
"http://device/xradio/xr806/xr_skylark/include/net/mbedtls-2.2.0/",
]
defines = [
"MQTTCLIENT_PLATFORM_HEADER=paho_osdepends.h",
"WITH_DTLS",
"MBEDTLS_AES_ROM_TABLES",
"MBEDTLS_CONFIG_FILE="los_mbedtls_config_dtls.h"",
"CONFIG_DTLS_MBEDTLS_CERT",
"CONFIG_DTLS_MBEDTLS_PSK",
"CFG_MBEDTLS_MODE=PSK_CERT",
"CONFIG_OC_MQTT_TINY_ENABLE=1"
]
}
- 修改iot_link中的部分文件
third_party/iot_link/network/mqtt/paho_mqtt/port/paho_mqtt_port.c
測試發(fā)現,當fd為0的時候,在執(zhí)行recv時會立馬返回-1,因此做下面規(guī)避操作。static int __socket_connect(Network *n, const char *host, int port) { ... int tmpfd = socket(AF_INET,SOCK_STREAM,0); // to skip fd = 0; fd = socket(AF_INET,SOCK_STREAM,0); if(fd == -1) { return ret; } close(tmpfd); // to skip fd = 0; ... }
系統(tǒng)setsockopt函數未適配,因此需要做下面的修改:
static int __socket_read(void *ctx, unsigned char *buf, int len, int timeout) { int fd; int ret = 0; #if 0 struct timeval timedelay = {timeout / 1000, (timeout % 1000) * 1000}; if(NULL== uf) { return ret; } fd = (int)(intptr_t)ctx; ///< socket could be zero if (timedelay.tv_sec < 0 || (timedelay.tv_sec == 0 && timedelay.tv_usec <= 0)) { timedelay.tv_sec = 0; timedelay.tv_usec = 100; } if(0 != setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&timedelay,sizeof(struct timeval))) { return ret; //could not support the rcv timeout } int bytes = 0; while (bytes < len) { int rc = recv(fd, &buf[bytes], (size_t)(len - bytes), 0); printf("[%s|%s|%d]fd = %d, rc = %dn", __FILE__,__func__,__LINE__, fd, rc); if (rc == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { bytes = -1; } break; } else if (rc == 0) { bytes = 0; break; } else { bytes += rc; } } return bytes; #else int bytes = 0; fd_set fdset; struct timeval timedelay = {timeout / 1000, (timeout % 1000) * 1000}; if(NULL== buf) { return ret; } fd = (int)(intptr_t)ctx; ///< socket could be zero if (timedelay.tv_sec < 0 || (timedelay.tv_sec == 0 && timedelay.tv_usec <= 0)) { timedelay.tv_sec = 0; timedelay.tv_usec = 100; } timedelay.tv_sec = 2; FD_ZERO(&fdset); FD_SET(fd, &fdset); ret = select(fd + 1, &fdset, NULL, NULL, &timedelay); if (ret > 0) { while (bytes < len) { int rc = recv(fd, &buf[bytes], (size_t)(len - bytes), 0); // printf("[%s|%s|%d]fd = %d, rc = %d, errno=%d(%s)n", __FILE__,__func__,__LINE__, fd, rc,errno, strerror(errno)); if (rc == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { bytes = -1; } break; } else if (rc == 0) { bytes = 0; break; } else { bytes += rc; } } } return bytes; #endif }
third_party/iot_link/network/dtls/mbedtls/mbedtls_port/dtls_interface.c
在文件頂部添加打印函數定義以及添加mbedtls_calloc以及mbedtls_free的定義,否則編譯會提示錯誤:#define MBEDTLS_LOG LINK_LOG_DEBUG #ifndef mbedtls_calloc #define mbedtls_calloc calloc #endif #ifndef mbedtls_free #define mbedtls_free free #endif
系統(tǒng)部分mbedtls接口不一致,固需要注釋部分接口代碼:
mbedtls_ssl_context dtls_ssl_new(dtls_establish_info_s *info, char plat_type) { ... if (info- >psk_or_cert == VERIFY_WITH_PSK) { /* if ((ret = mbedtls_ssl_conf_psk(conf, info- >v.p.psk, info- >v.p.psk_len, info- >v.p.psk_identity, strlen((const char *)info- >v.p.psk_identity))) != 0) { MBEDTLS_LOG("mbedtls_ssl_conf_psk failed: -0x%x", -ret); goto exit_fail; } */ } ... } int dtls_shakehand(mbedtls_ssl_context *ssl, const dtls_shakehand_info_s *info) { ... if (MBEDTLS_SSL_IS_CLIENT == info- >client_or_server) { ret = mbedtls_net_connect(server_fd, info- >u.c.host, info- >u.c.port, info- >udp_or_tcp); if( 0 != ret) { ret = MBEDTLS_ERR_NET_CONNECT_FAILED; goto exit_fail; } } else { //server_fd = (mbedtls_net_context*)atiny_net_bind(NULL, info- >u.s.local_port, MBEDTLS_NET_PROTO_UDP); ///< --TODO ,not implement yet } ... } void dtls_init(void) { (void)mbedtls_platform_set_calloc_free(calloc, free); (void)mbedtls_platform_set_snprintf(snprintf); // (void)mbedtls_platform_set_printf(printf); }
在iot_link/network/dtls/mbedtls/mbedtls_port/mbed_port.c文件中的dtls_imp_init()函數中,也需要注釋掉未實現的接口,否則編譯報錯:
int dtls_imp_init(void) { int ret =-1; // (void)mbedtls_platform_set_calloc_free(calloc, free); // (void)mbedtls_platform_set_snprintf(snprintf); // (void)mbedtls_platform_set_printf(printf); ret = dtls_al_install(&s_mbedtls_io); return ret; }
在文件iot_link/network/mqtt/paho_mqtt/port/paho_osdepends.c中添加對應timersub和timeradd的實現(系統(tǒng)中未實現該函數):
// add this for "timersub" && "timeradd" #ifndef timersub #define timersub(s,t,a) (void) ( (a)- >tv_sec = (s)- >tv_sec - (t)- >tv_sec, ((a)- >tv_usec = (s)- >tv_usec - (t)- >tv_usec) < 0 && ((a)- >tv_usec += 1000000, (a)- >tv_sec--) ) #endif #ifndef timeradd #define timeradd(s,t,a) (void) ( (a)- >tv_sec = (s)- >tv_sec + (t)- >tv_sec, ((a)- >tv_usec = (s)- >tv_usec + (t)- >tv_usec) >= 1000000 && ((a)- >tv_usec -= 1000000, (a)- >tv_sec++) ) #endif
編譯中會有部分頭文件提示找不到,這個時候直接將其注釋即可(iot_link/network/mqtt/paho_mqtt/port/paho_osdepends.h):
#define INVALID_SOCKET SOCKET_ERROR // #include < sys/socket.h > #include < sys/param.h > #include < sys/time.h > // #include < netinet/in.h > // #include < netinet/tcp.h > // #include < arpa/inet.h > // #include < netdb.h > #include < stdio.h > #include < unistd.h > #include < errno.h > #include < fcntl.h > #include < string.h > #include < stdlib.h > #endif #if defined(WIN32) #include < Iphlpapi.h > #else // #include < sys/ioctl.h > // #include < net/if.h > #endif
因為弱引用導致無法鏈接相關符號,因此需要注釋以下幾個文件中的弱引用。
文件一 third_party/iot_link/network/dtls/dtls_al/dtls_al.c #if 0 __attribute__((weak)) int dtls_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement dtls by yourself####",__FUNCTION__); return -1; } #endif extern int dtls_imp_init(void); 文件二 third_party/iot_link/network/mqtt/mqtt_al/mqtt_al.c #if 0 __attribute__((weak)) int mqtt_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement mqtt by yourself####",__FUNCTION__); return -1; } #endif extern int mqtt_imp_init(void); 文件三 third_party/iot_link/oc_mqtt/oc_mqtt_al/oc_mqtt_al.c #if 0 __attribute__ ((weak)) int oc_mqtt_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement oc mqtt by yourself####",__FUNCTION__); return 0; } __attribute__ ((weak)) int oc_mqtt_demo_main(void) { LINK_LOG_WARN("Please implement the oc mqtt v5 demo yourself"); return -1; } #endif extern int oc_mqtt_demo_main(void);
- 修改GPIO查找方式
因為GPIO框架修改了設備驅動注冊的管腳號,導致應用無法根據HCS的引腳操作對應的GPIO,此問題已經提issue,如果該問題已解決,可以忽略此步驟。
打開drivers/framework/support/platform/src/gpio/gpio_manager.c,將cntlr->start = start;注釋即可。
static int32_t GpioManagerAdd(struct PlatformManager *manager, struct PlatformDevice *device)
{
uint16_t start;
struct GpioCntlr *cntlr = CONTAINER_OF(device, struct GpioCntlr, device);
if ((start = GpioCntlrQueryStart(cntlr, &manager- >devices)) >= GPIO_NUM_MAX) {
PLAT_LOGE("GpioCntlrAdd: query range for start:%d fail:%d", cntlr- >start, start);
return HDF_ERR_INVALID_PARAM;
}
// cntlr- >start = start;
DListInsertTail(&device- >node, &manager- >devices);
PLAT_LOGI("%s: start:%u count:%u", __func__, cntlr- >start, cntlr- >count);
return HDF_SUCCESS;
}
將對應的驅動文件復制到drvier對應目錄:
因為主倉代碼中未將對應的驅動文件合并到driver/adpater/platform對應的目錄下,固需要手動將文件拷貝到對應目錄。若主倉已合入,可忽略此步驟。// 拷貝gpio驅動 cp -af device/soc/allwinner/xradio/drivers/gpio/gpio_xradio.* driver/adpater/platform/gpio // 修改driver/adpater/platform/gpio/BUILD.gn文件,加上gpio_xradio的編譯 hdf_driver(module_name) { sources = [] if (defined(LOSCFG_SOC_COMPANY_BESTECHNIC)) { sources += [ "gpio_bes.c" ] } if (defined(LOSCFG_SOC_COMPANY_ALLWINNER)) { sources += [ "gpio_xradio.c" ] } include_dirs = [ "." ] }
為了節(jié)省ram資源,可以把無用的資源先關閉,如關閉內部codec,將 device/soc/allwinner/xradio/xr806/project/prj_config.h中的PRJCONF_INTERNAL_SOUNDCARD_EN設置為0,如下:
/* Xradio internal codec sound card enable/disable */ #define PRJCONF_INTERNAL_SOUNDCARD_EN 0
4、代碼編譯
#首先可以查看一下hb的版本,如果hb版本為0.4.4版本就不需要更新。
查看hb版本
hb --version
更新hb, 以下指令需要在openharmony SDK根目錄執(zhí)行
pip3 uninstall ohos_build
pip3 install build/lite
編譯命令:
hb set // 如果是第一次編譯,Input code path 命令行中鍵入"./" 指定OpenHarmony工程編譯根目錄后 回車,
如下圖所示,使用鍵盤上下鍵選中wifi_skylark
hb build // 如果需要全量編譯,可以添加-f 選項
生成的固件保存在out/xradio/smart_weight_scale目錄下
5、固件燒錄
參照文檔:[XR806快速上手指導文檔]
6、設備配網
- 在設備上電前需準備好安裝了數字管家應用的HarmonyOS手機, 并在設置中開啟手機的NFC功能;
- 寫設備NFC標簽;
- 燒錄完成后,上電。開發(fā)者在觀察開發(fā)板上狀態(tài)LED燈以8Hz的頻率閃爍時,將手機上半部靠近開發(fā)板NFC標簽處(無NFC標簽的可用NFC貼紙?zhí)娲?;
- 碰一碰后手機將自動拉起數字管家應用并進入配網狀態(tài);
- 配網過程中需要 連接設備的AP熱點,然后填寫需要配置的wifi的密碼;
- 最后點擊配置,手機會將ssid以及對應的密碼通過AP熱點發(fā)送到設備。
審核編輯 黃宇
-
鴻蒙
+關注
關注
57文章
2339瀏覽量
42805 -
HarmonyOS
+關注
關注
79文章
1973瀏覽量
30143 -
OpenHarmony
+關注
關注
25文章
3713瀏覽量
16254
發(fā)布評論請先 登錄
相關推薦
評論