跟着鸿蒙生态的发展,鸿蒙开发已成为年代新风口,学习鸿蒙开发势在必行。鸿蒙开发可参阅学习文档:https://qr21.cn/FV7h05
一、简介
本 demo 依据 OpenHarmony3.1Beta 版别开发,该样例能够接入数字管家运用,经过数字管家运用监测体重秤上报数据,获得当时测量到的体重,身高,并在运用端形成一段时间内记录的体重值,以折线图的方法表现出来,依据计算的 BMI 值来提醒当时身体健康状况,推送健康小常识。
1. 交互流程
如上图所示,智能体重称整体方案原理图能够大致分红:智能体重称设备、数字管家运用、云渠道三部分。智能体重称经过 MQTT 协议衔接华为 IOT 物联网渠道,从而完成指令的接收和属性上报。 关于智能设备接入华为云 IoT 渠道的具体细节能够参阅 衔接 IOT 云渠道指南;智能设备同数字管家运用之间的设备模型界说能够参阅 profile .
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
二、 快速上手
1. 硬件预备
- 全志 xr806 模组
- hcsr04 超声波模块
- hx711 称重模块带支架托盘
- 预装 HarmonyOS 手机一台
2、环境预备
参照文档:XR806 快速上手辅导文档
3、编译前预备
设备侧代码下载
具体仓库地址:https://gitee.com/openharmony-sig/knowledge_demo_smart_home/
下载方法:运用 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 = [ "//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",
"//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", "//third_party/mbedtls/include/", "//third_party/mbedtls/include/", "//third_party/cJSON", "//kernel/liteos_m/components/cmsis/2.0", "//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 中的部分文件
1.third_party/iot_link/network/mqtt/paho_mqtt/port/paho_mqtt_port.c
测验发现,当 fd 为 0 的时候,在履行 recv 时会立马返回 – 1,因而做下面躲避操作。
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;
...
}
体系 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
}
2.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
体系部分 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;
}
3. 在文件 iot_link/network/mqtt/paho_mqtt/port/paho_osdepends.c 中增加对应 timersub 和 timeradd 的完成 (体系中未完成该函数):
// 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
4. 编译中会有部分头文件提示找不到,这个时候直接将其注释即可
(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
5. 由于弱引证导致无法链接相关符号,因而需求注释以下几个文件中的弱引证。
文件一 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 = [ "." ]
}
为了节约 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 根目录履行
pip3 uninstall ohos_build
pip3 install build/li
编译指令: hb set // 假如是第一次编译,Input code path 指令行中键入”./” 指定OpenHarmony工程编译根目录后 回车,
如下图所示,运用键盘上下键选中 wifi_skylark
hb build // 假如需求全量编译,能够增加-f 选项
生成的固件保存在 out/xradio/smart_weight_scale 目录下
5、固件烧录
参照文档:XR806 快速上手辅导文档
6、设备配网
在设备上电前需预备好安装了数字管家运用的 HarmonyOS 手机,详情见数字管家运用开发 , 并在设置中开启手机的 NFC 功能;
写设备 NFC 标签,具体操作见设备 NFC 标签辅导文档 ;
烧录完成后,上电。开发者在调查开发板上状况 LED 灯以8Hz 的频率闪烁时,将手机上半部接近开发板 NFC 标签处 (无 NFC 标签的可用 NFC 贴纸代替);
碰一碰后手机将自动拉起数字管家运用并进入配网状况;
配网过程中需求 衔接设备的 AP 热门,然后填写需求装备的 wifi 的暗码;
最终点击装备,手机会将 ssid 以及对应的暗码经过 AP 热门发送到设备。
跟着鸿蒙生态的发展,鸿蒙开发已成为年代新风口,学习鸿蒙开发势在必行。鸿蒙开发可参阅学习文档:https://qr21.cn/FV7h05