From bec7c508da32ca77f052c9f04e5b3828ed4d459a Mon Sep 17 00:00:00 2001 From: HuangXin Date: Fri, 7 Sep 2018 11:20:36 +0800 Subject: [PATCH] Move projects --- app/LogCtrlTools/Makefile | 47 + app/LogCtrlTools/src/Makefile | 24 + app/LogCtrlTools/src/log_ctrl.c | 323 +++ app/alarm/Makefile | 52 + app/alarm/src/Makefile | 25 + app/alarm/src/assistant.c | 863 ++++++ app/libuvdbus/Config.in | 17 + app/libuvdbus/Makefile | 68 + app/libuvdbus/src/Framework/Compress/zlib.c | 110 + .../src/Framework/Configure/config_engine.c | 1042 +++++++ .../src/Framework/Configure/ini_prase.c | 289 ++ app/libuvdbus/src/Framework/Crypto/aes.c | 104 + app/libuvdbus/src/Framework/Crypto/base64.c | 158 ++ app/libuvdbus/src/Framework/Crypto/crypto.c | 187 ++ app/libuvdbus/src/Framework/Crypto/md5.c | 156 ++ app/libuvdbus/src/Framework/Fifo/fifo.c | 554 ++++ .../src/Framework/HeartDaemon/heart_daemon.c | 197 ++ .../Framework/IoT/Boardlink/boardlink_iot.c | 181 ++ .../src/Framework/JsonUtils/json_struct.c | 1218 +++++++++ app/libuvdbus/src/Framework/Monitor/monitor.c | 347 +++ .../src/Framework/Network/inet_api.c | 1396 ++++++++++ .../src/Framework/Skins/skin_res_vtbl.c | 320 +++ app/libuvdbus/src/Framework/Skins/skins.c | 1442 ++++++++++ .../src/Framework/SvrManager/svr_manager.c | 235 ++ app/libuvdbus/src/Framework/Timer/timer.c | 773 ++++++ .../src/Framework/WireshartScript/log_pv1.lua | 93 + .../src/Framework/libuvEngine/libuv_dbus.c | 2405 +++++++++++++++++ app/libuvdbus/src/Makefile | 50 + app/libuvdbus/src/include/assistant.h | 168 ++ app/libuvdbus/src/include/boardlink_iot.h | 44 + app/libuvdbus/src/include/config_engine.h | 58 + app/libuvdbus/src/include/crypto.h | 81 + app/libuvdbus/src/include/fifo.h | 724 +++++ app/libuvdbus/src/include/inet_api.h | 51 + app/libuvdbus/src/include/json_struct.h | 150 + app/libuvdbus/src/include/libuv_dbus.h | 232 ++ app/libuvdbus/src/include/log.h | 233 ++ app/libuvdbus/src/include/log_info.h | 13 + app/libuvdbus/src/include/monitor.h | 21 + app/libuvdbus/src/include/ota.h | 156 ++ app/libuvdbus/src/include/server_addr.h | 49 + app/libuvdbus/src/include/skins.h | 58 + app/libuvdbus/src/include/skins_res.h | 319 +++ app/libuvdbus/src/include/smart_sound.h | 528 ++++ app/libuvdbus/src/log/hexdump.c | 326 +++ app/libuvdbus/src/log/log.c | 1332 +++++++++ app/ota_r311/Makefile | 52 + app/ota_r311/src/Makefile | 24 + app/ota_r311/src/ota_r311.c | 1067 ++++++++ res/system_resources/Makefile | 34 + .../resource/image/IconChaozuo001.jpg | Bin 0 -> 1280 bytes .../resource/image/IconChaozuo005.jpg | Bin 0 -> 10999 bytes .../resource/image/IconLianjie001.jpg | Bin 0 -> 11003 bytes .../resource/image/IconLianjie002.jpg | Bin 0 -> 9258 bytes .../resource/image/IconLianjie003.jpg | Bin 0 -> 9224 bytes .../resource/image/IconNaozhong001.jpg | Bin 0 -> 10988 bytes .../resource/image/IconTixing001.jpg | Bin 0 -> 10993 bytes .../resource/image/IconZhuangtai003.gif | Bin 0 -> 4818 bytes .../resource/image/Iconlianwang001.gif | Bin 0 -> 1366 bytes .../resource/image/Iconlianwang005.gif | Bin 0 -> 1350 bytes .../resource/image/Iconstart002.gif | Bin 0 -> 2552 bytes .../resource/image/Iconyinliang000.jpg | Bin 0 -> 1227 bytes .../resource/image/Iconyinliang001.jpg | Bin 0 -> 1247 bytes .../resource/image/Iconyinliang002.jpg | Bin 0 -> 1247 bytes .../resource/image/Iconyinliang003.jpg | Bin 0 -> 1247 bytes .../resource/image/Iconyinliang004.jpg | Bin 0 -> 1311 bytes .../resource/image/Iconyinliang005.jpg | Bin 0 -> 1311 bytes .../resource/image/Iconyinliang006.jpg | Bin 0 -> 1311 bytes .../resource/image/Iconyinliang007.jpg | Bin 0 -> 1316 bytes .../resource/image/Iconyinliang008.jpg | Bin 0 -> 1316 bytes .../resource/image/Iconyinliang009.jpg | Bin 0 -> 1316 bytes .../resource/image/Iconyinliang010.jpg | Bin 0 -> 1316 bytes .../resource/image/Iconyinliang011.jpg | Bin 0 -> 1304 bytes .../resource/image/Iconyinliang012.jpg | Bin 0 -> 1304 bytes .../resource/image/Iconyinliang013.jpg | Bin 0 -> 1316 bytes .../resource/image/Iconyinliang014.jpg | Bin 0 -> 1316 bytes .../resource/image/Iconyinliang015.jpg | Bin 0 -> 1319 bytes .../resource/image/Iconyinliang016.jpg | Bin 0 -> 1319 bytes .../resource/image/Iconyinliang017.jpg | Bin 0 -> 1314 bytes .../resource/image/Iconyinliang018.jpg | Bin 0 -> 1314 bytes .../resource/image/Iconyinliang019.jpg | Bin 0 -> 1257 bytes .../resource/image/Iconyinliang020.jpg | Bin 0 -> 1257 bytes .../resource/voice/Alianwang002.mp3 | Bin 0 -> 99097 bytes .../resource/voice/Alianwang003.mp3 | Bin 0 -> 77972 bytes .../resource/voice/Alianwang004.mp3 | Bin 0 -> 46868 bytes .../resource/voice/Alianwang005.mp3 | Bin 0 -> 61460 bytes .../resource/voice/Alianwang006.mp3 | Bin 0 -> 74132 bytes .../resource/voice/Alianwang007.mp3 | Bin 0 -> 54932 bytes .../resource/voice/Alianwang008.mp3 | Bin 0 -> 71444 bytes .../resource/voice/Alianwang009.mp3 | Bin 0 -> 58388 bytes .../resource/voice/Alianwang010.mp3 | Bin 0 -> 68756 bytes .../resource/voice/Alianwang011.mp3 | Bin 0 -> 35732 bytes .../resource/voice/Alianwang012.mp3 | Bin 0 -> 42260 bytes .../resource/voice/Alianwang013.mp3 | Bin 0 -> 42260 bytes .../resource/voice/Alianwang014.mp3 | Bin 0 -> 122900 bytes .../resource/voice/Ashiyong002.mp3 | Bin 0 -> 37190 bytes .../resource/voice/Ashiyong003.mp3 | Bin 0 -> 38342 bytes .../resource/voice/Ashiyong004.mp3 | Bin 0 -> 33734 bytes .../resource/voice/Ashiyong005.mp3 | Bin 0 -> 35654 bytes .../resource/voice/Ashiyong006.mp3 | Bin 0 -> 37190 bytes res/system_resources/resource/voice/B-b-1.mp3 | Bin 0 -> 37152 bytes res/system_resources/resource/voice/B-b-2.mp3 | Bin 0 -> 66648 bytes res/system_resources/resource/voice/B-b-3.mp3 | Bin 0 -> 37752 bytes .../resource/voice/B-h-60.mp3 | Bin 0 -> 13992 bytes .../resource/voice/B-h-61.mp3 | Bin 0 -> 16344 bytes .../resource/voice/B-h-62.mp3 | Bin 0 -> 13224 bytes .../resource/voice/B-h-63.mp3 | Bin 0 -> 15984 bytes .../resource/voice/B-h-64.mp3 | Bin 0 -> 19008 bytes .../resource/voice/B-h-65.mp3 | Bin 0 -> 11208 bytes .../resource/voice/B-h-66.mp3 | Bin 0 -> 42696 bytes .../resource/voice/B-h-67.mp3 | Bin 0 -> 38376 bytes .../resource/voice/B-h-68.mp3 | Bin 0 -> 51120 bytes .../resource/voice/B-h-69.mp3 | Bin 0 -> 52632 bytes .../resource/voice/B-h-70.mp3 | Bin 0 -> 56232 bytes .../resource/voice/B-h-71.mp3 | Bin 0 -> 59664 bytes .../resource/voice/C-yc-1.mp3 | Bin 0 -> 135490 bytes .../resource/voice/IoT-01.mp3 | Bin 0 -> 193838 bytes .../resource/voice/IoT-02.mp3 | Bin 0 -> 116078 bytes .../resource/voice/IoT-03.mp3 | Bin 0 -> 92462 bytes .../resource/voice/IoT-04.mp3 | Bin 0 -> 154094 bytes .../resource/voice/IoT-05.mp3 | Bin 0 -> 120686 bytes .../resource/voice/IoT-06.mp3 | Bin 0 -> 128750 bytes .../resource/voice/IoT-07.mp3 | Bin 0 -> 193262 bytes .../resource/voice/IoT-08.mp3 | Bin 0 -> 174830 bytes .../resource/voice/IoT-09.mp3 | Bin 0 -> 182894 bytes res/system_resources/resource/voice/S001.mp3 | Bin 0 -> 91292 bytes res/system_resources/resource/voice/S002.mp3 | Bin 0 -> 100566 bytes res/system_resources/resource/voice/S003.mp3 | Bin 0 -> 22618 bytes .../resource/voice/S004-1.mp3 | Bin 0 -> 209867 bytes .../resource/voice/S004-2.mp3 | Bin 0 -> 309341 bytes .../resource/voice/S004-3.mp3 | Bin 0 -> 474853 bytes .../resource/voice/S004-4.mp3 | Bin 0 -> 386246 bytes .../resource/voice/S004-5.mp3 | Bin 0 -> 545906 bytes res/system_resources/resource/voice/S005.mp3 | Bin 0 -> 25962 bytes res/system_resources/resource/voice/S006.mp3 | Bin 0 -> 21783 bytes res/system_resources/resource/voice/S007.mp3 | Bin 0 -> 29306 bytes res/system_resources/resource/voice/S008.mp3 | Bin 0 -> 20111 bytes res/system_resources/resource/voice/S009.mp3 | Bin 0 -> 6736 bytes res/system_resources/resource/voice/S010.mp3 | Bin 0 -> 5064 bytes res/system_resources/resource/voice/S011.mp3 | Bin 0 -> 58563 bytes .../resource/voice/a-a-01.mp3 | Bin 0 -> 40872 bytes .../resource/voice/a-a-02.mp3 | Bin 0 -> 55416 bytes .../resource/voice/a-a-03.mp3 | Bin 0 -> 56520 bytes .../resource/voice/a-n-01.mp3 | Bin 0 -> 40608 bytes .../resource/voice/b-h-50.mp3 | Bin 0 -> 93993 bytes .../resource/voice/b-h-51.mp3 | Bin 0 -> 120343 bytes res/system_resources/resource/voice/b-m-1.mp3 | Bin 0 -> 21192 bytes res/system_resources/resource/voice/b-m-2.mp3 | Bin 0 -> 21672 bytes 148 files changed, 18396 insertions(+) create mode 100644 app/LogCtrlTools/Makefile create mode 100644 app/LogCtrlTools/src/Makefile create mode 100644 app/LogCtrlTools/src/log_ctrl.c create mode 100644 app/alarm/Makefile create mode 100644 app/alarm/src/Makefile create mode 100644 app/alarm/src/assistant.c create mode 100644 app/libuvdbus/Config.in create mode 100644 app/libuvdbus/Makefile create mode 100644 app/libuvdbus/src/Framework/Compress/zlib.c create mode 100644 app/libuvdbus/src/Framework/Configure/config_engine.c create mode 100644 app/libuvdbus/src/Framework/Configure/ini_prase.c create mode 100644 app/libuvdbus/src/Framework/Crypto/aes.c create mode 100644 app/libuvdbus/src/Framework/Crypto/base64.c create mode 100644 app/libuvdbus/src/Framework/Crypto/crypto.c create mode 100644 app/libuvdbus/src/Framework/Crypto/md5.c create mode 100644 app/libuvdbus/src/Framework/Fifo/fifo.c create mode 100644 app/libuvdbus/src/Framework/HeartDaemon/heart_daemon.c create mode 100644 app/libuvdbus/src/Framework/IoT/Boardlink/boardlink_iot.c create mode 100644 app/libuvdbus/src/Framework/JsonUtils/json_struct.c create mode 100644 app/libuvdbus/src/Framework/Monitor/monitor.c create mode 100644 app/libuvdbus/src/Framework/Network/inet_api.c create mode 100644 app/libuvdbus/src/Framework/Skins/skin_res_vtbl.c create mode 100644 app/libuvdbus/src/Framework/Skins/skins.c create mode 100644 app/libuvdbus/src/Framework/SvrManager/svr_manager.c create mode 100644 app/libuvdbus/src/Framework/Timer/timer.c create mode 100644 app/libuvdbus/src/Framework/WireshartScript/log_pv1.lua create mode 100644 app/libuvdbus/src/Framework/libuvEngine/libuv_dbus.c create mode 100644 app/libuvdbus/src/Makefile create mode 100644 app/libuvdbus/src/include/assistant.h create mode 100644 app/libuvdbus/src/include/boardlink_iot.h create mode 100644 app/libuvdbus/src/include/config_engine.h create mode 100644 app/libuvdbus/src/include/crypto.h create mode 100644 app/libuvdbus/src/include/fifo.h create mode 100644 app/libuvdbus/src/include/inet_api.h create mode 100644 app/libuvdbus/src/include/json_struct.h create mode 100644 app/libuvdbus/src/include/libuv_dbus.h create mode 100644 app/libuvdbus/src/include/log.h create mode 100644 app/libuvdbus/src/include/log_info.h create mode 100644 app/libuvdbus/src/include/monitor.h create mode 100644 app/libuvdbus/src/include/ota.h create mode 100644 app/libuvdbus/src/include/server_addr.h create mode 100644 app/libuvdbus/src/include/skins.h create mode 100644 app/libuvdbus/src/include/skins_res.h create mode 100644 app/libuvdbus/src/include/smart_sound.h create mode 100644 app/libuvdbus/src/log/hexdump.c create mode 100644 app/libuvdbus/src/log/log.c create mode 100644 app/ota_r311/Makefile create mode 100644 app/ota_r311/src/Makefile create mode 100644 app/ota_r311/src/ota_r311.c create mode 100644 res/system_resources/Makefile create mode 100644 res/system_resources/resource/image/IconChaozuo001.jpg create mode 100644 res/system_resources/resource/image/IconChaozuo005.jpg create mode 100644 res/system_resources/resource/image/IconLianjie001.jpg create mode 100644 res/system_resources/resource/image/IconLianjie002.jpg create mode 100644 res/system_resources/resource/image/IconLianjie003.jpg create mode 100644 res/system_resources/resource/image/IconNaozhong001.jpg create mode 100644 res/system_resources/resource/image/IconTixing001.jpg create mode 100644 res/system_resources/resource/image/IconZhuangtai003.gif create mode 100644 res/system_resources/resource/image/Iconlianwang001.gif create mode 100644 res/system_resources/resource/image/Iconlianwang005.gif create mode 100644 res/system_resources/resource/image/Iconstart002.gif create mode 100644 res/system_resources/resource/image/Iconyinliang000.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang001.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang002.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang003.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang004.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang005.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang006.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang007.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang008.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang009.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang010.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang011.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang012.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang013.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang014.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang015.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang016.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang017.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang018.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang019.jpg create mode 100644 res/system_resources/resource/image/Iconyinliang020.jpg create mode 100644 res/system_resources/resource/voice/Alianwang002.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang003.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang004.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang005.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang006.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang007.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang008.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang009.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang010.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang011.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang012.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang013.mp3 create mode 100644 res/system_resources/resource/voice/Alianwang014.mp3 create mode 100644 res/system_resources/resource/voice/Ashiyong002.mp3 create mode 100644 res/system_resources/resource/voice/Ashiyong003.mp3 create mode 100644 res/system_resources/resource/voice/Ashiyong004.mp3 create mode 100644 res/system_resources/resource/voice/Ashiyong005.mp3 create mode 100644 res/system_resources/resource/voice/Ashiyong006.mp3 create mode 100644 res/system_resources/resource/voice/B-b-1.mp3 create mode 100644 res/system_resources/resource/voice/B-b-2.mp3 create mode 100644 res/system_resources/resource/voice/B-b-3.mp3 create mode 100644 res/system_resources/resource/voice/B-h-60.mp3 create mode 100644 res/system_resources/resource/voice/B-h-61.mp3 create mode 100644 res/system_resources/resource/voice/B-h-62.mp3 create mode 100644 res/system_resources/resource/voice/B-h-63.mp3 create mode 100644 res/system_resources/resource/voice/B-h-64.mp3 create mode 100644 res/system_resources/resource/voice/B-h-65.mp3 create mode 100644 res/system_resources/resource/voice/B-h-66.mp3 create mode 100644 res/system_resources/resource/voice/B-h-67.mp3 create mode 100644 res/system_resources/resource/voice/B-h-68.mp3 create mode 100644 res/system_resources/resource/voice/B-h-69.mp3 create mode 100644 res/system_resources/resource/voice/B-h-70.mp3 create mode 100644 res/system_resources/resource/voice/B-h-71.mp3 create mode 100644 res/system_resources/resource/voice/C-yc-1.mp3 create mode 100644 res/system_resources/resource/voice/IoT-01.mp3 create mode 100644 res/system_resources/resource/voice/IoT-02.mp3 create mode 100644 res/system_resources/resource/voice/IoT-03.mp3 create mode 100644 res/system_resources/resource/voice/IoT-04.mp3 create mode 100644 res/system_resources/resource/voice/IoT-05.mp3 create mode 100644 res/system_resources/resource/voice/IoT-06.mp3 create mode 100644 res/system_resources/resource/voice/IoT-07.mp3 create mode 100644 res/system_resources/resource/voice/IoT-08.mp3 create mode 100644 res/system_resources/resource/voice/IoT-09.mp3 create mode 100644 res/system_resources/resource/voice/S001.mp3 create mode 100644 res/system_resources/resource/voice/S002.mp3 create mode 100644 res/system_resources/resource/voice/S003.mp3 create mode 100644 res/system_resources/resource/voice/S004-1.mp3 create mode 100644 res/system_resources/resource/voice/S004-2.mp3 create mode 100644 res/system_resources/resource/voice/S004-3.mp3 create mode 100644 res/system_resources/resource/voice/S004-4.mp3 create mode 100644 res/system_resources/resource/voice/S004-5.mp3 create mode 100644 res/system_resources/resource/voice/S005.mp3 create mode 100644 res/system_resources/resource/voice/S006.mp3 create mode 100644 res/system_resources/resource/voice/S007.mp3 create mode 100644 res/system_resources/resource/voice/S008.mp3 create mode 100644 res/system_resources/resource/voice/S009.mp3 create mode 100644 res/system_resources/resource/voice/S010.mp3 create mode 100644 res/system_resources/resource/voice/S011.mp3 create mode 100644 res/system_resources/resource/voice/a-a-01.mp3 create mode 100644 res/system_resources/resource/voice/a-a-02.mp3 create mode 100644 res/system_resources/resource/voice/a-a-03.mp3 create mode 100644 res/system_resources/resource/voice/a-n-01.mp3 create mode 100644 res/system_resources/resource/voice/b-h-50.mp3 create mode 100644 res/system_resources/resource/voice/b-h-51.mp3 create mode 100644 res/system_resources/resource/voice/b-m-1.mp3 create mode 100644 res/system_resources/resource/voice/b-m-2.mp3 diff --git a/app/LogCtrlTools/Makefile b/app/LogCtrlTools/Makefile new file mode 100644 index 0000000..7ce3ca1 --- /dev/null +++ b/app/LogCtrlTools/Makefile @@ -0,0 +1,47 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common +include $(TOPDIR)/rules.mk + +PKG_NAME:=log_ctrl +PKG_RELEASE:=1 +PKG_VERSION:=0.0.1 + +PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME) + +include $(BUILD_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Netease + TITLE:=Log Control tools + MAINTAINER:=Huang xin + DEPENDS:=+libreadline +libncurses $(MAKE_COMMON_DEPEND) +endef + +define Package/$(PKG_NAME)/description + $(PKG_NAME) This tools used to control module's log actions from dbus bus. For example: enable/disable logs, set udp log server ip and port, and so on. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) -d ./src/ $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR)/src \ + ARCH="$(TARGET_ARCH)" \ + AR="$(TARGET_AR)" \ + CC="$(TARGET_CC)" \ + CXX="$(TARGET_CXX)" \ + CFLAGS="$(TARGET_CFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" \ + INSTALL_PREFIX="$(PKG_INSTALL_DIR)" \ + TARGET_NAME=$(PKG_NAME) \ + all +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/app/LogCtrlTools/src/Makefile b/app/LogCtrlTools/src/Makefile new file mode 100644 index 0000000..d60ae72 --- /dev/null +++ b/app/LogCtrlTools/src/Makefile @@ -0,0 +1,24 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common +TARGET := log_ctrl + +commonSources := log_ctrl.c + +local_CFLAGS := -DPLATFROM_R16 +local_LDFLAGS := -lreadline -lncurses $(BUILD_COMMON_LIB) + +OBJS = $(patsubst %.c, %.c.o, $(commonSources)) + +$(TARGET):$(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(local_LDFLAGS) -o $@ $^ + +$(OBJS):%.c.o:%.c + $(CC) $(CFLAGS) $(LDFLAGS) $(local_CFLAGS) -c $^ -o $@ + +clean: + -rm $(OBJS) $(TARGET) + +install: + mkdir -p $(INSTALL_PREFIX)/usr/bin + cp $(TARGET) $(INSTALL_PREFIX)/usr/bin/ + +all: $(TARGET) install diff --git a/app/LogCtrlTools/src/log_ctrl.c b/app/LogCtrlTools/src/log_ctrl.c new file mode 100644 index 0000000..ce94a86 --- /dev/null +++ b/app/LogCtrlTools/src/log_ctrl.c @@ -0,0 +1,323 @@ + #include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) +#include "log.h" +#include "libuv_dbus.h" +#include "json_struct.h" + +#else +#include +#include +#include +#endif + +static MOD_INFO_TABLE g_ModInfo; + + +static PDBUS_MSG_PACK DBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ + //int i, ret, err; + //uint32_t tm = LIBUV_CURRENT_TIME_US(); + + if(!pMsg || !pLoop || !pConn) + { + return NULL; + } + + //LOG_EX(LOG_Info, "Process Message(%u --> 0x%08X) at [%lu.%06lu]: cmd = %u, size = %u, key = %d, msg(%d) = [%s]\n", + // pMsg->msgSrc, pMsg->msgDests, tm / 1000000, tm % 1000000, pMsg->busCmd, pMsg->msgSize, pMsg->msgKey, pMsg->msgSize, pMsg->pMsg); + + return NULL; +} + +static void __logCtrlProc(void *pParams) +{ + int i = 0; + //int ret; + + LOG_LEVEL logLevelInfo[] = { + LOG_Fatal, LOG_Error, LOG_Warn, LOG_Debug, LOG_Info, + LOG_Test, LOG_Call, LOG_Devp, LOG_Step, LOG_Unknown, LOG_All, LOG_Close + }; + + const char* g_Menu[] = { + "Usage: enable/disable [params1] [params2]\n" + " help\n", + " quit\n", + }; + + const char* pOptMenu[] = { + "\n operation:\n" + " |--------------------------------------------------------------------------|\n", + " | command | operation | params1 | params2 |\n", + " |--------------------------------------------------------------------------|\n", + " | enable | | | |\n", + " |----------| 0: Set log level | Log level | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | | |\n", + " |----------| 1: Print to file | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | | |\n", + " |----------| 2: Backup to email | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + " | enable | | Log server ip address | Log server port |\n", + " |----------| 3: Send to network |-----------------------|-----------------|\n", + " | disable | | Unused | Unused |\n", + " |--------------------------------------------------------------------------|\n", + " | enable | | | |\n", + " |----------| 4: Backup to Server | Unused | Unused |\n", + " | disable | | | |\n", + " |----------|---------------------|-----------------------|-----------------|\n", + }; + + while(TRUE) + { + char *pInput = NULL; + char *pCmd = NULL; + + for(i = 0; i < sizeof(g_Menu) / sizeof(g_Menu[0]); i++) + { + LOG_EX2(LOG_Info, "%s", g_Menu[i]); + } + + pInput = readline("Enter Command:"); + + if(pInput == NULL) + { + continue; + } + + pCmd = strtok(pInput, " "); + i = 0; + + while(pCmd != NULL) + { + if(strcmp(pCmd, "help") == 0) + { + for(i = 0; i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0]); i++) + { + if(i == 0) + { + LOG_EX2(LOG_Info, " modName : %-2d --> %s\n", + i, ModuleNameToString(g_pModInfoTable[i].modName)); + } + else + { + LOG_EX2(LOG_Info, "%15s%-2d --> %s\n", "", + i, ModuleNameToString(g_pModInfoTable[i].modName)); + } + } + + for(i = 0; i < sizeof(logLevelInfo) / sizeof(logLevelInfo[0]); i++) + { + if(i == 0) + { + LOG_EX2(LOG_Info, "\n Log Level: %-2d --> %s\n", i, LogLeveToString(logLevelInfo[i])); + } + else + { + LOG_EX2(LOG_Info, "%15s%-2d --> %s\n", "", i, LogLeveToString(logLevelInfo[i])); + } + } + + for(i = 0; i < sizeof(pOptMenu) / sizeof(pOptMenu[0]); i++) + { + LOG_EX2(LOG_Info, "%s", pOptMenu[i]); + } + } + else if(strcmp(pCmd, "enable") == 0 + || strcmp(pCmd, "disable") == 0) + { + LOG_CFG_PROTOCOL logItem; + int iCmd, iMod; + char *pParams1 = NULL, *pParams2 = NULL; + char* pMod = strtok(NULL, " "); + char* pOperat = strtok(NULL, " "); + + if(pMod == NULL || strlen(pMod) == 0) + { + LOG_EX(LOG_Error, "Input error, see help\n"); + break; + } + + if(pOperat == NULL || strlen(pOperat) == 0) + { + LOG_EX(LOG_Error, "Input error, see help\n"); + break; + } + + iMod = strtol(pMod, NULL, 10); + + if(iMod < 0 || iMod >= MODULE_MAX) + { + LOG_EX(LOG_Error, "Input error: %s(%d)\n", pMod, iMod); + break; + } + + iCmd = strtol(pOperat, NULL, 10); + + memset(&logItem, 0, sizeof(LOG_CFG_PROTOCOL)); + + switch(iCmd) + { + case 0: + pParams1 = strtok(NULL, " "); + if(pParams1 && strlen(pParams1) > 0) + { + int logLevel = strtol(pParams1, NULL, 10); + + if(logLevel >= 0 && logLevel < sizeof(logLevelInfo) / sizeof(logLevelInfo[0])) + { + LOG_EX2(LOG_Info, "%s %d 0x%08X\n", pCmd, iCmd, logLevelInfo[logLevel]); + + logItem.cfgCmd = CMD_LOG_LEVEL; + logItem.iParams2 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + logItem.iParams1 = logLevelInfo[logLevel]; + + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + LOG_EX(LOG_Error, "Input error, see help\n"); + } + } + else + { + LOG_EX(LOG_Error, "Input error, see help\n"); + } + break; + + case 1: + logItem.cfgCmd = CMD_LOG_FILE; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + case 2: + logItem.cfgCmd = CMD_LOG_MAIL; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + case 3: + pParams1 = strtok(NULL, " "); + + logItem.cfgCmd = CMD_LOG_NETWORK; + if(pParams1 == NULL || strlen(pParams1) == 0) + { + + logItem.iParams1 = 0; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + pParams2 = strtok(NULL, " "); + + if(pParams2 != NULL && strlen(pParams2) > 0) + { + logItem.iParams1 = inet_addr(pParams1); + logItem.iParams2 = strtol(pParams2, NULL, 10); + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + } + else + { + LOG_EX(LOG_Error, "Input error, pParams2 = %s\n", + SAFE_STRING_VALUE(pParams2)); + } + } + + break; + + case 4: + logItem.cfgCmd = CMD_LOG_SERVER; + logItem.iParams1 = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE; + DBusJsonSendToCommand(NULL, + g_pModInfoTable[iMod].modAliase, + CMD_LOG_CONFIG, + JSON_ENGINE_LOG_CFG_CMD, + &logItem, TRUE); + break; + + default: + LOG_EX(LOG_Error, "Unknown operation(0-3) %s, see help\n", pOperat); + break; + } + } + else if(strcmp(pCmd, "quit") == 0) + { + return; + } + + pCmd = strtok(NULL, " "); + } + + usleep(1000); + } + + pthread_detach(pthread_self()); +} + +int main(int argc, char **argv) +{ + int ret = 0; + DBusConnection* pBus = NULL; + uv_thread_t uvThread; + uv_loop_t* pLoop = GetDBusDefaultLoop(); + + memcpy(&g_ModInfo, &g_pModInfoTable[MODULE_LOG_CTRL], sizeof(MOD_INFO_TABLE)); + + pBus = DBusWithLibuvInit(pLoop, g_ModInfo.modAliase, + DBusOnMessage, + NULL, + NULL, + &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return 0; + } + + uv_thread_create(&uvThread, __logCtrlProc, NULL); + + RunUVLoop(pLoop); + + while(TRUE) + { + usleep(1000); + } + + return (0); +} + diff --git a/app/alarm/Makefile b/app/alarm/Makefile new file mode 100644 index 0000000..3403741 --- /dev/null +++ b/app/alarm/Makefile @@ -0,0 +1,52 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common +include $(TOPDIR)/rules.mk + +PKG_NAME:=alarmer +PKG_RELEASE:=1 +PKG_VERSION:=0.0.1 + +PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME) + +include $(BUILD_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Netease + TITLE:=Alarmer + MAINTAINER:=Huang xin + DEPENDS:=$(MAKE_COMMON_DEPEND) +endef + +define Package/$(PKG_NAME)/description + $(PKG_NAME) alarm and reaminder +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) -d ./src/ $(PKG_BUILD_DIR)/ +endef + +define Build/Configure +endef +define Build/InstallDev +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR)/src \ + ARCH="$(TARGET_ARCH)" \ + AR="$(TARGET_AR)" \ + CC="$(TARGET_CC)" \ + CXX="$(TARGET_CXX)" \ + CFLAGS="$(TARGET_CFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" \ + INSTALL_PREFIX="$(PKG_INSTALL_DIR)" \ + TARGET_NAME=$(PKG_NAME) \ + all +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/app/alarm/src/Makefile b/app/alarm/src/Makefile new file mode 100644 index 0000000..1d2783e --- /dev/null +++ b/app/alarm/src/Makefile @@ -0,0 +1,25 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common + +TARGET := alarmer + +commonSources := assistant.c + +local_CFLAGS := +local_LDFLAGS := $(BUILD_COMMON_LIB) + +OBJS = $(patsubst %.c, %.c.o, $(commonSources)) + +$(TARGET):$(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(local_LDFLAGS) -o $@ $^ + +$(OBJS):%.c.o:%.c + $(CC) $(CFLAGS) $(LDFLAGS) $(local_CFLAGS) -c $^ -o $@ + +clean: + -rm $(OBJS) $(TARGET) + +install: + mkdir -p $(INSTALL_PREFIX)/usr/bin + cp $(TARGET) $(INSTALL_PREFIX)/usr/bin/ + +all: $(TARGET) install diff --git a/app/alarm/src/assistant.c b/app/alarm/src/assistant.c new file mode 100644 index 0000000..90b404e --- /dev/null +++ b/app/alarm/src/assistant.c @@ -0,0 +1,863 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) || defined(PLATFORM_R311) +#include "log.h" +#include "libuv_dbus.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#include "assistant.h" +#else +#include +#include +#include +#include +#include +#include +#endif + +#define SYNC_TIME_DELAY (1) + +static PASSISTANT_ARRAY_INFO g_pAlarmArray = NULL, + g_pRemaindArray = NULL, + g_pSessionArray = NULL; + +static uv_rwlock_t g_uvListRwLock; +static unsigned char g_syncFlags = 0; +static unsigned int g_sessionId = 0; + +static void __onAlarmCb(unsigned int tmId, unsigned int status, void *pUserData); + +static int __getTimerPriorty(ASSISTANT_TYPE itemType) +{ + switch(itemType) + { + case ASSISTANT_TYPE_CLOCK: + return (2); + + case ASSISTANT_TYPE_REMAIND: + return (3); + + case ASSISTANT_TYPE_SESSION: + return (1); + } + + return (0); +} + +static void __addTaskToTimer(PASSISTANT_ARRAY_INFO pItem) +{ + int ret = 0; + unsigned int alarmId; + + pItem->alarmItem.second = 0; + + alarmId = AlarmTimerAdd(pItem->alarmItem.year, + pItem->alarmItem.month, + pItem->alarmItem.day, + pItem->alarmItem.hour, + pItem->alarmItem.minute, + pItem->alarmItem.second, + pItem->alarmItem.weekDay, + pItem->alarmItem.repeatMode, + __onAlarmCb, + __getTimerPriorty(pItem->alarmItem.itemType), + &pItem->alarmItem, + &ret); + + if(alarmId != 0xFFFFFFFF && ret == 0) + { + pItem->alarmItem.timerId = alarmId; + } + else + { + pItem->alarmItem.timerId = 0xFFFFFFFF; + } +} + +static int __assistantRspStatus(int cmd, int val) +{ + int ret = 0; + ASSISTANT_RSP_STATUS oStatus; + + memset(&oStatus, 0, sizeof(ASSISTANT_RSP_STATUS)); + + oStatus.cmd = cmd; + oStatus.val = val; + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_STATUS, + JSON_ENGINE_ASSISTANT_STATUS, + &oStatus, TRUE); + + return (ret); +} + +static int __assistantRunningEvent(PASSISTANT_ITEM_INFO pInfo) +{ + int ret = 0; + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_RUNNING, + JSON_ENGINE_ASSISTANT_RUNNING, + pInfo, FALSE); + + return (ret); +} + +static int __assistantNotifyChange(int cmdNotify, int nItems, ASSISTANT_TYPE nType, PASSISTANT_ITEM_INFO pInfo) +{ + int ret = 0; + ASSISTANT_NOTIFY_INFO notifyInfo; + + memset(¬ifyInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO)); + + notifyInfo.type = nType; + notifyInfo.cmd = cmdNotify; + + if(pInfo) + { + notifyInfo.nItems = nItems; + for(int i = 0; i < nItems; i++) + { + notifyInfo.ids[i] = pInfo[i].itemId; + } + } + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_NOTIFY, + JSON_ENGINE_ASSISTANT_NOTIFY, + ¬ifyInfo, TRUE); + + return (ret); +} + +static int __assistantArrayNotifyChange(int cmdNotify, int nItems, ASSISTANT_TYPE nType, unsigned long long* pArray) +{ + int ret = 0; + ASSISTANT_NOTIFY_INFO notifyInfo; + + memset(¬ifyInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO)); + + notifyInfo.type = nType; + notifyInfo.cmd = cmdNotify; + + if(pArray) + { + notifyInfo.nItems = nItems; + for(int i = 0; i < nItems; i++) + { + notifyInfo.ids[i] = pArray[i]; + } + } + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ASSISTANT_NOTIFY, + JSON_ENGINE_ASSISTANT_NOTIFY, + ¬ifyInfo, TRUE); + + return (ret); +} + +static void __cleanupAlarmArray(void) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pAlarmArray, pItem, pTmp) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pAlarmArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvListRwLock); +} + +static void __cleanupRemaindArray(void) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pRemaindArray, pItem, pTmp) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pRemaindArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvListRwLock); +} + +static void __cleanupSessionArray(void) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pSessionArray, pItem, pTmp) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pSessionArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvListRwLock); +} + +static int __addNewItems(PASSISTANT_SYNC_INFO pInfo) +{ + struct tm localTime; + time_t loclStamp, tmStamp = time((time_t*)NULL); + + localtime_r(&tmStamp, &localTime); + loclStamp = mktime(&localTime); + + for(int i = 0; i < pInfo->nItems; i++) + { + PASSISTANT_ARRAY_INFO pItem = (PASSISTANT_ARRAY_INFO)malloc(sizeof(struct ASSISTANT_ARRAY_INFO)); + + if(pItem == NULL) + { + LOG_EX(LOG_Error, "Malloc Memory Error\n"); + return (-ERR_MALLOC_MEMORY); + } + + memset(pItem, 0, sizeof(struct ASSISTANT_ARRAY_INFO)); + + strcpy(pItem->alarmItem.strTips, pInfo->pAlarmInfo[i].strTips); + strcpy(pItem->alarmItem.resUrl, pInfo->pAlarmInfo[i].resUrl); + strcpy(pItem->alarmItem.voiceRes, pInfo->pAlarmInfo[i].voiceRes); + strcpy(pItem->alarmItem.voiceResType, pInfo->pAlarmInfo[i].voiceResType); + + pItem->alarmItem.itemType = pInfo->pAlarmInfo[i].itemType; + pItem->alarmItem.repeatMode = pInfo->pAlarmInfo[i].repeatMode; + pItem->alarmItem.voiceId = pInfo->pAlarmInfo[i].voiceId; + + pItem->alarmItem.year = pInfo->pAlarmInfo[i].year; + pItem->alarmItem.month = pInfo->pAlarmInfo[i].month; + pItem->alarmItem.day = pInfo->pAlarmInfo[i].day; + pItem->alarmItem.hour = pInfo->pAlarmInfo[i].hour; + pItem->alarmItem.minute = pInfo->pAlarmInfo[i].minute; + pItem->alarmItem.second = pInfo->pAlarmInfo[i].second; + pItem->alarmItem.weekDay = pInfo->pAlarmInfo[i].weekDay; + + if(ASSISTANT_TYPE_SESSION == pItem->alarmItem.itemType) + { + pItem->alarmItem.itemId = g_sessionId++; + } + else + { + pItem->alarmItem.itemId = pInfo->pAlarmInfo[i].itemId; + } + + if(pItem->alarmItem.repeatMode == REPEAT_MODE_NONE) + { + struct tm setTime; + time_t onTimeStamp; + int tmDiff; + + setTime.tm_year = pItem->alarmItem.year; + setTime.tm_mon = pItem->alarmItem.month; + setTime.tm_mday = pItem->alarmItem.day; + setTime.tm_hour = pItem->alarmItem.hour; + setTime.tm_min = pItem->alarmItem.minute; + setTime.tm_sec = pItem->alarmItem.second; + + onTimeStamp = mktime(&setTime); + tmDiff = (int)difftime(loclStamp, onTimeStamp); + + if(tmDiff >= 3) + { + LOG_EX(LOG_Warn, "%llu: Was Expired %d!!!!!!\n", pItem->alarmItem.itemId, tmDiff); + continue; + } + } + + uv_rwlock_wrlock(&g_uvListRwLock); + if(ASSISTANT_TYPE_CLOCK == pItem->alarmItem.itemType) + { + DL_APPEND(g_pAlarmArray, pItem); + } + else if(ASSISTANT_TYPE_REMAIND == pItem->alarmItem.itemType) + { + DL_APPEND(g_pRemaindArray, pItem); + } + else if(ASSISTANT_TYPE_SESSION == pItem->alarmItem.itemType) + { + DL_APPEND(g_pSessionArray, pItem); + } + else + { + LOG_EX(LOG_Error, "Unknown Type: %d\n", pItem->alarmItem.itemType); + } + uv_rwlock_wrunlock(&g_uvListRwLock); + + __addTaskToTimer(pItem); + } + + return (0); +} + +static void __removeAlarmItem(PASSISTANT_NOTIFY_INFO pRemove) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + for(int i = 0; i < pRemove->nItems; i++) + { + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pAlarmArray, pItem, pTmp) + { + if(pItem->alarmItem.itemId == pRemove->ids[i] + && pItem->alarmItem.itemType == pRemove->type) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pAlarmArray, pItem); + free(pItem); + } + } + uv_rwlock_wrunlock(&g_uvListRwLock); + } +} + +static void __removeRemaindItem(PASSISTANT_NOTIFY_INFO pRemove) +{ + PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL; + + for(int i = 0; i < pRemove->nItems; i++) + { + uv_rwlock_wrlock(&g_uvListRwLock); + DL_FOREACH_SAFE(g_pRemaindArray, pItem, pTmp) + { + if(pItem->alarmItem.itemId == pRemove->ids[i] + && pItem->alarmItem.itemType == pRemove->type) + { + AlarmTimerRemove(pItem->alarmItem.timerId); + DL_DELETE(g_pRemaindArray, pItem); + free(pItem); + } + } + uv_rwlock_wrunlock(&g_uvListRwLock); + } +} + +static int __alarmItemCmp(PASSISTANT_ARRAY_INFO pSrc, PASSISTANT_ARRAY_INFO pDst) +{ +#if 0 + fprintf(stdout, "id: %llu --> %llu, type: %u --> %u\n", + pSrc->alarmItem.itemId, pDst->alarmItem.itemId, + pSrc->alarmItem.itemType, pDst->alarmItem.itemType); +#endif + if(pSrc->alarmItem.itemId == pDst->alarmItem.itemId + && pSrc->alarmItem.itemType == pDst->alarmItem.itemType) + { + return (0); + } + else + { + return (1); + } +} + +static void __onAlarmCb(unsigned int tmId, unsigned int status, void *pUserData) +{ + PASSISTANT_ITEM_INFO pAlarm = (PASSISTANT_ITEM_INFO)pUserData; + PASSISTANT_ARRAY_INFO pItem = NULL; + struct ASSISTANT_ARRAY_INFO tmpItem; + + struct tm localTime; + time_t tmStamp = time((time_t*)NULL); + + localtime_r(&tmStamp, &localTime); + + LOG_EX(LOG_Debug, "Timer[%lld] %u On at [%04u-%02u-%02u %02u:%02u:%02u], status = %u\n", pAlarm->itemId, tmId, + localTime.tm_year + 1900, localTime.tm_mon + 1, localTime.tm_mday, + localTime.tm_hour, localTime.tm_min, localTime.tm_sec, + status); + + memset(&tmpItem, 0, sizeof(struct ASSISTANT_ARRAY_INFO)); + + tmpItem.alarmItem.itemId = pAlarm->itemId; + tmpItem.alarmItem.itemType = pAlarm->itemType; + + uv_rwlock_rdlock(&g_uvListRwLock); + if(pAlarm->itemType == ASSISTANT_TYPE_CLOCK) + { + DL_SEARCH(g_pAlarmArray, pItem, &tmpItem, __alarmItemCmp); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_REMAIND) + { + DL_SEARCH(g_pRemaindArray, pItem, &tmpItem, __alarmItemCmp); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_SESSION) + { + DL_SEARCH(g_pSessionArray, pItem, &tmpItem, __alarmItemCmp); + } + else + { + LOG_EX(LOG_Error, "Unknown type: %d\n", pAlarm->itemType); + } + uv_rwlock_rdunlock(&g_uvListRwLock); + + if(pItem) + { + pItem->alarmItem.year += 1900; + pItem->alarmItem.month += 1; + + __assistantRunningEvent(&pItem->alarmItem); + + if((pItem->alarmItem.repeatMode & 0xFF) == REPEAT_MODE_NONE) + { + uv_rwlock_wrlock(&g_uvListRwLock); + if(pAlarm->itemType == ASSISTANT_TYPE_CLOCK) + { + DL_DELETE(g_pAlarmArray, pItem); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_REMAIND) + { + DL_DELETE(g_pRemaindArray, pItem); + } + else if(pAlarm->itemType == ASSISTANT_TYPE_SESSION) + { + DL_DELETE(g_pSessionArray, pItem); + } + else + { + LOG_EX(LOG_Error, "Unknown type: %d\n", pAlarm->itemType); + } + uv_rwlock_wrunlock(&g_uvListRwLock); + + free(pItem); + } + } +} + +static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t *pLoop, DBusConnection *pConn, PDBUS_MSG_PACK pMsg) +{ + PASSISTANT_SYNC_INFO pInfo = NULL; + PASSISTANT_NOTIFY_INFO pNotifyInfo = NULL; + int err = 0; + + if(!pMsg || !pLoop || !pConn) + { + return (NULL); + } + + if(pMsg->msgDests == 0xFFFFFFFF) + { + return (NULL); + } + + LOG_EX(LOG_Debug, "JSON(%08X) %s: %s\n", pMsg->busCmd, DBusCmdToString(pMsg->busCmd), (const char *)pMsg->pMsg); + + switch(pMsg->busCmd) + { + case CMD_SESSION_ALARM_SYNC: + if(IsHolidayDBSynced() != TRUE) + { + LOG_EX(LOG_Warn, "CMD_SESSION_ALARM_SYNC: Wait sync holiday database, this is dirty data.\n"); + break; + } + + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err); + + if(pInfo) + { + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + __cleanupSessionArray(); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + } + + __assistantRspStatus(pMsg->busCmd, err); + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_ALARM_SYNC_RSP: + if(IsHolidayDBSynced() != TRUE) + { + LOG_EX(LOG_Warn, "CMD_ALARM_SYNC_RSP: Wait sync holiday database, this is dirty data.\n"); + break; + } + + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err); + + if(pInfo) + { + g_syncFlags |= 1 << ASSISTANT_TYPE_CLOCK; + + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + __cleanupAlarmArray(); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + } + + __assistantRspStatus(pMsg->busCmd, err); + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + break; + + case CMD_ALARM_ADD: + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, TRUE, &err); + + if(pInfo) + { + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + __assistantRspStatus(pMsg->busCmd, err); + + if(err == 0) + { + __assistantNotifyChange(pMsg->busCmd, pInfo->nItems, ASSISTANT_TYPE_CLOCK, pInfo->pAlarmInfo); + } + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_ALARM_REMOVE: + pNotifyInfo = (PASSISTANT_NOTIFY_INFO)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_ASSISTANT_NOTIFY, FALSE, &err); + + if(pNotifyInfo) + { + __printAssistantNofifyInfo(DBusCmdToString(pMsg->busCmd), pNotifyInfo); + + if(pNotifyInfo->nItems > 0) + { + __removeAlarmItem(pNotifyInfo); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantArrayNotifyChange(pMsg->busCmd, pNotifyInfo->nItems, ASSISTANT_TYPE_CLOCK, pNotifyInfo->ids); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pNotifyInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + break; + + case CMD_ALARM_REMOVEALL: + __cleanupAlarmArray(); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantNotifyChange(pMsg->busCmd, 0, ASSISTANT_TYPE_CLOCK, NULL); + break; + + case CMD_REMAIND_SYNC_RSP: + if(IsHolidayDBSynced() != TRUE) + { + LOG_EX(LOG_Warn, "CMD_REMAIND_SYNC_RSP: Wait sync holiday database, this is dirty data.\n"); + break; + } + + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err); + + if(pInfo) + { + g_syncFlags |= 1 << ASSISTANT_TYPE_REMAIND; + + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + __cleanupRemaindArray(); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + } + + __assistantRspStatus(pMsg->busCmd, err); + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_REMAIND_ADD: + pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, TRUE, &err); + + if(pInfo) + { + __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo); + + if(pInfo->pAlarmInfo && pInfo->nItems > 0) + { + err = __addNewItems(pInfo); + __assistantRspStatus(pMsg->busCmd, err); + + if(err == 0) + { + __assistantNotifyChange(pMsg->busCmd, pInfo->nItems, ASSISTANT_TYPE_REMAIND, pInfo->pAlarmInfo); + } + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pInfo->pAlarmInfo); + free(pInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_REMAIND_REMOVE: + pNotifyInfo = (PASSISTANT_NOTIFY_INFO)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_ASSISTANT_NOTIFY, FALSE, &err); + + if(pNotifyInfo) + { + __printAssistantNofifyInfo(DBusCmdToString(pMsg->busCmd), pNotifyInfo); + + if(pNotifyInfo->nItems > 0) + { + __removeRemaindItem(pNotifyInfo); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantArrayNotifyChange(pMsg->busCmd, pNotifyInfo->nItems, ASSISTANT_TYPE_REMAIND, pNotifyInfo->ids); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + + free(pNotifyInfo); + } + else + { + __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS); + } + break; + + case CMD_REMAIND_REMOVEALL: + __cleanupRemaindArray(); + __assistantRspStatus(pMsg->busCmd, 0); + __assistantNotifyChange(pMsg->busCmd, 0, ASSISTANT_TYPE_REMAIND, NULL); + break; + } + + return (NULL); +} + +static void __dBusDeameonCb(MODULE_NAME modName, int status) +{ + if(status) + { + LOG_EX(LOG_Error, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } + else + { + LOG_EX(LOG_Info, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect"); + } + +#if 0 + if(modName == MODULE_CONTROLLER && status == 0) + { + int ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ALARM_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret); + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_REMAIND_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret); + } +#endif +} + +static void __assistantSyncThread(void *pParam) +{ + int ret, i = 0, isSynced = -1; + + LOG_EX(LOG_Debug, "Beging Sync holiday Database\n"); + while(TRUE) + { + if(IsHolidayDBSynced() != TRUE) + { + CurrentIsWorkDay(0, 0); + if(i++ % 10 == 0 && i <= 1000) + { + LOG_EX(LOG_Debug, "Retry sync holiday database: %d\n", i); + } + sleep(SYNC_TIME_DELAY); + } + else + { + break; + } + } + LOG_EX(LOG_Debug, "Sync holiday Database Finished\n"); + + LOG_EX(LOG_Debug, "Beging sync ASSISTANT_TYPE_CLOCK\n"); + do + { + if(g_syncFlags & (1 << ASSISTANT_TYPE_CLOCK)) + { + LOG_EX(LOG_Debug, "Sync ASSISTANT_TYPE_CLOCK Finished\n"); + break; + } + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ALARM_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret); + + sleep(SYNC_TIME_DELAY); + } while(TRUE); + + LOG_EX(LOG_Debug, "Beging sync ASSISTANT_TYPE_REMAIND\n"); + do + { + if(g_syncFlags & (1 << ASSISTANT_TYPE_REMAIND)) + { + LOG_EX(LOG_Debug, "Sync ASSISTANT_TYPE_REMAIND Finished\n"); + break; + } + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_REMAIND_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret); + + sleep(SYNC_TIME_DELAY); + } while(TRUE); + +#if 0 + do + { + if((g_syncFlags & (1 << ASSISTANT_TYPE_CLOCK)) + && (g_syncFlags & (1 << ASSISTANT_TYPE_REMAIND))) + { + LOG_EX(LOG_Debug, "Sync Alarm And Remaind Finished\n"); + break; + } + + if((g_syncFlags & (1 << ASSISTANT_TYPE_CLOCK)) == 0) + { + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ALARM_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret); + } + + if((g_syncFlags & (1 << ASSISTANT_TYPE_REMAIND)) == 0) + { + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_REMAIND_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret); + } + + sleep(SYNC_TIME_DELAY); + } while(TRUE); + //while(g_syncFlags != ((1 << ASSISTANT_TYPE_CLOCK) | (1 << ASSISTANT_TYPE_REMAIND))); + + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_ALARM_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret); + + ret = DBusSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_REMAIND_SYNC_REQ, ""); + + LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret); +#endif + + pthread_detach(pthread_self()); +} + +int main(int argc, char **argv) +{ + int ret = 0; + DBusConnection* pBus; + uv_loop_t* pLoop = GetDBusDefaultLoop(); + uv_thread_t uvSyncThread; + + pBus = DBusWithLibuvInit(pLoop, g_pModInfoTable[MODULE_ALARM].modAliase, + __dBusOnMessage, + __dBusDeameonCb, + NULL, &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return 0; + } + + uv_rwlock_init(&g_uvListRwLock); + + AlarmTimerInit(pLoop); + + uv_thread_create(&uvSyncThread, __assistantSyncThread, NULL); + RunUVLoop(pLoop); + + while(TRUE) + { + usleep(1000); + } + + return 0; +} diff --git a/app/libuvdbus/Config.in b/app/libuvdbus/Config.in new file mode 100644 index 0000000..2c6deb0 --- /dev/null +++ b/app/libuvdbus/Config.in @@ -0,0 +1,17 @@ +if PACKAGE_libuvdbus + +comment "Resource Mode Select" + +choice + prompt "Select Resources Work Mode" + default RES_NORMAL_MODE + + config RES_FACTORY_MODE + bool "Used For Factory Mode" + + config RES_NORMAL_MODE + bool "Used For Normal Mode" + +endchoice + +endif diff --git a/app/libuvdbus/Makefile b/app/libuvdbus/Makefile new file mode 100644 index 0000000..890c765 --- /dev/null +++ b/app/libuvdbus/Makefile @@ -0,0 +1,68 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common +include $(TOPDIR)/rules.mk + +PKG_NAME:=libuvdbus +PKG_RELEASE:=1 +PKG_VERSION:=0.0.1 + +PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME) + +include $(BUILD_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Netease + TITLE:=Libuv dubs + MAINTAINER:=Huang xin + DEPENDS:=$(LIB_MAKE_COMMON_DEPEND) +endef + +ifeq ('$(CONFIG_RES_FACTORY_MODE)', 'y') + TARGET_CFLAGS += -DRES_FACTORY_MODE +endif + +define Package/$(PKG_NAME)/description + Libuv + dbus pack! +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) -d ./src/ $(PKG_BUILD_DIR)/ +endef + +define Package/$(PKG_NAME)/config + source "$(SOURCE)/Config.in" +endef + +define Build/Configure +endef + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include/ + $(INSTALL_DIR) $(1)/lib/ + $(CP) \ + $(PKG_BUILD_DIR)/src/include \ + $(1)/usr/include/uvdbus + + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libuvdbus.so $(1)/lib/ +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR)/src \ + ARCH="$(TARGET_ARCH)" \ + AR="$(TARGET_AR)" \ + CC="$(TARGET_CC)" \ + CXX="$(TARGET_CXX)" \ + CFLAGS="$(TARGET_CFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" \ + INSTALL_PREFIX="$(PKG_INSTALL_DIR)" \ + TARGET_NAME=$(PKG_NAME) \ + all +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/lib + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libuvdbus.so $(1)/lib/ +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/app/libuvdbus/src/Framework/Compress/zlib.c b/app/libuvdbus/src/Framework/Compress/zlib.c new file mode 100644 index 0000000..b78f863 --- /dev/null +++ b/app/libuvdbus/src/Framework/Compress/zlib.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "crypto.h" + +#define CHUNK_BLOCK (16384) + +/* Compress from file source to file dest until EOF on source. + def() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_STREAM_ERROR if an invalid compression + level is supplied, Z_VERSION_ERROR if the version of zlib.h and the + version of the library linked do not match, or Z_ERRNO if there is + an error reading or writing the files. */ +int GZipFileCompress(const char* pInput, const char* pOutput) +{ + int ret, isFlush; + unsigned int have; + z_stream strm; + char strPath[256]; + unsigned char in[CHUNK_BLOCK]; + unsigned char out[CHUNK_BLOCK]; + FILE *source, *dest; + + if (pInput == NULL) + { + return (Z_ERRNO); + } + + if(access(pInput, F_OK) != 0) + { + return (Z_ERRNO); + } + + //fprintf(stdout, "in: %s\n", pInput); + + source = fopen(pInput, "r+"); + + memset(strPath, 0, 256); + if (pOutput == NULL || strlen(pOutput) == 0) + { + sprintf(strPath, "%s.gz", pInput); + dest = fopen(strPath, "w+"); + + //fprintf(stdout, "out: %s\n", strPath); + } + else + { + dest = fopen(pOutput, "w+"); + //fprintf(stdout, "out: %s\n", pOutput); + } + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + //ret = deflateInit(&strm, level); + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY); + + if (ret != Z_OK) + { + fclose(source); + fclose(dest); + return ret; + } + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK_BLOCK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + fclose(source); + fclose(dest); + return Z_ERRNO; + } + isFlush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = CHUNK_BLOCK; + strm.next_out = out; + ret = deflate(&strm, isFlush); /* no bad return value */ + have = CHUNK_BLOCK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)deflateEnd(&strm); + fclose(source); + fclose(dest); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when last data in file processed */ + } while (isFlush != Z_FINISH); + + /* clean up and return */ + (void)deflateEnd(&strm); + + fflush(dest); + + fclose(source); + fclose(dest); + return Z_OK; +} + diff --git a/app/libuvdbus/src/Framework/Configure/config_engine.c b/app/libuvdbus/src/Framework/Configure/config_engine.c new file mode 100644 index 0000000..4b5c276 --- /dev/null +++ b/app/libuvdbus/src/Framework/Configure/config_engine.c @@ -0,0 +1,1042 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "config_engine.h" +#include "libuv_dbus.h" + +#define PROCESS_MUTEX_KEY ("/root/config_server.pid") +#define CFG_SYNC_TIME_OF_SECONDS (1) + + +static PCFG_ITEM __cfgAddItem(const char *pKeyName, const char *pKeyValue, int iType, int overWrite, int saveToDB, int* pErr); + +typedef struct +{ + char keyName[MAX_CFG_KEY_NAME]; + uint32_t tmCached; + + UT_hash_handle hh; ///< UT Hash handle +} CFG_CACHE_ITEM, *PCFG_CACHE_ITEM; + +static sqlite3* g_pSqlFileDB = NULL; +static PCFG_ITEM g_pCfgItems = NULL; +static PCFG_CACHE_ITEM g_pCfgCacheItems = NULL; +static int g_bIsCfgSvr = FALSE; +static uv_rwlock_t g_uvHashRwLock; +static uv_rwlock_t g_uvCacheRwLock; +static uv_timer_t g_uvSyncSvr; + +#if 0 +#define INT_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS integer(" \ + "keyName TEXT PRIMARY KEY NOT NULL," \ + "keyValue INTEGER NOT NULL," \ + "keyModule INTEGER NOT NULL," \ + "CreatedTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") + +#define STRING_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS string(" \ + "keyName TEXT PRIMARY KEY NOT NULL," \ + "keyValue TEXT NOT NULL," \ + "keyModule INTEGER NOT NULL," \ + "CreatedTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") + +#define FLOAT_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS double(" \ + "keyName TEXT PRIMARY KEY NOT NULL," \ + "keyValue NUMERIC NOT NULL," \ + "keyModule INTEGER NOT NULL," \ + "CreatedTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") +#endif + +#define FIRMWARE_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS %s (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "keyName TEXT UNIQUE NOT NULL," \ + "keyValue TEXT NOT NULL," \ + "keyType INTEGER NOT NULL);") + + +static const char* __cfgGetKeyTypeString(int keyType) +{ + switch(keyType) + { + case 0: + return ("string"); + case 1: + return ("integer"); + case 2: + return ("double"); + } + + return ("Unknown Type"); +} + + +static int __cfgItem2CfgRsp(PCFG_ITEM pCfgItem, PCFG_API_RSP pRsp) +{ + if(pCfgItem == NULL || pRsp == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + memset(pRsp->keyValue, 0, MAX_CFG_KEY_VALUE); + pRsp->keyType = pCfgItem->keyType; + + if(pCfgItem->keyType == CFG_TYPE_STRING) + { + strncpy(pRsp->keyValue, pCfgItem->pStrValue, MAX_CFG_KEY_VALUE); + } + else if(pCfgItem->keyType == CFG_TYPE_INT) + { + sprintf(pRsp->keyValue, "%d", pCfgItem->intValue); + } + else if(pCfgItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(pRsp->keyValue, "%f", pCfgItem->doubleValue); + } + + pRsp->errNo = 0; + + return (0); +} + +static int __cfgMsg2CfgItem(int keyType, const char *pKeyName, const char *pKeyValue, PCFG_ITEM pCfgItem) +{ + int iValue; + double dValue; + char *pEndPtr = NULL; + + if(pKeyName == NULL || pKeyValue == NULL || pCfgItem == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + strcpy(pCfgItem->pKeyName, pKeyName); + pCfgItem->keyType = keyType; + pCfgItem->keyModule = DBusLibuvGetRuntime()->modName; + + switch(keyType) + { + case CFG_TYPE_STRING: + strcpy(pCfgItem->pStrValue, pKeyValue); + break; + + case CFG_TYPE_INT: + iValue = strtol(pKeyValue, NULL, 10); + + if(errno == ERANGE || errno == EINVAL) + { + return (-ERR_STR_CONVERT); + } + else + { + pCfgItem->intValue = iValue; + } + break; + + case CFG_TYPE_DOUBLE: + dValue = strtod(pKeyValue, &pEndPtr); + + if((errno == ERANGE) || (dValue == 0 && (strcmp(pKeyValue, pEndPtr) == 0))) + { + return (-ERR_STR_CONVERT); + } + else + { + pCfgItem->doubleValue = dValue; + } + + break; + + default : + return (-ERR_UNKNOWN_TYPE); + } + + return (0); +} + +static int __cfgMsg2CfgItemV2(int keyType, const char *pKeyName, const char *pKeyValue, PCFG_ITEM* pItem) +{ + int iSize; + PCFG_ITEM pCfgItem = (PCFG_ITEM)malloc(sizeof(CFG_ITEM)); + char* pCache = NULL; + + if(pKeyName == NULL || pKeyValue == NULL || pCfgItem == NULL) + { + free(pCfgItem); + return (-ERR_INPUT_PARAMS); + } + + switch(keyType) + { + case CFG_TYPE_STRING: + iSize += strlen(pKeyValue) + 1; + pCache = (char*)malloc(iSize); + memset(pCache, 0, iSize); + pCfgItem->pKeyName = pCache; + pCfgItem->pStrValue = pCache + strlen(pKeyName) + 1; + __cfgMsg2CfgItem(pCfgItem->keyType, pKeyName, pKeyValue, pCfgItem);; + break; + + case CFG_TYPE_INT: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, pKeyName); + __cfgMsg2CfgItem(pCfgItem->keyType, pKeyName, pKeyValue, pCfgItem);; + break; + + case CFG_TYPE_DOUBLE: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, pKeyName); + __cfgMsg2CfgItem(pCfgItem->keyType, pKeyName, pKeyValue, pCfgItem);; + break; + + default: + free(pCfgItem); + return -ERR_UNKNOWN_TYPE; + } + + *pItem = pCfgItem; + + return 0; +} + +int Sqlite3SyncDB(sqlite3* pSqlMemory, const char* pMemDbName, const char* pDBFilePath, const char* pFileDbName, int isSave) +{ + int rc; + sqlite3* pSqlFile; + sqlite3_backup* pSqlBackup; + sqlite3* pSyncDest; + sqlite3* pSyncSrc; + + rc = sqlite3_open(pDBFilePath, &pSqlFile); + + if(rc != SQLITE_OK) + { + return -ERR_OPEN_SQLITE3_DB; + } + + if(pDBFilePath == NULL || strlen(pDBFilePath) == 0) + { + pMemDbName = "main"; + } + + if(pFileDbName == NULL || strlen(pFileDbName) == 0) + { + pFileDbName = "main"; + } + + pSyncSrc = isSave ? pSqlMemory : pSqlFile; + pSyncDest = isSave ? pSqlFile : pSqlMemory; + + pSqlBackup = sqlite3_backup_init(pSyncDest, pMemDbName, pSyncSrc, pFileDbName); + + if(pSqlBackup != NULL) + { +#if 1 + do + { + rc = sqlite3_backup_step(pSqlBackup, 10); + + if(rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED) + { + sqlite3_sleep(100); + } + } while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED); +#else + sqlite3_backup_step(pSqlBackup, -1); +#endif + sqlite3_backup_finish(pSqlBackup); + } + else + { + LOG_EX(LOG_Error, "Backup Database Error\n"); + } + + rc = sqlite3_errcode(pSyncDest); + + return rc; +} + +static int __sqlite3LoadCb(void* data, int argc, char** argv, char** azColName) +{ + + if(argc == 4) + { + int iSize; + PCFG_ITEM pCfgItem = (PCFG_ITEM)malloc(sizeof(CFG_ITEM)); + char* pCache = NULL; + int ret = 0; + + pCfgItem->keyType = atoi(argv[3]); + pCfgItem->keyModule = *(int*)data; + iSize = strlen(argv[1]) + 1; + + switch(pCfgItem->keyType) + { + case CFG_TYPE_STRING: + iSize += strlen(argv[2]) + 1; + pCache = (char*)malloc(iSize); + memset(pCache, 0, iSize); + pCfgItem->pKeyName = pCache; + pCfgItem->pStrValue = pCache + strlen(argv[1]) + 1; + ret = __cfgMsg2CfgItem(pCfgItem->keyType, argv[1], argv[2], pCfgItem);; + break; + + case CFG_TYPE_INT: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, argv[1]); + ret = __cfgMsg2CfgItem(pCfgItem->keyType, argv[1], argv[2], pCfgItem);; + break; + + case CFG_TYPE_DOUBLE: + pCfgItem->pKeyName = (char*)malloc(iSize); + memset(pCfgItem->pKeyName, 0, iSize); + strcpy(pCfgItem->pKeyName, argv[1]); + ret = __cfgMsg2CfgItem(pCfgItem->keyType, argv[1], argv[2], pCfgItem);; + break; + + default: + free(pCfgItem); + return -ERR_UNKNOWN_TYPE; + } + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + + if(ret == 0) + { + CfgItemPrint("Load Configure: ", pCfgItem); + } + } + else + { + LOG_EX(LOG_Error, "argc = %d\n", argc); + } + + return 0; +} + +static int __cfgLoadGlobalConfig(void) +{ + int rc = 0; + char* pErrMsg = NULL; + char sqlCmd[1024]; + PLIBUV_DBUS_PARAMS pContext = DBusLibuvGetRuntime(); + + memset(sqlCmd, 0, 1024); + sprintf(sqlCmd, "SELECT * FROM %s", MODULE_ALIAS_NAME(MODULE_CONFIGURE)); + + // get global configure + rc = sqlite3_exec(g_pSqlFileDB, sqlCmd, __sqlite3LoadCb, (void*)MODULE_CONFIGURE, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQLite3 Query Error: %s\n", pErrMsg); + return -ERR_SQL_QUERY; + } + + if(pContext->modName != MODULE_CONFIGURE) + { + memset(sqlCmd, 0, 1024); + sprintf(sqlCmd, "SELECT * FROM %s", MODULE_ALIAS_NAME(pContext->modName)); + + // get local configure + rc = sqlite3_exec(g_pSqlFileDB, sqlCmd, __sqlite3LoadCb, (void*)&pContext->modName, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQLite3 Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + return -ERR_SQL_QUERY; + } + } + + return 0; +} + + +void CfgItemPrint(const char* pPrefix, PCFG_ITEM pCfgItem) +{ + if(pCfgItem == NULL) + { + fprintf(stderr, "CfgItemPrint: NULL\n"); + return; + } + + switch(pCfgItem->keyType) + { + case 0: + LOG_EX(LOG_Debug, "%s[%s] = \"%s\", \ttype = %s, \tmodule = %s\n", pPrefix ? pPrefix : "", + pCfgItem->pKeyName, pCfgItem->pStrValue, __cfgGetKeyTypeString(pCfgItem->keyType), ModuleNameToString(pCfgItem->keyModule)); + break; + + case 1: + LOG_EX(LOG_Debug, "%s[%s] = %d, \ttype = %s, \tmodule = %s\n", pPrefix ? pPrefix : "", + pCfgItem->pKeyName, pCfgItem->intValue, __cfgGetKeyTypeString(pCfgItem->keyType), ModuleNameToString(pCfgItem->keyModule)); + break; + + case 2: + LOG_EX(LOG_Debug, "%s[%s] = %f, \ttype = %s, \tmodule = %s\n", pPrefix ? pPrefix : "", + pCfgItem->pKeyName, pCfgItem->doubleValue, __cfgGetKeyTypeString(pCfgItem->keyType), ModuleNameToString(pCfgItem->keyModule)); + break; + + default: + LOG_EX(LOG_Error, "Unknown type = %d\n", pCfgItem->keyType); + break; + } + +} + +int CfgAddGlobalConfig(const char *pKeyName, const char *pKeyValue, CFG_DATA_TYPE keyType) +{ + CFG_API_REQ req; + int ret; + + if(pKeyName == NULL || pKeyValue == NULL || strlen(pKeyName) == 0 || strlen(pKeyValue) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + if(keyType < 0 || keyType > CFG_TYPE_DOUBLE) + { + return (-ERR_INPUT_PARAMS); + } + + memset(&req, 0, sizeof(CFG_API_REQ)); + + strncpy(req.keyName, pKeyName, MAX_CFG_KEY_NAME); + strncpy(req.keyValue, pKeyValue, MAX_CFG_KEY_VALUE); + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONFIGURE].modAliase, + CMD_CFG_ADD_REQ, + JSON_ENGINE_CFG_REQ, + &req, TRUE); + + if(ret == 0) + { + return (-ERR_CFG_WAIT_RSP); + } + else + { + return (ret); + } +} + +int CfgAddKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB) +{ + int err = 0; + PCFG_ITEM pCfgItem = NULL; + + if(pItem == NULL || pKeyName == NULL || strlen(pKeyName) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem != NULL) + { + return (-ERR_CFG_ITEM_EXIST); + } + + if(pItem->keyType == CFG_TYPE_STRING) + { + __cfgAddItem(pKeyName, (const char*)pItem->pStrValue, pItem->keyType, FALSE, saveToDB, &err); + } + else + { + char buf[256]; + memset(buf, 0, 256); + + if(pItem->keyType == CFG_TYPE_INT) + { + sprintf(buf, "%d", pItem->intValue); + } + else if(pItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(buf, "%f", pItem->doubleValue); + } + + __cfgAddItem(pKeyName, (const char*)buf, pItem->keyType, FALSE, saveToDB, &err); + } + + return (err); +} + +int CfgChangeKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB) +{ + int err = 0; + PCFG_ITEM pCfgItem = NULL; + + if(pItem == NULL || pKeyName == NULL || strlen(pKeyName) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem == NULL) + { + return (-ERR_CFG_NOITEM); + } + + HASH_DEL(g_pCfgItems, pCfgItem); + + if(pItem->keyType == CFG_TYPE_STRING) + { + __cfgAddItem(pKeyName, (const char*)pItem->pStrValue, pItem->keyType, FALSE, saveToDB, &err); + } + else + { + char buf[256]; + memset(buf, 0, 256); + + if(pItem->keyType == CFG_TYPE_INT) + { + sprintf(buf, "%d", pItem->intValue); + } + else if(pItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(buf, "%f", pItem->doubleValue); + } + + __cfgAddItem(pKeyName, (const char*)buf, pItem->keyType, FALSE, saveToDB, &err); + } + + return (err); +} + +int CfgGetKeyValue(const char* pKeyName, PCFG_ITEM* pItem) +{ + PCFG_ITEM pCfgItem = NULL; + PLIBUV_DBUS_PARAMS pContext = DBusLibuvGetRuntime(); + + if(pItem == NULL || pKeyName == NULL || strlen(pKeyName) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem == NULL) + { + if(pContext->modName == MODULE_CONFIGURE) + { + return (-ERR_CFG_NOITEM); + } + else + { + CFG_API_REQ req; + int ret = 0; + memset(&req, 0, sizeof(CFG_API_REQ)); + strncpy(req.keyName, pKeyName, MAX_CFG_KEY_NAME); + ret = DBusJsonSendToCommand(NULL, g_pModInfoTable[MODULE_CONFIGURE].modAliase, CMD_CFG_GET_REQ, JSON_ENGINE_CFG_REQ, &req, TRUE); + + if(ret == 0) + { + return (-ERR_CFG_WAIT_RSP); + } + else + { + return (ret); + } + } + } + + *pItem = pCfgItem; + + return 0; +} + +static int __cfgCreateCfgFile(const char* pCfgFilePath) +{ + /*const char* pSqlIntDB = NULL; + const char* pSqlFloatDB = NULL; + const char* pSqlStringDB = NULL; */ + char* pErrMsg = NULL; + int rc = 0; + int i = 0; + + rc = sqlite3_open_v2(pCfgFilePath, &g_pSqlFileDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + + if(rc) + { + LOG_EX(LOG_Error, "sqlite3_open_v2 error: %s\n", pCfgFilePath); + return -ERR_OPEN_SQLITE3_DB; + } + + for(i = 0; (i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0])); i++) + { + char sqlBuf[1024]; + + memset(sqlBuf, 0, 1024); + + sprintf(sqlBuf, FIRMWARE_TBL_SQL_CMD, MODULE_ALIAS_NAME(i)); + + rc = sqlite3_exec(g_pSqlFileDB, sqlBuf, NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + uv_fs_t uvFs; + LOG_EX(LOG_Error, "Create Tbl[%d] Error: %s\n", i, pErrMsg); + sqlite3_free(pErrMsg); + uv_fs_unlink(GetDBusDefaultLoop(), &uvFs, pCfgFilePath, NULL); + return -ERR_SQLITE3_CREATE_TABLE; + } + } + + return 0; +} + +#if 0 +static void onSigTermProgressExit(int sign) +{ + if(g_bIsCfgSvr) + { + } + + kill(getpid(), SIGKILL); +} + +static void onProgressExit(void) +{ + onSigTermProgressExit(0); +} +#endif + + +static int __cfgCheckCfgSvrRun(void) +{ + int rc; + int fd = open(PROCESS_MUTEX_KEY, O_CREAT | O_RDWR, 0666); + + if(fd == -1) + { + LOG_EX(LOG_Debug, "Open File Error\n"); + } + + rc = flock(fd, LOCK_EX | LOCK_NB); + + if(rc == -1) + { + LOG_EX(LOG_Debug, "Configure server running\n"); + return FALSE; + } + else + { + LOG_EX(LOG_Debug, "Configure server stoped\n"); + return TRUE; + } +} + +static int __cfgAddToCache(const char *pKeyName) +{ + PCFG_CACHE_ITEM pItem = NULL; + + uv_rwlock_rdlock(&g_uvCacheRwLock); + HASH_FIND_STR(g_pCfgCacheItems, pKeyName, pItem); + uv_rwlock_rdunlock(&g_uvCacheRwLock); + + if(pItem != NULL) + { + HASH_DEL(g_pCfgCacheItems, pItem); + free(pItem); + } + + pItem = (PCFG_CACHE_ITEM)malloc(sizeof(CFG_CACHE_ITEM)); + + strncpy(pItem->keyName, pKeyName, MAX_CFG_KEY_NAME); + pItem->tmCached = LIBUV_CURRENT_TIME_MS(); + + uv_rwlock_wrlock(&g_uvCacheRwLock); + HASH_ADD_STR(g_pCfgCacheItems, keyName, pItem); + uv_rwlock_wrunlock(&g_uvCacheRwLock); + + return (0); +} + +static PCFG_ITEM __cfgAddItem(const char *pKeyName, const char *pKeyValue, int iType, int overWrite, int saveToDB, int* pErr) +{ + PCFG_ITEM pCfgItem = NULL; + int iSize = 0; + char *pCache = NULL; + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pCfgItem != NULL) + { + if(overWrite) + { + HASH_DEL(g_pCfgItems, pCfgItem); + free(pCfgItem->pKeyName); + free(pCfgItem); + } + else + { + if(pErr) + { + *pErr = -ERR_CFG_NOITEM; + } + + return NULL; + } + } + + if(iType == CFG_TYPE_STRING) + { + iSize = strlen(pKeyName) + strlen(pKeyValue) + 2; + } + else + { + iSize = strlen(pKeyName) + 1; + } + + pCache = (char *)malloc(iSize); + + memset(pCache, 0, iSize); + pCfgItem = (PCFG_ITEM)malloc(sizeof(CFG_ITEM)); + + + pCfgItem->pKeyName = pCache; + + if(iType == CFG_TYPE_STRING) + { + pCfgItem->pStrValue = pCache + strlen(pKeyName) + 1; + } + + __cfgMsg2CfgItem(iType, pKeyName, pKeyValue, pCfgItem); + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_STR(g_pCfgItems, pKeyName, pCfgItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + + // if need save this configure item to database + if(saveToDB) + { + __cfgAddToCache(pKeyName); + } + + if(pErr) + { + *pErr = 0; + } + + return (pCfgItem); +} + +static void __cfgSyncServer(void) +{ + if(HASH_COUNT(g_pCfgCacheItems) > 0) + { + PCFG_CACHE_ITEM pItem = NULL, pTemp = NULL; + + sqlite3_exec(g_pSqlFileDB, "BEGIN TRANSACTION;", NULL, NULL, NULL); + + HASH_ITER(hh, g_pCfgCacheItems, pItem, pTemp) + { + PCFG_ITEM pCfgItem = NULL; + + if(CfgGetKeyValue(pItem->keyName, &pCfgItem) == 0) + { + char* pSqlInsertCmd = (char*)malloc(1024 * 4); + char* pSqlUpgradeCmd = (char*)malloc(1024 * 4); + memset(pSqlInsertCmd, 0, 1024 * 4); + memset(pSqlUpgradeCmd, 0, 1024 * 4); + + if(pCfgItem->keyType == CFG_TYPE_STRING) + { + sprintf(pSqlInsertCmd, "INSERT OR IGNORE INTO %s (keyName, keyValue, keyType) VALUES (\'%s\', \'%s\', %d)", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pKeyName, pCfgItem->pStrValue, pCfgItem->keyType); + + sprintf(pSqlUpgradeCmd, "UPDATE %s SET keyValue = \'%s\', keyType = %d WHERE keyName = \'%s\'", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pStrValue, pCfgItem->keyType, pCfgItem->pKeyName); + } + else if(pCfgItem->keyType == CFG_TYPE_INT) + { + sprintf(pSqlInsertCmd, "INSERT OR IGNORE INTO %s (keyName, keyValue, keyType) VALUES (\'%s\', \'%d\', %d)", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pKeyName, pCfgItem->intValue, pCfgItem->keyType); + + sprintf(pSqlUpgradeCmd, "UPDATE %s SET keyValue = \'%d\', keyType = %d WHERE keyName = \'%s\'", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->intValue, pCfgItem->keyType, pCfgItem->pKeyName); + } + else if(pCfgItem->keyType == CFG_TYPE_DOUBLE) + { + sprintf(pSqlInsertCmd, "INSERT OR IGNORE INTO %s (keyName, keyValue, keyType) VALUES (\'%s\', \'%f\', %d)", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->pKeyName, pCfgItem->doubleValue, pCfgItem->keyType); + + sprintf(pSqlUpgradeCmd, "UPDATE %s SET keyValue = \'%f\', keyType = %d WHERE keyName = \'%s\'", + MODULE_ALIAS_NAME(pCfgItem->keyModule), pCfgItem->doubleValue, pCfgItem->keyType, pCfgItem->pKeyName); + } + + if((sqlite3_exec(g_pSqlFileDB, pSqlInsertCmd, NULL, NULL, NULL) == SQLITE_OK) + && (sqlite3_exec(g_pSqlFileDB, pSqlUpgradeCmd, NULL, NULL, NULL) == SQLITE_OK)) + { + // Delete this Key + HASH_DEL(g_pCfgCacheItems, pItem); + LOG_EX(LOG_Debug, "Sync Configure %s To Database\n", pCfgItem->pKeyName); + } + else + { + free(pSqlInsertCmd); + free(pSqlUpgradeCmd); + return; + } + + free(pSqlInsertCmd); + free(pSqlUpgradeCmd); + } + else + { + // Delete this Key + HASH_DEL(g_pCfgCacheItems, pItem); + } + } + + sqlite3_exec(g_pSqlFileDB, "END TRANSACTION;", NULL, NULL, NULL); + } +} +static void __uvThreadSyncCfg(void *pParams) +{ + while(TRUE) + { + __cfgSyncServer(); + sleep(CFG_SYNC_TIME_OF_SECONDS); + } + + pthread_detach(pthread_self()); +} + +static void __cfgStartSyncGlobalCfgSvr(void) +{ + uv_thread_t uvSyncThread; + + uv_rwlock_init(&g_uvCacheRwLock); + + uv_thread_create(&uvSyncThread, __uvThreadSyncCfg, NULL); +} + +static PCFG_ITEM __onCMD_CFG_GET_REQ(const char* pKeyName, int* pErr) +{ + PCFG_ITEM pItem = NULL; + + *pErr = CfgGetKeyValue(pKeyName, &pItem); + + if(*pErr == 0) + { + return (pItem); + } + + return (NULL); +} + +static int __onCMD_CFG_ADD_REQ(const char* pKeyName, const char* pKeyValue, int keyType) +{ + PCFG_ITEM pCfgItem = NULL; + int ret; + + if(pKeyName == NULL || pKeyValue == NULL || strlen(pKeyName) == 0 || strlen(pKeyValue) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + if(keyType < 0 || keyType > CFG_TYPE_DOUBLE) + { + return (-ERR_INPUT_PARAMS); + } + + ret = __cfgMsg2CfgItemV2(keyType, pKeyName, pKeyValue, &pCfgItem); + + if(ret != 0) + { + return (ret); + } + + return CfgAddKeyValue(pKeyName, pCfgItem, TRUE); +} + +static void __cfgSvrProcessCmd(DBUS_CMD cmd, const char* pKeyName, const char* pKeyValue, int keyType, PCFG_API_RSP pRsp) +{ + PCFG_ITEM pItem = NULL; + int err; + + memset(pRsp, 0, sizeof(CFG_API_RSP)); + pRsp->errNo = -ERR_UNKNOWN_TYPE; + + if(pKeyName == NULL) + { + pRsp->errNo = -ERR_INPUT_PARAMS; + return; + } + + strncpy(pRsp->keyName, pKeyName, MAX_CFG_KEY_NAME); + + switch(cmd) + { + case CMD_CFG_ADD_REQ: + err = __onCMD_CFG_ADD_REQ(pKeyName, pKeyValue, keyType); + + pRsp->keyType = keyType; + pRsp->errNo = err; + strncpy(pRsp->keyName, pKeyName, MAX_CFG_KEY_NAME); + strncpy(pRsp->keyValue, pKeyValue, MAX_CFG_KEY_VALUE); + + break; + + case CMD_CFG_GET_REQ: + + pItem = __onCMD_CFG_GET_REQ(pKeyName, &err); + + if(pItem == NULL || err != 0) + { + pRsp->keyType = -1; + pRsp->errNo = err; + strncpy(pRsp->keyName, pKeyName, MAX_CFG_KEY_NAME); + return; + } + else + { + __cfgItem2CfgRsp(pItem, pRsp); + return; + } + + break; + } + + return; +} + +int CfgGlobalEnvInit(void) +{ + int rc = 0; + + uv_rwlock_init(&g_uvHashRwLock); + + rc = __cfgCreateCfgFile(GLOBAL_CFG_FILE_PATH); + + if(rc != SQLITE_OK) + { + return rc; + } + +#if 0 + rc = sqlite3_open_v2(":memory:", &g_pSqlMemDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Memory SQLite3 DB Error\n"); + return -ERR_CREATE_SQLITE3_DB; + } + + //rc = sqlite3SyncDatabase(g_pSqlMemDB, GLOBAL_CFG_FILE_PATH, 0); +#endif + rc = __cfgLoadGlobalConfig(); + + if(rc != SQLITE_OK) + { + return (-ERR_OPEN_SQLITE3_DB); + //sqlite3_close(g_pSqlFileDB); + } + +#if 0 + g_bIsCfgSvr = cfgCheckCfgSvrRun(); + + if(atexit(onProgressExit) != 0) + { + fprintf(stderr, "atexit error\n"); + } + + signal(SIGINT, onSigTermProgressExit); +#endif + + __cfgStartSyncGlobalCfgSvr(); + + return 0; +} + +void OnCfgMsgProcess(MODULE_NAME dest, DBUS_CMD busCmd, const char* pJsonStr) +{ + CFG_API_RSP cfgRsp; + int err = 0; + PCFG_API_REQ pReq = NULL; + PCFG_API_RSP pRsp = NULL; + PLIBUV_DBUS_PARAMS pParams = DBusLibuvGetRuntime(); + + switch(busCmd) + { + case CMD_CFG_ADD_REQ: + case CMD_CFG_GET_REQ: + pReq = Json2Struct(pJsonStr, JSON_ENGINE_CFG_REQ, TRUE, &err); + + if(pReq != NULL && err == 0) + { + pRsp = &cfgRsp; + __cfgSvrProcessCmd(busCmd, pReq->keyName, pReq->keyValue, pReq->keyType, pRsp); + DBusJsonSendToCommand(NULL, g_pModInfoTable[dest].modAliase, busCmd + 1, JSON_ENGINE_CFG_RSP, pRsp, TRUE); + } + + free(pReq); + break; +#if 0 + case CMD_CFG_GET_REQ: + pReq = Json2Struct(pJsonStr, JSON_ENGINE_CFG_REQ, TRUE, &err); + + if(pReq != NULL && err == 0) + { + pRsp = &cfgRsp; + __cfgSvrProcessCmd(busCmd, pReq->keyName, NULL, pReq->keyType, pRsp); + DBusJsonSendToCommand(NULL, g_pModInfoTable[dest].modAliase, CMD_CFG_GET_RSP, JSON_ENGINE_CFG_RSP, pRsp, TRUE); + } + break; +#endif + case CMD_CFG_ADD_RSP: + case CMD_CFG_GET_RSP: + pRsp = Json2Struct(pJsonStr, JSON_ENGINE_CFG_RSP, TRUE, &err); + + if(pRsp != NULL && err == 0 && pRsp->errNo == 0) + { + // Add to local Hash Table cache + PCFG_ITEM pCfgItem = __cfgAddItem(pRsp->keyName, pRsp->keyValue, pRsp->keyType, TRUE, FALSE, &err); + + if(err == 0 && pCfgItem != NULL) + { + if(pParams->onCfgCb) + { + pParams->onCfgCb(busCmd, pCfgItem, 0); + } + } + else + { + LOG_EX(LOG_Error, "Add Configure {[%s]<%d> = \"%s\"} Error: %d\n", + pRsp->keyName, pRsp->keyValue, pRsp->keyType, err); + } + } + else + { + if(pParams->onCfgCb) + { + pParams->onCfgCb(busCmd, NULL, (err == 0) ? pRsp->errNo : err); + } + + LOG_EX(LOG_Error, "pRsp = %p, err = %d, rspErr = %d\n", pRsp, err, pRsp ? pRsp->errNo : -err); + } + + free(pRsp); + break; + } +} diff --git a/app/libuvdbus/src/Framework/Configure/ini_prase.c b/app/libuvdbus/src/Framework/Configure/ini_prase.c new file mode 100644 index 0000000..3542f87 --- /dev/null +++ b/app/libuvdbus/src/Framework/Configure/ini_prase.c @@ -0,0 +1,289 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" +#include "server_addr.h" + +#ifdef PLATFORM_R16 +#define DEVICE_CFG_FILE ("/mnt/UDISK/dev.conf") +#else +#define DEVICE_CFG_FILE ("./dev.conf") +#endif + +static config_t g_cfgInfo; + +void InitCfgToCfgFile(config_t* pCfg) +{ + config_setting_t *pRoot, *pSetting, *pGlobalgrp, *pLogGrp, *pSubGrp; + + if(pCfg == NULL) + { + return; + } + + pRoot = config_root_setting(pCfg); + + pGlobalgrp = config_setting_add(pRoot, "Global", CONFIG_TYPE_GROUP); + + pSetting = config_setting_add(pGlobalgrp, "ServerMode", CONFIG_TYPE_INT); + config_setting_set_int(pSetting, PUBLISH_MODE); + + pLogGrp = config_setting_add(pGlobalgrp, "Log", CONFIG_TYPE_GROUP); + + pSetting = config_setting_add(pLogGrp, "Enable", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, TRUE); + + pSetting = config_setting_add(pLogGrp, "Level", CONFIG_TYPE_INT); + config_setting_set_format(pSetting, CONFIG_FORMAT_HEX); + config_setting_set_int(pSetting, 0x000003FF); + + pSubGrp = config_setting_add(pLogGrp, "LogToEMail", CONFIG_TYPE_GROUP); + pSetting = config_setting_add(pSubGrp, "Enable", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, FALSE); + pSetting = config_setting_add(pSubGrp, "EMail", CONFIG_TYPE_STRING); + config_setting_set_string(pSetting, "pv1_es2@163.com"); + + pSetting = config_setting_add(pLogGrp, "LogToFile", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, TRUE); + + pSetting = config_setting_add(pLogGrp, "LogToServer", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, TRUE); + + pSubGrp = config_setting_add(pLogGrp, "LogToUDPServer", CONFIG_TYPE_GROUP); + pSetting = config_setting_add(pSubGrp, "Enable", CONFIG_TYPE_BOOL); + config_setting_set_bool(pSetting, FALSE); + pSetting = config_setting_add(pSubGrp, "UdpServerIp", CONFIG_TYPE_STRING); + config_setting_set_string(pSetting, "10.240.84.163"); + pSetting = config_setting_add(pSubGrp, "UdpBasePort", CONFIG_TYPE_INT); + config_setting_set_int(pSetting, 10000); + + + if(!config_write_file(pCfg, DEVICE_CFG_FILE)) + { + LOG_EX(LOG_Error, "Create Configure File %s Error\n", DEVICE_CFG_FILE); + } +} + +int CfgGetIntValueV2(const char* pTags, int defValue, int* pErr) +{ + char* pSvrMode = NULL; + char cmdBuf[MAX_PATH]; + int iValue = defValue; + + memset(cmdBuf, 0, MAX_PATH); + + sprintf(cmdBuf, "cat %s | grep %s | awk '{print $3}' | cut -d \";\" -f 1", + DEVICE_CFG_FILE, + pTags); + + GetShellExecResult(cmdBuf, &pSvrMode); + + if(pSvrMode == NULL) + { + if(pErr) + { + *pErr = -ERR_NO_ITEMS; + } + return defValue; + } + + iValue = strtol(pSvrMode, NULL, 10); + free(pSvrMode); + + if(errno == EINVAL || errno == ERANGE) + { + if(pErr) + { + *pErr = -ERR_STR_CONVERT; + } + + return defValue; + } + + if(pErr) + { + *pErr = 0; + } + return iValue; +} + +int CfgGetIntValueV1(const char* pTags, int defValue, int* pErr) +{ + int iValue = defValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + if(pErr) + { + *pErr = -ERR_INPUT_PARAMS; + } + + return defValue; + } + + if(!config_lookup_int(&g_cfgInfo, pTags, &iValue)) + { + if(pErr) + { + *pErr = -ERR_READ_FILE; + } + + return defValue; + } + + *pErr = 0; + + return iValue; +} + +int CfgGetIntValue(const char* pTags, int defValue) +{ + int iValue = defValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return defValue; + } + + if(!config_lookup_int(&g_cfgInfo, pTags, &iValue)) + { + return defValue; + } + + return iValue; +} + +void CfgSetIntValue(const char* pTags, int iValue) +{ + config_setting_t *pRoot, *pGlobalgrp, *pSet; + + LOG_EX(LOG_Debug, "Set: %s --> %d\n", pTags, iValue); + + if(pTags == NULL || strlen(pTags) == 0) + { + LOG_EX(LOG_Error, "Input Params error: pTags = [%s]\n", pTags ? pTags : "NULL"); + return; + } + + pRoot = config_root_setting(&g_cfgInfo); + + if(pRoot == NULL) + { + LOG_EX(LOG_Error, "pRoot = NULL\n"); + return; + } + + pGlobalgrp = config_setting_get_member(pRoot, "Global"); + + if(pGlobalgrp == NULL) + { + LOG_EX(LOG_Error, "pGlobalgrp = NULL\n"); + return; + } + + pSet = config_setting_get_member(pGlobalgrp, pTags); + + if(!pSet) + { + pSet = config_setting_add(pGlobalgrp, pTags, CONFIG_TYPE_INT); + } + + if(pSet == NULL) + { + LOG_EX(LOG_Error, "pSet = NULL\n"); + return; + } + + config_setting_set_int(pSet, iValue); + + + if(!config_write_file(&g_cfgInfo, DEVICE_CFG_FILE)) + { + LOG_EX(LOG_Error, "Set %s Value Error\n", pTags); + } +} + +char* CfgGetStringValue(const char* pTags, char* pDefValue) +{ + char* pValue = pDefValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return pDefValue; + } + + if(!config_lookup_string(&g_cfgInfo, pTags, (const char**)&pValue)) + { + return pDefValue; + } + + return pValue; +} + +double CfgGetFloatValue(const char* pTags, double defValue) +{ + double dValue = defValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return defValue; + } + + if(!config_lookup_float(&g_cfgInfo, pTags, &dValue)) + { + return defValue; + } + + return dValue; +} + +int CfgGetBoolValue(const char* pTags, int defValue) +{ + int iValue = defValue; + + if(pTags == NULL || strlen(pTags) == 0) + { + return defValue; + } + + if(!config_lookup_bool(&g_cfgInfo, pTags, &iValue)) + { + return defValue; + } + + return iValue; +} + +void CfgFileInit(void) +{ + //config_setting_t *pRoot, *pSetting; + + config_init(&g_cfgInfo); + +#if 0 + config_set_options(&g_cfgInfo, + (CONFIG_OPTION_SEMICOLON_SEPARATORS + | CONFIG_OPTION_COLON_ASSIGNMENT_FOR_GROUPS + | CONFIG_OPTION_OPEN_BRACE_ON_SEPARATE_LINE)); +#endif + + config_set_tab_width(&g_cfgInfo, 4); + + if(access(DEVICE_CFG_FILE, F_OK) != 0) + { + InitCfgToCfgFile(&g_cfgInfo); + } + else if(!config_read_file(&g_cfgInfo, DEVICE_CFG_FILE)) + { + LOG_EX(LOG_Error, "Read Configure File %s Error\n", DEVICE_CFG_FILE); + return; + } +} diff --git a/app/libuvdbus/src/Framework/Crypto/aes.c b/app/libuvdbus/src/Framework/Crypto/aes.c new file mode 100644 index 0000000..afff0ac --- /dev/null +++ b/app/libuvdbus/src/Framework/Crypto/aes.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include + +#include "log.h" +#include "smart_sound.h" +#include "crypto.h" +#include "libuv_dbus.h" + +int EvpAESEncrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey) +{ + int enBytes = 0; + EVP_CIPHER_CTX ctx; + //int decDataLen = 0; + if(!pInBuf || !pOutBuf || !pOutSize || !pKey) + { + return -ERR_INPUT_PARAMS; + } + + *pOutSize = 0; + //decDataLen = ((iSize + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + + EVP_CIPHER_CTX_init(&ctx); + + if(EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, pKey, NULL) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptInit_ex Error\n"); + return -ERR_EVP_INIT_KEY; + } + + if(EVP_EncryptUpdate(&ctx, pOutBuf, &enBytes, pInBuf, iSize) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptUpdate Error\n"); + return -ERR_EVP_UPDATE; + } + + pOutBuf += enBytes; + pInBuf += enBytes; + *pOutSize += enBytes; + + if(EVP_EncryptFinal_ex(&ctx, pOutBuf, &enBytes) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptFinal_ex Error\n"); + return -ERR_EVP_FINALE; + } + + *pOutSize += enBytes; + + EVP_CIPHER_CTX_cleanup(&ctx); + + return 0; +} + +int EvpAESDecrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey) +{ + int deBytes = 0; + EVP_CIPHER_CTX ctx; + + if(!pInBuf || !pOutBuf || !pOutSize || !pKey) + { + return -ERR_INPUT_PARAMS; + } + + EVP_CIPHER_CTX_init(&ctx); + + *pOutSize = 0; + + if(EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, pKey, NULL) == 0) + { + LOG_EX(LOG_Error, "EVP_DecryptInit_ex Error\n"); + return -ERR_EVP_INIT_KEY; + } + + if(EVP_DecryptUpdate(&ctx, pOutBuf, &deBytes, pInBuf, iSize) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptUpdate Error\n"); + return -ERR_EVP_UPDATE; + } + + pOutBuf += deBytes; + pInBuf += deBytes; + *pOutSize += deBytes; + + if(EVP_DecryptFinal_ex(&ctx, pOutBuf, &deBytes) == 0) + { + LOG_EX(LOG_Error, "EVP_EncryptFinal_ex Error\n"); + return -ERR_EVP_FINALE; + } + + *pOutSize += deBytes; + EVP_CIPHER_CTX_cleanup(&ctx); + + return 0; +} + diff --git a/app/libuvdbus/src/Framework/Crypto/base64.c b/app/libuvdbus/src/Framework/Crypto/base64.c new file mode 100644 index 0000000..6941073 --- /dev/null +++ b/app/libuvdbus/src/Framework/Crypto/base64.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +#include "log.h" +#include "crypto.h" + +const char* EvpBase64Encode(const char* pSrc) +{ + EVP_ENCODE_CTX ctx; + int enSize = 0; + int sLen, size; + char* pEncode = NULL; + + if(pSrc == NULL || strlen(pSrc) == 0) + { + return (NULL); + } + + sLen = strlen(pSrc); + size = ((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64; + + pEncode = (char*)malloc(size); + memset(pEncode, 0, size); + + EVP_EncodeInit(&ctx); + EVP_EncodeUpdate(&ctx, pEncode, &enSize, pSrc, strlen(pSrc)); + EVP_EncodeFinal(&ctx, pEncode + enSize, &enSize); + +// fprintf(stdout, "Src: \n[%s]\n", pSrc); +// fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode); + + return pEncode; +} + +const char* EvpBase64Decode(const char* pBase64) +{ + EVP_ENCODE_CTX ctx; + int enSize = 0; + int size = 0; + char *pDecode = NULL; + + if(pBase64 == NULL || strlen(pBase64) == 0) + { + return (NULL); + } + + size = strlen(pBase64); + pDecode = (char*)malloc(size); + memset(pDecode, 0, size); + + EVP_DecodeInit(&ctx); + EVP_DecodeUpdate(&ctx, pDecode, &enSize, pBase64, strlen(pBase64)); + EVP_DecodeFinal(&ctx, pDecode + enSize, &enSize); + +// fprintf(stdout, "Decode(%d --> %d) Bytes: \n[%s]\n", size, strlen(pDecode), pDecode); + + return pDecode; +} + +const char* EvpBase64EncodeNoAlign(const char* pSrc) +{ + int size, sLen; + char* pEncode = NULL; + + if(pSrc == NULL || strlen(pSrc) == 0) + { + return (NULL); + } + + sLen = strlen(pSrc); + size = ((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64; + + pEncode = (char*)malloc(size); + memset(pEncode, 0, size); + + EVP_EncodeBlock(pEncode, (const unsigned char *)pSrc, sLen); +// fprintf(stdout, "Src: \n[%s]\n", pSrc); +// fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode); + + return pEncode; +} + +const char* EvpBase64EncodeNoAlignV2(unsigned char* pSrc, int sLen) +{ + int size; + char* pEncode = NULL; + + if(pSrc == NULL || sLen <= 0) + { + return (NULL); + } + + size = ((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64; + + pEncode = (char*)malloc(size); + memset(pEncode, 0, size); + + EVP_EncodeBlock(pEncode, (const unsigned char *)pSrc, sLen); +// fprintf(stdout, "Src: \n[%s]\n", pSrc); +// fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode); + + return pEncode; +} + +const char* EvpBase64DecodeNoAlign(const char *pBase64) +{ + int size = 0; + char *pDecode = NULL; + + if(pBase64 == NULL || strlen(pBase64) == 0) + { + return (NULL); + } + + size = strlen(pBase64); + + pDecode = (char*)malloc(size); + memset(pDecode, 0, size); + + //CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); + EVP_DecodeBlock(pDecode, (const unsigned char *)pBase64, size); + //CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); + +// fprintf(stdout, "Decode(%d --> %d) Bytes: \n[%s]\n", size, strlen(pDecode), pDecode); + + return pDecode; +} + +unsigned char* EvpBase64DecodeNoAlignV2(const char *pBase64, int* pOutSize) +{ + int size = 0; + unsigned char *pDecode = NULL; + + if(pBase64 == NULL || strlen(pBase64) == 0) + { + return (NULL); + } + + size = strlen(pBase64); + + pDecode = (char*)malloc(size); + memset(pDecode, 0, size); + + //CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); + size = EVP_DecodeBlock(pDecode, (const unsigned char *)pBase64, size); + //CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); + +// fprintf(stdout, "Decode(%d --> %d) Bytes: \n[%s]\n", size, strlen(pDecode), pDecode); + + if(pOutSize) + { + *pOutSize = size; + } + + return (pDecode); +} diff --git a/app/libuvdbus/src/Framework/Crypto/crypto.c b/app/libuvdbus/src/Framework/Crypto/crypto.c new file mode 100644 index 0000000..226f1a3 --- /dev/null +++ b/app/libuvdbus/src/Framework/Crypto/crypto.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include + +#include "log.h" +#include "smart_sound.h" +#include "crypto.h" +#include "libuv_dbus.h" + +static uv_mutex_t *pEvpMutex = NULL; +typedef struct +{ + CRYPTO_TYPE type; + unsigned char* pInData; + int iInSize; + unsigned char* pOutData; + unsigned char pKey[EVP_MAX_KEY_LENGTH + 1]; + OnEVPCrypto onEvpEventCb; +} CRYPT_TASK_PARAMS, *PCRYPT_TASK_PARAMS; + +static void FreeEVPWorkCb(uv_work_t* pWork, int status) +{ + PCRYPT_TASK_PARAMS pTask = (PCRYPT_TASK_PARAMS)pWork->data; + free(pTask->pInData); + free(pTask); + free(pWork); +} + +static void OnEVPWorkCb(uv_work_t* pWork) +{ + PCRYPT_TASK_PARAMS pTask = (PCRYPT_TASK_PARAMS)pWork->data; + int iOutSize = 0; + int iError = 0; + + switch(pTask->type) + { + case CRYPTO_AES_ENCRYPT: + iError = EvpAESEncrypto(pTask->pInData, + pTask->iInSize, + pTask->pOutData, + &iOutSize, + pTask->pKey); + break; + + case CRYPTO_AES_DECRYPT: + iError = EvpAESDecrypto(pTask->pInData, + pTask->iInSize, + pTask->pOutData, + &iOutSize, + pTask->pKey); + break; + + case CRYPTO_BASE64_ENCODE: + pTask->pOutData = (unsigned char*)EvpBase64Encode((const char*)pTask->pInData); + iOutSize = strlen((char*)pTask->pOutData); + break; + + case CRYPTO_BASE64_DECODE: + pTask->pOutData = (unsigned char*)EvpBase64Decode((const char*)pTask->pInData); + iOutSize = strlen((char*)pTask->pOutData); + break; + + case CRYPTO_MD5_FILE: + pTask->pOutData = (unsigned char*)EvpMD5HashFile((const char*)pTask->pInData); + iOutSize = strlen((char*)pTask->pOutData); + break; + + default: + iError = -ERR_UNSUP_EVP_TYPE; + } + + if(iError != 0) + { + pTask->onEvpEventCb(pTask->type, pTask->pOutData, 0, pTask->pInData, iError); + } + else + { + pTask->onEvpEventCb(pTask->type, pTask->pOutData, iOutSize, pTask->pInData, 0); + } +} + +int EvpAddCryptoTask(CRYPTO_TYPE type, + unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + char* pKey, + OnEVPCrypto onEvpCryptCb) +{ + uv_work_t* puvWork = NULL; + PCRYPT_TASK_PARAMS pTask = NULL; + PLIBUV_DBUS_PARAMS pContext = DBusLibuvGetRuntime(); + + if(!pContext || !onEvpCryptCb) + { + return -ERR_INPUT_PARAMS; + } + + if(type == CRYPTO_AES_ENCRYPT || type == CRYPTO_AES_DECRYPT) + { + if(pKey == NULL || pOutBuf == NULL) + { + return -ERR_INPUT_PARAMS; + } + + switch(strlen(pKey) * 8) + { + case 128: + case 192: + case 256: + break; + default: + return -ERR_EVP_KEY_SIZE; + } + } + else if(type == CRYPTO_MD5_FILE) + { + uv_fs_t uvFs; + if(uv_fs_access(pContext->pLoop, &uvFs, (const char*)pInBuf, F_OK, NULL) != 0) + { + return -ERR_FILE_NOT_EXISTS; + } + } + + pTask = (PCRYPT_TASK_PARAMS)malloc(sizeof(CRYPT_TASK_PARAMS)); + puvWork = (uv_work_t*)malloc(sizeof(uv_work_t)); + + puvWork->data = (void*)pTask; + + pTask->type = type; + pTask->pInData = (unsigned char*)malloc(iSize + 1); + pTask->iInSize = iSize; + pTask->pOutData = pOutBuf; + pTask->onEvpEventCb = onEvpCryptCb; + + memset(pTask->pInData, 0, iSize + 1); + memset(pTask->pKey, 0, EVP_MAX_KEY_LENGTH + 1); + + if(pKey) + { + strncpy(pTask->pKey, pKey, EVP_MAX_KEY_LENGTH); + } + + memcpy(pTask->pInData, pInBuf, iSize); + + uv_queue_work(pContext->pLoop, puvWork, OnEVPWorkCb, FreeEVPWorkCb); + + return 0; +} + +static void __evpLockCb(int mode, int n, const char *pFile, int line) +{ + if(n >= CRYPTO_num_locks()) + { + return; + } + + if(mode & CRYPTO_LOCK) + { + uv_mutex_lock(&pEvpMutex[n]); + } + else + { + uv_mutex_unlock(&pEvpMutex[n]); + } +} + + +static unsigned long __evpIdCb(void) +{ + return ((unsigned long)uv_thread_self()); +} + +void EvpSystemInit(void) +{ + int i = 0; + + pEvpMutex = (uv_mutex_t *)malloc(CRYPTO_num_locks() * sizeof(uv_mutex_t)); + + for(i = 0; i < CRYPTO_num_locks(); i++) + { + uv_mutex_init(&pEvpMutex[i]); + } + + CRYPTO_set_id_callback(__evpIdCb); + CRYPTO_set_locking_callback(__evpLockCb); +} diff --git a/app/libuvdbus/src/Framework/Crypto/md5.c b/app/libuvdbus/src/Framework/Crypto/md5.c new file mode 100644 index 0000000..655e7b0 --- /dev/null +++ b/app/libuvdbus/src/Framework/Crypto/md5.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "crypto.h" +#include "libuv_dbus.h" + +const char* EvpMD5HashFile(const char* pFileName) +{ + int rdSize = 0; + int fd, size; + uint8_t md5[EVP_MAX_MD_SIZE]; + uint8_t buf[1024]; + EVP_MD_CTX ctx; + char* pString = NULL; + + memset(md5, 0, EVP_MAX_MD_SIZE); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + + fd = open(pFileName, O_RDONLY); + + if(fd == -1) + { + LOG_EX(LOG_Error, "Open File \'%s\' error\n", pFileName); + return NULL; + } + do + { + rdSize = read(fd, buf, 1024); + + if(rdSize > 0) + { + EVP_DigestUpdate(&ctx, buf, rdSize); + } + } while(rdSize > 0); + + close(fd); + + EVP_DigestFinal_ex(&ctx, md5, &rdSize); + EVP_MD_CTX_cleanup(&ctx); + + size = rdSize * 2 + 1; + + pString = (char*)malloc(size); + memset(pString, 0, size); + + IHW_bin2hex(pString, md5, rdSize); + +// print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, md5, rdSize); +// fprintf(stdout, "MD5: [%s]\n", pString); + + return (const char*)pString; +} + +int EvpMD5HashFileV2(const char* pFileName, unsigned char md5[16]) +{ + int rdSize = 0; + int fd; + uint8_t buf[1024]; + EVP_MD_CTX ctx; + //char* pString = NULL; + + memset(md5, 0, 16); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + + fd = open(pFileName, O_RDONLY); + + if(fd == -1) + { + LOG_EX(LOG_Error, "Open File %s error\n", pFileName); + return (-ERR_OPEN_FILE); + } + do + { + rdSize = read(fd, buf, 1024); + + EVP_DigestUpdate(&ctx, buf, rdSize); + } while(rdSize > 0); + + close(fd); + + EVP_DigestFinal_ex(&ctx, md5, &rdSize); + EVP_MD_CTX_cleanup(&ctx); + + +// print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, md5, rdSize); +// fprintf(stdout, "MD5: [%s]\n", pString); + + return 0; +} + +int EvpMD5HashBuf(const unsigned char* pBuf, int iBufLen, unsigned char* pOutBuf, int* pOutSize) +{ + EVP_MD_CTX ctx; + + if(pBuf == NULL || pOutBuf == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + memset(pOutBuf, 0, EVP_MAX_MD_SIZE); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + EVP_DigestUpdate(&ctx, pBuf, iBufLen); + EVP_DigestFinal_ex(&ctx, pOutBuf, &iBufLen); + EVP_MD_CTX_cleanup(&ctx); + + if(pOutSize) + { + *pOutSize = iBufLen; + } + + //print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, pOutBuf, iBufLen); + + return 0; +} + +const char* EvpMD5HashBufV2(const unsigned char* pBuf, int iBufLen) +{ + int size = 0; + EVP_MD_CTX ctx; + uint8_t md5[EVP_MAX_MD_SIZE]; + char* pString = NULL; + + if(pBuf == NULL || iBufLen <= 0) + { + return NULL; + } + + memset(md5, 0, EVP_MAX_MD_SIZE); + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + EVP_DigestUpdate(&ctx, pBuf, iBufLen); + EVP_DigestFinal_ex(&ctx, md5, &iBufLen); + EVP_MD_CTX_cleanup(&ctx); + + //print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, pOutBuf, iBufLen); + + size = iBufLen * 2 + 1; + + pString = (char*)malloc(size); + memset(pString, 0, size); + + IHW_bin2hex(pString, md5, iBufLen); + +// print_hex_dump_bytes("MD5_", DUMP_PREFIX_ADDRESS, md5, rdSize); +// fprintf(stdout, "MD5: [%s]\n", pString); + + return (const char*)pString; +} diff --git a/app/libuvdbus/src/Framework/Fifo/fifo.c b/app/libuvdbus/src/Framework/Fifo/fifo.c new file mode 100644 index 0000000..5fd3753 --- /dev/null +++ b/app/libuvdbus/src/Framework/Fifo/fifo.c @@ -0,0 +1,554 @@ +/* + * A generic kernel FIFO implementation + * + * Copyright (C) 2009/2010 Stefani Seibold + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#if 0 +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "fifo.h" + +#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +//#define EINVAL (1) +//#define ENOMEM (2) + +static inline int fls(int x); + +#if defined(PLATFORM_R16) || defined(PLATFORM_R311) +static inline int constant_fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +static int fls64(unsigned long long x) +{ + unsigned int h = x >> 32; + if (h) + return fls(h) + 32; + return fls(x); +} + +static inline int fls(int x) +{ + int ret; + + if (__builtin_constant_p(x)) + return constant_fls(x); + + asm("clz\t%0, %1" : "=r" (ret) : "r" (x)); + ret = 32 - ret; + return ret; +} +#endif + +#ifdef PLATFORM_CPU +#define __fls(x) (fls(x) - 1) +static __always_inline int fls64(unsigned long x) +{ + if (x == 0) + return 0; + return __fls(x) + 1; +} + +static inline int fls(int x) +{ + int r; + + long tmp = -1; + asm("bsrl %1,%0" + : "=r" (r) + : "rm" (x), "0" (tmp)); +#if 0 +#ifdef CONFIG_X86_64 + /* + * AMD64 says BSRL won't clobber the dest reg if x==0; Intel64 says the + * dest reg is undefined if x==0, but their CPU architect says its + * value is written to set it to the same as before, except that the + * top 32 bits will be cleared. + * + * We cannot do this on 32 bits because at the very least some + * 486 CPUs did not behave this way. + */ + long tmp = -1; + asm("bsrl %1,%0" + : "=r" (r) + : "rm" (x), "0" (tmp)); +#elif defined(CONFIG_X86_CMOV) + asm("bsrl %1,%0\n\t" + "cmovzl %2,%0" + : "=&r" (r) : "rm" (x), "rm" (-1)); +#else + asm("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n" + "1:" : "=r" (r) : "rm" (x)); +#endif +#endif + return r + 1; +} +#endif +/* + * internal helper to calculate the unused elements in a fifo + */ +static inline unsigned int kfifo_unused(struct __kfifo *fifo) +{ + return (fifo->mask + 1) - (fifo->in - fifo->out); +} + +static inline unsigned fls_long(unsigned long l) +{ + if (sizeof(l) == 4) + return fls(l); + return fls64(l); +} + +unsigned long roundup_pow_of_two(unsigned long n) +{ + return 1UL << (fls_long(n)); +} + +int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, unsigned int esize) +{ + /* + * round down to the next power of 2, since our 'let the indices + * wrap' technique works only in this case. + */ + if (!is_power_of_2(size)) + size = roundup_pow_of_two(size); + + fprintf(stdout, "+++++++++++kfifo malloc size = %u\n", size); + + fifo->in = 0; + fifo->out = 0; + fifo->esize = esize; + + if (size < 2) { + fifo->data = NULL; + fifo->mask = 0; + return -EINVAL; + } + + fifo->data = malloc(size * esize); + + if (!fifo->data) { + fifo->mask = 0; + return -ENOMEM; + } + fifo->mask = size - 1; + uv_mutex_init(&fifo->lock); + + return 0; +} + +void __kfifo_free(struct __kfifo *fifo) +{ + free(fifo->data); + fifo->in = 0; + fifo->out = 0; + fifo->esize = 0; + fifo->data = NULL; + fifo->mask = 0; +} + +int __kfifo_init(struct __kfifo *fifo, void *buffer, + unsigned int size, unsigned int esize) +{ + size /= esize; + + if (!is_power_of_2(size)) + size = roundup_pow_of_two(size); + + fifo->in = 0; + fifo->out = 0; + fifo->esize = esize; + fifo->data = buffer; + + if (size < 2) { + fifo->mask = 0; + return -EINVAL; + } + fifo->mask = size - 1; + uv_mutex_init(&fifo->lock); + + return 0; +} + +static void kfifo_copy_in(struct __kfifo *fifo, const void *src, + unsigned int len, unsigned int off) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + memcpy(fifo->data + off, src, l); + memcpy(fifo->data, src + l, len - l); + /* + * make sure that the data in the fifo is up to date before + * incrementing the fifo->in index counter + */ +// smp_wmb(); +} + +unsigned int __kfifo_in(struct __kfifo *fifo, + const void *buf, unsigned int len) +{ + unsigned int l; + + l = kfifo_unused(fifo); + if (len > l) + len = l; + + kfifo_copy_in(fifo, buf, len, fifo->in); + fifo->in += len; + return len; +} + +static void kfifo_copy_out(struct __kfifo *fifo, void *dst, + unsigned int len, unsigned int off) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + if (dst) { + memcpy(dst, fifo->data + off, l); + memcpy(dst + l, fifo->data, len - l); + } + /* + * make sure that the data is copied before + * incrementing the fifo->out index counter + */ +// smp_wmb(); +} + +unsigned int __kfifo_out_peek(struct __kfifo *fifo, + void *buf, unsigned int len) +{ + unsigned int l; + + l = fifo->in - fifo->out; + if (len > l) + len = l; + + kfifo_copy_out(fifo, buf, len, fifo->out); + return len; +} + +unsigned int __kfifo_out(struct __kfifo *fifo, + void *buf, unsigned int len) +{ + len = __kfifo_out_peek(fifo, buf, len); + fifo->out += len; + return len; +} + +#if 0 +static unsigned long kfifo_copy_from_user(struct __kfifo *fifo, + const void *from, unsigned int len, unsigned int off, + unsigned int *copied) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + unsigned long ret; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + ret = memcpy(fifo->data + off, from, l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret + len - l, esize); + else { + ret = memcpy(fifo->data, from + l, len - l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret, esize); + } + /* + * make sure that the data in the fifo is up to date before + * incrementing the fifo->in index counter + */ +// smp_wmb(); + *copied = len - ret; + /* return the number of elements which are not copied */ + return ret; +} + +int __kfifo_from_user(struct __kfifo *fifo, const void __user *from, + unsigned long len, unsigned int *copied) +{ + unsigned int l; + unsigned long ret; + unsigned int esize = fifo->esize; + int err; + + if (esize != 1) + len /= esize; + + l = kfifo_unused(fifo); + if (len > l) + len = l; + + ret = kfifo_copy_from_user(fifo, from, len, fifo->in, copied); + if (unlikely(ret)) { + len -= ret; + err = -EFAULT; + } else + err = 0; + fifo->in += len; + return err; +} + +static unsigned long kfifo_copy_to_user(struct __kfifo *fifo, void __user *to, + unsigned int len, unsigned int off, unsigned int *copied) +{ + unsigned int l; + unsigned long ret; + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + + off &= fifo->mask; + if (esize != 1) { + off *= esize; + size *= esize; + len *= esize; + } + l = min(len, size - off); + + ret = memcpy(to, fifo->data + off, l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret + len - l, esize); + else { + ret = memcpy(to + l, fifo->data, len - l); + if (unlikely(ret)) + ret = DIV_ROUND_UP(ret, esize); + } + /* + * make sure that the data is copied before + * incrementing the fifo->out index counter + */ + //smp_wmb(); + *copied = len - ret; + /* return the number of elements which are not copied */ + return ret; +} + +int __kfifo_to_user(struct __kfifo *fifo, void __user *to, + unsigned long len, unsigned int *copied) +{ + unsigned int l; + unsigned long ret; + unsigned int esize = fifo->esize; + int err; + + if (esize != 1) + len /= esize; + + l = fifo->in - fifo->out; + if (len > l) + len = l; + ret = kfifo_copy_to_user(fifo, to, len, fifo->out, copied); + if (unlikely(ret)) { + len -= ret; + err = -EFAULT; + } else + err = 0; + fifo->out += len; + return err; +} +#endif + +unsigned int __kfifo_max_r(unsigned int len, unsigned int recsize) +{ + unsigned int max = (1 << (recsize << 3)) - 1; + + if (len > max) + return max; + return len; +} + +#define __KFIFO_PEEK(data, out, mask) \ + ((data)[(out) & (mask)]) +/* + * __kfifo_peek_n internal helper function for determinate the length of + * the next record in the fifo + */ +static unsigned int __kfifo_peek_n(struct __kfifo *fifo, unsigned int recsize) +{ + unsigned int l; + unsigned int mask = fifo->mask; + unsigned char *data = fifo->data; + + l = __KFIFO_PEEK(data, fifo->out, mask); + + if (--recsize) + l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8; + + return l; +} + +#define __KFIFO_POKE(data, in, mask, val) \ + ( \ + (data)[(in) & (mask)] = (unsigned char)(val) \ + ) + +/* + * __kfifo_poke_n internal helper function for storeing the length of + * the record into the fifo + */ +static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, unsigned int recsize) +{ + unsigned int mask = fifo->mask; + unsigned char *data = fifo->data; + + __KFIFO_POKE(data, fifo->in, mask, n); + + if (recsize > 1) + __KFIFO_POKE(data, fifo->in + 1, mask, n >> 8); +} + +unsigned int __kfifo_len_r(struct __kfifo *fifo, unsigned int recsize) +{ + return __kfifo_peek_n(fifo, recsize); +} + +unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf, + unsigned int len, unsigned int recsize) +{ + if (len + recsize > kfifo_unused(fifo)) + return 0; + + __kfifo_poke_n(fifo, len, recsize); + + kfifo_copy_in(fifo, buf, len, fifo->in + recsize); + fifo->in += len + recsize; + return len; +} + +static unsigned int kfifo_out_copy_r(struct __kfifo *fifo, + void *buf, unsigned int len, unsigned int recsize, unsigned int *n) +{ + *n = __kfifo_peek_n(fifo, recsize); + + if (len > *n) + len = *n; + + kfifo_copy_out(fifo, buf, len, fifo->out + recsize); + return len; +} + +unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf, + unsigned int len, unsigned int recsize) +{ + unsigned int n; + + if (fifo->in == fifo->out) + return 0; + + return kfifo_out_copy_r(fifo, buf, len, recsize, &n); +} + +unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf, + unsigned int len, unsigned int recsize) +{ + unsigned int n; + + if (fifo->in == fifo->out) + return 0; + + len = kfifo_out_copy_r(fifo, buf, len, recsize, &n); + fifo->out += n + recsize; + return len; +} + +void __kfifo_skip_r(struct __kfifo *fifo, unsigned int recsize) +{ + unsigned int n; + + n = __kfifo_peek_n(fifo, recsize); + fifo->out += n + recsize; +} diff --git a/app/libuvdbus/src/Framework/HeartDaemon/heart_daemon.c b/app/libuvdbus/src/Framework/HeartDaemon/heart_daemon.c new file mode 100644 index 0000000..80e190b --- /dev/null +++ b/app/libuvdbus/src/Framework/HeartDaemon/heart_daemon.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include "log.h" +#include "libuv_dbus.h" + +typedef struct +{ + MODULE_NAME modName; + uint32_t hTm[MODULE_MAX]; + int isDaemonWork[MODULE_MAX]; + int isConnected[MODULE_MAX]; + OnDaemonMsg pOnHeartLostCb; +} HEART_DAEMON, *PHEART_DAEMON; + +uint32_t g_hblTout = HEART_LOST_DELAY; ///< nano second: heart lost timeout, default 1s +static uv_loop_t *g_DeamonLoop; +static uv_idle_t g_uvDeamonIdle; +static HEART_DAEMON g_heartDaemon; + +static unsigned int g_Cnt = 0; +static int timerExpire(uint32_t tm, uint32_t tExp) +{ + uint32_t now = LIBUV_CURRENT_TIME_MS(); + int64_t diff = now - tm; + + if(tm == 0 || tExp == 0) + { + return 0; + } + + if(diff > tExp * 1000) + { + return 0; + } + else if(diff >= tExp) + { + return 1; + } + + return (0); +} + +static void RunPingSvr(void) +{ + int ret = 0; + unsigned int tm = LIBUV_CURRENT_TIME_MS(); + PING_MSG pMsg; + struct timeval tv; + + gettimeofday(&tv, NULL); + + pMsg.PING = (double)tm / 1000; + pMsg.tmSec = tv.tv_sec; + pMsg.tmMSec = tv.tv_usec; + + ret = DBusJsonBoardcastCommand(NULL, 0xFFFFFFFF, CMD_MISC_PING, JSON_ENGINE_PING, &pMsg, FALSE); + + if(ret != 0) + { + LOG_EX(LOG_Error, "DBus boardcast message error: %d\n", ret); + } +} + +void HeartDaemonHblCheck(void) +{ + if(g_heartDaemon.modName != MODULE_CONTROLLER) + { + if(g_heartDaemon.isDaemonWork[MODULE_CONTROLLER] && timerExpire(g_heartDaemon.hTm[MODULE_CONTROLLER], g_hblTout)) + { + g_heartDaemon.pOnHeartLostCb(MODULE_CONTROLLER, TRUE); + g_heartDaemon.hTm[MODULE_CONTROLLER] = 0; + g_heartDaemon.isConnected[MODULE_CONTROLLER] = FALSE; + } + } + else + { + int i; + + for(i = 0; i < MODULE_MAX; i++) + { + if(g_heartDaemon.isDaemonWork[i] + && i != MODULE_CONTROLLER + && timerExpire(g_heartDaemon.hTm[i], g_hblTout)) + { + g_heartDaemon.pOnHeartLostCb(i, TRUE); + g_heartDaemon.hTm[i] = 0; + g_heartDaemon.isConnected[i] = FALSE; + } + } + } +} + +void HeartDaemonUpgrade(int iWatcher) +{ + if(iWatcher >= MODULE_MAX) + { + return; + } + + if(g_heartDaemon.hTm[iWatcher] == 0) + { + if(g_heartDaemon.modName == MODULE_CONTROLLER) + { + g_heartDaemon.pOnHeartLostCb(iWatcher, FALSE); + } + else if(iWatcher == MODULE_CONTROLLER) + { + g_heartDaemon.pOnHeartLostCb(iWatcher, FALSE); + } + + g_heartDaemon.isConnected[iWatcher] = TRUE; + RunPingSvr(); + } + + g_heartDaemon.hTm[iWatcher] = LIBUV_CURRENT_TIME_MS(); +} + +static int __isSendPingOnTime(void) +{ + static unsigned int tmPre = 0; + unsigned int tm = LIBUV_CURRENT_TIME_MS(); + unsigned int tmOut = HEART_SEND_DELAY; + + if(g_heartDaemon.modName != MODULE_CONTROLLER + && g_heartDaemon.isConnected[MODULE_CONTROLLER] == FALSE) + { + tmOut = 5000; + } + + if(tmPre != 0 && tm - tmPre < tmOut) + { + return (FALSE); + } + + tmPre = tm; + + return (TRUE); +} + +static void __uvIdleCb(uv_idle_t* phuvIdle) +{ + if(DBusLibuvGetRuntime()->onHblCb + && __isSendPingOnTime()) + { + RunPingSvr(); + } + + HeartDaemonHblCheck(); + sleep(1); +} + +static void __uvThreadDaemon(void *pParams) +{ + g_DeamonLoop = uv_loop_new(); + + uv_idle_init(g_DeamonLoop, &g_uvDeamonIdle); + uv_idle_start(&g_uvDeamonIdle, __uvIdleCb); + + uv_run(g_DeamonLoop, UV_RUN_DEFAULT); + + pthread_detach(pthread_self()); +} + +void HeartDaemonInit(MODULE_NAME mod, int msHblTout, OnDaemonMsg cb) +{ + uv_thread_t uvDaemonThread; + int i; + + memset(&g_heartDaemon, 0, sizeof(HEART_DAEMON)); + + if(msHblTout > 0) + { + g_hblTout = msHblTout; + } + + g_heartDaemon.modName = mod; + + for(i = 0; i < MODULE_MAX; i++) + { + if(mod == MODULE_CONTROLLER) + { + g_heartDaemon.isDaemonWork[i] = (g_pModInfoTable[i].modName != MODULE_CONTROLLER) ? TRUE : FALSE; + } + else + { + g_heartDaemon.isDaemonWork[i] = (g_pModInfoTable[i].modName == MODULE_CONTROLLER) ? TRUE : FALSE; + } + + g_heartDaemon.isConnected[i] = FALSE; + } + + g_heartDaemon.pOnHeartLostCb = cb; + + uv_thread_create(&uvDaemonThread, __uvThreadDaemon, NULL); +} diff --git a/app/libuvdbus/src/Framework/IoT/Boardlink/boardlink_iot.c b/app/libuvdbus/src/Framework/IoT/Boardlink/boardlink_iot.c new file mode 100644 index 0000000..0abd09b --- /dev/null +++ b/app/libuvdbus/src/Framework/IoT/Boardlink/boardlink_iot.c @@ -0,0 +1,181 @@ +#ifndef PLATFORM_CPU +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) || defined(PLATFORM_R311) +#include "log.h" +#include "libuv_dbus.h" +#include "boardlink_iot.h" +#else +#include +#include +#include +#endif + +#define BL_IOT_PROTO (30) +#define BL_MSG_BUF_MAX (1024 * 4) + +static int g_nlSock = -1; +static unsigned char g_MsgSendBuf[BL_MSG_BUF_MAX]; +static BlMsgCb g_blMsgCb = NULL; + +static void __recvMsgThread(void *pParam) +{ + unsigned char msgBuf[BL_MSG_BUF_MAX]; + struct iovec iov = {msgBuf, BL_MSG_BUF_MAX}; + struct nlmsghdr *pMsgHdr; + struct sockaddr_nl fromAddr; + struct msghdr msgHdr = {&fromAddr, sizeof(fromAddr), &iov, 1, NULL, 0, 0};; + + memset(&fromAddr, 0, sizeof(fromAddr)); + fromAddr.nl_family = AF_NETLINK; + fromAddr.nl_pid = 0; + fromAddr.nl_groups = 0; + + while(TRUE) + { + int len = recvmsg(g_nlSock, &msgHdr, 0); + + if(len > 0) + { + for(pMsgHdr = (struct nlmsghdr *)msgBuf; + NLMSG_OK(pMsgHdr, len); + pMsgHdr = NLMSG_NEXT(pMsgHdr, len)) + { + if(pMsgHdr->nlmsg_type == NLMSG_DONE) + { + continue; + } + else if(pMsgHdr->nlmsg_type == NLMSG_ERROR) + { + continue; + } + else + { + PBL_IOT_MSG pMsg = (PBL_IOT_MSG)NLMSG_DATA(pMsgHdr); + //LOG_EX(LOG_Debug, "Recv Message: %s\n", NLMSG_DATA(pMsgHdr)); + print_hex_dump_bytes("Msg", 0, pMsg, BL_IOT_MSG_LEN(pMsg->msglen)); + if(g_blMsgCb) + { + g_blMsgCb(pMsg); + } + } + } + } + + usleep(1000); + } + pthread_detach(pthread_self()); +} + +static int __nlCreateSocket(void) +{ + struct sockaddr_nl srcAddr; + + g_nlSock = socket(AF_NETLINK, SOCK_RAW, BL_IOT_PROTO); + + if(g_nlSock == -1) + { + LOG_EX(LOG_Error, "Create netlink socker error: %s\n", strerror(errno)); + return -ERR_CREATE_SOCKET; + } + + memset(&srcAddr, 0, sizeof(srcAddr)); + srcAddr.nl_family = AF_NETLINK; + srcAddr.nl_pid = getpid(); + srcAddr.nl_groups = 0; + + if(bind(g_nlSock, (struct sockaddr*)&srcAddr, sizeof(srcAddr)) < 0) + { + LOG_EX(LOG_Error, "Bind netlink socket failed: %s", strerror(errno)); + close(g_nlSock); + return -ERR_BIND_SOCKET; + } + + return 0; +} + +static int __sendMessage(unsigned char* pData, unsigned int len) +{ + struct iovec iov; + struct sockaddr_nl dstAddr; + struct nlmsghdr* pMsgHdr = (struct nlmsghdr*)g_MsgSendBuf; + struct msghdr msgHdr = {&dstAddr, sizeof(dstAddr), &iov, 1, NULL, 0, 0}; + + memset(&dstAddr, 0, sizeof(struct sockaddr_nl)); + dstAddr.nl_family = AF_NETLINK; + dstAddr.nl_pid = 0; + dstAddr.nl_groups = 0; + + memset(pMsgHdr, 0, BL_MSG_BUF_MAX); + pMsgHdr->nlmsg_len = len; + pMsgHdr->nlmsg_pid = getpid(); + pMsgHdr->nlmsg_flags = 0; + memcpy(NLMSG_DATA(pMsgHdr), pData, len); + + iov.iov_base = pMsgHdr; + iov.iov_len = NLMSG_SPACE(BL_MSG_BUF_MAX); + + return sendmsg(g_nlSock, &msgHdr, 0); +} + +int BL_SendBLMsg(BL_IOT_MSG_TYPE msgType, unsigned char* pData, unsigned int len) +{ + BL_IOT_MSG blMsg; + + memset(&blMsg, 0, sizeof(BL_IOT_MSG)); + blMsg.msgType = msgType; + blMsg.msglen = len; + strcpy(blMsg.msgTags, BL_IOT_MSG_TAGS); + + if(pData && len > 0) + { + memcpy(blMsg.msgData, pData, len); + } + + return __sendMessage((unsigned char*)&blMsg, BL_IOT_MSG_LEN(len)); +} + +int BL_SendBLMsgTo(BL_IOT_MSG_TYPE msgType, unsigned char* pData, unsigned int len, unsigned char dstMac[ETH_ALEN]) +{ + BL_IOT_MSG blMsg; + + memset(&blMsg, 0, sizeof(BL_IOT_MSG)); + blMsg.msgType = msgType; + blMsg.msglen = len; + memcpy(blMsg.dstMac, dstMac, ETH_ALEN); + strcpy(blMsg.msgTags, BL_IOT_MSG_TAGS); + + if(pData && len > 0) + { + memcpy(blMsg.msgData, pData, len); + } + + return __sendMessage((unsigned char*)&blMsg, BL_IOT_MSG_LEN(len)); +} + +int BL_Init(BlMsgCb cbOnMsg) +{ + int ret = 0; + uv_thread_t uvRecvThread; + + ret = __nlCreateSocket(); + + if(ret != 0) + { + return ret; + } + + g_blMsgCb = cbOnMsg; + + uv_thread_create(&uvRecvThread, __recvMsgThread, NULL); + + return 0; +} +#endif diff --git a/app/libuvdbus/src/Framework/JsonUtils/json_struct.c b/app/libuvdbus/src/Framework/JsonUtils/json_struct.c new file mode 100644 index 0000000..c9be8c3 --- /dev/null +++ b/app/libuvdbus/src/Framework/JsonUtils/json_struct.c @@ -0,0 +1,1218 @@ +#include +#include +#include +#include + +#include "log.h" +#include "smart_sound.h" +#include "libuv_dbus.h" +#include "json_struct.h" +#include "crypto.h" +#include "ota.h" +#include "assistant.h" + +typedef const char* (*StructToJsonCb)(void* pStruct); +typedef void* (*JsonToStructCb)(const char* pJsonStr); +typedef void (*Base64Code)(void *pStruct, int enCode); + +typedef struct +{ + JSON_ENGINE_TYPE typeId; + StructToJsonCb s2jCb; + JsonToStructCb j2sCb; + Base64Code base64Cb; +} JSON_ENGINE, *PJSON_ENGINE; + +static const char* __ping_MSG2Json(void* pData) +{ + PPING_MSG pReq = (PPING_MSG)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, double, PING); + s2j_json_set_basic_element(jObject, pReq, int, tmSec); + s2j_json_set_basic_element(jObject, pReq, int, tmMSec); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2PING_MSG(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, PING_MSG); + + memset(sObject, 0, sizeof(PING_MSG)); + + s2j_struct_get_basic_element(sObject, pJson, double, PING); + s2j_struct_get_basic_element(sObject, pJson, int, tmSec); + s2j_struct_get_basic_element(sObject, pJson, int, tmMSec); + + cJSON_Delete(pJson); + + return sObject; +} + +static const char* __cfg_API_REQ2Json(void* pData) +{ + PCFG_API_REQ pReq = (PCFG_API_REQ)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, string, keyName); + s2j_json_set_basic_element(jObject, pReq, string, keyValue); + s2j_json_set_basic_element(jObject, pReq, int, keyType); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2CFG_API_REQ(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, CFG_API_REQ); + + memset(sObject, 0, sizeof(CFG_API_REQ)); + + s2j_struct_get_basic_element(sObject, pJson, string, keyName); + s2j_struct_get_basic_element(sObject, pJson, string, keyValue); + s2j_struct_get_basic_element(sObject, pJson, int, keyType); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __cfg_API_REQBase64(void *pData, int enCode) +{ + PCFG_API_REQ pReq = (PCFG_API_REQ)pData; + + if(enCode) + { + if(strlen(pReq->keyName) > 0) + { + char* pBase64 = (char *)EvpBase64Encode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char* pBase64 = (char *)EvpBase64Encode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->keyName) > 0) + { + + char *pBase64 = (char *)EvpBase64Decode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } +} + +static const char* __cfg_API_RSP2Json(void* pData) +{ + PCFG_API_RSP pReq = (PCFG_API_RSP)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, string, keyName); + s2j_json_set_basic_element(jObject, pReq, string, keyValue); + s2j_json_set_basic_element(jObject, pReq, int, keyType); + s2j_json_set_basic_element(jObject, pReq, int, errNo); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2CFG_API_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, CFG_API_RSP); + + memset(sObject, 0, sizeof(CFG_API_RSP)); + + s2j_struct_get_basic_element(sObject, pJson, string, keyName); + s2j_struct_get_basic_element(sObject, pJson, string, keyValue); + s2j_struct_get_basic_element(sObject, pJson, int, keyType); + s2j_struct_get_basic_element(sObject, pJson, int, errNo); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __cfg_API_RSPBase64(void *pData, int enCode) +{ + PCFG_API_RSP pReq = (PCFG_API_RSP)pData; + + if(enCode) + { + if(strlen(pReq->keyName) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->keyName) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->keyName); + memset(pReq->keyName, 0, MAX_CFG_KEY_NAME); + strcpy(pReq->keyName, pBase64); + free(pBase64); + } + + if(strlen(pReq->keyValue) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->keyValue); + memset(pReq->keyValue, 0, MAX_CFG_KEY_VALUE); + strcpy(pReq->keyValue, pBase64); + free(pBase64); + } + } +} + +static const char* __player_TO_CTRL2Json(void* pData) +{ + PPLAYER_TO_CTRL pP2C = (PPLAYER_TO_CTRL)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pP2C, string, musicUuid); + s2j_json_set_basic_element(jObject, pP2C, int, plySt); + s2j_json_set_basic_element(jObject, pP2C, int, curPos); + s2j_json_set_basic_element(jObject, pP2C, int, duration); + + s2j_json_set_basic_element(jObject, pP2C, int, playerId); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2PLAYER_TO_CTRL(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, PLAYER_TO_CTRL); + + memset(sObject, 0, sizeof(PLAYER_TO_CTRL)); + + s2j_struct_get_basic_element(sObject, pJson, string, musicUuid); + s2j_struct_get_basic_element(sObject, pJson, int, plySt); + s2j_struct_get_basic_element(sObject, pJson, int, curPos); + s2j_struct_get_basic_element(sObject, pJson, int, duration); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __player_TO_CTRLBase64(void *pData, int enCode) +{ + PPLAYER_TO_CTRL pReq = (PPLAYER_TO_CTRL)pData; + + if(enCode) + { + if(strlen(pReq->musicUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->musicUuid); + memset(pReq->musicUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->musicUuid, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->musicUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->musicUuid); + memset(pReq->musicUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->musicUuid, pBase64); + free(pBase64); + } + } +} + +static const char* __ctrl_TO_PLAYER2Json(void* pData) +{ + PCTRL_TO_PLAYER pC2P = (PCTRL_TO_PLAYER)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pC2P, string, src); + s2j_json_set_basic_element(jObject, pC2P, string, srcUuid); + s2j_json_set_basic_element(jObject, pC2P, string, ttsText); + s2j_json_set_basic_element(jObject, pC2P, int, skTime); + s2j_json_set_basic_element(jObject, pC2P, int, plyMode); + s2j_json_set_basic_element(jObject, pC2P, int, plyListType); + s2j_json_set_basic_element(jObject, pC2P, int, adSrcType); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static void* __json2CTRL_TO_PLAYER(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, CTRL_TO_PLAYER); + + memset(sObject, 0, sizeof(CTRL_TO_PLAYER)); + + s2j_struct_get_basic_element(sObject, pJson, string, src); + s2j_struct_get_basic_element(sObject, pJson, string, srcUuid); + s2j_struct_get_basic_element(sObject, pJson, string, ttsText); + s2j_struct_get_basic_element(sObject, pJson, int, skTime); + s2j_struct_get_basic_element(sObject, pJson, int, plyMode); + s2j_struct_get_basic_element(sObject, pJson, int, plyListType); + s2j_struct_get_basic_element(sObject, pJson, int, adSrcType); + s2j_struct_get_basic_element(sObject, pJson, int, duration); + s2j_struct_get_basic_element(sObject, pJson, int, volRestoreTime); + s2j_struct_get_basic_element(sObject, pJson, int, volBegin); + s2j_struct_get_basic_element(sObject, pJson, string, fifo); + s2j_struct_get_basic_element(sObject, pJson, int, channel); + s2j_struct_get_basic_element(sObject, pJson, int, bytes); + s2j_struct_get_basic_element(sObject, pJson, int, sampleRate); + s2j_struct_get_basic_element(sObject, pJson, int, playerId); + s2j_struct_get_basic_element(sObject, pJson, double, gain); + s2j_struct_get_basic_element(sObject, pJson, string, backGroundUrl); + + cJSON_Delete(pJson); + + return sObject; +} + +static void __ctrl_TO_PLAYERBase64(void *pData, int enCode) +{ + PCTRL_TO_PLAYER pReq = (PCTRL_TO_PLAYER)pData; + + if(enCode) + { + if(strlen(pReq->src) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->src); + memset(pReq->src, 0, MAX_MUSIC_UUID); + strcpy(pReq->src, pBase64); + free(pBase64); + } + + if(strlen(pReq->srcUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Encode(pReq->srcUuid); + memset(pReq->srcUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->srcUuid, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->src) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->src); + memset(pReq->src, 0, MAX_MUSIC_UUID); + strcpy(pReq->src, pBase64); + free(pBase64); + } + + if(strlen(pReq->srcUuid) > 0) + { + char *pBase64 = (char *)EvpBase64Decode(pReq->srcUuid); + memset(pReq->srcUuid, 0, MAX_MUSIC_UUID); + strcpy(pReq->srcUuid, pBase64); + free(pBase64); + } + } +} + +#if 0 +const char* __ota_Notify_REQ2Json(void* pData) +{ + int i; + POTA_DATA_INFO pReq = (POTA_DATA_INFO)pData; + cJSON* pRoot = NULL; + cJSON* pSubArray = NULL; + const char* pJsonS; + + pRoot = cJSON_CreateObject(); + + cJSON_AddNumberToObject(pRoot, "version", pReq->version); + cJSON_AddNumberToObject(pRoot, "otaMode", pReq->otaMode); + + pSubArray = cJSON_CreateArray(); + cJSON_AddItemToObject(pRoot, "otaFile", pSubArray); + + for(i = 0; i < sizeof(pReq->otaFile) / sizeof(pReq->otaFile[0]); i++) + { + cJSON *pItem = cJSON_CreateObject(); + + cJSON_AddItemToObject(pSubArray, "", pItem); + + + cJSON_AddStringToObject(pItem, "url", pReq->otaFile[i].url); + cJSON_AddStringToObject(pItem, "md5", pReq->otaFile[i].md5); + cJSON_AddNumberToObject(pItem, "size", pReq->otaFile[i].size); + } + + pJsonS = cJSON_Print(pRoot); + cJSON_Delete(pRoot); + + return pJsonS; +} + +void* __json2OTA_Notify_REQ(const char* pJsonS) +{ + POTA_DATA_INFO pInfo; + cJSON* pSubArray = NULL; + cJSON* pItem = NULL; + + cJSON* pRoot = cJSON_Parse(pJsonS); + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "otaFile"); + + pInfo = (POTA_DATA_INFO)malloc(sizeof(OTA_DATA_INFO)); + memset(pInfo, 0, sizeof(OTA_DATA_INFO)); + + pItem = cJSON_GetObjectItem(pRoot, "version"); + pInfo->version = pItem->valueint; + + pItem = cJSON_GetObjectItem(pRoot, "otaMode"); + pInfo->otaMode = pItem->valueint; + + if(pSubArray) + { + int i; + cJSON *pList = pSubArray->child; + + for(i = 0; i < cJSON_GetArraySize(pSubArray); i++) + { + strcpy(pInfo->otaFile[i].url, cJSON_GetObjectItem(pList, "url")->valuestring); + strcpy(pInfo->otaFile[i].md5, cJSON_GetObjectItem(pList, "md5")->valuestring); + pInfo->otaFile[i].size = cJSON_GetObjectItem(pList, "size")->valueint; + + pList = pList->next; + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} +#else +const char* __ota_Notify_REQ2Json(void* pData) +{ + POTA_DATA_INFO pReq = (POTA_DATA_INFO)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, version); + s2j_json_set_basic_element(jObject, pReq, int, otaCmd); + s2j_json_set_basic_element(jObject, pReq, int, otaMode); + + s2j_json_set_struct_element(json_otaRes, jObject, struct_otaRes, pReq, OTA_FILE_INFO, otaFileInfo); + s2j_json_set_basic_element(json_otaRes, struct_otaRes, string, url); + s2j_json_set_basic_element(json_otaRes, struct_otaRes, string, md5); + s2j_json_set_basic_element(json_otaRes, struct_otaRes, int, size); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2OTA_Notify_REQ(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, OTA_DATA_INFO); + + memset(sObject, 0, sizeof(OTA_DATA_INFO)); + + s2j_struct_get_basic_element(sObject, pJson, int, version); + s2j_struct_get_basic_element(sObject, pJson, int, otaCmd); + s2j_struct_get_basic_element(sObject, pJson, int, otaMode); + + s2j_struct_get_struct_element(struct_otaRes, sObject, json_otaRes, pJson, OTA_FILE_INFO, otaFileInfo); + s2j_struct_get_basic_element(struct_otaRes, json_otaRes, string, url); + s2j_struct_get_basic_element(struct_otaRes, json_otaRes, string, md5); + s2j_struct_get_basic_element(struct_otaRes, json_otaRes, int, size); + + cJSON_Delete(pJson); + + return sObject; +} +#endif +static void __ota_NotifyBase64(void *pData, int enCode) +{ + POTA_DATA_INFO pReq = (POTA_DATA_INFO)pData; + + if(enCode) + { + if(strlen(pReq->otaFileInfo.url) > 0) + { + char *pBase64 = (char *)EvpBase64EncodeNoAlign(pReq->otaFileInfo.url); + memset(pReq->otaFileInfo.url, 0, SIZE_1K); + strcpy(pReq->otaFileInfo.url, pBase64); + free(pBase64); + } + } + else + { + if(strlen(pReq->otaFileInfo.url) > 0) + { + char *pBase64 = (char *)EvpBase64DecodeNoAlign(pReq->otaFileInfo.url); + memset(pReq->otaFileInfo.url, 0, SIZE_1K); + strcpy(pReq->otaFileInfo.url, pBase64); + free(pBase64); + } + } +} + +const char* __ota_Status_RSP2Json(void* pData) +{ + POTA_RSP_STATUS pReq = (POTA_RSP_STATUS)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, status); + s2j_json_set_basic_element(jObject, pReq, int, val); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2OTA_Status_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, OTA_RSP_STATUS); + + memset(sObject, 0, sizeof(OTA_RSP_STATUS)); + + s2j_struct_get_basic_element(sObject, pJson, int, status); + s2j_struct_get_basic_element(sObject, pJson, int, val); + + cJSON_Delete(pJson); + + return sObject; +} + +const char* __alarm_Run_Event_RSP2Json(void* pData) +{ + const char* pJsonS; + PASSISTANT_ITEM_INFO pReq = (PASSISTANT_ITEM_INFO)pData; + cJSON* pRoot = cJSON_CreateObject(); + cJSON* pSubArray = cJSON_CreateArray(); + + cJSON_AddItemToObject(pRoot, "data", pSubArray); + + cJSON *pItem = cJSON_CreateObject(); + + cJSON_AddItemToObject(pSubArray, "", pItem); + + cJSON_AddNumberToObject(pItem, "alarmId", pReq->itemId); + cJSON_AddNumberToObject(pItem, "itemType", pReq->itemType); + cJSON_AddNumberToObject(pItem, "priority", pReq->priority); + cJSON_AddNumberToObject(pItem, "repeatMode", pReq->repeatMode); + + cJSON_AddNumberToObject(pItem, "year", pReq->year); + cJSON_AddNumberToObject(pItem, "month", pReq->month); + cJSON_AddNumberToObject(pItem, "day", pReq->day); + cJSON_AddNumberToObject(pItem, "hour", pReq->hour); + cJSON_AddNumberToObject(pItem, "minute", pReq->minute); + cJSON_AddNumberToObject(pItem, "second", pReq->second); + cJSON_AddNumberToObject(pItem, "weekDay", pReq->weekDay); + + cJSON_AddNumberToObject(pItem, "voiceId", pReq->voiceId); + cJSON_AddStringToObject(pItem, "strTips", pReq->strTips); + cJSON_AddStringToObject(pItem, "resUrl", pReq->resUrl); + + cJSON_AddStringToObject(pItem, "voiceResType", pReq->voiceResType); + cJSON_AddStringToObject(pItem, "voiceRes", pReq->voiceRes); + + pJsonS = cJSON_Print(pRoot); + cJSON_Delete(pRoot); + + return pJsonS; +} + +static void __getAlarmDateTimeInfo(cJSON* pJson, PASSISTANT_ITEM_INFO pAlarmInfo) +{ + struct tm tmNow; + time_t timep; + + const char *pStrYear = cJSON_GetObjectItem(pJson, "year")->valuestring; + const char *pStrMonth = cJSON_GetObjectItem(pJson, "month")->valuestring; + const char *pStrDay = cJSON_GetObjectItem(pJson, "dayofMonth")->valuestring; + const char *pStrHour = cJSON_GetObjectItem(pJson, "hour")->valuestring; + const char *pStrMinute = cJSON_GetObjectItem(pJson, "minute")->valuestring; + const char *pStrSecond = cJSON_GetObjectItem(pJson, "second")->valuestring; + const char *pStrWeekDay = cJSON_GetObjectItem(pJson, "dayofWeek")->valuestring; + + time(&timep); + localtime_r(&timep, &tmNow); + + if(pStrYear != NULL && strlen(pStrYear) > 0) + { + pAlarmInfo->year = strtoul(pStrYear, NULL, 10) - 1900; + } + else + { + pAlarmInfo->year = -1;//tmNow.tm_year; + } + + if(pStrMonth != NULL && strlen(pStrMonth) > 0) + { + pAlarmInfo->month = strtoul(pStrMonth, NULL, 10) - 1; + } + else + { + pAlarmInfo->month = -1;//tmNow.tm_mon; + } + + if(pStrDay != NULL && strlen(pStrDay) > 0) + { + pAlarmInfo->day = strtoul(pStrDay, NULL, 10); + } + else + { + pAlarmInfo->day = -1; //tmNow.tm_mday; + } + + if(pStrHour != NULL && strlen(pStrHour) > 0) + { + pAlarmInfo->hour = strtoul(pStrHour, NULL, 10); + } + else + { + pAlarmInfo->hour = -1; + } + + if(pStrMinute != NULL && strlen(pStrMinute) > 0) + { + pAlarmInfo->minute = strtoul(pStrMinute, NULL, 10); + } + else + { + pAlarmInfo->minute = -1; + } + + if(pStrSecond != NULL && strlen(pStrSecond) > 0) + { + pAlarmInfo->second = strtoul(pStrSecond, NULL, 10); + } + else + { + pAlarmInfo->second = -1; + } + + if(pStrWeekDay != NULL && strlen(pStrWeekDay) > 0) + { + if(strchr(pStrWeekDay, '7') != NULL) + { + pAlarmInfo->weekDay |= 1; + } + + if(strchr(pStrWeekDay, '1') != NULL) + { + pAlarmInfo->weekDay |= 1 << 1; + } + + if(strchr(pStrWeekDay, '2') != NULL) + { + pAlarmInfo->weekDay |= 1 << 2; + } + + if(strchr(pStrWeekDay, '3') != NULL) + { + pAlarmInfo->weekDay |= 1 << 3; + } + + if(strchr(pStrWeekDay, '4') != NULL) + { + pAlarmInfo->weekDay |= 1 << 4; + } + + if(strchr(pStrWeekDay, '5') != NULL) + { + pAlarmInfo->weekDay |= 1 << 5; + } + + if(strchr(pStrWeekDay, '6') != NULL) + { + pAlarmInfo->weekDay |= 1 << 6; + } + } + else + { + pAlarmInfo->weekDay = 0; + } +} + +void* __json2Alarm_sync_RSP(const char *pJsonS) +{ + PASSISTANT_SYNC_INFO pInfo; + cJSON* pSubArray = NULL; + //cJSON* pItem = NULL; + + cJSON* pRoot = cJSON_Parse(pJsonS); + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "data"); + + pInfo = (PASSISTANT_SYNC_INFO)malloc(sizeof(ASSISTANT_SYNC_INFO)); + memset(pInfo, 0, sizeof(ASSISTANT_SYNC_INFO)); + + pInfo->pAlarmInfo = NULL; + + if(pSubArray) + { + cJSON *pList = pSubArray->child; + int arraySize = cJSON_GetArraySize(pSubArray); + + if(arraySize > 0) + { + pInfo->pAlarmInfo = (PASSISTANT_ITEM_INFO)malloc(sizeof(ASSISTANT_ITEM_INFO) * arraySize); + + pInfo->nItems = arraySize; + + for(int i = 0; i < arraySize; i++) + { + cJSON* pData = cJSON_GetObjectItem(pList, "vboxDate"); + + memset(&pInfo->pAlarmInfo[i], 0, sizeof(ASSISTANT_ITEM_INFO)); + + if(pData != NULL) + { + cJSON *pItem; + + __getAlarmDateTimeInfo(pData, &pInfo->pAlarmInfo[i]); + + pInfo->pAlarmInfo[i].itemType = cJSON_GetObjectItem(pList, "label")->valueint; + pInfo->pAlarmInfo[i].itemId = cJSON_GetObjectItem(pList, "id")->valueint; + pInfo->pAlarmInfo[i].repeatMode = cJSON_GetObjectItem(pList, "type")->valueint; + pInfo->pAlarmInfo[i].voiceId = cJSON_GetObjectItem(pList, "voiceType")->valueint; + + pItem = cJSON_GetObjectItem(pList, "remark"); + + if(pInfo->pAlarmInfo[i].itemType != ASSISTANT_TYPE_CLOCK && pItem) + { + strcpy(pInfo->pAlarmInfo[i].strTips, pItem->valuestring); + } + + pItem = cJSON_GetObjectItem(pList, "resUrl"); + + if(pItem) + { + strcpy(pInfo->pAlarmInfo[i].resUrl, pItem->valuestring); + } + + pItem = cJSON_GetObjectItem(pList, "voiceRes"); + + if(pItem) + { + strcpy(pInfo->pAlarmInfo[i].voiceRes, pItem->valuestring); + } + + pItem = cJSON_GetObjectItem(pList, "voiceResType"); + + if(pItem) + { + strcpy(pInfo->pAlarmInfo[i].voiceResType, pItem->valuestring); + } + + pList = pList->next; +#if 0 + fprintf(stdout, "%04u-%02u-%02u %02u:%02u:%02u %u\n", + pInfo->pAlarmInfo[i].year, + pInfo->pAlarmInfo[i].month, + pInfo->pAlarmInfo[i].day, + pInfo->pAlarmInfo[i].hour, + pInfo->pAlarmInfo[i].minute, + pInfo->pAlarmInfo[i].second, + pInfo->pAlarmInfo[i].weekDay); +#endif + } + } + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} + +const char* __alarm_Status_RSP2Json(void* pData) +{ + const char* pJsonS; + + PASSISTANT_RSP_STATUS pReq = (PASSISTANT_RSP_STATUS)pData; + + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, cmd); + s2j_json_set_basic_element(jObject, pReq, int, val); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2Alarm_Status_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, ASSISTANT_RSP_STATUS); + + memset(sObject, 0, sizeof(ASSISTANT_RSP_STATUS)); + + s2j_struct_get_basic_element(sObject, pJson, int, cmd); + s2j_struct_get_basic_element(sObject, pJson, int, val); + + cJSON_Delete(pJson); + + return sObject; + +} + +const char* __alarm_change_RSP2Json(void* pData) +{ + const char* pJsonS; + PASSISTANT_NOTIFY_INFO pReq = (PASSISTANT_NOTIFY_INFO)pData; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, cmd); + s2j_json_set_basic_element(jObject, pReq, int, type); + s2j_json_set_array_element(jObject, pReq, double, ids, pReq->nItems); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2Alarm_change_RSP(const char* pJsonS) +{ + PASSISTANT_NOTIFY_INFO pInfo = NULL; + cJSON* pSubArray = NULL; + cJSON* pItem = NULL; + + cJSON* pRoot = cJSON_Parse(pJsonS); + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "ids"); + + pInfo = (PASSISTANT_NOTIFY_INFO)malloc(sizeof(ASSISTANT_NOTIFY_INFO)); + memset(pInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO)); + + pItem = cJSON_GetObjectItem(pRoot, "type"); + pInfo->type = pItem->valueint; + +#if 0 + pItem = cJSON_GetObjectItem(pRoot, "cmd"); + pInfo->cmd = pItem->valueint; +#endif + + if(pSubArray) + { + int arraySize = cJSON_GetArraySize(pSubArray); + + if(arraySize > 0) + { + pInfo->nItems = arraySize; + + for(int i = 0; i < arraySize; i++) + { + pInfo->ids[i] = (unsigned long long)(cJSON_GetArrayItem(pSubArray, i)->valuedouble); + } + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} +#if 0 +const char* __alarm_change_RSP2Json(void* pData) +{ + int i = 0; + PALARM_REMOVE_INFO pReq = (PALARM_REMOVE_INFO)pData; + cJSON* pRoot = NULL; + cJSON* pSubArray = NULL; + const char* pJsonS; + + pRoot = cJSON_CreateObject(); + + cJSON_AddNumberToObject(pRoot, "nItems", pReq->nItems); + + pSubArray = cJSON_CreateArray(); + cJSON_AddItemToObject(pRoot, "data", pSubArray); + + for(i = 0; i < pReq->nItems; i++) + { + cJSON *pItem = cJSON_CreateObject(); + + cJSON_AddItemToObject(pSubArray, "", pItem); + + cJSON_AddNumberToObject(pItem, "alarmId", pReq->pItemInfo[i].alarmId); + cJSON_AddNumberToObject(pItem, "itemType", pReq->pItemInfo[i].itemType); + } + + pJsonS = cJSON_Print(pRoot); + cJSON_Delete(pRoot); + + return pJsonS; +} + +void* __json2Alarm_change_RSP(const char* pJsonS) +{ + PALARM_REMOVE_INFO pInfo = NULL; + cJSON* pRoot = cJSON_Parse(pJsonS); + cJSON* pSubArray = NULL; + cJSON* pItem = NULL; + int itemType = 0; + + if(pRoot == NULL) + { + return (NULL); + } + + pSubArray = cJSON_GetObjectItem(pRoot, "data"); + + pInfo = (PALARM_REMOVE_INFO)malloc(sizeof(ALARM_REMOVE_INFO)); + memset(pInfo, 0, sizeof(ALARM_REMOVE_INFO)); + + pItem = cJSON_GetObjectItem(pRoot, "type"); + itemType = pItem->valueint; + + pInfo->pItemInfo = NULL; + + if(pSubArray) + { + int i; + cJSON *pList = pSubArray->child; + int arraySize = cJSON_GetArraySize(pSubArray); + + if(arraySize > 0) + { + pInfo->pItemInfo = (PITEM_INFO)malloc(sizeof(ITEM_INFO) * arraySize); + pInfo->nItems = arraySize; + + for(i = 0; i < arraySize; i++) + { + memset(&pInfo->pItemInfo[i], 0, sizeof(ALARM_ITEM_INFO)); + + pInfo->pItemInfo[i].itemType = itemType; + pInfo->pItemInfo[i].alarmId = cJSON_GetObjectItem(pList, "id")->valueint; + + pList = pList->next; + } + } + } + + cJSON_Delete(pRoot); + + return pInfo; +} +#endif + +const char* __alarm_WorkData_RSP2Json(void* pData) +{ + const char* pJsonS; + PWORKDAY_INFO pReq = (PWORKDAY_INFO)pData; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, year); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2Alarm_WorkData_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, WORKDAY_INFO); + + memset(sObject, 0, sizeof(WORKDAY_INFO)); + + s2j_struct_get_basic_element(sObject, pJson, int, year); + s2j_struct_get_array_element(sObject, pJson, int, days); + + cJSON_Delete(pJson); + + return sObject; +} + + +const char* __logCfg_RSP2Json(void* pData) +{ + PLOG_CFG_PROTOCOL pReq = (PLOG_CFG_PROTOCOL)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, cfgCmd); + s2j_json_set_basic_element(jObject, pReq, int, iParams1); + s2j_json_set_basic_element(jObject, pReq, int, iParams2); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2LogCfg_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, LOG_CFG_PROTOCOL); + + memset(sObject, 0, sizeof(LOG_CFG_PROTOCOL)); + + s2j_struct_get_basic_element(sObject, pJson, int, cfgCmd); + s2j_struct_get_basic_element(sObject, pJson, int, iParams1); + s2j_struct_get_basic_element(sObject, pJson, int, iParams2); + + cJSON_Delete(pJson); + + return sObject; +} + +const char* __wifiStatus_RSP2Json(void* pData) +{ + PWIFI_STATUS_PRO pReq = (PWIFI_STATUS_PRO)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, int, wifi_evt); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +void* __json2WifiStatus_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, WIFI_STATUS_PRO); + + memset(sObject, 0, sizeof(WIFI_STATUS_PRO)); + + s2j_struct_get_basic_element(sObject, pJson, int, wifi_evt); + + cJSON_Delete(pJson); + + return sObject; +} + +void* __json2McuGuideCmd_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, MCU_TEST_GUIDE_CMD); + + memset(sObject, 0, sizeof(MCU_TEST_GUIDE_CMD)); + + s2j_struct_get_basic_element(sObject, pJson, int, red); + s2j_struct_get_basic_element(sObject, pJson, int, green); + s2j_struct_get_basic_element(sObject, pJson, int, blue); + + cJSON_Delete(pJson); + + return sObject; +} + +void* __json2McuMatrixCmd_RSP(const char* pJsonS) +{ + cJSON* pJson = cJSON_Parse(pJsonS); + + s2j_create_struct_obj(sObject, MCU_TEST_MATRIX_CMD); + + memset(sObject, 0, sizeof(MCU_TEST_MATRIX_CMD)); + + s2j_struct_get_basic_element(sObject, pJson, int, level); + + cJSON_Delete(pJson); + + return sObject; +} + +const char* __mcuVersion_RSP2Json(void* pData) +{ + PMCU_TEST_VER_CMD pReq = (PMCU_TEST_VER_CMD)pData; + const char* pJsonS; + + s2j_create_json_obj(jObject); + + s2j_json_set_basic_element(jObject, pReq, string, McuVer); + + pJsonS = cJSON_Print(jObject); + cJSON_Delete(jObject); + + return pJsonS; +} + +static JSON_ENGINE g_jSonEngine[] = +{ + {JSON_ENGINE_P2C, __player_TO_CTRL2Json, __json2PLAYER_TO_CTRL, __player_TO_CTRLBase64}, + {JSON_ENGINE_C2P, __ctrl_TO_PLAYER2Json, __json2CTRL_TO_PLAYER, __ctrl_TO_PLAYERBase64}, + {JSON_ENGINE_CFG_REQ, __cfg_API_REQ2Json, __json2CFG_API_REQ, __cfg_API_REQBase64}, + {JSON_ENGINE_CFG_RSP, __cfg_API_RSP2Json, __json2CFG_API_RSP, __cfg_API_RSPBase64 }, + {JSON_ENGINE_ASSISTANT_SYNC_RSP, NULL, __json2Alarm_sync_RSP, NULL}, + {JSON_ENGINE_ASSISTANT_NOTIFY, __alarm_change_RSP2Json, __json2Alarm_change_RSP, NULL}, + {JSON_ENGINE_ASSISTANT_STATUS, __alarm_Status_RSP2Json, __json2Alarm_Status_RSP, NULL}, + {JSON_ENGINE_ASSISTANT_RUNNING, __alarm_Run_Event_RSP2Json, NULL, NULL}, + {JSON_ENGINE_WORKDAY_REQ, __alarm_WorkData_RSP2Json, __json2Alarm_WorkData_RSP, NULL}, + {JSON_ENGINE_PING, __ping_MSG2Json, __json2PING_MSG, NULL}, + {JSON_ENGINE_OTA_REQ, __ota_Notify_REQ2Json, __json2OTA_Notify_REQ, __ota_NotifyBase64}, + {JSON_ENGINE_OTA_RSP, __ota_Status_RSP2Json, __json2OTA_Status_RSP, NULL}, + {JSON_ENGINE_LOG_CFG_CMD, __logCfg_RSP2Json, __json2LogCfg_RSP, NULL}, + {JSON_WIFI_STATUS_NOTIFY, __wifiStatus_RSP2Json, __json2WifiStatus_RSP, NULL}, + {JSON_MCU_GUIDE_TEST_CMD, NULL, __json2McuGuideCmd_RSP, NULL}, + {JSON_MCU_MATRIX_TEST_CMD, NULL, __json2McuMatrixCmd_RSP, NULL}, + {JSON_MCU_TEST_GET_VER_CMD, __mcuVersion_RSP2Json, NULL, NULL}, +}; + +void* Json2Struct(const char* pJsonStr, JSON_ENGINE_TYPE type, int enBase64, int* pErr) +{ + if(pJsonStr == NULL || pErr == NULL) + { + if(pErr) + { + *pErr = -ERR_INPUT_PARAMS; + } + return NULL; + } + + if(type < 0 || type >= JSON_ENGINE_MAX) + { + *pErr = -ERR_INPUT_PARAMS; + return NULL; + } + + *pErr = 0; + + //LOG_EX(LOG_Debug, "Json:\n%s\n", pJsonStr); + + if(g_jSonEngine[type].j2sCb) + { + void *pStruct = g_jSonEngine[type].j2sCb(pJsonStr); + + if(enBase64 && g_jSonEngine[type].base64Cb) + { + g_jSonEngine[type].base64Cb(pStruct, FALSE); + } + + return (pStruct); + } + else + { + return (NULL); + } +} + +const char* Struct2Json(void* pStruct, JSON_ENGINE_TYPE type, int enBase64, int* pErr) +{ + if(pStruct == NULL || pErr == NULL) + { + if(pErr) + { + *pErr = -ERR_INPUT_PARAMS; + } + return NULL; + } + + if(type < 0 || type >= JSON_ENGINE_MAX) + { + *pErr = -ERR_INPUT_PARAMS; + return NULL; + } + + *pErr = 0; + + if(enBase64 && g_jSonEngine[type].base64Cb) + { + g_jSonEngine[type].base64Cb(pStruct, TRUE); + } + + if(g_jSonEngine[type].s2jCb) + { + const char *pJsongStr = g_jSonEngine[type].s2jCb(pStruct); + + //LOG_EX(LOG_Debug, "Json: \n%s\n", pJsongStr); + return (pJsongStr); + } + else + { + return NULL; + } +} diff --git a/app/libuvdbus/src/Framework/Monitor/monitor.c b/app/libuvdbus/src/Framework/Monitor/monitor.c new file mode 100644 index 0000000..6e78f6b --- /dev/null +++ b/app/libuvdbus/src/Framework/Monitor/monitor.c @@ -0,0 +1,347 @@ +#ifdef ENABLE_COUNT_DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" + +#define LOG_SAVE_TIME (1000) + +typedef struct +{ + long long maxValue; + long long minValue; + long long avgValue; +} STATISTICAL_VALUE, *PSTATISTICAL_VALUE; + +typedef struct +{ + long long curVaule; + long long tolValue; + unsigned int tolCount; + STATISTICAL_VALUE cVal; +} CSTATISTICAL_INFO, *PSTATISTICAL_INFO; + +typedef struct +{ + char* pMonName; + unsigned long nCount; + CSTATISTICAL_INFO nCstInfo; + uv_rwlock_t rwLock; + + uv_timer_t logTimer; + unsigned int logTime; + + UT_hash_handle hh; ///< UT Hash handle +} MONITOR_INFO, *PMONITOR_INFO; + +static uv_rwlock_t g_uvMonRwLock; +static PMONITOR_INFO g_MonTbl = NULL; +static uv_loop_t* g_MonLogLoop = NULL; + +static void __uvMonLogProc(void *pParams) +{ + RunUVLoop(g_MonLogLoop); + + while(TRUE) + { + usleep(1000); + } + + pthread_detach(pthread_self()); +} + +static void __logMonTimerProc(uv_timer_t* pTimer) +{ + PMONITOR_INFO pInfo = (PMONITOR_INFO)pTimer->data; + + if(pInfo && (pInfo->nCount + pInfo->nCstInfo.tolCount > 0)) + { + UT_string* pMsg = NULL; + utstring_new(pMsg); + + uv_rwlock_rdlock(&pInfo->rwLock); + + utstring_printf(pMsg, "%s Statistical Information:\n", pInfo->pMonName); + //LOG_EX(LOG_Debug, "%s Statistical Information:\n", pInfo->pMonName); + + if(pInfo->nCount) + { + UT_string* pMsgCount = NULL; + utstring_new(pMsgCount); + utstring_printf(pMsgCount, " Total Count = %lu\n", pInfo->nCount); + utstring_concat(pMsg, pMsgCount); + utstring_free(pMsgCount); + //LOG_EX(LOG_Debug, " Total Count = %u\n", pInfo->nCount); + } + + if(pInfo->nCstInfo.tolCount > 0) + { + UT_string* pMsgStat = NULL; + utstring_new(pMsgStat); + utstring_printf(pMsgStat, " Max Value = %lld\n" + " Min Value = %lld\n" + " Avg Value = %lld\n" + " ---- Statistical by total %lld of %u times\n", + pInfo->nCstInfo.cVal.maxValue, + pInfo->nCstInfo.cVal.minValue, + pInfo->nCstInfo.cVal.avgValue, + pInfo->nCstInfo.tolValue, + pInfo->nCstInfo.tolCount); + utstring_concat(pMsg, pMsgStat); + utstring_free(pMsgStat); +#if 0 + LOG_EX(LOG_Debug, " Max Value = %lld\n", pInfo->nCstInfo.cVal.maxValue); + LOG_EX(LOG_Debug, " Min Value = %lld\n", pInfo->nCstInfo.cVal.minValue); + LOG_EX(LOG_Debug, " Avg Value = %lld\n", pInfo->nCstInfo.cVal.avgValue); + LOG_EX(LOG_Debug, " ---- Statistical by total %lld of %u times\n", + pInfo->nCstInfo.tolValue, pInfo->nCstInfo.tolCount); +#endif + } + + LOG_EX(LOG_Debug, "%s", utstring_body(pMsg)); + + uv_rwlock_rdunlock(&pInfo->rwLock); + utstring_free(pMsg); + } +} + +int MonitorInit(void) +{ + uv_thread_t uvMonLogThread; + + g_MonLogLoop = uv_loop_new(); + + uv_rwlock_init(&g_uvMonRwLock); + + uv_thread_create(&uvMonLogThread, __uvMonLogProc, NULL); + + return 0; +} + +int MonAddNewItem(const char* pName, int logSaveTime) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo != NULL) + { + return -ERR_CFG_ITEM_EXIST; + } + + pInfo = (PMONITOR_INFO)malloc(sizeof(MONITOR_INFO)); + + if(pInfo == NULL) + { + return -ERR_MALLOC_MEMORY; + } + + memset(pInfo, 0, sizeof(MONITOR_INFO)); + + pInfo->nCstInfo.cVal.minValue = INT_MAX; + pInfo->logTime = logSaveTime; + pInfo->pMonName = strdup(pName); + + if(pInfo->logTime > 0) + { + pInfo->logTimer.data = pInfo; + uv_timer_init(g_MonLogLoop, &pInfo->logTimer); + uv_timer_start(&pInfo->logTimer, __logMonTimerProc, pInfo->logTime, pInfo->logTime); + } + else + { + pInfo->logTime = 0; + } + + uv_rwlock_init(&pInfo->rwLock); + + uv_rwlock_wrlock(&g_uvMonRwLock); + HASH_ADD_STR(g_MonTbl, pMonName, pInfo); + uv_rwlock_wrunlock(&g_uvMonRwLock); + + return 0; +} + +int MonIncreaseCount(const char* pName) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + uv_rwlock_wrlock(&pInfo->rwLock); + pInfo->nCount++; + uv_rwlock_wrunlock(&pInfo->rwLock); + + return 0; +} + +int MonDiffStatistical(const char* pName, long long newVal) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + uv_rwlock_wrlock(&pInfo->rwLock); + + if(pInfo->nCstInfo.curVaule != 0) + { + long long diffValue = newVal - pInfo->nCstInfo.curVaule; + + pInfo->nCstInfo.tolValue += diffValue; + pInfo->nCstInfo.tolCount++; + + if(pInfo->nCstInfo.tolCount > 10) + { + pInfo->nCstInfo.cVal.avgValue = pInfo->nCstInfo.tolValue / pInfo->nCstInfo.tolCount; + + if(pInfo->nCstInfo.cVal.maxValue < diffValue) + { + pInfo->nCstInfo.cVal.maxValue = diffValue; + } + + if(pInfo->nCstInfo.cVal.minValue > diffValue) + { + pInfo->nCstInfo.cVal.minValue = diffValue; + } + } + } + + pInfo->nCstInfo.curVaule = newVal; + uv_rwlock_wrunlock(&pInfo->rwLock); + + //fprintf(stdout, "%s value %lld diffValue %lld\n", pName, newVal, diffValue); + return 0; +} + +int MonUpgradeStatistical(const char* pName, long newVal) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + uv_rwlock_wrlock(&pInfo->rwLock); + + pInfo->nCstInfo.curVaule = newVal; + pInfo->nCstInfo.tolValue += newVal; + pInfo->nCstInfo.tolCount++; + pInfo->nCstInfo.cVal.avgValue = pInfo->nCstInfo.tolValue / pInfo->nCstInfo.tolCount; + + if(pInfo->nCstInfo.cVal.maxValue < newVal) + { + pInfo->nCstInfo.cVal.maxValue = newVal; + } + + if(pInfo->nCstInfo.cVal.minValue > newVal) + { + pInfo->nCstInfo.cVal.minValue = newVal; + } + + uv_rwlock_wrunlock(&pInfo->rwLock); + + //fprintf(stdout, "%s value %ld\n", pName, newVal); + return 0; +} + +int MonItemLogout(const char* pName) +{ + PMONITOR_INFO pInfo; + + if(pName == NULL || strlen(pName) == 0) + { + return -ERR_INPUT_PARAMS; + } + + uv_rwlock_rdlock(&g_uvMonRwLock); + HASH_FIND_STR(g_MonTbl, pName, pInfo); + uv_rwlock_rdunlock(&g_uvMonRwLock); + + if(pInfo == NULL) + { + return -ERR_CFG_NOITEM; + } + + if(pInfo->nCount + pInfo->nCstInfo.tolCount == 0) + { + LOG_EX(LOG_Debug, "%s Statistical Unchanged\n", pInfo->pMonName); + return 0; + } + + uv_rwlock_rdlock(&pInfo->rwLock); + + LOG_EX(LOG_Debug, "%s Statistical Information:\n", pInfo->pMonName); + + if(pInfo->nCount) + { + LOG_EX(LOG_Debug, " Total Count = %u\n", pInfo->nCount); + } + + if(pInfo->nCstInfo.tolCount > 0) + { + LOG_EX(LOG_Debug, " Max Value = %lld\n", pInfo->nCstInfo.cVal.maxValue); + LOG_EX(LOG_Debug, " Min Value = %lld\n", pInfo->nCstInfo.cVal.minValue); + LOG_EX(LOG_Debug, " Avg Value = %lld\n", pInfo->nCstInfo.cVal.avgValue); + LOG_EX(LOG_Debug, " ---- Statistical by total %lld of %u times\n", + pInfo->nCstInfo.tolValue, pInfo->nCstInfo.tolCount); + } + + uv_rwlock_rdunlock(&pInfo->rwLock); + + return 0; +} +#endif diff --git a/app/libuvdbus/src/Framework/Network/inet_api.c b/app/libuvdbus/src/Framework/Network/inet_api.c new file mode 100644 index 0000000..ee3a9db --- /dev/null +++ b/app/libuvdbus/src/Framework/Network/inet_api.c @@ -0,0 +1,1396 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "inet_api.h" + +#define MAX_TIMEOUT_VALUE (10) +#define SSL_CA_FILE ("/etc/ssl/certs/ca-certificates.crt") + +typedef enum +{ + INET_HTTP_DOWNLOAD_FILE = 0, + INET_HTTP_WEBSERVICE_POST, +} INET_ACCESS_TYPE; + +typedef struct +{ + uv_poll_t uvPool; + curl_socket_t sock; +} CURL_CONTEXT_DATA, *PCURL_CONTEXT_DATA; + +typedef struct +{ + char* pReqUrl; + char sPath[MAX_PATH]; + char sDlPath[MAX_PATH]; + char* pTaskUuid; + INET_ACCESS_TYPE type; + unsigned int dlSize; + unsigned int lastTm; + unsigned int createTm; + uv_fs_t uvFsOpen; + uv_fs_t uvFsWrite; + uv_fs_t uvFsDataSync; + uv_fs_t uvFsClose; + uv_buf_t uvFsBuf; + OnProgressNotify onPrgCb; + OnHttpResponse onRspCb; + int isCancel; + CURL* pCurl; + void* pData; + int errCode; +} HTTP_REQ_PARAMS, *PHTTP_REQ_PARAMS; + +typedef struct +{ + char *pTaskUuid; + unsigned int uRetryTimes; + PHTTP_REQ_PARAMS pCurlItem; + + UT_hash_handle hh; ///< UT Hash handle +} CURL_HANDLE_TBL, *PCURL_HANDLE_TBL; + +static uv_timer_t g_uvCurlTm; +static uv_timer_t g_uvDlTm; +static CURLM* g_pCurl = NULL; +static uv_loop_t* g_pMainLoop = NULL; +static PCURL_HANDLE_TBL g_ReqHandleTbl = NULL; +static uv_rwlock_t g_uvHashRwLock; +static unsigned g_TotalDownloads = 0; + +static void __addReqIdToTable(const char* pTaskUuid, PHTTP_REQ_PARAMS pParams) +{ + PCURL_HANDLE_TBL pItem = NULL; + + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + + if(pItem == NULL) + { + pItem = (PCURL_HANDLE_TBL)malloc(sizeof(CURL_HANDLE_TBL)); + + memset(pItem, 0, sizeof(CURL_HANDLE_TBL)); + pItem->pTaskUuid = (char*)pTaskUuid; + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_STR(g_ReqHandleTbl, pTaskUuid, pItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + } + + pItem->pCurlItem = pParams; + pItem->uRetryTimes++; +} + +static void __removeReqIdFromTable(const char* pTaskUuid) +{ + PCURL_HANDLE_TBL pItem = NULL; + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + if(pItem != NULL) + { + HASH_DEL(g_ReqHandleTbl, pItem); + + if(pItem->pTaskUuid) + { + free(pItem->pTaskUuid); + } + + free(pItem); + } + uv_rwlock_wrunlock(&g_uvHashRwLock); +} + +static void __cancelDownloadTask(PHTTP_REQ_PARAMS pItem) +{ + if(pItem) + { + pItem->isCancel = TRUE; + } +} + +static void __uvFsCloseCb(uv_fs_t *puvFs) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)puvFs->data; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "[%s] Error: %d\n", __FUNCTION__, puvFs->result); + } + + uv_fs_req_cleanup(puvFs); + + if(pParams->type == INET_HTTP_DOWNLOAD_FILE) + { + if(strcmp(pParams->sDlPath, pParams->sPath) != 0) + { + CopyFile(pParams->sDlPath, pParams->sPath); + unlink(pParams->sDlPath); + } + + if(pParams->errCode == CURLE_ABORTED_BY_CALLBACK) + { + pParams->errCode = CURLE_OPERATION_TIMEDOUT; + } + + if(pParams->onRspCb && pParams->isCancel == FALSE) + { + pParams->onRspCb(NULL, pParams->dlSize, pParams->pReqUrl, pParams->sPath, + pParams->pTaskUuid, -pParams->errCode, pParams->pData); + } + } + + __removeReqIdFromTable(pParams->pTaskUuid); + + if(pParams->pReqUrl) + { + free(pParams->pReqUrl); + pParams->pReqUrl = NULL; + } + + free(pParams); + pParams = NULL; +} + +static void __uvFsDataSyncCb(uv_fs_t *puvFs) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)puvFs->data; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "[%s] Error: %d\n", __FUNCTION__, puvFs->result); + } + + uv_fs_req_cleanup(puvFs); + + uv_fs_close(g_pMainLoop, &pParams->uvFsClose, pParams->uvFsOpen.result, __uvFsCloseCb); +} + +static PCURL_CONTEXT_DATA __createCurlContext(curl_socket_t sock) +{ + PCURL_CONTEXT_DATA pContext = (PCURL_CONTEXT_DATA)malloc(sizeof(CURL_CONTEXT_DATA)); + + pContext->sock = sock; + + if(uv_poll_init_socket(g_pMainLoop, &pContext->uvPool, sock) != 0) + { + LOG_EX(LOG_Error, "uv_poll_init_socket Error\n"); + } + + pContext->uvPool.data = pContext; + + return (pContext); +} + +static void __uvCloseCb(uv_handle_t *puvPoll) +{ + PCURL_CONTEXT_DATA pContext = (PCURL_CONTEXT_DATA)puvPoll->data; + free(pContext); +} + +static void __destoryCurlContext(PCURL_CONTEXT_DATA pContext) +{ + uv_close((uv_handle_t *)&pContext->uvPool, __uvCloseCb); +} + +static void __checkMultiInfoTimeout(void) +{ + PHTTP_REQ_PARAMS pReq; + CURLMsg *pMsg = NULL; + int iPending; + + while((pMsg = curl_multi_info_read(g_pCurl, &iPending))) + { + switch(pMsg->msg) + { + case CURLMSG_DONE: + curl_easy_getinfo(pMsg->easy_handle, CURLINFO_PRIVATE, (void*)&pReq); + + LOG_EX(LOG_Debug, "Cleanup CURL: %p\n", pMsg->easy_handle); + + curl_multi_remove_handle(g_pCurl, pMsg->easy_handle); + curl_easy_cleanup(pMsg->easy_handle); + + if(pReq) + { + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + uv_fs_close(g_pMainLoop, &pReq->uvFsDataSync, pReq->uvFsOpen.result, NULL); + } + + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, pReq->pData); + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + + break; + + default: + LOG_EX(LOG_Error, "pMsg->msg(%d) != CURLMSG_DONE\n", pMsg->msg); + return; + } + } +} + +static void __checkMultiInfo(void) +{ + PHTTP_REQ_PARAMS pReq; + CURLMsg *pMsg = NULL; + int iPending; + + while((pMsg = curl_multi_info_read(g_pCurl, &iPending))) + { + switch(pMsg->msg) + { + case CURLMSG_DONE: + curl_easy_getinfo(pMsg->easy_handle, CURLINFO_PRIVATE, (void*)&pReq); + + curl_multi_remove_handle(g_pCurl, pMsg->easy_handle); + LOG_EX(LOG_Debug, "Cleanup CURL: %p\n", pMsg->easy_handle); + curl_easy_cleanup(pMsg->easy_handle); + + if(pReq) + { + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + if(pMsg->data.result != CURLE_OK) + { + pReq->errCode = pMsg->data.result; + } + else + { + pReq->errCode = 0; + } + + uv_fs_fdatasync(g_pMainLoop, &pReq->uvFsDataSync, pReq->uvFsOpen.result, __uvFsDataSyncCb); + } + else if(pReq->type == INET_HTTP_WEBSERVICE_POST) + { + if(pMsg->data.result != CURLE_OK) + { + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(pReq->uvFsBuf.base, pReq->dlSize, pReq->pReqUrl, pReq->sPath, + pReq->pTaskUuid, -pMsg->data.result, pReq->pData); + } + } + else + { + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(pReq->uvFsBuf.base, pReq->dlSize, pReq->pReqUrl, pReq->sPath, + pReq->pTaskUuid, 0, pReq->pData); + } + } + + if(pReq->uvFsBuf.base) + { + free(pReq->uvFsBuf.base); + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + else + { + if(pMsg->data.result != CURLE_OK) + { + if(pReq->onRspCb && pReq->isCancel == FALSE){ + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, -pMsg->data.result, pReq->pData); + } + } + else + { + if(pReq->onRspCb && pReq->isCancel == FALSE) + { + pReq->onRspCb(NULL, 0, pReq->pReqUrl, pReq->sPath, pReq->pTaskUuid, 0, pReq->pData); + } + } + + if(pReq->pReqUrl) + { + free(pReq->pReqUrl); + pReq->pReqUrl = NULL; + } + + __removeReqIdFromTable(pReq->pTaskUuid); + + free(pReq); + pReq = NULL; + } + } + + break; + + default: + LOG_EX(LOG_Error, "pMsg->msg(%d) != CURLMSG_DONE\n", pMsg->msg); + return; + } + } +} + +static void __onDlTmoutCb(uv_timer_t *pufTimer) +{ + PCURL_HANDLE_TBL pItem = NULL, pTemp = NULL; + unsigned int curTm = (unsigned int)LIBUV_CURRENT_TIME_S(); + + HASH_ITER(hh, g_ReqHandleTbl, pItem, pTemp) + { + int dlTime; + + if(pItem->pCurlItem->isCancel) + { + continue; + } + + dlTime = curTm - pItem->pCurlItem->createTm; + + // 下载时间大于10s且平均下载速度小于10K/s超时 + if((dlTime * 10000 > pItem->pCurlItem->dlSize) && dlTime > 10) + { + LOG_EX(LOG_Error, "Download Speed less than 10k/s: %s (%uK/%ds)\n", + pItem->pTaskUuid, pItem->pCurlItem->dlSize / 1000, dlTime); + + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + break; + } + + // 10秒内没有下载任何数据超时 + if(pItem->pCurlItem->lastTm > 0) + { + if(curTm > pItem->pCurlItem->lastTm + MAX_TIMEOUT_VALUE) + { + LOG_EX(LOG_Error, "Download Timeout: %s\n", pItem->pTaskUuid); + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + break; + } + } + + // 下载最长时间设置为1800秒(30分钟) + if(dlTime > 1800) + { + LOG_EX(LOG_Error, "Download More than 1800 seconds: %s (%uK/%ds)\n", + pItem->pTaskUuid, pItem->pCurlItem->dlSize/1000, dlTime); + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + break; + } + } +} + +static void __onTimeoutCb(uv_timer_t *pufTimer) +{ + int iRun; + + curl_multi_socket_action(g_pCurl, CURL_SOCKET_TIMEOUT, 0, &iRun); + + __checkMultiInfoTimeout(); +} + +static int __curlTimerCb(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp) /* private callback pointer */ +{ + if(timeout_ms <= 0) + { + timeout_ms = 1; + } + + uv_timer_start(&g_uvCurlTm, __onTimeoutCb, timeout_ms, 0); + + return 0; +} + +static void __curlPollCb(uv_poll_t *pPoll, int status, int events) +{ + int iRun; + int flags; + PCURL_CONTEXT_DATA pContext = NULL; + + uv_timer_stop(&g_uvCurlTm); + + if(events & UV_READABLE) + { + flags = CURL_CSELECT_IN; + } + else if(events & UV_WRITABLE) + { + flags = CURL_CSELECT_OUT; + } + + pContext = (PCURL_CONTEXT_DATA)pPoll; + curl_multi_socket_action(g_pCurl, pContext->sock, flags, &iRun); + __checkMultiInfo(); +} + +static int __curlSockCb(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* describes the socket */ + void *userp, /* private callback pointer */ + void *socketp) /* private socket pointer */ +{ + PCURL_CONTEXT_DATA pContext = NULL; + + if(what == CURL_POLL_IN || what == CURL_POLL_OUT) + { + if(socketp) + { + pContext = (PCURL_CONTEXT_DATA)socketp; + } + else + { + pContext = __createCurlContext(s); + } + + curl_multi_assign(g_pCurl, s, (void *)pContext); + } + + switch(what) + { + case CURL_POLL_IN: + uv_poll_start(&pContext->uvPool, UV_READABLE, __curlPollCb); + break; + + case CURL_POLL_OUT: + uv_poll_start(&pContext->uvPool, UV_WRITABLE, __curlPollCb); + break; + + case CURL_POLL_REMOVE: + if(socketp) + { + uv_poll_stop(&((PCURL_CONTEXT_DATA)socketp)->uvPool); + __destoryCurlContext((PCURL_CONTEXT_DATA)socketp); + curl_multi_assign(g_pCurl, s, NULL); + } + break; + + default: + return (0); + } + + return (0); +} + +static size_t __writeDataCb(void *pData, size_t size, size_t nmemb, void *pParams) +{ + PHTTP_REQ_PARAMS pReq = (PHTTP_REQ_PARAMS)pParams; + int iMemSize = size * nmemb; + + //print_hex_dump_bytes("OTA", DUMP_PREFIX_ADDRESS, pData, size * nmemb); + + if(pReq->isCancel) + { + return 0; + } + + pReq->lastTm = LIBUV_CURRENT_TIME_S(); + + if(pReq->type == INET_HTTP_DOWNLOAD_FILE) + { + int wr = 0; + + pReq->uvFsBuf = uv_buf_init(pData, iMemSize); + + wr = uv_fs_write(g_pMainLoop, &pReq->uvFsWrite, pReq->uvFsOpen.result, &pReq->uvFsBuf, 1, -1, NULL); + + if(wr > 0) + { + pReq->dlSize += wr; + } + } + else if(pReq->type == INET_HTTP_WEBSERVICE_POST) + { + int newSize = 0; + + if(pReq->uvFsBuf.base == NULL && pReq->uvFsBuf.len == 0) + { + newSize = iMemSize + 1; + //fprintf(stdout, "size = %d, newsize = %d, dlsize = %d\n", iMemSize, newSize, pReq->dlSize); + pReq->uvFsBuf.base = malloc(newSize); + memcpy(pReq->uvFsBuf.base, pData, iMemSize); + } + else + { + newSize = pReq->dlSize + iMemSize + 1; + //fprintf(stdout, "::size = %d, newsize = %d, dlsize = %d\n", iMemSize, newSize, pReq->dlSize); + pReq->uvFsBuf.base = realloc(pReq->uvFsBuf.base, newSize); + memcpy(pReq->uvFsBuf.base + pReq->dlSize, pData, iMemSize); + } + + pReq->uvFsBuf.base[pReq->dlSize] = 0; + pReq->dlSize += iMemSize; + } + + return (size * nmemb); +} + +static int __progressCb(void* pData, + double total, + double now, + double ultotal, + double ulnow) +{ + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)pData; + + if(pParams->onPrgCb) + { + if(pParams->type == INET_HTTP_DOWNLOAD_FILE) + { + pParams->onPrgCb(pParams->pReqUrl, pParams->pTaskUuid, (unsigned char)(now * 100.0 / total), pParams->pData); + } + } + + if(pParams->isCancel) + { + LOG_EX(LOG_Debug, "Cancel Download: %s\n", pParams->pTaskUuid); + return (-CURLE_OPERATION_TIMEDOUT); + } + + return (0); +} + +static size_t __getRemoteSizeCb(void *pData, size_t size, size_t nmemb, void *pParams) +{ + return (size * nmemb); +} + +static int __iNetGetRemoteSize(const char* pURL, unsigned int reqId) +{ + double size = 0.0; + CURL *pCurl = curl_easy_init(); + CURLcode res; + + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_NOBODY, 1L); + curl_easy_setopt(pCurl, CURLOPT_HEADERFUNCTION, __getRemoteSizeCb); + curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L); + + curl_easy_perform(pCurl); + + res = curl_easy_getinfo(pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size); + + if(res != CURLE_OK) + { + return (-1); + } + + curl_easy_cleanup(pCurl); + + return (int)(size); +} + +#if 0 +static const char* __restartDlFileAsync(PHTTP_REQ_PARAMS pParams) +{ + CURL *pCurl = curl_easy_init(); + + pParams->type = INET_HTTP_DOWNLOAD_FILE; + pParams->dlSize = 0; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + + uv_fs_open(g_pMainLoop, + &pParams->uvFsOpen, + pParams->sDlPath, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, + NULL); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pParams->pReqUrl); + + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, __progressCb); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, pParams); + + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_LIMIT, 10000L); // 10K bytes + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_TIME, 10L); // 30 seconds + + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + //LOG_EX(LOG_Debug, "Total Size = %d\n", __iNetGetRemoteSize(pURL, 0)); + + curl_multi_add_handle(g_pCurl, pCurl); + + __addReqIdToTable(pParams->pTaskUuid, pCurl); + + return (pParams->pTaskUuid); +} +#endif + +const char* InetHttpDlFileAsync(const char *pURL, + const char *pPath, + OnHttpResponse onRespCb, + OnProgressNotify onProgressCb, + void* pData) +{ + CURLMcode ret; + uuid_t msgId; + char strMsgId[64]; + PHTTP_REQ_PARAMS pParams = NULL; + CURL *pCurl = NULL; + unsigned long long uMemFreeSize = GetPartitionFreeSize("/tmp/"); + + if(pURL == NULL || strlen(pURL) == 0 || onRespCb == NULL) + { + free(pParams); + return (NULL); + } + + LOG_EX(LOG_Debug, "Begin Download: %s --> %s\n", pURL, pPath); + + pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); + + memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); + + pCurl = curl_easy_init(); + + pParams->onRspCb = onRespCb; + pParams->pReqUrl = (char *)malloc(strlen(pURL) + 1); + pParams->type = INET_HTTP_DOWNLOAD_FILE; + pParams->dlSize = 0; + pParams->onPrgCb = onProgressCb; + pParams->pData = pData; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + pParams->isCancel = FALSE; + pParams->createTm = (unsigned int)LIBUV_CURRENT_TIME_S(); + + memset(pParams->pReqUrl, 0, strlen(pURL) + 1); + strcpy(pParams->pReqUrl, pURL); + + uuid_generate_random(msgId); + memset(strMsgId, 0, 64); + uuid_unparse_lower(msgId, strMsgId); + pParams->pTaskUuid = strdup(strMsgId); + + if(pPath == NULL) + { + sprintf(pParams->sPath, "./%s", basename_v2(pURL)); + } + else + { + strcpy(pParams->sPath, pPath); + } + + // Memory Free More Than 100M, Download Temp File To Memory + if(uMemFreeSize >= 100 * 1024 * 1024 && + strncmp(pParams->sPath, "/tmp/", 5) != 0) + { + int ret = system("mkdir /tmp/dl -p"); + sprintf(pParams->sDlPath, "/tmp/dl/%s_%s.dl", basename_v2(pParams->sPath), pParams->pTaskUuid); + } + else + { + strcpy(pParams->sDlPath, pParams->sPath); + } + + pParams->uvFsDataSync.data = pParams; + pParams->uvFsClose.data = pParams; + + uv_fs_open(g_pMainLoop, + &pParams->uvFsOpen, + pParams->sDlPath, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, + NULL); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, __progressCb); + curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, pParams); + + //curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 1800L); // Max download times (30 minutes)1800s + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_LIMIT, 10000L); // 10K bytes + curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_TIME, 10L); // 30 seconds + + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); + //curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT_MS, 10L); + + + //curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + LOG_EX(LOG_Debug, "Download(%u): %s --> %p\n", g_TotalDownloads++, pParams->pTaskUuid, pCurl); + ret = curl_multi_add_handle(g_pCurl, pCurl); + if(ret == CURLE_OK) + { + __addReqIdToTable(pParams->pTaskUuid, pParams); + return (pParams->pTaskUuid); + } + else + { + free(pParams->pTaskUuid); + LOG_EX(LOG_Error, "Add Handle Error: %d\n", ret); + return NULL; + } +} + +int InetCancelDownload(const char *pTaskUuid) +{ + if(pTaskUuid && strlen(pTaskUuid) > 0) + { + PCURL_HANDLE_TBL pItem = NULL; + + HASH_FIND_STR(g_ReqHandleTbl, pTaskUuid, pItem); + + if(pItem != NULL && pItem->pCurlItem->isCancel != TRUE) + { + __cancelDownloadTask(pItem->pCurlItem); + if(pItem->pCurlItem->onRspCb) + { + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + -CURLE_OPERATION_TIMEDOUT, + pItem->pCurlItem->pData); + } + } + } + + return (0); +} + +static size_t __uploadCb(char *d, size_t n, size_t l, void *p) +{ + return n*l; +} + +#ifdef LIBCURL_DEBUG +struct data { + char trace_ascii; /* 1 or 0 */ +}; + +static +void dump(const char *text, + FILE *stream, unsigned char *ptr, size_t size, + char nohex) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(nohex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", + text, (long)size, (long)size); + + for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && + ptr[i + c + 2] == 0x0A) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} + +static +int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + struct data *config = (struct data *)userp; + const char *text; + (void)handle; /* prevent compiler warning */ + + switch(type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + /* FALLTHROUGH */ + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + } + + dump(text, stderr, (unsigned char *)data, size, config->trace_ascii); + return 0; +} +#endif + +int InetHttpUploadFileSync(const char *pURL, const char* pPath, void* pAttachInfo) +{ + CURL *pCurl = NULL; + int rc = 0; + CURLcode ret; + struct curl_httppost *pPost = NULL, *pLastPtr = NULL; + +#ifdef LIBCURL_DEBUG + struct data config; + config.trace_ascii = 1; /* enable ascii tracing */ +#endif + + if(pURL == NULL || strlen(pURL) == 0) + { + LOG_EX(LOG_Error, "Url: %s(%p)\n", SAFE_STRING_VALUE(pURL), pURL); + return -ERR_INPUT_PARAMS; + } + + if(pPath == NULL || strlen(pPath) == 0) + { + LOG_EX(LOG_Error, "Url: %s(%p)\n", SAFE_STRING_VALUE(pPath), pPath); + return -ERR_INPUT_PARAMS; + } + + curl_formadd(&pPost, &pLastPtr, + CURLFORM_COPYNAME, "file", + CURLFORM_FILE, pPath, + CURLFORM_END); + + if(pAttachInfo) + { + PHTTP_POST_ATTACH pDevInfoArray = (PHTTP_POST_ATTACH)pAttachInfo; + PHTTP_POST_ATTACH pItem = NULL, pTmp = NULL; + + LL_FOREACH_SAFE(pDevInfoArray, pItem, pTmp) + { + curl_formadd(&pPost, &pLastPtr, + CURLFORM_COPYNAME, pItem->keyName, + CURLFORM_COPYCONTENTS, pItem->keyValue, + CURLFORM_END); + } + } + + pCurl = curl_easy_init(); + + if(pCurl == NULL) + { + LOG_EX(LOG_Error, "curl_easy_init() Error\n"); + return -ERR_MALLOC_MEMORY; + } + + curl_easy_setopt(pCurl, CURLOPT_ACCEPT_ENCODING, "gzip, deflate"); + curl_easy_setopt(pCurl, CURLOPT_POST, 1L); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_HTTPPOST, pPost); + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __uploadCb); + curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); +#ifdef LIBCURL_DEBUG + curl_easy_setopt(pCurl, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(pCurl, CURLOPT_DEBUGDATA, &config); +#endif + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + +#ifdef LIBCURL_DEBUG + curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); +#else + curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 0L); +#endif + + ret = curl_easy_perform(pCurl); + + if(ret != CURLE_OK) + { + LOG_EX(LOG_Error, "Upload %s File %s Error %s(%d)\n", pURL, pPath, curl_easy_strerror(ret), ret); + rc = -ERR_NETWORK_SEND; + } + + curl_easy_cleanup(pCurl); + curl_formfree(pPost); + + return rc; +} + +const char* InetHttpWebServicePostAsync(const char *pURL, const char* pPost, OnHttpResponse onRespCb, void* pData) +{ + uuid_t msgId; + char strMsgId[64]; + PHTTP_REQ_PARAMS pParams = (PHTTP_REQ_PARAMS)malloc(sizeof(HTTP_REQ_PARAMS)); + CURL *pCurl = NULL; + + if(pURL == NULL || strlen(pURL) == 0 || onRespCb == NULL) + { + free(pParams); + return (NULL); + } + + memset(pParams, 0, sizeof(HTTP_REQ_PARAMS)); + + pCurl = curl_easy_init(); + + pParams->onRspCb = onRespCb; + pParams->pReqUrl = (char *)malloc(strlen(pURL) + 1); + pParams->type = INET_HTTP_WEBSERVICE_POST; + pParams->dlSize = 0; + pParams->pData = pData; + pParams->pCurl = pCurl; + pParams->lastTm = 0; + pParams->isCancel = FALSE; + + memset(pParams->pReqUrl, 0, strlen(pURL) + 1); + strcpy(pParams->pReqUrl, pURL); + + uuid_generate_random(msgId); + memset(strMsgId, 0, 64); + uuid_unparse_lower(msgId, strMsgId); + pParams->pTaskUuid = strdup(strMsgId); + + curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, __writeDataCb); + curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, pParams); + curl_easy_setopt(pCurl, CURLOPT_PRIVATE, pParams); + curl_easy_setopt(pCurl, CURLOPT_URL, pURL); + curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(pCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + if(pPost != NULL && strlen(pPost) > 0) + { + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, pPost); + curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE, (long)strlen(pPost)); + } + +#ifdef SKIP_PEER_VERIFICATION + /* + * If you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the CA bundle you have, you can skip the + * verification of the server's certificate. This makes the connection + * A LOT LESS SECURE. + * + * If you have a CA cert for the server stored someplace else than in the + * default bundle, then the CURLOPT_CAPATH option might come handy for + * you. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); +#else + curl_easy_setopt(pCurl, CURLOPT_CAINFO, SSL_CA_FILE); + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + curl_multi_add_handle(g_pCurl, pCurl); + + __addReqIdToTable(pParams->pTaskUuid, pParams); + + return (pParams->pTaskUuid); +} + +#if 0 +static void __curlTaskRuntimeCb(void *pParams) +{ + PCURL_HANDLE_TBL pItem = NULL, pTmpItem = NULL; + + while(TRUE) + { + uv_rwlock_rdlock(&g_uvHashRwLock); + + HASH_ITER(hh, g_ReqHandleTbl, pItem, pTmpItem) + { + if(pItem->pCurlItem->type == INET_HTTP_DOWNLOAD_FILE + && pItem->pCurlItem->lastTm > 0) + { + //unsigned int tmNow = LIBUV_CURRENT_TIME_S(); + + if(pItem->pCurlItem->lastTm > 0) + { + //curl_multi_cleanup(pItem->pCurlItem->pCurl); + curl_multi_remove_handle(g_pCurl, pItem->pCurlItem->pCurl); + + if(pItem->uRetryTimes >= 3) + { + if(pItem->pCurlItem->onRspCb) + { + if(strcmp(pItem->pCurlItem->sPath, pItem->pCurlItem->sDlPath) != 0) + { + unlink(pItem->pCurlItem->sDlPath); + } + + pItem->pCurlItem->onRspCb(NULL, + pItem->pCurlItem->dlSize, + pItem->pCurlItem->pReqUrl, + pItem->pCurlItem->sPath, + pItem->pCurlItem->pTaskUuid, + TRUE, + pItem->pCurlItem->pData); + } + + if(pItem->pCurlItem->pReqUrl) + { + free(pItem->pCurlItem->pReqUrl); + } + } + else + { + __restartDlFileAsync(pItem->pCurlItem); + } + } + } + } + uv_rwlock_rdunlock(&g_uvHashRwLock); + usleep(100000); + } + + pthread_detach(pthread_self()); +} +#endif + +static int __getUsernameFromMail(const char *pMailAddr, char **pUsername) +{ + char *pTail; + + if(pMailAddr == NULL || pUsername == NULL || strlen(pMailAddr) == 0) + { + LOG_EX(LOG_Error, "Input Params Error: pMailAddr = [%s], pUsername = %p\n", + pMailAddr ? pMailAddr : "NULL", pUsername); + return (-ERR_INPUT_PARAMS); + } + + *pUsername = (char *)malloc(strlen(pMailAddr) + 1); + + if(*pUsername == NULL) + { + LOG_EX(LOG_Error, "Error Malloc Memory\n"); + *pUsername = ""; + return (-ERR_MALLOC_MEMORY); + } + + memset(*pUsername, 0, strlen(pMailAddr) + 1); + + pTail = strchr(pMailAddr, '@'); + + if(pTail == NULL) + { + strcpy(*pUsername, pMailAddr); + } + else + { + memcpy(*pUsername, pMailAddr, pTail - pMailAddr); + } + + return (0); +} + +int InetSmtpSendEmail(const char* pFrom, + const char* pTo[], + const char* pCc[], + const char* pTitle, + const char* pMessage, + const char* pAttach[], + PSMTP_MAIL_CONFIG pConfig) +{ + const char *pErrMsg = NULL; + quickmail pMail; + + if(pConfig == NULL) + { + LOG_EX(LOG_Error, "Input Param pConfig = NULL\n"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pPassword == NULL || strlen(pConfig->pPassword) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pPassword = [%s]\n", pConfig->pPassword ? pConfig->pPassword : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pUserName == NULL || strlen(pConfig->pUserName) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pUserName = [%s]\n", pConfig->pUserName ? pConfig->pUserName : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pConfig->pSmtpServer == NULL || strlen(pConfig->pSmtpServer) == 0) + { + LOG_EX(LOG_Error, "Input Param Error: pConfig->pUserName = [%s]\n", pConfig->pSmtpServer ? pConfig->pSmtpServer : "NULL"); + return (-ERR_INPUT_PARAMS); + } + + if(pFrom == NULL) + { + LOG_EX(LOG_Error, "Input Param pFrom = NULL\n"); + return (-ERR_INPUT_PARAMS); + } + + if(pTo == NULL && pCc == NULL) + { + LOG_EX(LOG_Error, "Input Param pTo = %p, pCc = %p\n", pTo, pCc); + return (-ERR_INPUT_PARAMS); + } + + if(pTitle == NULL) + { + pTitle = ""; + } + + if(pMessage == NULL) + { + pMessage = ""; + } + + quickmail_initialize(); + + pMail = quickmail_create(pFrom, pTitle); + + if(pMail == NULL) + { + LOG_EX(LOG_Error, "Create Quickmail Object Error\n"); + return (-ERR_MALLOC_MEMORY); + } + + for(const char **pValue = pTo; pTo && *pValue; pValue++) + { + quickmail_add_to(pMail, *pValue); + } + + for(const char **pValue = pCc; pCc && *pValue; pValue++) + { + quickmail_add_cc(pMail, *pValue); + } + + quickmail_add_header(pMail, "Importance: Low"); + quickmail_add_header(pMail, "X-Priority: 5"); + quickmail_add_header(pMail, "X-MSMail-Priority: Low"); + quickmail_add_body_memory(pMail, "text/html", (char*)pMessage, strlen(pMessage), 0); + + for(const char **pValue = pAttach; pAttach && *pValue; pValue++) + { + quickmail_add_attachment_file(pMail, *pValue, NULL); + } + + //quickmail_set_debug_log(pMail, stderr); + + pErrMsg = quickmail_send(pMail, pConfig->pSmtpServer, pConfig->smtpPort, pConfig->pUserName, pConfig->pPassword); + + if(pErrMsg != NULL) + { + LOG_EX(LOG_Error, "Send Mail Error: %s\n", pErrMsg); + return (-ERR_SEND_MAIL); + } + + return (0); +} + +int InetInit(void) +{ + int ret = 0; + + ret = curl_global_init(CURL_GLOBAL_ALL); + + if(ret != 0) + { + LOG_EX(LOG_Error, "curl init error: %d\n", ret); + return ret; + } + + g_pMainLoop = DBusLibuvGetRuntime()->pLoop; + + uv_timer_init(g_pMainLoop, &g_uvCurlTm); + uv_timer_init(g_pMainLoop, &g_uvDlTm); + + g_pCurl = curl_multi_init(); + + curl_multi_setopt(g_pCurl, CURLMOPT_SOCKETFUNCTION, __curlSockCb); + curl_multi_setopt(g_pCurl, CURLMOPT_TIMERFUNCTION, __curlTimerCb); + + uv_rwlock_init(&g_uvHashRwLock); + + uv_timer_start(&g_uvDlTm, __onDlTmoutCb, 1000, 1000); + + return (0); +} + +void InetUnInit(void) +{ + curl_multi_cleanup(g_pCurl); + curl_global_cleanup(); +} + diff --git a/app/libuvdbus/src/Framework/Skins/skin_res_vtbl.c b/app/libuvdbus/src/Framework/Skins/skin_res_vtbl.c new file mode 100644 index 0000000..ae30711 --- /dev/null +++ b/app/libuvdbus/src/Framework/Skins/skin_res_vtbl.c @@ -0,0 +1,320 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" +#include "skins.h" +#include "log.h" + +typedef struct +{ + sqlite3_vtab vTable; + sqlite3 *pSqlDb; + char *pTblName; +} SKINRES_VTBL, *PSKINRES_VTBL; + +typedef struct +{ + sqlite3_vtab_cursor base; + int count; + int eof; +} SKINRES_CURSOR, *PSKINRES_CURSOR; + +static int __skin_res_destructor(sqlite3_vtab *pVtab) +{ + PSKINRES_VTBL p = (PSKINRES_VTBL)pVtab; + + if(p->pTblName != NULL) + { + free(p->pTblName); + p->pTblName = NULL; + } + sqlite3_free(p); + + return 0; +} + +static int __skin_res_create(sqlite3 *pDb, + void *pAux, + int argc, const char * const *argv, + sqlite3_vtab **pp_vt, + char **pzErr) +{ + UT_string *pSqlCmd; + int rc = SQLITE_OK; + PSKINRES_VTBL pVTbl; + + /* Allocate the sqlite3_vtab/example_vtab structure itself */ + pVTbl = (PSKINRES_VTBL)sqlite3_malloc(sizeof(SKINRES_VTBL)); + + if(pVTbl == NULL) + { + return SQLITE_NOMEM; + } + + pVTbl->pSqlDb = pDb; + pVTbl->pTblName = strdup(argv[2]); + + utstring_new(pSqlCmd); + if(strcmp(argv[0], RES_MODE_NAME) == 0) + { + utstring_printf(pSqlCmd, CREATE_RES_TBL_SQL, ""); + } + else + { + utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL, ""); + } + + /* Declare the vtable's structure */ + rc = sqlite3_declare_vtab(pDb, utstring_body(pSqlCmd)); + utstring_free(pSqlCmd); + + if(rc != SQLITE_OK) + { + __skin_res_destructor((sqlite3_vtab*)pVTbl); + + return SQLITE_ERROR; + } + + /* Success. Set *pp_vt and return */ + *pp_vt = &pVTbl->vTable; + + return SQLITE_OK; +} + +static int __skin_res_connect( sqlite3 *db, void *p_aux, + int argc, const char * const *argv, + sqlite3_vtab **pp_vt, char **pzErr ) +{ + return __skin_res_create(db, p_aux, argc, argv, pp_vt, pzErr); +} + +static int __skin_res_disconnect(sqlite3_vtab *pVtab) +{ + return __skin_res_destructor(pVtab); +} + +static int __skin_res_destroy(sqlite3_vtab *pVtab) +{ + int rc = SQLITE_OK; + //PSKINRES_VTBL p = (PSKINRES_VTBL)pVtab; + + if(rc == SQLITE_OK) + { + rc = __skin_res_destructor(pVtab); + } + + return rc; +} + +static int __skin_res_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)sqlite3_malloc(sizeof(SKINRES_CURSOR)); + *ppCursor = (sqlite3_vtab_cursor*)pCur; + + return (pCur ? SQLITE_OK : SQLITE_NOMEM); +} + +static int __skin_res_close(sqlite3_vtab_cursor *cur) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)cur; + sqlite3_free(pCur); + + return SQLITE_OK; +} + +static int __skin_res_eof(sqlite3_vtab_cursor *cur) +{ + return ((PSKINRES_CURSOR)cur)->eof; +} + +static int __skin_res_next(sqlite3_vtab_cursor *pInCur) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + //PSKINRES_VTBL pvTable = (PSKINRES_VTBL)pInCur->pVtab; + + /* Increment the current row count. */ + pCur->count += 1; + + /* Arbitrary contstraint: when we get to 10 rows, then stop. */ + if(pCur->count >= SkinsDefaultSize()) + { + pCur->eof = 1; + } + + return SQLITE_OK; +} + +static int __skin_res_column(sqlite3_vtab_cursor *pInCur, sqlite3_context *ctx, int iCol) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + PSKIN_RES_INFO pItem = SkinsItemById(pCur->count); + //PSKINRES_VTBL pvTable = (PSKINRES_VTBL)pInCur->pVtab; + + /* Just return the ordinal of the column requested. */ + switch(iCol) + { + case 0: + sqlite3_result_int(ctx, pCur->count); + break; + + case 1: + sqlite3_result_text(ctx, pItem->pResVer, strlen(pItem->pResVer), SQLITE_STATIC); + break; + + case 2: + sqlite3_result_text(ctx, pItem->pLocalPath, strlen(pItem->pLocalPath), SQLITE_STATIC); + break; + + case 3: + sqlite3_result_text(ctx, pItem->pLocalPath, strlen(pItem->pLocalPath), SQLITE_STATIC); + break; + + case 4: + sqlite3_result_text(ctx, pItem->pMD5Chksum, strlen(pItem->pMD5Chksum), SQLITE_STATIC); + break; + } + + return SQLITE_OK; +} + +static int __skin_cfg_column(sqlite3_vtab_cursor *pInCur, sqlite3_context *ctx, int iCol) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + PSKIN_RES_INFO pItem = SkinsItemById(pCur->count); + //PSKINRES_VTBL pvTable = (PSKINRES_VTBL)pInCur->pVtab; + + /* Just return the ordinal of the column requested. */ + switch(iCol) + { + case 0: + sqlite3_result_int(ctx, pCur->count); + break; + + case 1: + sqlite3_result_text(ctx, pItem->pKeyName, strlen(pItem->pKeyName), SQLITE_STATIC); + break; + + case 2: + sqlite3_result_int(ctx, pItem->resType); + break; + + case 3: + sqlite3_result_int(ctx, 0); + break; + + case 4: + sqlite3_result_int(ctx, pCur->count); + break; + + case 5: + sqlite3_result_text(ctx, "", 0, SQLITE_STATIC); + break; + } + + return SQLITE_OK; +} + +static int __skin_res_rowid(sqlite3_vtab_cursor *pInCur, sqlite_int64 *p_rowid) +{ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pInCur; + + /* Just use the current row count as the rowid. */ + *p_rowid = pCur->count; + + return SQLITE_OK; +} + +static int __skin_res_filter( sqlite3_vtab_cursor *pVtc, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv ) +{ + //int rc; + //int i; + + /* Initialize the cursor structure. */ + PSKINRES_CURSOR pCur = (PSKINRES_CURSOR)pVtc; + + /* Zero rows returned thus far. */ + pCur->count = 0; + + /* Have not reached end of set. */ + pCur->eof = 0; + + /* Move cursor to first row. */ + return __skin_res_next(pVtc); +} + +/* Pretty involved. We don't implement in this example. */ +static int __skin_res_best_index(sqlite3_vtab *pVTbl, sqlite3_index_info *pIdxInfo) +{ + return SQLITE_OK; +} + +static sqlite3_module g_ResModule = +{ + 0, /* iVersion */ + __skin_res_create, /* xCreate - create a vtable */ + __skin_res_connect, /* xConnect - associate a vtable with a connection */ + __skin_res_best_index, /* xBestIndex - best index */ + __skin_res_disconnect, /* xDisconnect - disassociate a vtable with a connection */ + __skin_res_destroy, /* xDestroy - destroy a vtable */ + __skin_res_open, /* xOpen - open a cursor */ + __skin_res_close, /* xClose - close a cursor */ + __skin_res_filter, /* xFilter - configure scan constraints */ + __skin_res_next, /* xNext - advance a cursor */ + __skin_res_eof, /* xEof - inidicate end of result set*/ + __skin_res_column, /* xColumn - read data */ + __skin_res_rowid, /* xRowid - read data */ + NULL, /* xUpdate - write data */ + NULL, /* xBegin - begin transaction */ + NULL, /* xSync - sync transaction */ + NULL, /* xCommit - commit transaction */ + NULL, /* xRollback - rollback transaction */ + NULL, /* xFindFunction - function overloading */ +}; + +static sqlite3_module g_SkinModule = +{ + 0, /* iVersion */ + __skin_res_create, /* xCreate - create a vtable */ + __skin_res_connect, /* xConnect - associate a vtable with a connection */ + __skin_res_best_index, /* xBestIndex - best index */ + __skin_res_disconnect, /* xDisconnect - disassociate a vtable with a connection */ + __skin_res_destroy, /* xDestroy - destroy a vtable */ + __skin_res_open, /* xOpen - open a cursor */ + __skin_res_close, /* xClose - close a cursor */ + __skin_res_filter, /* xFilter - configure scan constraints */ + __skin_res_next, /* xNext - advance a cursor */ + __skin_res_eof, /* xEof - inidicate end of result set*/ + __skin_cfg_column, /* xColumn - read data */ + __skin_res_rowid, /* xRowid - read data */ + NULL, /* xUpdate - write data */ + NULL, /* xBegin - begin transaction */ + NULL, /* xSync - sync transaction */ + NULL, /* xCommit - commit transaction */ + NULL, /* xRollback - rollback transaction */ + NULL, /* xFindFunction - function overloading */ +}; + +int InitSkinRomDatabase(sqlite3 *pDataBase) +{ + if((sqlite3_create_module(pDataBase, SKIN_MODE_NAME, &g_SkinModule, NULL) == SQLITE_OK) + && (sqlite3_create_module(pDataBase, RES_MODE_NAME, &g_ResModule, NULL) == SQLITE_OK)) + { + return 0; + } + else + { + return -ERR_SQL_REG_MODULE; + } +} + + diff --git a/app/libuvdbus/src/Framework/Skins/skins.c b/app/libuvdbus/src/Framework/Skins/skins.c new file mode 100644 index 0000000..2fc624b --- /dev/null +++ b/app/libuvdbus/src/Framework/Skins/skins.c @@ -0,0 +1,1442 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#include "skins_res.h" +#include "inet_api.h" + +#define MAX_DOWNLOAD_ITEMS (10) + +#define DEBUG_SQL_CMD (0) + +typedef enum +{ + STATUS_CREATE_NEW = 0, + STATUS_DOWNLOADING, + STATUS_DOWNLOADED, +} RES_DOWNLOAD_STATUS; + +typedef enum +{ + UPG_STATUS_ADDNEW = (1 << 0), + UPG_STATUS_DL_NEW = (1 << 1), + UPG_STATUS_DOWNLOADED = (1 << 2), +} UPGRADE_RES_STATUS; + +typedef struct +{ + char* pKeyName; + char* pResPath; + + UT_hash_handle hh; ///< UT Hash handle +} SKINS_CACHE_ITEM, *PSKINS_CACHE_ITEM; +static uv_rwlock_t g_SkinCacheRwLock; + +#ifdef PLATFORM_CPU +#define DOWNLOAD_RES_ROOT_PATH (DEF_SKINS_ROOT_PATH) +#else +#define DOWNLOAD_RES_ROOT_PATH ("/mnt/UDISK/resources/") +#endif + +//select * FROM upgrade_skin WHERE resVersion == 4 ORDER BY resType DESC, RANDOM() LIMIT 1 +//#define SKIN_GET_SQL_CMD ("") + +#define ATTACH_DB_SQL_CMD ("ATTACH \'%s\' AS \'%s\'") +#define UPGRADE_TBL_SQL_CMD ("CREATE TABLE IF NOT EXISTS %supgrade (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "keyName TEXT NOT NULL," \ + "resType INTEGER NOT NULL," \ + "priority INTEGER NOT NULL DEFAULT (1)," \ + "resVersion TEXT NOT NULL," \ + "localPath TEXT NOT NULL," \ + "serverURL TEXT NOT NULL," \ + "md5Chksum TEXT NOT NULL," \ + "resReadme TEXT NOT NULL DEFAULT (\'\')," \ + "resStatus INTEGER NOT NULL DEFAULT (1)," \ + "dlId TEXT NOT NULL DEFAULT (\'\')," \ + "dlStatus INTEGER NOT NULL DEFAULT (0)," \ + "dlRetrys INTEGER NOT NULL DEFAULT (0)," \ + "dlTime TimeStamp NOT NULL DEFAULT (datetime('now','localtime')));") + +#define CREATE_TMP_TBL_SQL "CREATE TABLE IF NOT EXISTS %stmp (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "localPath TEXT NOT NULL);" + +static int g_isDlFinished = FALSE; +static unsigned int g_curDlItems = 0; +static sqlite3* g_pMemDb = NULL; +static uv_rwlock_t g_uvSkinRwLock; +static uv_rwlock_t g_uvDlRwLock; +static const unsigned int g_tolDefaultSkins = (sizeof(g_SkinDefaultResTable) / sizeof(g_SkinDefaultResTable[0])); +static PSKINS_CACHE_ITEM g_pSkinCackeTbl = NULL; + +char* TblGetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom); +static int __getUpgradeInfo(const char *pUpdFilePath); +static int __reTryDlSkinResCb(void *pData, int argc, char **argv, char **azColName); +extern int InitSkinRomDatabase(sqlite3 *pDataBase); +static int g_isVerifyRes = FALSE; +static int g_isUpgradeRunning = FALSE; + +static int __dumpSkinsInfo(PSKIN_RES_INFO pItem, int nItems) +{ + LOG_EX2(LOG_Debug, "Skins Items Information:\n"); + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------" + "--------------------------------------------------------\n"); + + LOG_EX2(LOG_Debug, "| Key Name | Type | MD5 Checksum |" + " Contexts " + " |\n"); + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------" + "--------------------------------------------------------\n"); + + for(int i = 0; i < nItems && pItem; i++, pItem++) + { + LOG_EX2(LOG_Debug, "| %-8s | %-8s | %-32s | %-80s |\n", + pItem->pKeyName, pItem->pResVer, pItem->pMD5Chksum, pItem->pLocalPath); + } + + LOG_EX2(LOG_Debug, "-------------------------------------------------------------" + "--------------------------------------------------------\n"); +} + +static int __verifyResMD5Chksum(const char* pPath, const char* pChksum, int resType) +{ + const char* pMD5Chksum; + + if(resType == TEXT_RES) + { + return (TRUE); + } + + if(pPath == NULL || pChksum == NULL) + { + return (FALSE); + } + + switch(resType) + { + case IMAGE_RES: + case VOICE_RES: + pMD5Chksum = EvpMD5HashFile(pPath); + + if(pMD5Chksum == NULL) + { + return (FALSE); + } + + if(strcmp(pMD5Chksum, pChksum) != 0) + { + LOG_EX(LOG_Error, "%s MD5 Verify Error: %s -> %s\n", pPath, pMD5Chksum, pChksum); + + free((char*)pMD5Chksum); + return (FALSE); + } + else + { + free((char*)pMD5Chksum); + } + + break; + + default: + return (FALSE); + } + + return (TRUE); +} + +static void __checkRes(sqlite3_context *pContext, int argc, sqlite3_value **argv) +{ + if(access(sqlite3_value_text(argv[0]), F_OK) != 0) + { + sqlite3_result_int(pContext, -1); + } + else if(__verifyResMD5Chksum(sqlite3_value_text(argv[0]), + sqlite3_value_text(argv[1]), + sqlite3_value_int(argv[2])) == FALSE) + { + sqlite3_result_int(pContext, -2); + } + else + { + sqlite3_result_int(pContext, 0); + } +} + +static int __cleanupSkinTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE %s.%s", SKIN_USER_DB, SKIN_TBL_NAME); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL, SKIN_USER_DB"."); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __cleanupResTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE %s.%s", SKIN_USER_DB, RES_TBL_NAME); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_RES_TBL_SQL, SKIN_USER_DB"."); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __cleanupUpgTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE %s.upgrade", SKIN_USER_DB); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, UPGRADE_TBL_SQL_CMD, SKIN_USER_DB"."); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __cleanupTmpTbl(void) +{ + int rc; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "DROP TABLE main.tmp"); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Delete Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_TMP_TBL_SQL, "main."); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + return 0; +} + +static int __skinCreateCfgDB(void) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string *pSqlCmd = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "CREATE VIRTUAL TABLE main.%s USING %s;" + "CREATE VIRTUAL TABLE main.%s USING %s;", + SKIN_TBL_NAME, SKIN_MODE_NAME, RES_TBL_NAME, RES_MODE_NAME); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + + return (0); +} + +static int __skinCreateCfgFile(const char* pCfgFilePath) +{ + char* pErrMsg = NULL; + int rc = 0; + static sqlite3* pSqlFileDB = NULL; + UT_string *pSqlCmd = NULL; + + rc = sqlite3_open(":memory:", &g_pMemDb); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "sqlite3_open memory: %s\n", pCfgFilePath); + return -ERR_OPEN_SQLITE3_DB; + } + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_TMP_TBL_SQL, ""); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + rc = sqlite3_open_v2(pCfgFilePath, &pSqlFileDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "sqlite3_open_v2 error: %s\n", pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_OPEN_SQLITE3_DB; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, CREATE_SKIN_TBL_SQL""CREATE_RES_TBL_SQL, "", ""); + + rc = sqlite3_exec(pSqlFileDB, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, UPGRADE_TBL_SQL_CMD, ""); + rc = sqlite3_exec(pSqlFileDB, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Create Tbl %s Error: %s\n", UPGRADE_TBL_SQL_CMD, pErrMsg); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + utstring_free(pSqlCmd); + return -ERR_SQLITE3_CREATE_TABLE; + } + + sqlite3_close(pSqlFileDB); + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, ATTACH_DB_SQL_CMD, pCfgFilePath, SKIN_USER_DB); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Attach Database %s Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + utstring_free(pSqlCmd); + sqlite3_free(pErrMsg); + unlink(pCfgFilePath); + sqlite3_close(g_pMemDb); + return -ERR_SQLITE3_CREATE_TABLE; + } + + utstring_free(pSqlCmd); + + rc = sqlite3_create_function(g_pMemDb, "ResCheck", 3, SQLITE_UTF8, NULL, __checkRes, NULL, NULL); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Don't Support Resurces Verify Function\n"); + } + + if(InitSkinRomDatabase(g_pMemDb) != 0) + { + sqlite3_close(g_pMemDb); + return (-ERR_SQL_REG_MODULE); + } + + rc = __skinCreateCfgDB(); + + if(rc != 0) + { + sqlite3_close(g_pMemDb); + return rc; + } + + return (0); +} + +static void __onDlFileCb(void *pData, unsigned int size, + const char *pReqUrl, const char* pDlPath, + const char *pTaskUuid, int iFinished, void *pUserData) +{ + char* pId = (char*)pUserData; + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + + if(g_curDlItems > 0) + { + g_curDlItems--; + } + + if(iFinished == 0 && pId != NULL) + { + //LOG_EX(LOG_Debug, "Request(%s): [%s] --> [%s] Response: [%u] OK\n", pTaskUuid, pReqUrl, pDlPath, size); + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET dlStatus = %d, dlRetrys = %d, " + "dlTime = datetime(\'now\', \'localtime\') WHERE ID = %s AND " + "ResCheck(localPath, md5Chksum, resType) = 0", + SKIN_USER_DB, STATUS_DOWNLOADED, 0, pId); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + else + { + if(iFinished == 1) + { + LOG_EX(LOG_Error, "Request(%s): [%s] --> [%s] Response: [%u] Error\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else + { + LOG_EX(LOG_Error, "Download %s Error: %d\n", pReqUrl, iFinished); + } + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT * FROM %s.upgrade WHERE ID = %s AND dlRetrys < 5 ", SKIN_USER_DB, pId); + + //fprintf(stdout, "SQL:\n%s\n", utstring_body(pSqlCmd)); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __reTryDlSkinResCb, NULL, &pErrMsg); + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL %s Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + + if(pId) + { + free(pId); + } +} + +static int __reTryDlSkinResCb(void *pData, int argc, char **argv, char **azColName) +{ + UT_string *pSqlCmd = NULL; + char* pErrMsg = NULL; + + const char* pDlTaskId = InetHttpDlFileAsync(argv[6], + argv[5], + __onDlFileCb, + NULL, + strdup(argv[0])); + + if(pDlTaskId != NULL) + { + int rc = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET dlId = \'%s\', dlRetrys = dlRetrys + 1, " + "dlTime = datetime(\'now\', \'localtime\') WHERE ID = %s", + SKIN_USER_DB, pDlTaskId, argv[0]); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + + return 0; +} + +static int __loadDownloadSkinsCb(void *pData, int argc, char **argv, char **azColName) +{ + const char *pDlTaskId; + char* pItemId = argv[0]; + char* pURL = argv[6]; + char* pDlPath = argv[5]; + char* pDlId = argv[10]; + int dlStatus = strtol(argv[3], NULL, 10); + int dlRetry = strtol(argv[4], NULL, 10) + 1; + + if(dlStatus == STATUS_DOWNLOADING) + { + if(strlen(pDlId) > 0) + { + InetCancelDownload(pDlId); + } + + dlRetry++; + } + + //LOG_EX(LOG_Debug, "Download: %s --> %s\n", pURL, pDlPath); + + pDlTaskId = InetHttpDlFileAsync(pURL, + pDlPath, + __onDlFileCb, + NULL, + strdup(pItemId)); + + if(pDlTaskId) + { + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + + g_curDlItems++; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET dlStatus = %d, dlRetrys = %d, " + "dlId = \'%s\', dlTime = datetime(\'now\', \'localtime\') WHERE ID = %s", + SKIN_USER_DB, STATUS_DOWNLOADING, dlRetry, pDlTaskId, pItemId); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + } + else + { + LOG_EX(LOG_Error, "Download %s error\n", pURL); + } + + return (0); +} + +static void __uvDownloadResThread(void *pParams) +{ + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + LOG_EX(LOG_Debug, "Beging Download Skins\n"); + + while(!g_isDlFinished) + { + int rc = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT *, STRFTIME(\"%%s\", datetime(\'now\', \'localtime\')) " + "- STRFTIME(\"%%s\", upgrade.dlTime) AS diff FROM %s.upgrade " + "WHERE resStatus = %d AND (dlRetrys < 5 OR diff > 600) " + "AND (dlStatus = %d OR (dlStatus = %d AND diff > 600)) " + "LIMIT 10 - %d", + SKIN_USER_DB, UPG_STATUS_DL_NEW, STATUS_CREATE_NEW, STATUS_DOWNLOADING, g_curDlItems); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __loadDownloadSkinsCb, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Query Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + + sleep(1); + } + + LOG_EX(LOG_Debug, "Download Skins Finished\n"); + + pthread_detach(pthread_self()); +} + +static int __sqlCbRemoveUnusedFile(void *pData, int argc, char **argv, char **azColName) +{ + LOG_EX(LOG_Debug, "Clean up resources: [%s]\n", argv[1]); + + if(access(argv[1], F_OK) == 0 + && strncmp(argv[1], DEF_SKINS_ROOT_PATH, strlen(DEF_SKINS_ROOT_PATH)) != 0) + { + unlink(argv[1]); + } +} + +static int __createResTblCb(void *pData, int argc, char **argv, char **azColName) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + //DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName); + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "INSERT INTO %s.%s " + "VALUES (NULL, \'%s\', \'%s\', \'%s\', \'%s\')", + SKIN_USER_DB, RES_TBL_NAME, argv[0], argv[1], argv[2], argv[3]); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "[%s] Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -1; + } + + utstring_free(pSqlCmd); + + return 0; +} + +static int __createSkinTblCb(void *pData, int argc, char **argv, char **azColName) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + //DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName); + + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, "INSERT INTO %s.%s " + "VALUES (NULL, \'%s\', %s, %s, %s, \'%s\')", + SKIN_USER_DB, SKIN_TBL_NAME, + argv[1], argv[2], argv[3], argv[0], argv[4]); + + //fprintf(stdout, "AutoId: %lld: %s\n", sqlite3_last_insert_rowid(g_pMemDb), argv[3]); + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "[%s] Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + return -1; + } + + utstring_free(pSqlCmd); + return 0; +} + +static void __uvSyncResThread(void *pParams) +{ + int tolCnt = 0; + PSKINS_CACHE_ITEM pItem = NULL, pTemp = NULL; + + LOG_EX(LOG_Debug, "Beging Sync Download Skins\n"); + + while(TRUE) + { + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + char **pResult = NULL; + int iRow = 0, iCol = 0; + int nItems = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT COUNT(*) FROM %s.upgrade " + "WHERE resStatus = %d AND dlStatus != %d", + SKIN_USER_DB, UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_get_table(g_pMemDb, utstring_body(pSqlCmd), &pResult, &iRow, &iCol, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + + nItems = strtol(pResult[1], NULL, 10); + sqlite3_free_table(pResult); + + if(tolCnt++ % 20 == 0) + { + LOG_EX(LOG_Debug, "Download: Remain %d\n", nItems); + } + + if(nItems == 0) + { + g_isDlFinished = TRUE; + utstring_new(pSqlCmd); + sqlite3_exec(g_pMemDb, "BEGIN TRANSACTION;", NULL, NULL, NULL); + + utstring_printf(pSqlCmd, "INSERT INTO main.tmp " + "SELECT %s.ID, %s.localPath FROM %s.%s " + "LEFT JOIN %s.upgrade on %s.md5Chksum = upgrade.md5Chksum " + "WHERE upgrade.md5Chksum IS NULL;", + RES_TBL_NAME, RES_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + SKIN_USER_DB, RES_TBL_NAME); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + utstring_free(pSqlCmd); + break; + } + + __cleanupSkinTbl(); + __cleanupResTbl(); + + utstring_renew(pSqlCmd); + + utstring_printf(pSqlCmd, "SELECT resVersion, localPath, serverURL, md5Chksum, " + "keyName, resType, priority, resReadme, resStatus, dlStatus " + "FROM %s.upgrade WHERE resStatus = %d " + "OR (resStatus = %d AND dlStatus = %d) " + "GROUP BY md5Chksum", + SKIN_USER_DB, UPG_STATUS_DOWNLOADED, + UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __createResTblCb, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + utstring_free(pSqlCmd); + break; + } + else + { + utstring_renew(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT %s.ID, keyName, resType, priority, " + "resReadme, resStatus, dlStatus, %s.md5Chksum " + "FROM %s.upgrade, %s.res WHERE %s.md5Chksum = upgrade.md5Chksum" + " AND (resStatus = %d OR (resStatus = %d AND dlStatus = %d)) " + "ORDER BY keyName", + RES_TBL_NAME, RES_TBL_NAME, SKIN_USER_DB, SKIN_USER_DB, RES_TBL_NAME, + UPG_STATUS_DOWNLOADED, UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __createSkinTblCb, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + utstring_free(pSqlCmd); + break; + } + else + { + sqlite3_exec(g_pMemDb, "SELECT * FROM main.tmp", __sqlCbRemoveUnusedFile, NULL, NULL); + utstring_free(pSqlCmd); + + if(__cleanupUpgTbl() != 0) + { + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + } + else + { + sqlite3_exec(g_pMemDb, "END TRANSACTION;", NULL, NULL, NULL); + break; + } + } + } + } + + sleep(1); + } + + LOG_EX(LOG_Debug, "Sync Download Skins Finished\n"); + + uv_rwlock_wrlock(&g_SkinCacheRwLock); + HASH_ITER(hh, g_pSkinCackeTbl, pItem, pTemp) + { + free(pItem->pKeyName); + free(pItem->pResPath); + free(pItem); + pItem = NULL; + } + + g_pSkinCackeTbl = NULL; + uv_rwlock_wrunlock(&g_SkinCacheRwLock); + + g_isUpgradeRunning = FALSE; + pthread_detach(pthread_self()); +} + +static int __upgStatusTblCb(void *pData, int argc, char **argv, char **azColName) +{ + int rc = 0; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName); + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET resStatus = %d WHERE ID = %s", + SKIN_USER_DB, UPG_STATUS_DL_NEW, argv[2]); + + rc = sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, NULL, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "[%s] Query Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return -1; + } + + utstring_free(pSqlCmd); + + return 0; +} + +static int __saveUpgradeInfo(PSKIN_RES_INFO pInfo, int nItems) +{ + int isError = FALSE; + char* pErrMsg = NULL; + UT_string* pSqlCmd = NULL; + + if(pInfo == NULL || nItems <= 0) + { + return (-ERR_INPUT_PARAMS); + } + + utstring_new(pSqlCmd); + + sqlite3_exec(g_pMemDb, "BEGIN TRANSACTION;", NULL, NULL, NULL); + __cleanupUpgTbl(); + __cleanupTmpTbl(); + + for(int i = 0; i < nItems; i++) + { + UT_string* pPath = NULL; + PSKIN_RES_INFO pItem = &pInfo[i]; + + utstring_new(pPath); + utstring_renew(pSqlCmd); + +#if 0 + if(pItem->resType == VOICE_RES) + { + utstring_printf(pPath, "%svoice/%s", DOWNLOAD_RES_ROOT_PATH, basename_v2(pItem->pLocalPath)); + } + + else if(pItem->resType == IMAGE_RES) + { + utstring_printf(pPath, "%simage/%s", DOWNLOAD_RES_ROOT_PATH, basename_v2(pItem->pLocalPath)); + } + else if(pItem->resType == TEXT_RES) + { + utstring_printf(pPath, "%s", pItem->pLocalPath); + } + else + { + utstring_free(pPath); + continue; + } +#else + utstring_printf(pPath, "%svoice/%s", DOWNLOAD_RES_ROOT_PATH, basename_v2(pItem->pLocalPath)); +#endif + utstring_printf(pSqlCmd, "INSERT INTO %s.upgrade (keyName, resType, resVersion, localPath, serverURL, md5Chksum)" + " SELECT \'%s\', %d, \'%s\', \'%s\', \'%s\', \'%s\' ", + SKIN_USER_DB, pItem->pKeyName, pItem->resType, pItem->pResVer, utstring_body(pPath), + pItem->pLocalPath, pItem->pMD5Chksum); + +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + if((sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg) != SQLITE_OK)) + { + LOG_EX(LOG_Error, "Add Skins[%d] %s To Database Error: %s\n", i, pItem->pKeyName, utstring_body(pSqlCmd)); + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + isError = TRUE; + utstring_free(pPath); + break; + } + + utstring_free(pPath); + } + + utstring_renew(pSqlCmd); + + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET resStatus = %d " + "WHERE EXISTS (SELECT %s.keyName, upgrade.md5Chksum FROM main.%s, user_db.upgrade " + "WHERE upgrade.keyName = %s.keyName)", + SKIN_USER_DB, UPG_STATUS_DL_NEW, + SKIN_TBL_NAME, SKIN_TBL_NAME, + SKIN_TBL_NAME); + +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + if(sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __upgStatusTblCb, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "Upgrade Status: %s\n", utstring_body(pSqlCmd)); + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + isError = TRUE; + } + + utstring_renew(pSqlCmd); + + utstring_printf(pSqlCmd, "UPDATE %s.upgrade SET resStatus = %d " + "WHERE EXISTS (SELECT %s.md5Chksum FROM %s.%s " + "WHERE upgrade.md5Chksum = %s.md5Chksum);" + "UPDATE %s.upgrade SET resStatus = %d, localPath = " + "(SELECT %s.localPath FROM main.%s " + "WHERE upgrade.md5Chksum = %s.md5Chksum) " + "WHERE EXISTS (SELECT %s.md5Chksum FROM main.%s " + "WHERE upgrade.md5Chksum = %s.md5Chksum);", + SKIN_USER_DB, UPG_STATUS_DOWNLOADED, + RES_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + RES_TBL_NAME, + SKIN_USER_DB, UPG_STATUS_DOWNLOADED, + RES_TBL_NAME, RES_TBL_NAME, RES_TBL_NAME, + RES_TBL_NAME, RES_TBL_NAME, RES_TBL_NAME); + +#if DEBUG_SQL_CMD + LOG_EX(LOG_Debug, "SQL CMD: [%s]\n", utstring_body(pSqlCmd)); +#endif + + if(sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), NULL, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "Upgrade Status: %s\n", utstring_body(pSqlCmd)); + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + isError = TRUE; + } + + utstring_free(pSqlCmd); + + + if(isError == TRUE) + { + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + return (-ERR_SQL_QUERY); + } + else + { + uv_thread_t uvSyncThread, uvDlThread; + sqlite3_exec(g_pMemDb, "END TRANSACTION;", NULL, NULL, NULL); + g_curDlItems = 0; + g_isDlFinished = FALSE; + uv_thread_create(&uvDlThread, __uvDownloadResThread, NULL); + uv_thread_create(&uvSyncThread, __uvSyncResThread, NULL); + } + + return 0; +} + +static int __loadPreUpgradeInfo(void) +{ + UT_string *pSqlCmd = NULL; + int rc = 0; + char* pErrMsg = NULL; + char **pResult = NULL; + int iRow = 0, iCol = 0; + int nItems = 0; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT COUNT(*) FROM %s.upgrade WHERE resStatus = %d AND dlStatus != %d", + SKIN_USER_DB, UPG_STATUS_DL_NEW, STATUS_DOWNLOADED); + + rc = sqlite3_get_table(g_pMemDb, utstring_body(pSqlCmd), &pResult, &iRow, &iCol, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s\n", utstring_body(pSqlCmd), pErrMsg); + sqlite3_free(pErrMsg); + } + + utstring_free(pSqlCmd); + + nItems = strtol(pResult[1], NULL, 10); + sqlite3_free_table(pResult); + + if(nItems > 0) + { + uv_thread_t uvSyncThread, uvDlThread; + g_curDlItems = 0; + g_isDlFinished = FALSE; + g_isUpgradeRunning = TRUE; + uv_thread_create(&uvDlThread, __uvDownloadResThread, NULL); + uv_thread_create(&uvSyncThread, __uvSyncResThread, NULL); + LOG_EX(LOG_Debug, "Load Pre Download Items: %d\n", nItems); + } +} + +static int __getEnumResInfo(void) +{ + __saveUpgradeInfo((PSKIN_RES_INFO)g_emuUpgradeInfo, sizeof(g_emuUpgradeInfo) / sizeof(g_emuUpgradeInfo[0])); +} + +int SkinUpgrade(char* pUpdData) +{ + int nItems = 0; + PSKIN_RES_INFO pUpgResInfo; + cJSON *pRoot, *pList; + +#if 1 + FILE *pFile = fopen("/mnt/UDISK/skinupgrade.txt", "w+"); + fwrite(pUpdData, 1, strlen(pUpdData), pFile); + fclose(pFile); +#endif + + if (pUpdData == NULL || strlen(pUpdData) == 0) + { + LOG_EX(LOG_Error, "Input Params Error\n"); + return (-ERR_INPUT_PARAMS); + } + + LOG_EX(LOG_Debug, "Upgrade Cmd: [%s]\n", pUpdData); + //fprintf(stdout, "%s\n", pUpdData); + + pRoot = cJSON_Parse(pUpdData); + + if(pRoot == NULL) + { + LOG_EX(LOG_Error, "Parse Json Error\n"); + return (-ERR_NO_ITEMS); + } + + nItems = cJSON_GetArraySize(pRoot); + + if(nItems <= 0) + { + LOG_EX(LOG_Error, "Upgrade Item: %d\n", nItems); + cJSON_Delete(pRoot); + return (-ERR_NO_ITEMS); + } + + pUpgResInfo = (PSKIN_RES_INFO)malloc(sizeof(SKIN_RES_INFO) * nItems); + + if(pUpgResInfo == NULL) + { + LOG_EX(LOG_Error, "Malloc %d Memory Error\n", nItems); + cJSON_Delete(pRoot); + return (-ERR_MALLOC_MEMORY); + } + + LOG_EX(LOG_Debug, "Array Size = %d\n", nItems); + + memset(pUpgResInfo, 0, sizeof(SKIN_RES_INFO) * nItems); + pList = pRoot->child; + + for(int i = 0; i < nItems; i++) + { + pUpgResInfo[i].resType = VOICE_RES;//cJSON_GetObjectItem(pList, "resourceType")->valueint; + pUpgResInfo[i].pResVer = strdup(cJSON_GetObjectItem(pList, "resourceVersion")->valuestring); + pUpgResInfo[i].pKeyName = strdup(cJSON_GetObjectItem(pList, "resourceName")->valuestring); + pUpgResInfo[i].pLocalPath = strdup(cJSON_GetObjectItem(pList, "url")->valuestring); + pUpgResInfo[i].pMD5Chksum = strdup(cJSON_GetObjectItem(pList, "md5")->valuestring); + + pList = pList->next; + } + + cJSON_Delete(pRoot); + + g_isUpgradeRunning = TRUE; + __dumpSkinsInfo(pUpgResInfo, nItems); + __saveUpgradeInfo(pUpgResInfo, nItems); + + free(pUpgResInfo); +} + +char* SQLiteGetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom) +{ + char *pSkinPath = strdup(""); + int rc = 0; + char* pErrMsg = NULL; + UT_string *pSqlCmd = NULL; + char **pResult = NULL; + int iRow = 0, iCol = 0; + int queCol = 13; + int colPath = 21; + + utstring_new(pSqlCmd); + + if(g_isVerifyRes) + { + utstring_printf(pSqlCmd, "SELECT *, RANDOM() AS rnd, ResCheck(localPath, md5Chksum, resType) as resOK " + "FROM %s.%s, %s.%s\n" + "WHERE %s.keyName = \'%s\' AND resOK = 0 AND %s.resId = %s.ID\n" + "UNION\n" + "SELECT *, RANDOM() AS rnd, ResCheck(localPath, md5Chksum, resType) as resOK " + "FROM main.%s, main.%s\n" + "WHERE %s.keyName = \'%s\' AND resOK = 0 AND %s.resId = %s.ID\n" + "ORDER BY priority DESC, rnd " + "LIMIT 1", + SKIN_USER_DB, SKIN_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME); + } + else + { + utstring_printf(pSqlCmd, "SELECT *, RANDOM() AS rnd " + "FROM %s.%s, %s.%s\n" + "WHERE %s.keyName = \'%s\' AND %s.resId = %s.ID\n" + "UNION\n" + "SELECT *, RANDOM() AS rnd " + "FROM main.%s, main.%s\n" + "WHERE %s.keyName = \'%s\' AND %s.resId = %s.ID\n" + "ORDER BY priority DESC, rnd " + "LIMIT 1", + SKIN_USER_DB, SKIN_TBL_NAME, SKIN_USER_DB, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, RES_TBL_NAME, + SKIN_TBL_NAME, pKeyName, SKIN_TBL_NAME, RES_TBL_NAME); + queCol = 12; + colPath = 20; + } + + rc = sqlite3_get_table(g_pMemDb, utstring_body(pSqlCmd), &pResult, &iRow, &iCol, &pErrMsg); + + if(rc != SQLITE_OK) + { + LOG_EX(LOG_Error, "Run SQL \n[%s]\n Error: %s(%d)\n", utstring_body(pSqlCmd), pErrMsg, rc); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return (pSkinPath); + } + + if(iRow == 1 && iCol == queCol) + { + + if(access(pResult[colPath], F_OK) != 0) + { + LOG_EX(LOG_Error, "Res %s --> %s not exists\n", pKeyName, pResult[colPath]); + } + else + { + free(pSkinPath); + pSkinPath = strdup(pResult[colPath]); + } +#if 0 + for(int i = 0; i <= 21; i++) + { + LOG_EX(LOG_Debug, "[%d]: {%s}\n", i, pResult[i]); + } +#endif + } + +#if 0 + int index = iCol; + for(int i = 0; i < iRow; i++) + { + fprintf(stdout, "----------%d[%d, %d]---------\n", i, iRow, iCol); + + for(int j = 0; j < iCol; j++) + { + int tblCol = i * iCol + j; + + fprintf(stdout, "%s(%d, %d) = [%s]\n", pResult[tblCol], j, index, pResult[index]); + index++; + } + } +#endif + + sqlite3_free_table(pResult); + utstring_free(pSqlCmd); + + if(strcmp(pSkinPath, "") == 0) + { + free(pSkinPath); + return TblGetSkinsResource(pKeyName, pResType, pVersion, pComeFrom); + } + else + { + return (pSkinPath); + } +} + +char* TblGetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom) +{ + + for(int i = 0; i < sizeof(g_SkinDefaultResTable) / sizeof(g_SkinDefaultResTable[0]); i++) + { + if(strcmp(g_SkinDefaultResTable[i].pKeyName, pKeyName) == 0) + { + return strdup(g_SkinDefaultResTable[i].pLocalPath); + } + } + + return strdup(""); +} + +char* GetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom) +{ + if(g_isUpgradeRunning) + { + return TblGetSkinsResource(pKeyName, pResType, pVersion, pComeFrom); + } + else + { + return SQLiteGetSkinsResource(pKeyName, pResType, pVersion, pComeFrom); + } +} + +unsigned int SkinsDefaultSize(void) +{ + return (g_tolDefaultSkins + 1); +} + +PSKIN_RES_INFO SkinsItemById(int iId) +{ + if(iId < 0 || iId > g_tolDefaultSkins) + { + return (NULL); + } + + return ((PSKIN_RES_INFO)&g_SkinDefaultResTable[iId - 1]); +} + +static int __verifyResValuableCb(void *pData, int argc, char **argv, char **azColName) +{ + char sqlCmd[256]; + char* pErrMsg = NULL; + + if(argc < 3) + { + return 0; + } + + sqlite3_exec(g_pMemDb, "BEGIN TRANSACTION;", NULL, NULL, NULL); + for(int i = 0; i < argc; i++) + { + if(strcmp(azColName[i], "ID") == 0) + { + LOG_EX(LOG_Error, "Cleanup Bad Resources: %s\n", argv[i + 1]); + + memset(sqlCmd, 0, 256); + sprintf(sqlCmd, "DELETE FROM %s.%s WHERE ID = %s", SKIN_USER_DB, RES_TBL_NAME, argv[i]); + + if(sqlite3_exec(g_pMemDb, sqlCmd, __verifyResValuableCb, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL: %s\nError: %s\n", sqlCmd, pErrMsg); + sqlite3_free(pErrMsg); + sqlite3_exec(g_pMemDb, "ROLLBACK;", NULL, NULL, NULL); + return -1; + } + + unlink(argv[i + 1]); + } + } + sqlite3_exec(g_pMemDb, "END TRANSACTION;", NULL, NULL, NULL); + + return (0); +} + +static void VerifySkinResInfo(void) +{ + UT_string *pSqlCmd = NULL; + char* pErrMsg = NULL; + + utstring_new(pSqlCmd); + utstring_printf(pSqlCmd, "SELECT ID, localPath, md5Chksum FROM %s.%s " + "WHERE ResCheck(localPath, md5Chksum, 1) != 0", SKIN_USER_DB, RES_TBL_NAME); + + if(sqlite3_exec(g_pMemDb, utstring_body(pSqlCmd), __verifyResValuableCb, 0, &pErrMsg) != SQLITE_OK) + { + LOG_EX(LOG_Error, "SQL Error: %s\n", pErrMsg); + sqlite3_free(pErrMsg); + utstring_free(pSqlCmd); + return; + } + + utstring_free(pSqlCmd); +} + +void SkinIsVerifyRes(int isVerify) +{ + g_isVerifyRes = isVerify; +} + +int SkinInit(void) +{ + int rc = 0; + UT_string* pPath = NULL; +#if 0 + int tmUsed = 0; + struct timeval tmStart, tmEnd; + + if(DBusLibuvGetRuntime() == NULL) + { + int ret = 0; + uv_thread_t uvThread; + LOG_EX(LOG_Warn, "+++++++++++++++++++++++System Uninit\n"); + + DBusConnection* pBus = DBusWithLibuvInit(GetDBusDefaultLoop(), + g_pModInfoTable[MODULE_SKINS].modAliase, + __dusOnMsg, + NULL, + NULL, //KeyEventCb, + &ret); + + if(pBus == NULL) + { + LOG_EX(LOG_Error, "DBusWithLibuvInit Error: %d\n", ret); + return -ERR_UNINIT_ITEM; + } + + uv_thread_create(&uvThread, uvLoopProc, NULL); + } +#endif + + uv_rwlock_init(&g_uvSkinRwLock); + uv_rwlock_init(&g_uvDlRwLock); + uv_rwlock_init(&g_SkinCacheRwLock); + + utstring_new(pPath); + + utstring_printf(pPath, "mkdir -p %s/image > /dev/zero", DOWNLOAD_RES_ROOT_PATH); + rc = system(utstring_body(pPath)); + + utstring_renew(pPath); + utstring_printf(pPath, "mkdir -p %s/voice > /dev/zero", DOWNLOAD_RES_ROOT_PATH); + rc = system(utstring_body(pPath)); + + utstring_free(pPath); + + rc = __skinCreateCfgFile(SKINS_DB_PATH); + + if(rc != SQLITE_OK) + { + return rc; + } + + // gettimeofday(&tmStart, NULL); + VerifySkinResInfo(); +// gettimeofday(&tmEnd, NULL); + +// tmUsed = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmStart.tv_sec * 1000000 + tmStart.tv_usec); +// LOG_EX(LOG_Debug, "VerifySkinResInfo used time: %d(us)\n", tmUsed); + + __loadPreUpgradeInfo(); + //__getEnumResInfo(); + //__getUpgradeInfo("./hotfix.txt"); + //__loadDownloadItems(); + + //__dumpSkinsInfo(); +} diff --git a/app/libuvdbus/src/Framework/SvrManager/svr_manager.c b/app/libuvdbus/src/Framework/SvrManager/svr_manager.c new file mode 100644 index 0000000..2a15b1c --- /dev/null +++ b/app/libuvdbus/src/Framework/SvrManager/svr_manager.c @@ -0,0 +1,235 @@ +#include "server_addr.h" +#include "log.h" +#include "config_engine.h" +#include "libuv_dbus.h" + +const char* g_ServerModuleStr[] = +{ + "YUNXIN_MODULE", + "VOICE_MODULE", + "VOICE_AI_MODULE", + "SERVER_MODULE", + "LOG_MODULE", + "MARK_POINT_MODULE", + "TTS_MODULE", + "DC_MODULE", + "UNKNOWN_MODULE" +}; + +const char* g_ServerModeStr[] = +{ + "DEV_MODE", + "TEST_MODE", + "PUBLISH_MODE", + "PUBLISH_PREBUILD", + "UNKNOWN_MODE" +}; + +const char* g_KeyMapStr[] = +{ + "VOICE_APP_KEY", + "VOICE_APP_SECRET", + "UNKNOWN_KEYMAP" +}; + +const char* SvrModuleStr(SERVER_MODULE_TYPE module) +{ + return g_ServerModuleStr[module]; +} + +const char* SvrModeStr(SERVER_MODE_TYPE mode) +{ + return g_ServerModeStr[mode]; +} + +const char* g_VoiceKeyMap[VOICE_MAX][MAX_MODE] = { + { // VOICE_APP_KEY + "vbox-dev", + "vbox-dev", + "vbox-online", + "vbox-online", + }, + { // VOICE_APP_SECRET + "b1ec33c03df80ea3035bc9ccaa4af09c", + "b1ec33c03df80ea3035bc9ccaa4af09c", + "8714d6de1c83f21dda5fc9a905a59ac1", + "8714d6de1c83f21dda5fc9a905a59ac1", + }, +}; + +const char* g_ServerAddr[MAX_MODULE][MAX_MODE] = { + { // YUNXIN_MODULE + "2e37bc56a9b7ec3f6b8f41f60b81eb92", + "2e37bc56a9b7ec3f6b8f41f60b81eb92", + "dbb00213c23ea3709aae12ceb4c4e54e", + "7fc939cdb26ec2fa343b7c47a0617190", + }, + { // VOICE_MODULE + "ws://vbox-test.netease.com/netty/websocket", + "ws://vbox-test.netease.com/netty3/websocket", + "wss://vbox-asr.3.163.com/websocket", + "ws://vbox-test.netease.com/asr/websocket", + }, + { // VOICE_AI_MODULE + "http://api.multimedia.netease.com/imgtest/yqbot31_8686/", + "http://api.multimedia.netease.com/imgtest/yqbot29_8686/", + "https://vbox-smart.3.163.com/ ", + "http://api.multimedia.netease.com/imgtest/yqbot30_8888/", + }, + { // SERVER_MODULE + "http://api.multimedia.netease.com/imgtest/yqbot27_7677/", + "http://api.multimedia.netease.com/imgtest/yqbot31_7676/", + "https://vbox-server.3.163.com/", + "http://api.multimedia.netease.com/imgtest/yqbot22_7678/", + }, + { // LOG_MODULE + "http://vbox-log-test.netease.com/logCollectDev/vbox/logCollect/uploadLog", + "http://vbox-log-test.netease.com/logCollect/vbox/logCollect/uploadLog", + "https://vbox-log.3.163.com/vbox/logCollect/uploadLog", + "http://vbox-log-test.netease.com/logCollectOnline/vbox/logCollect/uploadLog", + }, + { // MARK_POINT_MODULE + "http://vbox-log-test.netease.com/buriedDev/vbox/log/add", + "http://vbox-log-test.netease.com/buriedTest/vbox/log/add", + "https://vbox-log.3.163.com/vbox/log/add", + "http://vbox-log-test.netease.com/buriedOnline/vbox/log/add", + }, + { // TTS_MODULE + "http://api.openai.netease.com/vbox-tts-dev/vbox/tts/transform", + "http://api.openai.netease.com/vbox-tts-test/vbox/tts/transform", + "https://vbox-tts.3.163.com/vbox/tts/transform", + "http://api.openai.netease.com/vbox-tts-online/vbox/tts/transform", + }, + { // DC_MODULE + "http://api.multimedia.netease.com/imgtest/yqbot27_7677/vbox/uploadFile", + "http://api.multimedia.netease.com/imgtest/yqbot31_7676/vbox/uploadFile", + "https://vbox-server.3.163.com/vbox/uploadFile", + "http://api.multimedia.netease.com/imgtest/yqbot22_7678/vbox/uploadFile", + }, +}; + +static unsigned int g_SvrMode = PUBLISH_MODE; + +void DumpCurServerAddr(const char* pTags) +{ + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Info, "%s\t Current Server Mode: %s\n", pTags, SvrModeStr(g_SvrMode)); + } + else + { + LOG_EX2(LOG_Info, "Current Server Mode: %s\n", SvrModeStr(g_SvrMode)); + } + +#if 0 + LOG_EX2(LOG_Info, "Voice Key = [%s], Secret = [%s]\n", + GetCurVoiceKeyValue(VOICE_APP_KEY), GetCurVoiceKeyValue(VOICE_APP_SECRET)); + + LOG_EX2(LOG_Info, "--------------------------------------------------------" + "----------------------------------------------\n"); + + LOG_EX2(LOG_Info, "| Module | " + "Server URL |\n"); + + LOG_EX2(LOG_Info, "--------------------------------------------------------" + "----------------------------------------------\n"); + + for(int i = 0; i < MAX_MODULE; i++) + { + LOG_EX2(LOG_Info, "| %-17s | %-78s |\n", SvrModuleStr(i), GetCurServerAddr(i)); + } + + LOG_EX2(LOG_Info, "--------------------------------------------------------" + "----------------------------------------------\n"); +#endif + +} + +SERVER_MODE_TYPE GetCurrentServerMode(void) +{ + return g_SvrMode; +} + +void SetCurrentServerMode(SERVER_MODE_TYPE mode) +{ + if(mode >= 0 && mode < MAX_MODE) + { + if(g_SvrMode != mode) + { + LOG_EX(LOG_Debug, "Change server mode from %s(%d) to %s(%d)\n", + g_ServerModeStr[g_SvrMode], g_SvrMode, g_ServerModeStr[mode], mode); + + g_SvrMode = mode; + + CfgSetIntValue("ServerMode", mode); + } + else + { + LOG_EX(LOG_Warn, "Current mode is %s(%d) yet\n", g_ServerModeStr[mode], mode); + } + } + else + { + LOG_EX(LOG_Error, "Unknown Mode: %d, current mode: %s(%d)\n", + mode, g_ServerModeStr[g_SvrMode], g_SvrMode); + } +} + +char* GetCurServerAddr(SERVER_MODULE_TYPE module) +{ + if(module >= 0 && module < MAX_MODULE) + { + return (char*)g_ServerAddr[module][g_SvrMode]; + } + else + { + LOG_EX(LOG_Error, "Unknown Module: %s(%d)\n", g_ServerModuleStr[module], module); + return ""; + } +} + +char* GetCurVoiceKeyValue(VOICE_KEYMAP_TYPE keyMap) +{ + if(keyMap >= 0 && keyMap < VOICE_MAX) + { + return (char*)g_VoiceKeyMap[keyMap][g_SvrMode]; + } + else + { + LOG_EX(LOG_Error, "Unknown KeyMap Type: %s(%d)\n", g_KeyMapStr[keyMap], keyMap); + return ""; + } +} + +static PDBUS_MSG_PACK __dusOnMsg(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ + return NULL; +} + +static void uvLoopProc(void *pParams) +{ + RunUVLoop(GetDBusDefaultLoop()); + pthread_detach(pthread_self()); +} + +void ServerManagerInit(void) +{ + int ret = 0; + uv_thread_t uvThread; + LOG_EX(LOG_Warn, "+++++++++++++++++++++++System Uninit\n"); + + DBusConnection* pBus = DBusWithLibuvInit(GetDBusDefaultLoop(), + g_pModInfoTable[MODULE_SKINS].modAliase, + __dusOnMsg, + NULL, + NULL, //KeyEventCb, + &ret); + + if(pBus == NULL) + { + LOG_EX(LOG_Error, "DBusWithLibuvInit Error: %d\n", ret); + return; + } + + uv_thread_create(&uvThread, uvLoopProc, NULL); +} diff --git a/app/libuvdbus/src/Framework/Timer/timer.c b/app/libuvdbus/src/Framework/Timer/timer.c new file mode 100644 index 0000000..0263dd8 --- /dev/null +++ b/app/libuvdbus/src/Framework/Timer/timer.c @@ -0,0 +1,773 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" + +#define TIMER_TIMEOUT (200) + +#define IS_LEAP_YEAR(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +static unsigned char g_DayOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +typedef struct +{ + void* pUserData; + OnAlarmTimer pOnAlarmCb; + unsigned int alarmId; + + struct tm setDateTime; + int setWeekDay; + unsigned int repeatMode; + + struct tm onDateTime; + time_t onTimestamp; + unsigned int timerPriority; + + UT_hash_handle hh; ///< UT Hash handle +} ALARM_ITEM_DATA, *PALARM_ITEM_DATA; + +static uv_timer_t g_uvTimer; +static unsigned int g_iAlarmId = 1; +static struct tm g_LocalTime; +static time_t g_TimeStamp; +static uv_loop_t* g_pMainLoop = NULL; +static uv_rwlock_t g_uvHashRwLock; +static PALARM_ITEM_DATA g_TimerTbl = NULL; + +const char* DumpTimerRepeatModeString(int mode) +{ + switch(mode & 0xFF) + { + case REPEAT_MODE_NONE: return "NONE"; + case REPEAT_MODE_EVERY_DAY: return "EVERY_DAY"; + case REPEAT_MODE_WORKDAY: return "WORKDAY"; + case REPEAT_MODE_HOLIDAY: return ("REPEAT_MODE_HOLIDAY"); + case REPEAT_MODE_WEEKEND: return "WEEKEND"; + case REPEAT_MODE_WEEKDAY: return "WEEKDAY"; + case REPEAT_MODE_EVERY_MONTH_DAY: return "EVERY_MONTH_DAY"; + case REPEAT_MODE_EVERY_YEAR_DAY: return "EVERY_YEAR_DAY"; + case REPEAT_MODE_EVERY_TIME: return ("EVERY_TIME"); + case REPEAT_MODE_MONTH_LAST_DAY: return "REPEAT_MODE_MONTH_LAST_DAY"; + default: return ("Unknown Mode"); + } +} + +static int __timestampSort(PALARM_ITEM_DATA p1, PALARM_ITEM_DATA p2) +{ + if(p1->onTimestamp == p2->onTimestamp) + { + return (p2->timerPriority - p1->timerPriority); + } + else + { + return (p1->onTimestamp - p2->onTimestamp); + } +} + +static int __getNextOnTimestamp(PALARM_ITEM_DATA pInfo) +{ + int ret; + struct tm setTime; + time_t timestamp; + + if(pInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + if(pInfo->repeatMode == REPEAT_MODE_NONE) + { + pInfo->onTimestamp = 0; + return (-ERR_INPUT_PARAMS); + } + + timestamp = pInfo->onTimestamp + 24 * 3600; + pInfo->onTimestamp = timestamp; + localtime_r(×tamp, &setTime); + + switch(pInfo->repeatMode) + { + case REPEAT_MODE_EVERY_DAY: + localtime_r(×tamp, &pInfo->onDateTime); + break; + + case REPEAT_MODE_WORKDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 0); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_HOLIDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 1); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_WEEKEND: + while(setTime.tm_wday != 0 && setTime.tm_wday != 6) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + + case REPEAT_MODE_WEEKDAY: + if(pInfo->setDateTime.tm_wday == 0) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + else if(pInfo->setDateTime.tm_wday & (1 << 7)) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + + while(((1 << setTime.tm_wday) & pInfo->setDateTime.tm_wday) == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + + break; + + case REPEAT_MODE_EVERY_TIME: + timestamp = mktime(&g_LocalTime); + + if(pInfo->setDateTime.tm_hour > 0) + { + timestamp += pInfo->setDateTime.tm_hour * 3600; + } + + if(pInfo->setDateTime.tm_min > 0) + { + timestamp += pInfo->setDateTime.tm_min * 60; + } + + if(pInfo->setDateTime.tm_sec > 0) + { + timestamp += pInfo->setDateTime.tm_sec; + } + + localtime_r(×tamp, &pInfo->onDateTime); + pInfo->onTimestamp = timestamp; + break; + + case REPEAT_MODE_MONTH_LAST_DAY: + if(pInfo->onDateTime.tm_mon < 11) + { + pInfo->onDateTime.tm_mon++; + } + else + { + pInfo->onDateTime.tm_mon = 0; + pInfo->onDateTime.tm_year++; + } + + pInfo->onDateTime.tm_mday = g_DayOfMonth[pInfo->onDateTime.tm_mon]; + if(IS_LEAP_YEAR(pInfo->onDateTime.tm_year) && (pInfo->onDateTime.tm_mon == 1)) + { + pInfo->onDateTime.tm_mday += 1; + } + + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + } + + return (0); +} + +static int __getOnTimestamp(PALARM_ITEM_DATA pInfo) +{ + int ret = 0; + struct tm setTime; + time_t timestamp; + + if(pInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + if(pInfo->setDateTime.tm_hour == -1) + { + pInfo->onDateTime.tm_hour = g_LocalTime.tm_hour; + } + else + { + pInfo->onDateTime.tm_hour = pInfo->setDateTime.tm_hour; + } + + if(pInfo->setDateTime.tm_min == -1) + { + pInfo->onDateTime.tm_min = g_LocalTime.tm_min; + } + else + { + pInfo->onDateTime.tm_min = pInfo->setDateTime.tm_min; + } + + if(pInfo->setDateTime.tm_sec == -1) + { + pInfo->onDateTime.tm_sec = g_LocalTime.tm_sec; + } + else + { + pInfo->onDateTime.tm_sec = pInfo->setDateTime.tm_sec; + } + + switch(pInfo->repeatMode) + { + case REPEAT_MODE_EVERY_MONTH_DAY: + pInfo->setDateTime.tm_mon = -1; + pInfo->setDateTime.tm_year = -1; + case REPEAT_MODE_EVERY_YEAR_DAY: + pInfo->setDateTime.tm_year = -1; + case REPEAT_MODE_NONE: + if(pInfo->setDateTime.tm_year == -1) + { + pInfo->onDateTime.tm_year = g_LocalTime.tm_year; + } + else + { + pInfo->onDateTime.tm_year = pInfo->setDateTime.tm_year; + } + + if(pInfo->setDateTime.tm_mon == -1) + { + pInfo->onDateTime.tm_mon = g_LocalTime.tm_mon; + } + else + { + pInfo->onDateTime.tm_mon = pInfo->setDateTime.tm_mon; + } + + if(pInfo->setDateTime.tm_mday == -1) + { + pInfo->onDateTime.tm_mday = g_LocalTime.tm_mday; + } + else + { + pInfo->onDateTime.tm_mday = pInfo->setDateTime.tm_mday; + } + break; + + case REPEAT_MODE_EVERY_DAY: + case REPEAT_MODE_WORKDAY: + case REPEAT_MODE_WEEKEND: + case REPEAT_MODE_WEEKDAY: + case REPEAT_MODE_EVERY_TIME: + case REPEAT_MODE_HOLIDAY: + pInfo->onDateTime.tm_year = g_LocalTime.tm_year; + pInfo->onDateTime.tm_mon = g_LocalTime.tm_mon; + pInfo->onDateTime.tm_mday = g_LocalTime.tm_mday; + break; + case REPEAT_MODE_MONTH_LAST_DAY: + pInfo->onDateTime.tm_year = g_LocalTime.tm_year; + pInfo->onDateTime.tm_mon = g_LocalTime.tm_mon; + pInfo->onDateTime.tm_mday = g_DayOfMonth[g_LocalTime.tm_mon]; + if(IS_LEAP_YEAR(g_LocalTime.tm_year) && (g_LocalTime.tm_mon == 1)) + { + pInfo->onDateTime.tm_mday += 1; + } + break; + } + + pInfo->onDateTime.tm_wday = g_LocalTime.tm_wday; + pInfo->onDateTime.tm_yday = g_LocalTime.tm_yday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + + if(pInfo->repeatMode == REPEAT_MODE_NONE) + { + return (0); + } + + memcpy(&setTime, &g_LocalTime, sizeof(struct tm)); + + if(mktime(&setTime) > (pInfo->onTimestamp + 1)) + { + if(pInfo->repeatMode == REPEAT_MODE_EVERY_MONTH_DAY) + { + DEBUG_CODE_LINE(); + if(pInfo->onDateTime.tm_mon < 11) + { + pInfo->onDateTime.tm_mon++; + } + else + { + pInfo->onDateTime.tm_mon = 0; + pInfo->onDateTime.tm_year++; + } + + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + return (0); + } + else if(pInfo->repeatMode == REPEAT_MODE_EVERY_YEAR_DAY) + { + pInfo->onDateTime.tm_year++; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + return (0); + } + else if(pInfo->repeatMode == REPEAT_MODE_MONTH_LAST_DAY) + { + if(pInfo->onDateTime.tm_mon < 11) + { + pInfo->onDateTime.tm_mon++; + } + else + { + pInfo->onDateTime.tm_mon = 0; + pInfo->onDateTime.tm_year++; + } + + pInfo->onDateTime.tm_mday = g_DayOfMonth[pInfo->onDateTime.tm_mon]; + if(IS_LEAP_YEAR(pInfo->onDateTime.tm_year) && (pInfo->onDateTime.tm_mon == 1)) + { + pInfo->onDateTime.tm_mday += 1; + } + + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + return (0); + } + else + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + } + + switch(pInfo->repeatMode) + { + case REPEAT_MODE_EVERY_DAY: + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + + case REPEAT_MODE_WORKDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 0); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_HOLIDAY: + do + { + ret = CurrentIsWorkDay(setTime.tm_year, setTime.tm_yday); + + if(ret == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + + localtime_r(×tamp, &setTime); + } + } while(ret == 1); + + if(ret < 0) + { + pInfo->onTimestamp = 0; + pInfo->onDateTime.tm_year = -1; + pInfo->onDateTime.tm_mon = -1; + pInfo->onDateTime.tm_mday = -1; + } + else + { + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + } + break; + + case REPEAT_MODE_WEEKEND: + while(setTime.tm_wday != 0 && setTime.tm_wday != 6) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + break; + + case REPEAT_MODE_WEEKDAY: + if(pInfo->setDateTime.tm_wday == 0) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + else if(pInfo->setDateTime.tm_wday & (1 << 7)) + { + pInfo->setDateTime.tm_wday = 1 << 0; + } + + while(((1 << setTime.tm_wday) & pInfo->setDateTime.tm_wday) == 0) + { + timestamp = mktime(&setTime) + 24 * 3600; + localtime_r(×tamp, &setTime); + } + + pInfo->onDateTime.tm_year = setTime.tm_year; + pInfo->onDateTime.tm_mon = setTime.tm_mon; + pInfo->onDateTime.tm_mday = setTime.tm_mday; + pInfo->onTimestamp = mktime(&pInfo->onDateTime); + + break; + + case REPEAT_MODE_EVERY_TIME: + timestamp = mktime(&g_LocalTime); + + if(pInfo->setDateTime.tm_hour > 0) + { + timestamp += pInfo->setDateTime.tm_hour * 3600; + } + + if(pInfo->setDateTime.tm_min > 0) + { + timestamp += pInfo->setDateTime.tm_min * 60; + } + + if(pInfo->setDateTime.tm_sec > 0) + { + timestamp += pInfo->setDateTime.tm_sec; + } + + localtime_r(×tamp, &pInfo->onDateTime); + pInfo->onTimestamp = timestamp; + break; + } + + return (0); +} + +static void __timerout200msCb(uv_timer_t *pTimer) +{ + PALARM_ITEM_DATA pItem = NULL, pTemp = NULL; + + // upgrade current time and timestamp + g_TimeStamp = time((time_t*)NULL); + localtime_r(&g_TimeStamp, &g_LocalTime); + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ITER(hh, g_TimerTbl, pItem, pTemp) + { + // cleanup out of time more than 10s timer + if(g_TimeStamp - pItem->onTimestamp > 10) + { + LOG_EX(LOG_Warn, "Remove out of time timer: %u, %ld, %ld\n", pItem->alarmId, g_TimeStamp, pItem->onTimestamp); + HASH_DEL(g_TimerTbl, pItem); + free(pItem); + + continue; + } + + // timer not on time + if(pItem->onTimestamp != g_TimeStamp) + { + break; + } + + // timer on time, call callback + if(pItem->pOnAlarmCb) + { + pItem->pOnAlarmCb(pItem->alarmId, g_TimeStamp, pItem->pUserData); + } + + //LOG_EX(LOG_Debug, "Timer %d Alarming..................\n", pItem->alarmId); + + // cleanup not repeat timer + if(pItem->repeatMode == REPEAT_MODE_NONE) + { + HASH_DEL(g_TimerTbl, pItem); + free(pItem); + } + else + { + // calc next on time + int ret = __getNextOnTimestamp(pItem); + + if(ret != 0 || pItem->onTimestamp == 0) + { + // some error, remove it + LOG_EX(LOG_Error, "Timer %d repeat error: ret = %d, timestamp = %u\n", pItem->alarmId, ret, pItem->onTimestamp); + HASH_DEL(g_TimerTbl, pItem); + free(pItem); + } + else + { + // resort table by upgrade timestamp + HASH_SORT(g_TimerTbl, __timestampSort); + + // show log + LOG_EX(LOG_Debug, "Readd Timer: %u at [%04u-%02u-%02u %02u:%02u:%02u], repMode = %s, Timestamp = %u\n", + pItem->alarmId, + pItem->onDateTime.tm_year + 1900, + pItem->onDateTime.tm_mon + 1, + pItem->onDateTime.tm_mday, + pItem->onDateTime.tm_hour, + pItem->onDateTime.tm_min, + pItem->onDateTime.tm_sec, + DumpTimerRepeatModeString(pItem->repeatMode), + pItem->onTimestamp); + } + } + } + uv_rwlock_wrunlock(&g_uvHashRwLock); +} + +int AlarmTimerInit(uv_loop_t* pLoop) +{ + g_pMainLoop = pLoop; + uv_rwlock_init(&g_uvHashRwLock); + uv_timer_init(g_pMainLoop, &g_uvTimer); + + g_TimeStamp = time((time_t*)NULL); + localtime_r(&g_TimeStamp, &g_LocalTime); + + g_iAlarmId = 1; + + uv_timer_start(&g_uvTimer, __timerout200msCb, 0, TIMER_TIMEOUT); +} + +int AlarmTimerCleanup(void) +{ + uv_timer_stop(&g_uvTimer); + uv_rwlock_destroy(&g_uvHashRwLock); + + if(g_pMainLoop != NULL) + { + AlarmTimerInit(g_pMainLoop); + } +} + +int AlarmTimerRemove(unsigned int tmId) +{ + PALARM_ITEM_DATA pItem = NULL; + + uv_rwlock_rdlock(&g_uvHashRwLock); + HASH_FIND_INT(g_TimerTbl, &tmId, pItem); + uv_rwlock_rdunlock(&g_uvHashRwLock); + + if(pItem == NULL) + { + LOG_EX(LOG_Error, "Can't find item: %u\n", tmId); + return (-ERR_NO_ITEMS); + } + + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_DEL(g_TimerTbl, pItem); + uv_rwlock_wrunlock(&g_uvHashRwLock); + free(pItem); + + return (tmId); +} + +unsigned int AlarmTimerAdd(int year, + int month, + int day, + int hour, + int minute, + int second, + int weekDay, + int repMode, + OnAlarmTimer pOnTimerCb, + int priority, + void *pUserData, + int *pError) +{ + int et; + PALARM_ITEM_DATA pAlarmData = NULL; + + if(pOnTimerCb == NULL) + { + LOG_EX(LOG_Error, "Input Params Error: pOnTimerCb = %p\n", pOnTimerCb); + if(pError) + { + *pError = -ERR_INPUT_PARAMS; + } + + return (0xFFFFFFFF); + } + + g_TimeStamp = time((time_t*)NULL); + localtime_r(&g_TimeStamp, &g_LocalTime); + + pAlarmData = (PALARM_ITEM_DATA)malloc(sizeof(ALARM_ITEM_DATA)); + + if(pAlarmData == NULL) + { + LOG_EX(LOG_Error, "Malloc Memory Error\n"); + + if(pError) + { + *pError = -ERR_MALLOC_MEMORY; + } + + return (0xFFFFFFFF); + } + + memset(pAlarmData, 0, sizeof(ALARM_ITEM_DATA)); + + // save input params + pAlarmData->setDateTime.tm_year = year; + pAlarmData->setDateTime.tm_mon = month; + pAlarmData->setDateTime.tm_mday = day; + pAlarmData->setDateTime.tm_hour = hour; + pAlarmData->setDateTime.tm_min = minute; + pAlarmData->setDateTime.tm_sec = second; + pAlarmData->setDateTime.tm_wday = weekDay; + + pAlarmData->repeatMode = repMode; + pAlarmData->pOnAlarmCb = pOnTimerCb; + pAlarmData->pUserData = pUserData; + pAlarmData->timerPriority = priority; + + // get timer on time + __getOnTimestamp(pAlarmData); + + // check on time + et = pAlarmData->onTimestamp - mktime(&g_LocalTime); + + if(et < -1 || pAlarmData->onTimestamp == 0) + { + LOG_EX(LOG_Debug, "Add Timer Error: [%04u-%02u-%02u %02u:%02u:%02u], repMode = %s(%u), %d, %u/%u\n", + pAlarmData->setDateTime.tm_year + 1900, + pAlarmData->setDateTime.tm_mon + 1, + pAlarmData->setDateTime.tm_mday, + pAlarmData->setDateTime.tm_hour, + pAlarmData->setDateTime.tm_min, + pAlarmData->setDateTime.tm_sec, + DumpTimerRepeatModeString(repMode), repMode, + et, pAlarmData->onTimestamp, mktime(&g_LocalTime)); + + if(pError) + { + *pError = -ERR_INPUT_PARAMS; + } + + return (0xFFFFFFFF); + } + + if(pError) + { + *pError = 0; + } + + // upgrade time global id + pAlarmData->alarmId = __sync_fetch_and_add(&g_iAlarmId, 1); + + // save new timer to hash table, and sort it by timestamp + uv_rwlock_wrlock(&g_uvHashRwLock); + HASH_ADD_INT(g_TimerTbl, alarmId, pAlarmData); + HASH_SORT(g_TimerTbl, __timestampSort); + uv_rwlock_wrunlock(&g_uvHashRwLock); + + LOG_EX(LOG_Debug, "Add: %u [%04u-%02u-%02u %02u:%02u:%02u] at [%04u-%02u-%02u %02u:%02u:%02u], repMode = %s, priority = %d, Timestamp = %u\n", + pAlarmData->alarmId, + (pAlarmData->setDateTime.tm_year == -1) ? 1900 : pAlarmData->setDateTime.tm_year + 1900, + (pAlarmData->setDateTime.tm_mon == -1) ? 0 : pAlarmData->setDateTime.tm_mon + 1, + (pAlarmData->setDateTime.tm_mday == -1) ? 0 : pAlarmData->setDateTime.tm_mday, + (pAlarmData->setDateTime.tm_hour == -1) ? 0 : pAlarmData->setDateTime.tm_hour, + (pAlarmData->setDateTime.tm_min == -1) ? 0 : pAlarmData->setDateTime.tm_min, + (pAlarmData->setDateTime.tm_sec == -1) ? 0 : pAlarmData->setDateTime.tm_sec, + pAlarmData->onDateTime.tm_year + 1900, + pAlarmData->onDateTime.tm_mon + 1, + pAlarmData->onDateTime.tm_mday, + pAlarmData->onDateTime.tm_hour, + pAlarmData->onDateTime.tm_min, + pAlarmData->onDateTime.tm_sec, + DumpTimerRepeatModeString(repMode), + pAlarmData->timerPriority, + pAlarmData->onTimestamp); + + return (pAlarmData->alarmId); +} + + diff --git a/app/libuvdbus/src/Framework/WireshartScript/log_pv1.lua b/app/libuvdbus/src/Framework/WireshartScript/log_pv1.lua new file mode 100644 index 0000000..c5edfdd --- /dev/null +++ b/app/libuvdbus/src/Framework/WireshartScript/log_pv1.lua @@ -0,0 +1,93 @@ +pv1_log_proto = Proto("PV1_Log", "PV1 ES2 Log Protocol") + +log_level_str = +{ + [ 1 ] = "[F]", + [ 2 ] = "[E]", + [ 4 ] = "[W]", + [ 8 ] = "[D]", + [ 16 ] = "[I]", + [ 32 ] = "[T]", + [ 64 ] = "[I]", + [ 128 ] = "[V]", + [ 256 ] = "[S]", + [ 512 ] = "[U]", + [ 0xFFFFFFFF ] = "[A]", +} + +local log_content = ProtoField.string("logContent", "Message:\t") +local log_Seq = ProtoField.uint16("logSeq", "Sequence: \t", base.DEC) +local log_pid = ProtoField.uint32("logPid", "PID: \t\t", base.DEC) +local log_datetime = ProtoField.string("logDateTime", "DateTime:\t\t") +local log_time = ProtoField.string("logTime", "Date:\t\t") +local log_level = ProtoField.uint32("logLevel", "Level: \t\t", base.DEC, log_level_str) + +pv1_log_proto.fields = { +log_Seq, log_content, log_pid, log_datetime, log_level +} + +function pv1_log_proto.dissector(buffer, pinfo, tree) + pinfo.cols.protocol:set("LOG") + local offset = 0 + local buf_len = buffer:len() + local logInfoTree = tree:add(pv1_log_proto, buffer(0, 18), "Log Message Information") + + logInfoTree:add(log_Seq, buffer(offset, 2)) + offset = offset + 2 + + local l_pid = buffer(offset, 4):uint() + logInfoTree:add(log_pid, buffer(offset, 4)) + offset = offset + 4 + + local l_second = buffer(offset, 4):uint() + offset = offset + 4 + + local l_nsecond = buffer(offset, 4):uint() + offset = offset + 4 + + logInfoTree:add(log_datetime, "[" .. os.date("%c", l_second) .. "." .. string.format("%03d", l_nsecond / 1000) .. "]") + + local l_level = buffer(offset, 4):uint() + local l_lvStr + + if l_level == 1 then + l_lvStr = "F" + elseif l_level == 2 then + l_lvStr = "E" + elseif l_level == 4 then + l_lvStr = "W" + elseif l_level == 8 then + l_lvStr = "D" + elseif l_level == 16 then + l_lvStr = "I" + elseif l_level == 32 then + l_lvStr = "T" + elseif l_level == 64 then + l_lvStr = "C" + elseif l_level == 128 then + l_lvStr = "V" + elseif l_level == 256 then + l_lvStr = "S" + elseif l_level == 0xFFFFFFFF then + l_lvStr = "A" + else + l_lvStr = "U" + end + + logInfoTree:add(log_level, buffer(offset, 4)) + offset = offset + 4 + + local logInfo = buffer(offset, buf_len - 19):string() + local logMsgTree = tree:add(pv1_log_proto, buffer(18, buf_len - 18), "Log Message Content") + logMsgTree:add(log_content, logInfo) + + if buffer(buf_len - 1, 1):string() == '\n' then + pinfo.cols.info:set("{" .. tostring(l_pid) .. "} [" .. os.date("%X", l_second) .. "." .. string.format("%03d", l_nsecond / 1000) .. "] [" .. tostring(l_lvStr) .. "] " .. buffer(18, buf_len - 19):string()) + else + pinfo.cols.info:set("{" .. tostring(l_pid) .. "} [" .. os.date("%X", l_second) .. "." .. string.format("%03d", l_nsecond / 1000) .. "] [" .. tostring(l_lvStr) .. "] " .. buffer(18, buf_len - 18):string()) + end +end + +local pv1_log_udp_port_table = DissectorTable.get("udp.port") +--local pv1_log_port = 10000 +pv1_log_udp_port_table:add("10000-10020", pv1_log_proto) diff --git a/app/libuvdbus/src/Framework/libuvEngine/libuv_dbus.c b/app/libuvdbus/src/Framework/libuvEngine/libuv_dbus.c new file mode 100644 index 0000000..e73264b --- /dev/null +++ b/app/libuvdbus/src/Framework/libuvEngine/libuv_dbus.c @@ -0,0 +1,2405 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "libuv_dbus.h" +#include "json_struct.h" +#include "inet_api.h" +#include "crypto.h" +#include "server_addr.h" +#ifdef ENABLE_COUNT_DEBUG +#include "monitor.h" +#endif + +#ifdef ENABLE_COUNT_DEBUG +#define MON_MSG_PROC_STAT ("Message Process") +#define MON_MSG_BST_PROC_STAT ("Boardcast Message Process") +#define MON_USER_MSG_PROC_STAT ("User Message Process") +#define MON_USER_MSG_BST_PROC_STAT ("User Boardcast Message Process") +#endif + +typedef void (*OnDBusSendError)(int, void*); +static void uvOpenKeyEventCb(uv_fs_t* puvFs); + +typedef struct LOOP_TASK_ARRAY +{ + uv_loop_t* pLoop; + int isRunning; + + struct LOOP_TASK_ARRAY *next, *prev; +} *PLOOP_TASK_ARRAY; + +typedef struct +{ + key_t shmKey; +// uint32_t tarMask; +// uint32_t tmSend; + uint32_t msgSize; + + UT_hash_handle hh; ///< UT Hash handle +} UV_SHM_ITEM, *PUV_SHM_ITEM; + +typedef struct +{ + long int msgMask; + unsigned char pMsgContext[0]; +} DBUS_MSG_DATA, *PDBUS_MSG_DATA; + +typedef struct +{ + DBusConnection* pBus; + const char* pBusName; + uint32_t busCmd; + JSON_ENGINE_TYPE type; + void* pStruct; + int iSize; + OnDBusAsyncSendTo cbSendTo; + int enBase64; +} DBUS_ASYNC_PARAMS, *PDBUS_ASYNC_PARAMS; + +static LIBUV_DBUS_PARAMS g_LibuvDBusParam; + +static uv_idle_t g_uvIdleHandle; +static uv_timer_t g_uvTimerPing; +static uv_fs_t g_uvKeyEvent; +static WORKDAY_INFO g_workDayArray; +static WIFI_STATUS g_WifiConnStatus = WIFI_CONNECTED; +static PDBUS_MSG_PROC g_pMsgProcList = NULL; +static uv_rwlock_t g_uvLoopRwLock; +static PLOOP_TASK_ARRAY g_LoopArray = NULL; +static unsigned int g_EnHBLExit = TRUE; +static uv_rwlock_t g_uvMsgProcRwLock; + +#if USED_SHM_TO_DBUS +static uv_rwlock_t g_uvShmHashRwLock; +static PUV_SHM_ITEM g_pShmTbl = NULL; + +static void __addShmIdToTable(key_t shmKey, uint32_t tmSend, uint32_t tarMask, uint32_t msgSize) +{ + PUV_SHM_ITEM pItem = NULL; + + uv_rwlock_rdlock(&g_uvShmHashRwLock); + HASH_FIND_INT(g_pShmTbl, &shmKey, pItem); + uv_rwlock_rdunlock(&g_uvShmHashRwLock); + + if(pItem == NULL) + { + pItem = (PUV_SHM_ITEM)malloc(sizeof(UV_SHM_ITEM)); + + memset(pItem, 0, sizeof(UV_SHM_ITEM)); + pItem->shmKey = shmKey; + + uv_rwlock_wrlock(&g_uvShmHashRwLock); + HASH_ADD_INT(g_pShmTbl, shmKey, pItem); + uv_rwlock_wrunlock(&g_uvShmHashRwLock); + } + + pItem->tmSend = tmSend; + pItem->tarMask = tarMask; + pItem->msgSize = msgSize; +} + +static void __removeReqIdFromTable(key_t shmKey) +{ + PUV_SHM_ITEM pItem = NULL; + + uv_rwlock_rdlock(&g_uvShmHashRwLock); + HASH_FIND_INT(g_pShmTbl, &shmKey, pItem); + uv_rwlock_rdunlock(&g_uvShmHashRwLock); + + if(pItem != NULL) + { + uv_rwlock_wrlock(&g_uvShmHashRwLock); + HASH_DEL(g_pShmTbl, pItem); + uv_rwlock_wrunlock(&g_uvShmHashRwLock); + free(pItem); + } +} + +static void __uvShmTblTaskThreadCb(void *pParam) +{ + struct timeval tv; + PUV_SHM_ITEM pItem = NULL, pTmpItem = NULL; + + while(TRUE) + { + gettimeofday(&tv, NULL); + + HASH_ITER(hh, g_pShmTbl, pItem, pTmpItem) + { + int msgId; + + if(tv.tv_sec - pItem->tmSend <= 60) + { + continue; + } + + msgId = shmget((key_t)pItem->shmKey, pItem->msgSize, 0666 | IPC_CREAT); + + if(msgId == -1) + { + continue; + } + + // Not Boardcast Message + if((pItem->tarMask & 0xFFFF0000) != 0xFFFF0000) + { + PDBUS_MSG_DATA pData = (PDBUS_MSG_DATA)shmat(msgId, NULL, 0); + + if(pData == (void*)-1) + { + continue; + } + + // Nevery Recevied By Anyone + if(pData->msgMask == pItem->tarMask) + { + continue; + } + + shmdt(pData); + shmctl(msgId, IPC_RMID, 0); + __removeReqIdFromTable((key_t)pItem->shmKey); + } + } + + sleep(1); + } + + pthread_detach(pthread_self()); +} +#endif + +PLIBUV_DBUS_PARAMS DBusLibuvGetRuntime(void) +{ + if(g_LibuvDBusParam.pBus == NULL || g_LibuvDBusParam.pLoop == NULL) + { + return NULL; + } + + return &g_LibuvDBusParam; +} + +MODULE_NAME DBusLibGetModName(void) +{ + return g_LibuvDBusParam.modName; +} + +uv_loop_t* GetDBusDefaultLoop(void) +{ + if(g_LibuvDBusParam.pBus == NULL || g_LibuvDBusParam.pLoop == NULL) + { + return uv_default_loop(); + } + + return g_LibuvDBusParam.pLoop; +} + +static void uvAsyncCb(uv_async_t* pAsync) +{ + DBusConnection* pConn = (DBusConnection*)pAsync->data; + dbus_connection_read_write(pConn, 0); + + while(dbus_connection_dispatch(pConn) == DBUS_DISPATCH_DATA_REMAINS); +} + +static void uvTimeoutCb(uv_timer_t* pTimer) +{ + DBusTimeout* timeout = (DBusTimeout*)pTimer->data; + dbus_timeout_handle(timeout); +} + +static void uvPollCb(uv_poll_t* pPoll, int status, int events) +{ + DBusWatch* watch = (DBusWatch*)pPoll->data; + unsigned int uvFlags = 0; + + if(events & UV_READABLE) + { + uvFlags |= DBUS_WATCH_READABLE; + } + + if(events & UV_WRITABLE) + { + uvFlags |= DBUS_WATCH_WRITABLE; + } + + dbus_watch_handle(watch, uvFlags); +} + +static void uvIdleCb(uv_idle_t* phuvIdle) +{ + usleep(1000); +} + +static void uvFsAccessCb(uv_fs_t* puvFs) +{ + if(puvFs->result != 0) + { + IHW_EnableLogLevel((LOG_LEVEL)(LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info), 1); + } + + uv_fs_req_cleanup(puvFs); + free(puvFs); +} + +static void uvReadKeyEventCb(uv_fs_t* puvFs) +{ + if(puvFs->result < 0) + { + uv_fs_req_cleanup(puvFs); + return; + } + else if(puvFs->result == 0) + { + uv_fs_t uvClose; + uv_fs_close(g_LibuvDBusParam.pLoop, &uvClose, g_uvKeyEvent.result, NULL); + } + else + { + uv_buf_t* puvIov = (uv_buf_t*)puvFs->data; + + if(puvIov->len == sizeof(struct input_event)) + { + struct input_event* pKeyEvt = (struct input_event*)puvIov->base; + + if(g_LibuvDBusParam.onKeyCb) + { +// LOG_EX(LOG_Info, "type = %u, code = %u, value = %u\n", pKeyEvt->type, pKeyEvt->code, pKeyEvt->value); + g_LibuvDBusParam.onKeyCb(pKeyEvt->type, pKeyEvt->code, pKeyEvt->value); + } + } + } + + uv_fs_req_cleanup(puvFs); + + usleep(1000); + uv_fs_open(g_LibuvDBusParam.pLoop, &g_uvKeyEvent, R16_TINA_KEY_EVENT_PATH, O_RDONLY, 0, uvOpenKeyEventCb); +} + +static void uvOpenKeyEventCb(uv_fs_t* puvFs) +{ + static uv_buf_t uvIoV; + static struct input_event keyEvent; + + if(puvFs->result < 0) + { + LOG_EX(LOG_Error, "Open Key Event File[%s] Error: %d\n", R16_TINA_KEY_EVENT_PATH, puvFs->result); + uv_fs_req_cleanup(puvFs); + return; + } + + uvIoV = uv_buf_init((void*)&keyEvent, sizeof(struct input_event)); + puvFs->data = (void*)&uvIoV; + + uv_fs_read(g_LibuvDBusParam.pLoop, &g_uvKeyEvent, puvFs->result, &uvIoV, 1, -1, uvReadKeyEventCb); + uv_fs_req_cleanup(puvFs); + + return; +} + +static void DBusAsyncFreeCb(void* pData) +{ + uv_async_t* pAsync = (uv_async_t*)pData; + + if(pAsync) + { + pAsync->data = NULL; + uv_close((uv_handle_t*)pAsync, (uv_close_cb)free); + } +} + +static void DBusPollFreeCb(void* pData) +{ + uv_poll_t* pPoll = (uv_poll_t*)pData; + + if(pPoll) + { + pPoll->data = NULL; + + uv_ref((uv_handle_t*)pPoll); + uv_poll_stop(pPoll); + uv_close((uv_handle_t*)pPoll, (uv_close_cb)free); + } +} + +static dbus_bool_t DBusAddWatchCb(DBusWatch* pWatch, void* pData) +{ + static int isCreate = 0; + int fdDBus, uvPollFlags = 0; + unsigned int dBusWatchFlags; + uv_poll_t* pPoll = NULL; + uv_loop_t* pLoop = (uv_loop_t*)pData; + + if(!dbus_watch_get_enabled(pWatch) + || dbus_watch_get_data(pWatch) != NULL + || isCreate != 0) + { + return TRUE; + } + + fdDBus = dbus_watch_get_unix_fd(pWatch); + dBusWatchFlags = dbus_watch_get_flags(pWatch); + + if(dBusWatchFlags & DBUS_WATCH_READABLE) + { + uvPollFlags |= UV_READABLE; + } + + if(dBusWatchFlags & DBUS_WATCH_WRITABLE) + { + uvPollFlags |= UV_WRITABLE; + } + + pPoll = (uv_poll_t*)malloc(sizeof(uv_poll_t)); + pPoll->data = (void*)pWatch; + + uv_poll_init(pLoop, pPoll, fdDBus); + uv_poll_start(pPoll, uvPollFlags, uvPollCb); + LOG_EX(LOG_Debug, "Create POOL by FD: %d\n", fdDBus); + + uv_unref((uv_handle_t*)pPoll); + + dbus_watch_set_data(pWatch, (void*)pPoll, DBusPollFreeCb); + + isCreate = 1; + return TRUE; +} + +static void DBusRemoveWatchCb(DBusWatch* pWatch, void* pData) +{ + uv_poll_t* pPoll = (uv_poll_t*)dbus_watch_get_data(pWatch); + + if(pPoll) + { + dbus_watch_set_data(pWatch, NULL, NULL); + } +} + +static void DBusNotifyWatchCb(DBusWatch* pWatch, void* pData) +{ + if(dbus_watch_get_enabled(pWatch)) + { + DBusAddWatchCb(pWatch, pData); + } + else + { + DBusRemoveWatchCb(pWatch, pData); + } +} + +static void DBusTimeoutFreeCb(void* pData) +{ + uv_timer_t* pTimer = (uv_timer_t*)pData; + + if(pTimer == NULL) + { + return; + } + + pTimer->data = NULL; + uv_timer_stop(pTimer); + uv_unref((uv_handle_t*)pTimer); + uv_close((uv_handle_t*)pTimer, (uv_close_cb)free); +} + +static dbus_bool_t DBusAddTimeoutCb(DBusTimeout* pTimeout, void* pData) +{ + uv_timer_t* pTimer = NULL; + uv_loop_t* pLoop = (uv_loop_t*)pData; + + if(!dbus_timeout_get_enabled(pTimeout) + || dbus_timeout_get_data(pTimeout) != NULL) + { + return TRUE; + } + + pTimer = (uv_timer_t*)malloc(sizeof(uv_timer_t)); + pTimer->data = pTimeout; + + uv_timer_init(pLoop, pTimer); + uv_timer_start(pTimer, uvTimeoutCb, dbus_timeout_get_interval(pTimeout), 0); + + dbus_timeout_set_data(pTimeout, (void*)pTimer, DBusTimeoutFreeCb); + return TRUE; +} + +static void DBusRemoveTimeoutCb(DBusTimeout* pTimeout, void* pData) +{ + uv_timer_t* pTimer = (uv_timer_t*)dbus_timeout_get_data(pTimeout); + + if(pTimer) + { + dbus_timeout_set_data(pTimeout, NULL, NULL); + } +} + +static void DBusNotifyTimeoutCb(DBusTimeout* pTimeout, void* pData) +{ + if(dbus_timeout_get_enabled(pTimeout)) + { + DBusAddTimeoutCb(pTimeout, pData); + } + else + { + DBusRemoveTimeoutCb(pTimeout, pData); + } +} + +static void DBusWakeupMainLoopCb(void* pData) +{ + uv_async_t* pAsync = (uv_async_t*)pData; + uv_async_send(pAsync); +} + +static void FreeDBusOnMsgCb(uv_work_t* pWork, int status) +{ + PDBUS_MSG_PACK pMsg = (PDBUS_MSG_PACK)pWork->data; + + if(pMsg) + { + free(pMsg); + } + free(pWork); +} + +#if 0 +static void DBusOnBoardcastMsgWorkCb(uv_work_t* pWork) +#else +static int DBusOnBoardcastMsgWorkCb(PDBUS_MSG_PACK pMsg) +#endif +{ + + pMsg->isBstMsg = TRUE; + // Message context on dbus message pad + if(pMsg->msgSize < DBUS_MSG_MAX_PAD_SIZE) + { + if(pMsg->busCmd == CMD_WIFI_STATE_NTF) + { + int err = 0; + PWIFI_STATUS_PRO pWifiInfo = (PWIFI_STATUS_PRO)Json2Struct((const char *)pMsg->pMsg, + JSON_WIFI_STATUS_NOTIFY, FALSE, &err); + + //LOG_EX(LOG_Debug, "pWifiInfo: %s\n", pMsg->pMsg); + if(pWifiInfo && err == 0) + { + if(pWifiInfo->wifi_evt == 0) + { + g_WifiConnStatus = WIFI_CONNECTED; + } + else + { + g_WifiConnStatus = WIFI_DISCONNECTED; + } + } + + if(pWifiInfo) + { + free(pWifiInfo); + } + } + else if(pMsg->busCmd == CMD_CFG_UPG_NOTIFY) + { + } + else if(pMsg->busCmd == CMD_LOG_CONFIG) + { + int err = 0; + PLOG_CFG_PROTOCOL pCfgInfo = (PLOG_CFG_PROTOCOL)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_LOG_CFG_CMD, FALSE, &err); + + //LOG_EX(LOG_Debug, "pCfgInfo: %s\n", pMsg->pMsg); + if(pCfgInfo && err == 0) + { + UpgradLogConfigure(pCfgInfo); + } + + if(pCfgInfo) + { + free(pCfgInfo); + } + } + else if(pMsg->busCmd != CMD_MISC_PING) + { + pMsg->msgDests = 0xFFFFFFFF; + if(g_LibuvDBusParam.onMsgCb) + { + g_LibuvDBusParam.onMsgCb(g_LibuvDBusParam.pLoop, g_LibuvDBusParam.pBus, pMsg); + } + + return 1; + } + } + + return 0; +} + +#if 0 +static void DBusOnMsgWorkAPICb(uv_work_t* pWork) +#else +static int DBusOnMsgWorkAPICb(PDBUS_MSG_PACK pMsg) +#endif +{ + int err = 0; + + pMsg->isBstMsg = FALSE; + + // Message context on dbus message pad + if(pMsg->msgSize < DBUS_MSG_MAX_PAD_SIZE) + { + if(pMsg->busCmd >= CMD_CFG_ADD_REQ && pMsg->busCmd < CMD_CFG_UPG_NOTIFY) + { + OnCfgMsgProcess(pMsg->msgSrc, pMsg->busCmd, pMsg->pMsg); + } + else if(pMsg->busCmd == CMD_LOG_CONFIG) + { + PLOG_CFG_PROTOCOL pCfgInfo = (PLOG_CFG_PROTOCOL)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_LOG_CFG_CMD, FALSE, &err); + + //LOG_EX(LOG_Debug, "pCfgInfo: %s\n", pMsg->pMsg); + if(pCfgInfo && err == 0) + { + UpgradLogConfigure(pCfgInfo); + } + + if(pCfgInfo) + { + free(pCfgInfo); + } + } + else if(pMsg->busCmd == CMD_WORKDAY_DB_RSP) + { + PWORKDAY_INFO pWorkDayInfo = (PWORKDAY_INFO)Json2Struct((const char *)pMsg->pMsg, + JSON_ENGINE_WORKDAY_REQ, FALSE, &err); + + //LOG_EX(LOG_Debug, "WorkDay: %s\n", pMsg->pMsg); + if(pWorkDayInfo && err == 0) + { + memcpy(&g_workDayArray, pWorkDayInfo, sizeof(WORKDAY_INFO)); + g_workDayArray.isReady = TRUE; + LOG_EX(LOG_Debug, "Sync Alarm Database: %s\n", pMsg->pMsg); + } + + //LOG_EX2(LOG_Debug, "Database: %s\n", pMsg->pMsg); + + if(pWorkDayInfo) + { + free(pWorkDayInfo); + } + } + else if(pMsg->busCmd != CMD_MISC_PING) + { + if(g_LibuvDBusParam.onMsgCb) + { + g_LibuvDBusParam.onMsgCb(g_LibuvDBusParam.pLoop, g_LibuvDBusParam.pBus, pMsg); + } + + return 1; + } + } + else // More than 4K size used Share Memory + { + LOG_EX(LOG_Error, "Receive Message Error Size: %d\n", pMsg->msgSize); +#if 0 + PDBUS_MSG_DATA pData = NULL; + int key = strtol(pMsg->pMsg, NULL, 10); + + int msgId = shmget((key_t)key, pMsg->msgSize, 0666 | IPC_CREAT); + + if(msgId == -1) + { + return; + } + + pData = (PDBUS_MSG_DATA)shmat(msgId, NULL, 0); + + if(pData == (void*)-1) + { + return; + } + + //print_hex_dump_bytes("send_", 2, pData, pMsg->msgSize); + + pMsg->pMsg = pData->pMsgContext; + pMsg->msgSize -= sizeof(long int); + + if(pMsg->busCmd != CMD_MISC_PING) + { + g_LibuvDBusParam.onMsgCb(g_LibuvDBusParam.pLoop, g_LibuvDBusParam.pBus, pMsg); + } + + pData->msgMask &= ~(1 << g_LibuvDBusParam.modName); + + // Cleanup Share Memory + if(pData->msgMask == 0) + { + shmctl(msgId, IPC_RMID, 0); +#if USED_SHM_TO_DBUS + __removeReqIdFromTable((key_t)key); +#endif + } + + shmdt(pData); +#endif + } + + return 0; +} + +static DBusHandlerResult DBusOnMsgCb(DBusConnection* pConn, DBusMessage* pMsg, void* user_data) +{ +#if 0 + struct timeval tmBegin, tmEnd; + long long diffTm; +#endif + DBusError error; + PDBUS_MSG_PROC pMsgProc = NULL; + + PDBUS_MSG_PACK pMsgPack = (PDBUS_MSG_PACK)malloc(sizeof(DBUS_MSG_PACK)); + + if(pMsgPack == NULL) + { + LOG_EX(LOG_Error, "Receive Message: No Memory\n"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + memset(pMsgPack, 0, sizeof(DBUS_MSG_PACK)); + + dbus_error_init(&error); + + if(dbus_message_is_signal(pMsg, DBUS_MESSAGE_INTERFACE_NAME, "Notify")) + { + if(dbus_message_get_args(pMsg, &error, + DBUS_TYPE_UINT32, &pMsgPack->msgSrc, // from + DBUS_TYPE_UINT32, &pMsgPack->msgDests, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &pMsgPack->tmTickMSec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &pMsgPack->busCmd, // command type + DBUS_TYPE_STRING, &pMsgPack->pMsg, // message context if had + DBUS_TYPE_INVALID)) + { + pMsgPack->msgSize = strlen((char*)pMsgPack->pMsg); + // reset timeout timer + if(g_LibuvDBusParam.onHblCb && pMsgPack->msgSrc != g_LibuvDBusParam.modName) + { + HeartDaemonUpgrade(pMsgPack->msgSrc); + } + + // Dispatch message except from it's self + if(pMsgPack->msgSrc != g_LibuvDBusParam.modName + && pMsgPack->msgDests & (1 << g_LibuvDBusParam.modName)) + { + if(g_LibuvDBusParam.onMsgCb == NULL) + { + pMsgProc = (PDBUS_MSG_PROC)malloc(sizeof(struct DBUS_MSG_PROC)); + + if(pMsgProc == NULL) + { + LOG_EX(LOG_Error, "Receive Message: No Memory\n"); + free(pMsgPack); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + memset(pMsgProc, 0, sizeof(struct DBUS_MSG_PROC)); + memcpy(&pMsgProc->msgContent, pMsgPack, sizeof(DBUS_MSG_PACK)); + pMsgProc->msgContent.pMsg = strdup(pMsgPack->pMsg); + pMsgProc->msgFrom = 0; + + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_APPEND(g_pMsgProcList, pMsgProc); + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + } + else + { + DBusOnBoardcastMsgWorkCb(pMsgPack); + } + } + } + else + { + LOG_EX(LOG_Error, "Receive Notify Message Error: %s\n", error.message); + dbus_error_free(&error); + } + + free(pMsgPack); + return DBUS_HANDLER_RESULT_HANDLED; + } + else if(dbus_message_is_method_call(pMsg, DBUS_MESSAGE_INTERFACE_NAME, "API")) + { + if(dbus_message_get_args(pMsg, &error, + DBUS_TYPE_UINT32, &pMsgPack->msgSrc, // from + DBUS_TYPE_UINT32, &pMsgPack->msgDests, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &pMsgPack->tmTickMSec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &pMsgPack->busCmd, // command type + DBUS_TYPE_UINT32, &pMsgPack->msgSize, // message size(in bytes) + DBUS_TYPE_STRING, &pMsgPack->pMsg, // message context if had + DBUS_TYPE_INVALID)) + { + // reset timeout timer + if(g_LibuvDBusParam.onHblCb && pMsgPack->msgSrc != g_LibuvDBusParam.modName) + { + HeartDaemonUpgrade(pMsgPack->msgSrc); + } + + // Dispatch message except from it's self + if(pMsgPack->msgSrc != g_LibuvDBusParam.modName + && pMsgPack->msgDests == (1 << g_LibuvDBusParam.modName)) + { + if(g_LibuvDBusParam.onMsgCb == NULL) + { + pMsgProc = (PDBUS_MSG_PROC)malloc(sizeof(struct DBUS_MSG_PROC)); + + if(pMsgProc == NULL) + { + LOG_EX(LOG_Error, "Receive Message: No Memory\n"); + free(pMsgPack); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + memset(pMsgProc, 0, sizeof(struct DBUS_MSG_PROC)); + memcpy(&pMsgProc->msgContent, pMsgPack, sizeof(DBUS_MSG_PACK)); + pMsgProc->msgContent.pMsg = strdup(pMsgPack->pMsg); + pMsgProc->msgFrom = 1; + + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_APPEND(g_pMsgProcList, pMsgProc); + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + } + else + { + DBusOnMsgWorkAPICb(pMsgPack); + } + } + } + else + { + LOG_EX(LOG_Error, "Receive API Message Error: %s\n", error.message); + dbus_error_free(&error); + } + + free(pMsgPack); + return DBUS_HANDLER_RESULT_HANDLED; + } + + free(pMsgPack); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void freeSHMResource(int shmId, void* pData) +{ + // Cleanup Share Memory + if(pData) + { + shmdt(pData); + } + + shmctl(shmId, IPC_RMID, 0); +} + +static void FreeDBusSendToAsyncCb(uv_work_t* pWork, int status) +{ + PDBUS_ASYNC_PARAMS pParam = (PDBUS_ASYNC_PARAMS)pWork->data; + free(pParam->pStruct); + free(pParam); + free(pWork); +} + +static void DBusSendToAsyncCb(uv_work_t* pWork) +{ + int err = 0; + PDBUS_ASYNC_PARAMS pParam = (PDBUS_ASYNC_PARAMS)pWork->data; + const char *pJsonStr = Struct2Json(pParam->pStruct, pParam->type, pParam->enBase64, &err); + + if(pJsonStr == NULL || err != 0) + { + pParam->cbSendTo(err); + return; + } + + err = DBusSendToCommand(pParam->pBus, pParam->pBusName, pParam->busCmd, pJsonStr); + + free((void*)pJsonStr); + + pParam->cbSendTo(err); +} + +int DBusJsonSendToCommandAsync(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int iSize, + OnDBusAsyncSendTo cbSendTo, + int enBase64) +{ + PDBUS_ASYNC_PARAMS pParam = NULL; + uv_work_t* puvWork = NULL; + + if(cbSendTo == NULL) + { + return 0; + } + + pParam = (PDBUS_ASYNC_PARAMS)malloc(sizeof(DBUS_ASYNC_PARAMS)); + puvWork = (uv_work_t*)malloc(sizeof(uv_work_t)); + + pParam->pBus = pBus; + pParam->pBusName = pBusName; + pParam->busCmd = busCmd; + pParam->type = type; + pParam->iSize = iSize; + pParam->pStruct = malloc(iSize); + pParam->cbSendTo = cbSendTo; + pParam->enBase64 = enBase64; + memcpy(pParam->pStruct, pStruct, iSize); + + puvWork->data = (void*)pParam; + uv_queue_work(g_LibuvDBusParam.pLoop, puvWork, DBusSendToAsyncCb, FreeDBusSendToAsyncCb); + + return 0; +} + +int DBusJsonSendToCommand(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64) +{ + int ret, err = 0; + const char* pJsonStr = Struct2Json(pStruct, type, enBase64, &err); + + if(pJsonStr == NULL || err != 0) + { + return err; + } + + ret = DBusSendToCommand(pBus, pBusName, busCmd, pJsonStr); + + free((void*)pJsonStr); + + return ret; +} + +int DBusJsonBoardcastCommand(DBusConnection* pBus, + uint32_t msgToMask, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64) +{ + int ret, err = 0; + const char* pJsonStr = Struct2Json(pStruct, type, enBase64, &err); + + if(pJsonStr == NULL || err != 0) + { + return err; + } + + ret = DBusBoardcastCommand(pBus, msgToMask, busCmd, pJsonStr); + + free((void*)pJsonStr); + return ret; +} + +static unsigned int __getShmReqId(void) +{ + static unsigned int g_shmReqId = 1; + unsigned int iReqId; + + if(g_shmReqId >= 0xFFFF - 1) + { + g_shmReqId = 1; + } + + iReqId = __sync_fetch_and_add(&g_shmReqId, 1); + + return (iReqId & 0xFFFF) | (g_LibuvDBusParam.modName << 16); +} + +int DBusSendToCommand(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + const char* pContext) +{ +#if USED_SHM_TO_DBUS + struct timeval tv; +#endif + int i; + int msgId; + //char msgContext[DBUS_MSG_MAX_PAD_SIZE]; + DBusMessage* pMsg = NULL; + uint32_t msgLen = 0; + uint32_t msgToMask = 0; + OnDBusSendError pErrorCb = NULL; + uint8_t* pMsgInfo = NULL; + PDBUS_MSG_DATA pShmData = NULL; + const char* pPath = NULL; + char* pMsgContent = NULL; + +#if 0 + if(pContext == NULL || (msgLen = strlen(pContext)) <= 0) + { + return (-ERR_INPUT_PARAMS); + } +#else + if(pContext == NULL) + { + pContext = ""; + msgLen = 0; + } + else + { + msgLen = strlen(pContext); + } +#endif + + pMsgContent = (char*)malloc(msgLen + 1); + + if(pMsgContent == NULL) + { + LOG_EX(LOG_Error, "Malloc memory %d error\n", msgLen + 1); + return -ERR_MALLOC_MEMORY; + } + + pMsgInfo = (uint8_t*)pMsgContent; + + memset(pMsgContent, 0, msgLen + 1); + + if(pBus == NULL) + { + pBus = g_LibuvDBusParam.pBus; + } + + for(i = 0; (i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0])); i++) + { + // Skip match it'self + if(strcmp(g_pModInfoTable[i].modAliase, pBusName) == 0) + { + msgToMask = 1 << i; + pPath = g_pModInfoTable[i].modPath; + break; + } + } + + pMsg = dbus_message_new_method_call(pBusName, + pPath, + DBUS_MESSAGE_INTERFACE_NAME, + "API"); + + if(pMsg == NULL) + { + free(pMsgContent); + LOG_EX(LOG_Error, "DBus Create Message Error\n"); + return -ERR_DBUS_CREATE_MSG; + } + + dbus_message_set_no_reply(pMsg, TRUE); + +#if USED_SHM_TO_DBUS + gettimeofday(&tv, NULL); +#endif + + if(msgLen < DBUS_MSG_MAX_PAD_SIZE) + { + strcpy(pMsgContent, pContext); + } + else + { +#if 0 + int msgKey = __getShmReqId(); + msgLen += sizeof(long int); + + // Make message with Memory Share + msgId = shmget((key_t)msgKey, msgLen, 0666 | IPC_CREAT); + + if(msgId == -1) + { + perror("shmget_"); + return (-ERR_CREATE_SHM); + } + else + { + pShmData = (PDBUS_MSG_DATA)shmat(msgId, NULL, 0); + + if(pShmData == (void*)-1) + { + return -ERR_MAP_SHM; + } + + pShmData->msgMask = msgToMask; + + memcpy(pShmData->pMsgContext, pContext, msgLen); + sprintf(pMsgInfo, "%d", msgKey); + + shmdt(pShmData); + //print_hex_dump_bytes("send_", 2, pShmData, msgLen); + //strcpy(pMsgInfo, (void*)&msgKey, sizeof(key_t)); + +#if USED_SHM_TO_DBUS + __addShmIdToTable((key_t)msgKey, tv.tv_sec, msgToMask, msgLen); +#endif + pErrorCb = freeSHMResource; + } +//#else +#endif + free(pMsgContent); + LOG_EX(LOG_Error, "Send Message size %d more than DBUS_MSG_MAX_PAD_SIZE, busCmd = %u, pBusName = %s\n", + msgLen, busCmd, pBusName); + return -ERR_INPUT_PARAMS; + } + + dbus_message_append_args(pMsg, + DBUS_TYPE_UINT32, &g_LibuvDBusParam.modName, // from + DBUS_TYPE_UINT32, &msgToMask, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &tv.tv_sec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &busCmd, // command type + DBUS_TYPE_UINT32, &msgLen, // message size(in bytes) + DBUS_TYPE_STRING, &pMsgInfo, + // msgLen[0, 512): pad to message; msgLen[512, ~): memory map key, + //DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pMsgInfo, (msgLen < DBUS_MSG_MAX_PAD_SIZE) ? msgLen : sizeof(key_t), + DBUS_TYPE_INVALID); + + free(pMsgContent); + + if(!dbus_connection_send(pBus, pMsg, NULL)) + { + LOG_EX(LOG_Error, "Send Message Error\n"); + if(pErrorCb) + { + pErrorCb(msgId, pShmData); + } + + return -ERR_BUS_SEND_MSG; + } + + //dbus_connection_flush(pBus); + dbus_message_unref(pMsg); + + usleep(100); + + return 0; +} + +int DBusBoardcastCommand(DBusConnection* pBus, + uint32_t msgToMask, + uint32_t busCmd, + const char* pContext) +{ +#if USED_SHM_TO_DBUS + struct timeval tv; +#endif + DBusMessage* pMsg = NULL; + + if(pContext == NULL) + { + pContext = ""; + } + + if(strlen(pContext) >= DBUS_MSG_MAX_PAD_SIZE) + { + LOG_EX(LOG_Error, "Msg size = %u more than DBUS_MSG_MAX_PAD_SIZE\n", strlen(pContext)); + return -ERR_DBUS_MSG_TO_LARGE; + } + + if(pBus == NULL) + { + pBus = g_LibuvDBusParam.pBus; + } + + pMsg = dbus_message_new_signal(g_LibuvDBusParam.pBusPath, DBUS_MESSAGE_INTERFACE_NAME, "Notify"); + + if(pMsg == NULL) + { + return -ERR_DBUS_CREATE_MSG; + } + + dbus_message_set_no_reply(pMsg, TRUE); + +#if USED_SHM_TO_DBUS + gettimeofday(&tv, NULL); +#endif + + dbus_message_append_args(pMsg, + DBUS_TYPE_UINT32, &g_LibuvDBusParam.modName, // from + DBUS_TYPE_UINT32, &msgToMask, // to -1 means all except it's self +#if USED_SHM_TO_DBUS + DBUS_TYPE_UINT32, &tv.tv_sec, // timestamp for msecond +#endif + DBUS_TYPE_UINT32, &busCmd, // command type + DBUS_TYPE_STRING, &pContext, + DBUS_TYPE_INVALID); + + if(!dbus_connection_send(pBus, pMsg, NULL)) + { + return -ERR_BUS_SEND_MSG; + } + + //dbus_connection_flush(pBus); + dbus_message_unref(pMsg); + + usleep(100); + return 0; +} + +static void __addNewLoopTask(uv_loop_t* pLoop) +{ + PLOOP_TASK_ARRAY pItem = NULL; + PLOOP_TASK_ARRAY pTask = NULL; + if(pLoop == NULL) + { + return; + } + + uv_rwlock_wrlock(&g_uvLoopRwLock); + LL_FOREACH(g_LoopArray, pItem) + { + if(pItem->pLoop == pLoop) + { + LOG_EX(LOG_Warn, "Loop %p is added\n", pLoop); + uv_rwlock_wrunlock(&g_uvLoopRwLock); + return; + } + } + + pTask = (PLOOP_TASK_ARRAY)malloc(sizeof(struct LOOP_TASK_ARRAY)); + if(pTask == NULL) + { + LOG_EX(LOG_Error, "Malloc Memory Error\n"); + return; + } + memset(pTask, 0, sizeof(struct LOOP_TASK_ARRAY)); + pTask->pLoop = pLoop; + pTask->isRunning = FALSE; + LL_APPEND(g_LoopArray, pTask); + uv_rwlock_wrunlock(&g_uvLoopRwLock); +} + +static void __uvLoopRuntime(void *pParam) +{ + uv_loop_t* pLoop = (uv_loop_t*)pParam; + + if(pLoop) + { + while(TRUE) + { + uv_run(pLoop, UV_RUN_DEFAULT); + usleep(1000); + } + } + + pthread_detach(pthread_self()); +} + +static void __runUVLoopTask(uv_loop_t* pLoop, void* pCallback) +{ + uv_thread_t uvThread; + if(pLoop == NULL) + { + return; + } + + uv_thread_create(&uvThread, __uvLoopRuntime, pLoop); +} + +void RunUVLoop(uv_loop_t *pLoop) +{ +#if 1 + int more; + + while(TRUE) + { + more = uv_run(g_LibuvDBusParam.pLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(g_LibuvDBusParam.pLoop); + + if(uv_run(g_LibuvDBusParam.pLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } +#else + int more; + + do + { + if(pLoop && pLoop != g_LibuvDBusParam.pUserLoop) + { + more = uv_run(pLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(pLoop); + + if(uv_run(pLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } + + if(g_LibuvDBusParam.pUserLoop) + { + more = uv_run(g_LibuvDBusParam.pUserLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(g_LibuvDBusParam.pUserLoop); + + if(uv_run(g_LibuvDBusParam.pUserLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } + + if(g_LibuvDBusParam.pLoop) + { + more = uv_run(g_LibuvDBusParam.pLoop, UV_RUN_ONCE); + + if(more == FALSE) + { + more = uv_loop_alive(g_LibuvDBusParam.pLoop); + + if(uv_run(g_LibuvDBusParam.pLoop, UV_RUN_NOWAIT) != 0) + { + more = TRUE; + } + } + } + } + while(TRUE); +//#else + //__runUVLoopTask(pLoop, NULL); + //__addNewLoopTask(pLoop); +#endif +} + +static void __uvDBusRecvProc(void *pParams) +{ + while(TRUE) + { + DBusMessage* pMsg = NULL; + dbus_connection_read_write(g_LibuvDBusParam.pBus, 0); + + pMsg = dbus_connection_pop_message(g_LibuvDBusParam.pBus); + + if(pMsg != NULL) + { + DBusOnMsgCb(g_LibuvDBusParam.pBus, pMsg, NULL); + } + + usleep(100); + } +} + +void DBusMsgCleanup(PDBUS_MSG_PACK pMsg) +{ + if(pMsg) + { + if(pMsg->pMsg) + { + free(pMsg->pMsg); + } + + free(pMsg); + } +} + +PDBUS_MSG_PACK DBusGetMessage(void) +{ + int iCount, ret = 0; + PDBUS_MSG_PACK pMsg = NULL; + PDBUS_MSG_PROC pItem = NULL, pTmp = NULL; + + if(g_LibuvDBusParam.onMsgCb) + { + return NULL; + } + + DL_COUNT(g_pMsgProcList, pItem, iCount); + + if(iCount == 0) + { + return pMsg; + } + + pItem = NULL; + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_FOREACH_SAFE(g_pMsgProcList, pItem, pTmp) + { + if(pItem->msgFrom == 0) + { + ret = DBusOnBoardcastMsgWorkCb(&pItem->msgContent); + } + else + { + ret = DBusOnMsgWorkAPICb(&pItem->msgContent); + } + + if(ret != 0) + { + pMsg = (PDBUS_MSG_PACK)malloc(sizeof(DBUS_MSG_PACK)); + + if(pMsg) + { + memset(pMsg, 0, sizeof(DBUS_MSG_PACK)); + memcpy(pMsg, &pItem->msgContent, sizeof(DBUS_MSG_PACK)); + pMsg->pMsg = strdup(pItem->msgContent.pMsg); + } + } + + DL_DELETE(g_pMsgProcList, pItem); + free(pItem->msgContent.pMsg); + free(pItem); + + break; + } + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + + return pMsg; +} + +#if 0 +static void __uvMsgProc(void *pParams) +{ +#ifdef ENABLE_COUNT_DEBUG + struct timeval tmBegin, tmEnd; + long long diffTm; +#endif + + while(TRUE) + { + int iMaxProcMsg = 100; + PDBUS_MSG_PROC pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvMsgProcRwLock); + DL_FOREACH_SAFE(g_pMsgProcList, pItem, pTmp) + { + if(--iMaxProcMsg == 0) + { + break; + } + +#ifdef ENABLE_COUNT_DEBUG + gettimeofday(&tmBegin, NULL); +#endif + if(pItem->msgFrom == 0) + { + DBusOnBoardcastMsgWorkCb(&pItem->msgContent); +#ifdef ENABLE_COUNT_DEBUG + gettimeofday(&tmEnd, NULL); + diffTm = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmBegin.tv_sec * 1000000 + tmBegin.tv_usec); + MonUpgradeStatistical(MON_MSG_BST_PROC_STAT, diffTm); +#endif + } + else + { + DBusOnMsgWorkAPICb(&pItem->msgContent); +#ifdef ENABLE_COUNT_DEBUG + gettimeofday(&tmEnd, NULL); + diffTm = (tmEnd.tv_sec * 1000000 + tmEnd.tv_usec) - (tmBegin.tv_sec * 1000000 + tmBegin.tv_usec); + MonUpgradeStatistical(MON_MSG_PROC_STAT, diffTm); +#endif + } + + if(pItem->msgContent.pMsg) + { + free(pItem->msgContent.pMsg); + } + + DL_DELETE(g_pMsgProcList, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_uvMsgProcRwLock); + usleep(1000); + } + + pthread_detach(pthread_self()); +} +#endif + +void SetHBLAutoExit(int flag) +{ + g_EnHBLExit = flag ? TRUE : FALSE; +} + +static void __dBusDeameonCb(MODULE_NAME modName, int status) +{ + LOG_EX(status == 0 ? LOG_Info : LOG_Error, + "Daemon %s(%d) Msg: [%s]\n", ModuleNameToString(modName), modName, + status == 0 ? "Connect" : "Disconnect"); + + if(status != 0 && modName == MODULE_CONTROLLER && g_EnHBLExit) + { + sleep(1); + //exit(0); + } +} + +static void __waitUDISKMount(void) +{ +#ifdef PLATFORM_R16 + const char* pDoneStat = "done"; + const char* pBootStatFile = "/tmp/booting_state"; + char buf[5]; + FILE* pFile; + + // wait system create setup status file + fprintf(stdout, "Wait boot status file create ......\n"); + while(access(pBootStatFile, F_OK) != 0) + { + usleep(10000); + } + + pFile = fopen(pBootStatFile, "rb"); + + if(pFile == NULL) + { + fprintf(stdout, "Open boot status file error\n"); + return; + } + + fprintf(stdout, "Wait boot status done ......\n"); + + // when UDISK mount, file /tmp/booting_state content is "done" + do + { + fseek(pFile, 0, SEEK_SET); + memset(buf, 0, 5); + fread(buf, 1, 4, pFile); // read 4 bytes status tags + + usleep(10000); + } + while(strncmp(buf, pDoneStat, strlen(pDoneStat)) != 0); + + fclose(pFile); + + fprintf(stdout, "Boot status done ......\n"); +#endif +} + +int GetServerModeFromCC(int defValue, int* pErr) +{ + char* pSvrMode = NULL; + int iValue = defValue; + + GetShellExecResult("curl --silent http://localhost:1705/httpenv/999 | grep 'env:' | awk '{print $3}'", &pSvrMode); + + if(pSvrMode == NULL) + { + if(pErr) + { + *pErr = -ERR_NO_ITEMS; + } + return defValue; + } + + iValue = strtol(pSvrMode, NULL, 10); + free(pSvrMode); + + if(errno == EINVAL || errno == ERANGE) + { + if(pErr) + { + *pErr = -ERR_STR_CONVERT; + } + + return defValue; + } + + if(pErr) + { + *pErr = 0; + } + + return iValue; +} + +DBusConnection* DBusWithLibuvInit(uv_loop_t* pUserLoop, + const char* pBusName, + OnDBusMessage cbOnMsg, + OnDaemonMsg cbOnHbl, + OnKeyEvent cbOnKey, + int* pErrno) +{ + int i, ret = 0; + DBusError error; + SERVER_MODULE_TYPE svrMode; + uv_async_t* pAsync = NULL; + DBusConnection* pBus = NULL; + uv_fs_t* puvFsReq; + //uv_thread_t uvMsgProcThread; + //uv_thread_t uvMsgRecvThread; + + //uv_thread_t uvLoopThread; + char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH - 1]; +#if USED_SHM_TO_DBUS + uv_thread_t uvSyncThread; +#endif + //uv_loop_t *pLoop = uv_loop_new(); + uv_loop_t *pLoop = pUserLoop; + + memset(&g_LibuvDBusParam, 0, sizeof(LIBUV_DBUS_PARAMS)); + + for(i = 0; (i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0])); i++) + { + // Skip match it'self + if(strcmp(g_pModInfoTable[i].modAliase, pBusName) == 0) + { + g_LibuvDBusParam.modName = g_pModInfoTable[i].modName; + g_LibuvDBusParam.pBusName = g_pModInfoTable[i].modAliase; + g_LibuvDBusParam.pBusPath = g_pModInfoTable[i].modPath; + break; + } + } + + memset(&g_workDayArray, 0, sizeof(WORKDAY_INFO)); + srand(time(NULL)); + + if(pLoop == NULL || pBusName == NULL || pErrno == NULL) + { + if(pErrno) + { + *pErrno = -ERR_INPUT_PARAMS; + } + + LOG_EX(LOG_Error, "Input params error: pLoop = %p, pBusName = %p, pErrno = %p\n", + pLoop, pBusName, pErrno); + return NULL; + } + + puvFsReq = (uv_fs_t*)malloc(sizeof(uv_fs_t)); + + // wait UDISK mount, configure file save in UDISK partition + __waitUDISKMount(); + + CfgFileInit(); + + IHW_InitLOG(strrchr(pBusName, '.') + 1, NULL, TRUE); + IHW_EnableLogLevel(LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info, 1); + IHW_RunLogService(); + + APP_BUILD_INFO(strrchr(pBusName, '.') + 1, GetCurrentVersion()); + + i = 0; + do + { + svrMode = CfgGetIntValueV1("Global.ServerMode", PUBLISH_MODE, &ret); + + if(ret != 0) + { + sleep(1); + } + else + { + usleep(1000); + } + + LOG_EX(LOG_Debug, "ServerMode = %d, Error = %d\n", svrMode, ret); + } while (ret != 0 && i++ <= 3); + + if(ret != 0) + { + LOG_EX(LOG_Error, "Read Server Mode Error: ret = %d\n", ret); + svrMode = CfgGetIntValueV2("ServerMode", PUBLISH_MODE, &ret); + + if(ret == 0) + { + LOG_EX(LOG_Warn, "Recovery Server Mode OK: ServerMode = %d\n", svrMode); + } + else + { + LOG_EX(LOG_Error, "CfgGetInvValueV2 Read Server Mode Error: ret = %d\n", ret); + svrMode = GetServerModeFromCC(PUBLISH_MODE, &ret); + + if(ret == 0) + { + LOG_EX(LOG_Warn, "Netease Controller Server Mode OK: ServerMode = %d\n", svrMode); + } + else + { + svrMode = PUBLISH_MODE; + LOG_EX(LOG_Error, "GetServerModeFromCC Read Server Mode Error: " + "ret = %d, Set to default: PUBLISH_MODE\n", ret); + } + } + } + + SetCurrentServerMode(svrMode); + DumpCurServerAddr("Default"); + +#if USED_SHM_TO_DBUS + uv_rwlock_init(&g_uvShmHashRwLock); +#endif + + uv_rwlock_init(&g_uvMsgProcRwLock); + uv_rwlock_init(&g_uvLoopRwLock); + + uv_fs_access(pLoop, puvFsReq, "/mnt/UDISK/debug.dbg", F_OK, uvFsAccessCb); + + memset(rule, 0, DBUS_MAXIMUM_MATCH_RULE_LENGTH - 1); + srand(time(NULL)); + + //setenv("UV_THREADPOOL_SIZE", "128", 1); + + dbus_error_init(&error); + + pBus = dbus_bus_get(DBUS_BUS_SESSION, &error); + + if (dbus_error_is_set(&error)) + { + LOG_EX(LOG_Error, "dbus: Could not acquire the session bus\n"); + + dbus_error_free(&error); + *pErrno = -ERR_GET_BUS; + return NULL; + } + + ret = dbus_bus_request_name(pBus, pBusName, DBUS_NAME_FLAG_REPLACE_EXISTING, &error); + + if(dbus_error_is_set(&error)) + { + LOG_EX(LOG_Error, "dbus: Could not request dbus name\n"); + + dbus_error_free(&error); + *pErrno = -ERR_REQUEST_BUS_NAME; + return NULL; + } + + if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + LOG_EX(LOG_Error, "dbus: Could not request dbus name\n"); + + dbus_error_free(&error); + *pErrno = -ERR_REQUEST_BUS_NAME; + return NULL; + } +#if 1 + if(!dbus_connection_set_watch_functions(pBus, + DBusAddWatchCb, + DBusRemoveWatchCb, + DBusNotifyWatchCb, + (void*)pLoop, NULL)) + { + LOG_EX(LOG_Error, "dbus: Could not set watch function\n"); + + *pErrno = -ERR_SET_WATCH_FUNCTION; + return NULL; + } + + if(!dbus_connection_set_timeout_functions(pBus, + DBusAddTimeoutCb, + DBusRemoveTimeoutCb, + DBusNotifyTimeoutCb, + (void*)pLoop, NULL)) + { + LOG_EX(LOG_Error, "dbus: Could not set watch function\n"); + + *pErrno = -ERR_SET_TIMEOUT_FUNCTION; + return NULL; + } +#endif + + pAsync = malloc(sizeof(uv_async_t)); + pAsync->data = (void*)pBus; + + uv_async_init(pLoop, pAsync, uvAsyncCb); + uv_unref((uv_handle_t*)pAsync); + +#if 1 + dbus_connection_set_wakeup_main_function(pBus, + DBusWakeupMainLoopCb, + (void*)pAsync, DBusAsyncFreeCb); +#endif + + sprintf(rule, "type='signal', interface='%s'", DBUS_MESSAGE_INTERFACE_NAME); + dbus_bus_add_match(pBus, rule, &error); + + if(dbus_error_is_set(&error)) + { + LOG_EX(LOG_Error, "dbus_bus_add_match [%s] error: %s\n", DBUS_MESSAGE_INTERFACE_NAME, error.message); + dbus_error_free(&error); + *pErrno = -ERR_BUS_MATCH; + return NULL; + } +#if 1 + if(!dbus_connection_add_filter(pBus, DBusOnMsgCb, pLoop, NULL)) + { + LOG_EX(LOG_Error, "dbus_connection_add_filter error\n"); + *pErrno = -ERR_BUS_SET_MSG_CB; + return NULL; + } +#endif + + uv_idle_init(pLoop, &g_uvIdleHandle); + g_uvIdleHandle.data = pBus; + uv_idle_start(&g_uvIdleHandle, uvIdleCb); + + if(cbOnKey) + { + uv_fs_open(pLoop, &g_uvKeyEvent, R16_TINA_KEY_EVENT_PATH, O_RDONLY, 0, uvOpenKeyEventCb); + g_LibuvDBusParam.onKeyCb = cbOnKey; + } + + g_LibuvDBusParam.pLoop = pLoop; + g_LibuvDBusParam.pUserLoop = pUserLoop; + g_LibuvDBusParam.pBus = pBus; + g_LibuvDBusParam.onMsgCb = cbOnMsg; + +#if 0 + if(cbOnHbl) + { + g_LibuvDBusParam.onHblCb = cbOnHbl; + HeartDaemonInit(g_LibuvDBusParam.modName, HEART_LOST_DELAY, cbOnHbl); + } +#else + g_LibuvDBusParam.onHblCb = __dBusDeameonCb; + HeartDaemonInit(g_LibuvDBusParam.modName, HEART_LOST_DELAY, __dBusDeameonCb); +#endif + +#if USED_SHM_TO_DBUS + uv_thread_create(&uvSyncThread, __uvShmTblTaskThreadCb, NULL); +#endif + +#ifdef ENABLE_COUNT_DEBUG + MonitorInit(); + MonAddNewItem(MON_MSG_PROC_STAT, 100000); + MonAddNewItem(MON_MSG_BST_PROC_STAT, 100000); + MonAddNewItem(MON_USER_MSG_PROC_STAT, 100000); + MonAddNewItem(MON_USER_MSG_BST_PROC_STAT, 100000); +#endif + + InetInit(); + EvpSystemInit(); + +#if 0 + if(g_LibuvDBusParam.onMsgCb) + { + uv_thread_create(&uvMsgProcThread, __uvMsgProc, NULL); + } +#endif + + return pBus; +} + +int DBusWithLibuvCfgInit(OnCfgMsg cbOnCfgMsg) +{ + CfgGlobalEnvInit(); + + if(cbOnCfgMsg == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + g_LibuvDBusParam.onCfgCb = cbOnCfgMsg; + + return (0); +} + +int GetShellExecResult(const char *pCmd, char **pResult) +{ + FILE *pFile = NULL; + unsigned int uRdSize = 0; + char *pCmdOut; + + *pResult = NULL; + + if(pCmd == NULL || strlen(pCmd) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + pFile = popen(pCmd, "r"); + + if(pFile == NULL) + { + return (-ERR_OPEN_FILE); + } + + *pResult = (char *)malloc(4096); + pCmdOut = *pResult; + + uRdSize = fread(pCmdOut, sizeof(char), 4096, pFile); + + pCmdOut[uRdSize] = 0; + + if(pCmdOut[strlen(pCmdOut) - 1] == '\n') + { + pCmdOut[strlen(pCmdOut) - 1] = 0; + } + + pclose(pFile); + //fprintf(stdout, "%s --> [%s](%u)\n", pCmd, pCmdOut, uRdSize); + return (0); +} + +void SystemSafeReboot(void) +{ + int ret, reTry = 0; +#if 0 + ret = system("sync"); + + ret = system("ubus call system watchdog \'{\"stop\" : true}\'"); + + reTry = 3; + do + { + sleep(1); + } while(reTry--); + + reTry = 0; + + LOG_EX(LOG_Debug, "Reboot System By Power Control Chips\n"); + sleep(1); + + ret = system("echo 3140 > /sys/bus/platform/devices/axp22_board/axp22_reg"); + + sleep(10); +#endif + while(TRUE) + { + LOG_EX(LOG_Debug, "Reboot System: %d times\n", reTry++); + sleep(1); + ret = system("reboot -f"); + sleep(3); + } +} + +char* GetCpuChipId(void) +{ + char* pRet = NULL; +#ifdef PLATFORM_R16 + char* pChipId = NULL; + + GetShellExecResult("cat /proc/cpuinfo | grep Chipid | awk '{print $3}'", &pChipId); + + if(pChipId == NULL) + { + return strdup(""); + } + + pRet = strdup(pChipId); + free(pChipId); + return pRet; +#else + return strdup("Unknown CPU Chip ID"); +#endif +} + +char* GetCpuSerial(void) +{ + char* pRet = NULL; +#ifdef PLATFORM_R16 + char* pSerial = NULL; + + GetShellExecResult("cat /proc/cpuinfo | grep Serial | awk '{print $3}'", &pSerial); + + if(pSerial == NULL) + { + return strdup(""); + } + + pRet = strdup(pSerial); + free(pSerial); + return pRet; +#else + return strdup("Unknown CPU Serial"); +#endif +} + +int CopyFile(const char *pSrc, const char *pDest) +{ + int fdSrc, fdDest; + struct stat st; + ssize_t sz; + + if(stat(pSrc, &st) != 0) + { + LOG_EX(LOG_Error, "Get File %s Size Error\n", pSrc); + return (-ERR_GET_FILE_SIZE); + } + + fdSrc = open(pSrc, O_RDONLY); + + if(fdSrc < 0) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pSrc); + return (-ERR_OPEN_FILE); + } + + fdDest = open(pDest, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + if(fdDest < 0) + { + close(fdSrc); + LOG_EX(LOG_Error, "Open File %s Error\n", pDest); + return (-ERR_OPEN_FILE); + } + + sz = sendfile(fdDest, fdSrc, NULL, st.st_size); + + if(sz != st.st_size) + { + LOG_EX(LOG_Error, "Copy File Size Error: %d, %d\n", sz, st.st_size); + close(fdSrc); + close(fdDest); + return (-ERR_COPY_FILE); + } + + fsync(fdDest); + + close(fdSrc); + close(fdDest); + + return (0); +} + +int CopyFileWithSize(const char *pSrc, const char *pDest, int iSize) +{ + int fdSrc, fdDest; + struct stat st; + ssize_t sz; + size_t cpSize = iSize; + + if(iSize <= 0) + { + if(stat(pSrc, &st) != 0) + { + LOG_EX(LOG_Error, "Get File %s Size Error\n", pSrc); + return (-ERR_GET_FILE_SIZE); + } + + cpSize = st.st_size; + } + + fdSrc = open(pSrc, O_RDONLY); + + if(fdSrc < 0) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pSrc); + return (-ERR_OPEN_FILE); + } + + fdDest = open(pDest, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |S_IWOTH); + + if(fdDest < 0) + { + close(fdSrc); + LOG_EX(LOG_Error, "Open File %s Error\n", pDest); + return (-ERR_OPEN_FILE); + } + + sz = sendfile(fdDest, fdSrc, NULL, cpSize); + + if(sz != cpSize) + { + LOG_EX(LOG_Error, "Copy File Size Error: %d, %d\n", sz, cpSize); + close(fdSrc); + close(fdDest); + return (-ERR_COPY_FILE); + } + + close(fdSrc); + close(fdDest); + + return (0); +} + +int ReadFileToBuf(const char *pSrc, unsigned char *pBuf, int iSize) +{ + int fdSrc; + struct stat st; + ssize_t sz; + size_t cpSize = iSize; + + if(iSize < 0) + { + if(stat(pSrc, &st) != 0) + { + LOG_EX(LOG_Error, "Get File %s Size Error\n", pSrc); + return (-ERR_GET_FILE_SIZE); + } + + cpSize = st.st_size; + } + + fdSrc = open(pSrc, O_RDONLY); + + if(fdSrc < 0) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pSrc); + return (-ERR_OPEN_FILE); + } + + sz = read(fdSrc, pBuf, cpSize); + + if(sz != cpSize) + { + LOG_EX(LOG_Error, "Copy File Size Error: %d, %d\n", sz, cpSize); + close(fdSrc); + return (-ERR_COPY_FILE); + } + + close(fdSrc); + + return (sz); +} + +static int __reqWorkDayInfo(int year) +{ + int ret = 0; + WORKDAY_INFO reqInfo; + + memset(&reqInfo, 0, sizeof(WORKDAY_INFO)); + + if(year <= 0) + { + struct tm localTime; + time_t tmStamp = time((time_t*)NULL); + + localtime_r(&tmStamp, &localTime); + + reqInfo.year = localTime.tm_year; + } + else + { + reqInfo.year = year; + } + + if(reqInfo.year < (2018 - 1900)) + { + return 0; + } + + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_WORKDAY_DB_REQ, + JSON_ENGINE_WORKDAY_REQ, + &reqInfo, FALSE); + + return (ret); +} + +int IsHolidayDBSynced(void) +{ + return g_workDayArray.isReady; +} + +int CurrentIsWorkDay(int year, int day) +{ + static unsigned int i = 0; + + if(year != 0) + { + LOG_EX(LOG_Debug, "CurrentIsWorkDay: year = %d, day = %d\n", year, day); + } + + if(day > 365) + { + LOG_EX(LOG_Error, "Error Input Params: day = %d\n", day); + return (-ERR_INPUT_PARAMS); + } + + if(g_workDayArray.year <= 0) + { + __reqWorkDayInfo(year); + if(i++ % 10 == 0) + { + LOG_EX(LOG_Error, "Unsync Database: year = %d\n", year); + } + return (-ERR_UNINIT_ITEM); + } + + if(day < 0 || year <= 0) + { + struct tm localTime; + time_t tmStamp = time((time_t*)NULL); + localtime_r(&tmStamp, &localTime); + + if(day < 0) + { + day = localTime.tm_yday; + } + + if(year <= 0) + { + year = localTime.tm_year; + } + } + + if(year != g_workDayArray.year - 1900) + { + __reqWorkDayInfo(year); + LOG_EX(LOG_Error, "Have No Current Year Database: year = %d, g_workDayArray.year = %d\n", + year, g_workDayArray.year); + + return (-ERR_NO_ITEMS); + } + + // 0 work day, 1 holiday + return (g_workDayArray.days[day] == 0); +} + +unsigned long long GetPartitionFreeSize(const char *pPartPath) +{ + struct statfs myStatfs; + unsigned long long freeSize; + + if(statfs(pPartPath, &myStatfs) == -1) + { + return 0; + } + + freeSize = myStatfs.f_bsize * myStatfs.f_bfree; + + //fprintf(stdout, "%s free = %llu bytes\n", pPartPath, freeSize); + + return freeSize; +} + +#ifdef CURRENT_VERSION +char* GetCurrentVersion(void) +{ + return CURRENT_VERSION; +} +#else +char* GetCurrentVersion(void) +{ + return "0.0.1"; +} +#endif + +WIFI_STATUS GetCurrWIFIConnStatus(void) +{ + return g_WifiConnStatus; +} + +const char* ErrcodeToString(int errCode) +{ + switch(errCode) + { + case ERR_INPUT_PARAMS: return "ERR_INPUT_PARAMS"; + case ERR_NO_ITEMS: return "ERR_NO_ITEMS"; + case ERR_GET_BUS: return "ERR_GET_BUS"; + case ERR_DBUS_CONNECTION: return "ERR_DBUS_CONNECTION"; + case ERR_REQUEST_BUS_NAME: return "ERR_REQUEST_BUS_NAME"; + case ERR_SET_WATCH_FUNCTION: return "ERR_SET_WATCH_FUNCTION"; + case ERR_SET_TIMEOUT_FUNCTION: return "ERR_SET_TIMEOUT_FUNCTION"; + case ERR_BUS_MATCH: return "ERR_BUS_MATCH"; + case ERR_BUS_SET_MSG_CB: return "ERR_BUS_SET_MSG_CB"; + case ERR_DBUS_CREATE_MSG: return "ERR_DBUS_CREATE_MSG"; + case ERR_BUS_SEND_MSG: return "ERR_BUS_SEND_MSG"; + case ERR_DBUS_MSG_TO_LARGE: return "ERR_DBUS_MSG_TO_LARGE"; + case ERR_BUS_RCV_MSG: return "ERR_BUS_RCV_MSG"; + case ERR_ADD_TASK: return "ERR_ADD_TASK"; + case ERR_UNSUP_EVP_TYPE: return "ERR_UNSUP_EVP_TYPE"; + case ERR_CREATE_MQ: return "ERR_CREATE_MQ"; + case ERR_MQ_SENDMSG: return "ERR_MQ_SENDMSG"; + case ERR_CREATE_SHM: return "ERR_CREATE_SHM"; + case ERR_MAP_SHM: return "ERR_MAP_SHM"; + case ERR_MALLOC_MEMORY: return "ERR_MALLOC_MEMORY"; + case ERR_EVP_INIT_KEY: return "ERR_EVP_INIT_KEY"; + case ERR_EVP_UPDATE: return "ERR_EVP_UPDATE"; + case ERR_EVP_FINALE: return "ERR_EVP_FINALE"; + case ERR_EVP_KEY_SIZE: return "ERR_EVP_KEY_SIZE"; + case ERR_OPEN_FILE: return "ERR_OPEN_FILE"; + case ERR_READ_FILE: return "ERR_READ_FILE"; + case ERR_WRITE_FILE: return "ERR_WRITE_FILE"; + case ERR_COPY_FILE: return "ERR_COPY_FILE"; + case ERR_FILE_NOT_EXISTS: return "ERR_FILE_NOT_EXISTS"; + case ERR_GET_FILE_SIZE: return "ERR_GET_FILE_SIZE"; + case ERR_UNINIT_ITEM: return "ERR_UNINIT_ITEM"; + case ERR_FILE_EMPTY: return "ERR_FILE_EMPTY"; + case ERR_SEND_MAIL: return "ERR_SEND_MAIL"; + case ERR_NETWORK_SEND: return "ERR_NETWORK_SEND"; + case ERR_NETWORK_NOT_CONNECTED: return "ERR_NETWORK_NOT_CONNECTED"; + case ERR_UNSUPPORT: return "ERR_UNSUPPORT"; + case ERR_NO_INIT_IPL3: return "ERR_NO_INIT_IPL3"; + case ERR_BAD_IPL3: return "ERR_BAD_IPL3"; + case ERR_BAD_FILE_SIZE: return "ERR_BAD_FILE_SIZE"; + case ERR_MD5_FILE: return "ERR_MD5_FILE"; + case ERR_MD5_CHECK_SUM: return "ERR_MD5_CHECK_SUM"; + case ERR_OTA_WRITE_BOOT: return "ERR_OTA_WRITE_BOOT"; + case ERR_OTA_WRITE_ROOTFS: return "ERR_OTA_WRITE_ROOTFS"; + case ERR_OTA_WRITE_IPL3: return "ERR_OTA_WRITE_IPL3"; + case ERR_OTA_WRITE_PARAMS: return "ERR_OTA_WRITE_PARAMS"; + case ERR_OTA_DOWNLOAD_FILE: return "ERR_OTA_DOWNLOAD_FILE"; + case ERR_VERIFY_PARTITION_MD5: return "ERR_VERIFY_PARTITION_MD5"; + case ERR_OTA_PRE_STATR: return "ERR_OTA_PRE_STATR"; + case ERR_OTA_YET_CUR_VER: return "ERR_OTA_YET_CUR_VER"; + case ERR_OTA_NOT_READY: return "ERR_OTA_NOT_READY"; + case ERR_CREATE_CFG_FILE: return "ERR_CREATE_CFG_FILE"; + case ERR_CREATE_SQLITE3_DB: return "ERR_CREATE_SQLITE3_DB"; + case ERR_OPEN_SQLITE3_DB: return "ERR_OPEN_SQLITE3_DB"; + case ERR_SQLITE3_CREATE_TABLE: return "ERR_SQLITE3_CREATE_TABLE"; + case ERR_SYNC_DATABASE: return "ERR_SYNC_DATABASE"; + case ERR_SQL_QUERY: return "ERR_SQL_QUERY"; + case ERR_SQL_DELETE: return "ERR_SQL_DELETE"; + case ERR_UNKNOWN_TYPE: return "ERR_UNKNOWN_TYPE"; + case ERR_PERMISSION_DENIED: return "ERR_PERMISSION_DENIED"; + case ERR_CFG_NOITEM: return "ERR_CFG_NOITEM"; + case ERR_CFG_ITEM_EXIST: return "ERR_CFG_ITEM_EXIST"; + case ERR_CFG_WAIT_RSP: return "ERR_CFG_WAIT_RSP"; + case ERR_CFG_BUSY: return "ERR_CFG_BUSY"; + case ERR_STR_CONVERT: return "ERR_STR_CONVERT"; + case ERR_SQL_REG_MODULE: return "ERR_SQL_REG_MODULE"; + default: return "Unknown Error"; + } +} + +const char* DBusCmdToString(DBUS_CMD cmd) +{ + switch(cmd) + { + case CMD_MISC_PING: return "CMD_MISC_PING"; + case CMD_MISC_OTA: return "CMD_MISC_OTA"; + case CMD_MISC_WEATHER: return "CMD_MISC_WEATHER"; + case CMD_MISC_NOWTIME: return "CMD_MISC_NOWTIME"; + case CMD_MISC_UPGRADE: return "CMD_MISC_UPGRADE"; + case CMD_SYSTEM_STANDBY: return "CMD_SYSTEM_STANDBY"; + case CMD_MISC_QUERY_OTA_STATUS: return "CMD_MISC_QUERY_OTA_STATUS"; + case CMD_MISC_QUERY_DL_STATUS: return "CMD_MISC_QUERY_DL_STATUS"; + case CMD_CALL_DIAL: return "CMD_CALL_DIAL"; + case CMD_CALL_ACCEPI: return "CMD_CALL_ACCEPI"; + case CMD_CALL_HANGUP: return "CMD_CALL_HANGUP"; + case CMD_CALL_MESSAGE: return "CMD_CALL_MESSAGE"; + case CMD_PLAY_MODECHANGE: return "CMD_PLAY_MODECHANGE"; + case CMD_PLAY_PLAY: return "CMD_PLAY_PLAY"; + case CMD_PLAY_PAUSE: return "CMD_PLAY_PAUSE"; + case CMD_PLAY_STOP: return "CMD_PLAY_STOP"; + case CMD_PLAY_SEEKTO: return "CMD_PLAY_SEEKTO"; + case CMD_PLAY_SHOWMODE: return "CMD_PLAY_SHOWMODE"; + case CMD_PLAY_NEXT: return "CMD_PLAY_NEXT"; + case CMD_PLAY_PRE: return "CMD_PLAY_PRE"; + case CMD_PLAY_SHOWLIST: return "CMD_PLAY_SHOWLIST"; + case CMD_PLAY_UPDATELIST: return "CMD_PLAY_UPDATELIST"; + case CMD_PLAY_PREPARE_NEXT: return "CMD_PLAY_PREPARE_NEXT"; + case CMD_PLAY_ADDTOLIST: return "CMD_PLAY_ADDTOLIST"; + case CMD_PLAY_DELETEFROMLIST: return "CMD_PLAY_DELETEFROMLIST"; + case CMD_PLAY_RESETLIST: return "CMD_PLAY_RESETLIST"; + case CMD_PLAY_AUDIO_STOP: return "CMD_PLAY_AUDIO_STOP"; + case CMD_PLAY_AUDIO_PLAY: return "CMD_PLAY_AUDIO_PLAY"; + case CMD_SE_PLAY: return "CMD_SE_PLAY"; + case CMD_PLAY_RET_STATUS: return "CMD_PLAY_RET_STATUS"; + case CMD_CFG_ADD_REQ: return "CMD_CFG_ADD_REQ"; + case CMD_CFG_ADD_RSP: return "CMD_CFG_ADD_RSP"; + case CMD_CFG_CHANGE_REQ: return "CMD_CFG_CHANGE_REQ"; + case CMD_CFG_CHANGE_RSP: return "CMD_CFG_CHANGE_RSP"; + case CMD_CFG_GET_REQ: return "CMD_CFG_GET_REQ"; + case CMD_CFG_GET_RSP: return "CMD_CFG_GET_RSP"; + case CMD_CFG_UPG_NOTIFY: return "CMD_CFG_UPG_NOTIFY"; + case CMD_MSC_MSG_CONTROLLER_RECOG_SUCCESS: return "CMD_MSC_MSG_CONTROLLER_RECOG_SUCCESS"; + case CMD_MSC_MSG_CONTROLLER_RECOG_ERROR: return "CMD_MSC_MSG_CONTROLLER_RECOG_ERROR"; + case CMD_MSC_MSG_CONTROLLER_WAKEUP: return "CMD_MSC_MSG_CONTROLLER_WAKEUP"; + case CMD_MSC_MSG_CONTROLLER_RECOGING: return "CMD_MSC_MSG_CONTROLLER_RECOGING"; + case CMD_CONTROLLER_REQMSG_INITARGS: return "CMD_CONTROLLER_REQMSG_INITARGS"; + case CMD_CONTROLLER_RSPMSG_INITARGS: return "CMD_CONTROLLER_RSPMSG_INITARGS"; + case CMD_CONTROLLER_REQMSG_PLAYERSTATUS: return "CMD_CONTROLLER_REQMSG_PLAYERSTATUS"; + case CMD_CONTROLLER_RSPMSG_PLAYERSTATUS: return "CMD_CONTROLLER_RSPMSG_PLAYERSTATUS"; + case CMD_MSC_REQMSG_MIC_CONTROL: return "CMD_MSC_REQMSG_MIC_CONTROL"; + case CMD_MSC_RSPMSG_MIC_CONTROL: return "CMD_MSC_RSPMSG_MIC_CONTROL"; + case CMD_YUNXIN_RECVMSG: return "CMD_YUNXIN_RECVMSG"; + case CMD_YUNXIN_SENDMSG: return "CMD_YUNXIN_SENDMSG"; + case CMD_YUNXIN_SENDMSG_BYPASS: return "CMD_YUNXIN_SENDMSG_BYPASS"; + case CMD_YUNXIN_SENDMSGCB: return "CMD_YUNXIN_SENDMSGCB"; + case CMD_CONTROLLER_MSG_YUNXIN: return "CMD_CONTROLLER_MSG_YUNXIN"; + case CMD_YUNXIN_STATUS: return "CMD_YUNXIN_STATUS"; + case CMD_YUNXIN_SYSMSG: return "CMD_YUNXIN_SYSMSG"; + case CMD_WIFI_CONF: return "CMD_WIFI_CONF"; + case CMD_WIFI_CONF_RESP: return "CMD_WIFI_CONF_RESP"; + case CMD_WIFI_AUTO_CONN: return "CMD_WIFI_AUTO_CONN"; + case CMD_WIFI_AUTO_CONN_RESP: return "CMD_WIFI_AUTO_CONN_RESP"; + case CMD_WIFI_STATE_REQ: return "CMD_WIFI_STATE_REQ"; + case CMD_WIFI_STATE_RESP: return "CMD_WIFI_STATE_RESP"; + case CMD_WIFI_STATE_NTF: return "CMD_WIFI_STATE_NTF"; + case CMD_BT_NAME_GET_REQ: return "CMD_BT_NAME_GET_REQ"; + case CMD_BT_NAME_GET_RESP: return "CMD_BT_NAME_GET_RESP"; + case CMD_BT_EVT_NTF: return "CMD_BT_EVT_NTF"; + case CMD_KPLAYER_START: return "CMD_KPLAYER_START"; + case CMD_KPLAYER_STOP: return "CMD_KPLAYER_STOP"; + case CMD_KPLAYER_NOTIF_DUR: return "CMD_KPLAYER_NOTIF_DUR"; + case CMD_KPLAYER_HOST_ACTION: return "CMD_KPLAYER_HOST_ACTION"; + case CMD_KPLAYER_CTR_NTF_BASE: return "CMD_KPLAYER_CTR_NTF_BASE"; + case CMD_KPLAYER_CTR_CREATED: return "CMD_KPLAYER_CTR_CREATED"; + case CMD_KPLAYER_CTR_DELED: return "CMD_KPLAYER_CTR_DELED"; + case CMD_KPLAYER_CTR_PLAY: return "CMD_KPLAYER_CTR_PLAY"; + case CMD_KPLAYER_CTR_STOP: return "CMD_KPLAYER_CTR_STOP"; + case CMD_KPLAYER_CTR_PAUSE: return "CMD_KPLAYER_CTR_PAUSE"; + case CMD_KPLAYER_CTR_SEEK: return "CMD_KPLAYER_CTR_SEEK"; + case CMD_KPLAYER_CTR_SET_URL: return "CMD_KPLAYER_CTR_SET_URL"; + case CMD_KPLAYER_CTR_SET_VOLUME: return "CMD_KPLAYER_CTR_SET_VOLUME"; + case CMD_KPLAYER_CTR_SET_MUTE: return "CMD_KPLAYER_CTR_SET_MUTE"; + case CMD_KPLAYER_CTR_SET_NXT_URL: return "CMD_KPLAYER_CTR_SET_NXT_URL"; + case CMD_KPLAYER_CTR_SET_NEXT: return "CMD_KPLAYER_CTR_SET_NEXT"; + case CMD_KPLAYER_CTR_SET_PREV: return "CMD_KPLAYER_CTR_SET_PREV"; + case CMD_ALARM_SYNC_REQ: return "CMD_ALARM_SYNC_REQ"; + case CMD_ALARM_SYNC_RSP: return "CMD_ALARM_SYNC_RSP"; + case CMD_ALARM_ADD: return "CMD_ALARM_ADD"; + case CMD_ALARM_REMOVE: return "CMD_ALARM_REMOVE"; + case CMD_ALARM_REMOVEALL: return "CMD_ALARM_REMOVEALL"; + case CMD_REMAIND_SYNC_REQ: return "CMD_REMAIND_SYNC_REQ"; + case CMD_REMAIND_SYNC_RSP: return "CMD_REMAIND_SYNC_RSP"; + case CMD_REMAIND_ADD: return "CMD_REMAIND_ADD"; + case CMD_REMAIND_REMOVE: return "CMD_REMAIND_REMOVE"; + case CMD_REMAIND_REMOVEALL: return "CMD_REMAIND_REMOVEALL"; + case CMD_ASSISTANT_STATUS: return "CMD_ASSISTANT_STATUS"; + case CMD_ASSISTANT_RUNNING: return "CMD_ASSISTANT_RUNNING"; + case CMD_ASSISTANT_NOTIFY: return "CMD_ASSISTANT_NOTIFY"; + case CMD_SESSION_ALARM_SYNC: return "CMD_SESSION_ALARM_SYNC"; + case CMD_WORKDAY_DB_REQ: return "CMD_WORKDAY_DB_REQ"; + case CMD_WORKDAY_DB_RSP: return "CMD_WORKDAY_DB_RSP"; + case CMD_OTA_NOTIFY: return "CMD_OTA_NOTIFY"; + case CMD_OTA_STATUS: return "CMD_OTA_STATUS"; + case CMD_OTA_RUNNOW: return "CMD_OTA_RUNNOW"; + case CMD_LOG_CONFIG: return "CMD_LOG_CONFIG"; + default: return "Unknown CMD"; + } +} + +const char* ModuleNameToString(MODULE_NAME modName) +{ + switch(modName) + { + case MODULE_CONTROLLER: return "MODULE_CONTROLLER"; + case MODULE_ALARM: return "MODULE_ALARM"; + case MODULE_CALL: return "MODULE_CALL"; + case MODULE_VOICEENGINE: return "MODULE_VOICEENGINE"; + case MODULE_PLAYER: return "MODULE_PLAYER"; + case MODULE_CONFIGURE: return "MODULE_CONFIGURE"; + case MODULE_OTA: return "MODULE_OTA"; + case MODULE_WIFI: return "MODULE_WIFI"; + case MODULE_BT: return "MODULE_BT"; + case MODULE_KPLAYER: return "MODULE_KPLAYER"; + case MODULE_KPLAYER_TEST: return "MODULE_KPLAYER_TEST"; + case MODULE_SPLAYER: return "MODULE_SPLAYER"; + case MODULE_SPLAYER_TEST: return "MODULE_SPLAYER_TEST"; + case MODULE_LIGHT_MCU: return "MODULE_LIGHT_MCU"; + case MODULE_BLUEKC: return "MODULE_BLUEKC"; + case MODULE_BLUEKC_TEST: return "MODULE_BLUEKC_TEST"; + case MODULE_MANUFACTURE: return "MODULE_MANUFACTURE"; + case MODULE_BT_DEMO: return "MODULE_BT_DEMO"; + case MODULE_LOG_CTRL: return "MODULE_LOG_CTRL"; + } + + return "Unknown Module Name"; +} diff --git a/app/libuvdbus/src/Makefile b/app/libuvdbus/src/Makefile new file mode 100644 index 0000000..138edf1 --- /dev/null +++ b/app/libuvdbus/src/Makefile @@ -0,0 +1,50 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common + +GIT_TAG:=$(shell git describe --tags --always --dirty="-dev") +TARGET := libuvdbus.so + +commonSources := \ + log/hexdump.c \ + log/log.c \ + Framework/IoT/Boardlink/boardlink_iot.c \ + Framework/HeartDaemon/heart_daemon.c \ + Framework/Configure/config_engine.c \ + Framework/Configure/ini_prase.c \ + Framework/Crypto/md5.c \ + Framework/Crypto/base64.c \ + Framework/Crypto/crypto.c \ + Framework/Crypto/aes.c \ + Framework/libuvEngine/libuv_dbus.c \ + Framework/JsonUtils/json_struct.c \ + Framework/Network/inet_api.c \ + Framework/Skins/skins.c \ + Framework/Skins/skin_res_vtbl.c \ + Framework/Timer/timer.c \ + Framework/Fifo/fifo.c \ + Framework/Monitor/monitor.c \ + Framework/SvrManager/svr_manager.c \ + Framework/Compress/zlib.c + +local_CFLAGS := -I./include -DPLATFORM_R311 -DCURRENT_VERSION=\"$(GIT_TAG)\" +#local_CFLAGS += -DENABLE_COUNT_DEBUG + +local_LDFLAGS := $(LIB_BUILD_COMMON_LIB) + +OBJS = $(patsubst %.c, %.c.o, $(commonSources)) + +$(TARGET):$(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(local_CFLAGS) -o $@ $^ -fPIC -shared + +$(OBJS):%.c.o:%.c + $(CC) $(CFLAGS) $(LDFLAGS) $(local_CFLAGS) -c $^ -o $@ -fPIC -shared + +all: $(TARGET) install + +clean: + -rm $(OBJS) $(TARGET) +install: + mkdir -p $(INSTALL_PREFIX)/usr/lib + cp $(TARGET) $(INSTALL_PREFIX)/usr/lib + + mkdir -p $(INSTALL_PREFIX)/usr/include + cp -r include/* $(INSTALL_PREFIX)/usr/include diff --git a/app/libuvdbus/src/include/assistant.h b/app/libuvdbus/src/include/assistant.h new file mode 100644 index 0000000..56b28f7 --- /dev/null +++ b/app/libuvdbus/src/include/assistant.h @@ -0,0 +1,168 @@ +#ifndef ASSISTANT_H +#define ASSISTANT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_TIP_LEN (60 * 4 + 1) +#define MAX_ALARM_ITEMS (1024) + +typedef enum +{ + ASSISTANT_TYPE_CLOCK = 0, + ASSISTANT_TYPE_REMAIND, + ASSISTANT_TYPE_SESSION, +} ASSISTANT_TYPE; + +typedef enum +{ + STATUS_IDLE = 0, + STATUS_PREPARE_STANDBY, + STATUS_RUNNING, + STATUS_NOT_IN_USE, + STATUS_REMOVE_ITEM, + STATUS_ADD_ITEM, +} ASSISTANT_STATUS; + +typedef struct +{ + unsigned long long itemId; ///< 提醒、闹钟ID + ASSISTANT_TYPE itemType; ///< 类型: 0 闹钟, 1 提醒 + int priority; ///< 优先级: 暂未使用 + REPEAT_MODE repeatMode; ///< 重复模式 + + int year; ///< 年 + int month; ///< 月 + int day; ///< 日 + int hour; ///< 小时 + int minute; ///< 分钟 + int second; ///< 秒钟 + int weekDay; ///< 星期 + + unsigned int timerId; ///< 关联的定时器ID + unsigned long long voiceId; ///< 闹钟资源ID + char strTips[MAX_TIP_LEN]; ///< 提醒 TTS 文本 + char resUrl[2048]; ///< 资源URL + char voiceRes[32]; ///< 资源声音文件ID + char voiceResType[64]; ///< 资源类型 +} ASSISTANT_ITEM_INFO, *PASSISTANT_ITEM_INFO; + +typedef struct +{ + int nItems; ///< 协议包含的数据个数 + PASSISTANT_ITEM_INFO pAlarmInfo; ///< 提醒、闹钟数据详细信息 +} ASSISTANT_SYNC_INFO, *PASSISTANT_SYNC_INFO; + +typedef struct ASSISTANT_ARRAY_INFO +{ + ASSISTANT_ITEM_INFO alarmItem; + struct ASSISTANT_ARRAY_INFO *next, *prev; +} *PASSISTANT_ARRAY_INFO; + +typedef struct +{ + int cmd; + int nItems; + ASSISTANT_TYPE type; + unsigned long long ids[MAX_ALARM_ITEMS]; +} ASSISTANT_NOTIFY_INFO, *PASSISTANT_NOTIFY_INFO; + +typedef struct +{ + int cmd; + int val; +} ASSISTANT_RSP_STATUS, *PASSISTANT_RSP_STATUS; + +typedef struct +{ + int cmd; + int val; + int errCode; +} ASSISTANT_NOFIFY_EVENT, *PASSISTANT_NOFIFY_EVENT; + +static void __printAssistantNofifyInfo(const char *pTags, PASSISTANT_NOTIFY_INFO pInfo) +{ + int i; + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Debug, "%s:\n", pTags); + LOG_EX2(LOG_Debug, "**************************************************************\n"); + } + + LOG_EX2(LOG_Debug, "Sync Items : %d\n", pInfo->nItems); + LOG_EX2(LOG_Debug, "-------------------------\n"); + LOG_EX2(LOG_Debug, "| Alarm Id | Type |\n"); + LOG_EX2(LOG_Debug, "-------------------------\n"); + + for(i = 0; i < pInfo->nItems; i++) + { + LOG_EX2(LOG_Debug, "| %8llu | %11s |\n", + pInfo->ids[i], + (pInfo->type == ASSISTANT_TYPE_REMAIND) ? "Remaind" : "Alarm Clock"); + } + + LOG_EX2(LOG_Debug, "-------------------------\n"); +} + +static void __printAssistantSyncInfo(const char* pTags, PASSISTANT_SYNC_INFO pInfo) +{ + int i; + char buf[MAX_PATH]; + struct tm localTime; + time_t tmStamp; + + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Debug, "%s:\n", pTags); + LOG_EX2(LOG_Debug, "**************************************************************\n"); + } + + //fprintf(stdout, "Command : %d(%08X)\n", pInfo->cmd, pInfo->cmd); + LOG_EX2(LOG_Debug, "Sync Items : %d\n", pInfo->nItems); + + LOG_EX2(LOG_Debug, "---------------------------------------------------------------------" + "-----------------------------------------------------------\n"); + + LOG_EX2(LOG_Debug, "| Alarm Id | Type | Priority | Repeat Mode | Week Day |" + " DateTime | Tips | Resource |\n"); + + LOG_EX2(LOG_Debug, "---------------------------------------------------------------------" + "-----------------------------------------------------------\n"); + + for(i = 0; i < pInfo->nItems; i++) + { + memset(buf, 0, MAX_PATH); + + sprintf(buf, "%04u-%02u-%02u %02u:%02u:%02u", + (pInfo->pAlarmInfo[i].year == -1) ? 1900 : pInfo->pAlarmInfo[i].year + 1900, + (pInfo->pAlarmInfo[i].month == -1) ? 0 : pInfo->pAlarmInfo[i].month + 1, + (pInfo->pAlarmInfo[i].day == -1) ? 0 : pInfo->pAlarmInfo[i].day, + (pInfo->pAlarmInfo[i].hour == -1) ? 0 : pInfo->pAlarmInfo[i].hour, + (pInfo->pAlarmInfo[i].minute == -1) ? 0 : pInfo->pAlarmInfo[i].minute, + (pInfo->pAlarmInfo[i].second == -1) ? 0 : pInfo->pAlarmInfo[i].second); + + LOG_EX2(LOG_Debug, "| %8llu | %11s | %8d | %15s | %d%d%d%d %d%d%d%d | %20s | %20s | %8llu |\n", + pInfo->pAlarmInfo[i].itemId, + (pInfo->pAlarmInfo[i].itemType == ASSISTANT_TYPE_REMAIND) ? "Remaind" : "Alarm Clock", + pInfo->pAlarmInfo[i].priority, + DumpTimerRepeatModeString(pInfo->pAlarmInfo[i].repeatMode), + (pInfo->pAlarmInfo[i].weekDay & (1 << 7))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 6))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 5))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 4))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 3))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 2))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 1))? 1 : 0, + (pInfo->pAlarmInfo[i].weekDay & (1 << 0))? 1 : 0, + buf, + pInfo->pAlarmInfo[i].strTips, + pInfo->pAlarmInfo[i].voiceId); + } + + LOG_EX2(LOG_Debug, "---------------------------------------------------------------------" + "-----------------------------------------------------------\n"); +} +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/boardlink_iot.h b/app/libuvdbus/src/include/boardlink_iot.h new file mode 100644 index 0000000..65dd47a --- /dev/null +++ b/app/libuvdbus/src/include/boardlink_iot.h @@ -0,0 +1,44 @@ +#ifndef BOARDLINK_IOT_H +#define BOARDLINK_IOT_H +#ifndef PLATFORM_CPU +#define BL_IOT_MSG_TAGS ("BLNLINK") +#define BL_MAX_MSG (1024) +#define ETH_ALEN (6) + +typedef enum +{ + MSG_IN_DISCOVERY_MODE = 0, + MSG_OUT_DISCOVERY_MODE, + MSG_GET_WLAN_INFO, + MSG_BYPASS_MODE, +} BL_IOT_MSG_TYPE; + +#pragma pack (push) +#pragma pack (1) +typedef struct +{ + unsigned char msgTags[8]; + unsigned char dstMac[ETH_ALEN]; + unsigned char msgType; + unsigned int msglen; + unsigned char msgData[BL_MAX_MSG]; +} BL_IOT_MSG, *PBL_IOT_MSG; + +typedef struct +{ + unsigned char channel; + unsigned char dev_mac[ETH_ALEN]; + unsigned char bssid[ETH_ALEN]; + unsigned char ssid[32]; +} WL_INFO, *PWL_INFO; +#pragma pack (pop) + +#define BL_IOT_MSG_LEN(len) (sizeof(BL_IOT_MSG) - BL_MAX_MSG + len) + +typedef void (*BlMsgCb)(PBL_IOT_MSG pMsg); + +int BL_Init(BlMsgCb cbOnMsg); +int BL_SendBLMsg(BL_IOT_MSG_TYPE msgType, unsigned char* pData, unsigned int len); +int BL_SendBLMsgTo(BL_IOT_MSG_TYPE msgType, unsigned char* pData, unsigned int len, unsigned char dstMac[ETH_ALEN]); +#endif +#endif diff --git a/app/libuvdbus/src/include/config_engine.h b/app/libuvdbus/src/include/config_engine.h new file mode 100644 index 0000000..80dfc49 --- /dev/null +++ b/app/libuvdbus/src/include/config_engine.h @@ -0,0 +1,58 @@ +#ifndef CONFIG_ENGINE_H +#define CONFIG_ENGINE_H +#include +#include + +#include "smart_sound.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GLOBAL_CFG_FILE_PATH ("/mnt/UDISK/global.db") + + +typedef enum +{ + CFG_TYPE_STRING = 0, + CFG_TYPE_INT = 1, + CFG_TYPE_DOUBLE = 2, +} CFG_DATA_TYPE; + +typedef struct +{ + char* pKeyName; + int keyType; + int keyModule; + + union + { + char* pStrValue; + int intValue; + double doubleValue; + }; + + UT_hash_handle hh; ///< UT Hash handle +} CFG_ITEM, *PCFG_ITEM; + +typedef void (*OnCfgMsg)(DBUS_CMD cmd, PCFG_ITEM pMsg, int err); + +int CfgGlobalEnvInit(void); + +void CfgItemPrint(const char* pPrefix, PCFG_ITEM pCfgItem); + +int CfgGetKeyValue(const char* pKeyName, PCFG_ITEM* pItem); +int CfgChangeKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB); +int CfgAddKeyValue(const char *pKeyName, PCFG_ITEM pItem, int saveToDB); + +void CfgSetIntValue(const char* pTags, int iValue); + +void OnCfgMsgProcess(MODULE_NAME dest, DBUS_CMD busCmd, const char *pJsonStr); + +int Sqlite3SyncDB(sqlite3* pSqlMemory, const char* pMemDbName, const char* pDBFilePath, const char* pFileDbName, int isSave); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/app/libuvdbus/src/include/crypto.h b/app/libuvdbus/src/include/crypto.h new file mode 100644 index 0000000..57961f8 --- /dev/null +++ b/app/libuvdbus/src/include/crypto.h @@ -0,0 +1,81 @@ +#ifndef CRYPTO_H +#define CRYPTO_H +#include +#include +#ifdef __cplusplus +extern "C" { +#endif +#define ALIGN_AES_BLOCK(size) (((size + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE) + +#define MD5_VALUE_LEN (16) +#define MD5_STR_VALUE_LEN (MD5_VALUE_LEN * 2) + +typedef enum +{ + CRYPTO_AES_ENCRYPT = 0, + CRYPTO_AES_DECRYPT, + CRYPTO_BASE64_ENCODE, + CRYPTO_BASE64_DECODE, + CRYPTO_MD5_FILE, +} CRYPTO_TYPE; + +void EvpSystemInit(void); + +//***************************************************** +// AES +//***************************************************** +typedef void (*OnEVPCrypto)(CRYPTO_TYPE type, + const unsigned char* pData, + int iSize, + const unsigned char* pSrcData, + int iError); + + + +int EvpAESEncrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey); + +int EvpAESDecrypto(unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + int* pOutSize, + unsigned char* pKey); + +//***************************************************** +// BASE64 +//***************************************************** +const char* EvpBase64Encode(const char* pSrc); +const char* EvpBase64Decode(const char* pBase64); +const char* EvpBase64EncodeNoAlign(const char *pSrc); +const char* EvpBase64DecodeNoAlign(const char *pBase64); +const char* EvpBase64EncodeNoAlignV2(unsigned char *pSrc, int sLen); +unsigned char* EvpBase64DecodeNoAlignV2(const char *pBase64, int *pOutSize); +//***************************************************** +// MD5 +//***************************************************** +const char* EvpMD5HashFile(const char* pFileName); +int EvpMD5HashFileV2(const char *pFileName, unsigned char md5[16]);; +int EvpMD5HashBuf(const unsigned char *pBuf, int iBufLen, unsigned char *pOutBuf, int *pOutSize); +const char* EvpMD5HashBufV2(const unsigned char *pBuf, int iBufLen); +//***************************************************** +// Async Engine +//***************************************************** +int EvpAddCryptoTask(CRYPTO_TYPE type, + unsigned char* pInBuf, + int iSize, + unsigned char* pOutBuf, + char* pKey, + OnEVPCrypto onEvpCryptCb); + +//***************************************************** +// Compress +//***************************************************** +int GZipFileCompress(const char *pInput, const char *pOutput); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/fifo.h b/app/libuvdbus/src/include/fifo.h new file mode 100644 index 0000000..4ea395b --- /dev/null +++ b/app/libuvdbus/src/include/fifo.h @@ -0,0 +1,724 @@ +/* + * A generic kernel FIFO implementation + * + * Copyright (C) 2009/2010 Stefani Seibold + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef FIFO_H +#define FIFO_H + +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#define __must_check __attribute__((warn_unused_result)) +/* + * How to porting drivers to the new generic FIFO API: + * + * - Modify the declaration of the "struct kfifo *" object into a + * in-place "struct kfifo" object + * - Init the in-place object with kfifo_alloc() or kfifo_init() + * Note: The address of the in-place "struct kfifo" object must be + * passed as the first argument to this functions + * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get + * into kfifo_out + * - Replace the use of kfifo_put into kfifo_in_spinlocked and kfifo_get + * into kfifo_out_spinlocked + * Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc + * must be passed now to the kfifo_in_spinlocked and kfifo_out_spinlocked + * as the last parameter + * - The formerly __kfifo_* functions are renamed into kfifo_* + */ + +/* + * Note about locking : There is no locking required until only * one reader + * and one writer is using the fifo and no kfifo_reset() will be * called + * kfifo_reset_out() can be safely used, until it will be only called + * in the reader thread. + * For multiple writer and one reader there is only a need to lock the writer. + * And vice versa for only one writer and multiple reader there is only a need + * to lock the reader. + */ + + +struct __kfifo { + unsigned int in; + unsigned int out; + unsigned int mask; + unsigned int esize; + void *data; + uv_mutex_t lock; +}; + +#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \ + union { \ + struct __kfifo kfifo; \ + datatype *type; \ + char (*rectype)[recsize]; \ + ptrtype *ptr; \ + const ptrtype *ptr_const; \ + } + +#define __STRUCT_KFIFO(type, size, recsize, ptrtype) \ +{ \ + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \ +} + +#define STRUCT_KFIFO(type, size) \ + struct __STRUCT_KFIFO(type, size, 0, type) + +#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \ +{ \ + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[0]; \ +} + +#define STRUCT_KFIFO_PTR(type) \ + struct __STRUCT_KFIFO_PTR(type, 0, type) + +/* + * define compatibility "struct kfifo" for dynamic allocated fifos + */ +struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void); + +#define STRUCT_KFIFO_REC_1(size) \ + struct __STRUCT_KFIFO(unsigned char, size, 1, void) + +#define STRUCT_KFIFO_REC_2(size) \ + struct __STRUCT_KFIFO(unsigned char, size, 2, void) + +/* + * define kfifo_rec types + */ +struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void); +struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void); + +/* + * helper macro to distinguish between real in place fifo where the fifo + * array is a part of the structure and the fifo type where the array is + * outside of the fifo structure. + */ +#define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo)) + +/** + * DECLARE_KFIFO_PTR - macro to declare a fifo pointer object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + */ +#define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) fifo + +/** + * DECLARE_KFIFO - macro to declare a fifo object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + */ +#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo + +/** + * INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO + * @fifo: name of the declared fifo datatype + */ +#define INIT_KFIFO(fifo) \ +(void)({ \ + typeof(&(fifo)) __tmp = &(fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __kfifo->in = 0; \ + __kfifo->out = 0; \ + __kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\ + __kfifo->esize = sizeof(*__tmp->buf); \ + __kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \ +}) + +/** + * DEFINE_KFIFO - macro to define and initialize a fifo + * @fifo: name of the declared fifo datatype + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + * + * Note: the macro can be used for global and local fifo data type variables. + */ +#define DEFINE_KFIFO(fifo, type, size) \ + DECLARE_KFIFO(fifo, type, size) = \ + (typeof(fifo)) { \ + { \ + { \ + .in = 0, \ + .out = 0, \ + .mask = __is_kfifo_ptr(&(fifo)) ? \ + 0 : \ + ARRAY_SIZE((fifo).buf) - 1, \ + .esize = sizeof(*(fifo).buf), \ + .data = __is_kfifo_ptr(&(fifo)) ? \ + NULL : \ + (fifo).buf, \ + } \ + } \ + } + + +static inline unsigned int __must_check +__kfifo_uint_must_check_helper(unsigned int val) +{ + return val; +} + +static inline int __must_check +__kfifo_int_must_check_helper(int val) +{ + return val; +} + +/** + * kfifo_initialized - Check if the fifo is initialized + * @fifo: address of the fifo to check + * + * Return %true if fifo is initialized, otherwise %false. + * Assumes the fifo was 0 before. + */ +#define kfifo_initialized(fifo) ((fifo)->kfifo.mask) + +/** + * kfifo_esize - returns the size of the element managed by the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_esize(fifo) ((fifo)->kfifo.esize) + +/** + * kfifo_recsize - returns the size of the record length field + * @fifo: address of the fifo to be used + */ +#define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype)) + +/** + * kfifo_size - returns the size of the fifo in elements + * @fifo: address of the fifo to be used + */ +#define kfifo_size(fifo) ((fifo)->kfifo.mask + 1) + +/** + * kfifo_reset - removes the entire fifo content + * @fifo: address of the fifo to be used + * + * Note: usage of kfifo_reset() is dangerous. It should be only called when the + * fifo is exclusived locked or when it is secured that no other thread is + * accessing the fifo. + */ +#define kfifo_reset(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->kfifo.in = __tmp->kfifo.out = 0; \ +}) + +/** + * kfifo_reset_out - skip fifo content + * @fifo: address of the fifo to be used + * + * Note: The usage of kfifo_reset_out() is safe until it will be only called + * from the reader thread and there is only one concurrent reader. Otherwise + * it is dangerous and must be handled in the same way as kfifo_reset(). + */ +#define kfifo_reset_out(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->kfifo.out = __tmp->kfifo.in; \ +}) + +/** + * kfifo_len - returns the number of used elements in the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_len(fifo) \ +({ \ + typeof((fifo) + 1) __tmpl = (fifo); \ + __tmpl->kfifo.in - __tmpl->kfifo.out; \ +}) + +/** + * kfifo_is_empty - returns true if the fifo is empty + * @fifo: address of the fifo to be used + */ +#define kfifo_is_empty(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + __tmpq->kfifo.in == __tmpq->kfifo.out; \ +}) + +/** + * kfifo_is_full - returns true if the fifo is full + * @fifo: address of the fifo to be used + */ +#define kfifo_is_full(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + kfifo_len(__tmpq) > __tmpq->kfifo.mask; \ +}) + +/** + * kfifo_avail - returns the number of unused elements in the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_avail(fifo) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + const unsigned int __recsize = sizeof(*__tmpq->rectype); \ + unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \ + (__recsize) ? ((__avail <= __recsize) ? 0 : \ + __kfifo_max_r(__avail - __recsize, __recsize)) : \ + __avail; \ +}) \ +) + +/** + * kfifo_skip - skip output data + * @fifo: address of the fifo to be used + */ +#define kfifo_skip(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__recsize) \ + __kfifo_skip_r(__kfifo, __recsize); \ + else \ + __kfifo->out++; \ +}) + +/** + * kfifo_peek_len - gets the size of the next fifo record + * @fifo: address of the fifo to be used + * + * This function returns the size of the next fifo record in number of bytes. + */ +#define kfifo_peek_len(fifo) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (!__recsize) ? kfifo_len(__tmp) * sizeof(*__tmp->type) : \ + __kfifo_len_r(__kfifo, __recsize); \ +}) \ +) + +/** + * kfifo_alloc - dynamically allocates a new fifo buffer + * @fifo: pointer to the fifo + * @size: the number of elements in the fifo, this must be a power of 2 + * @gfp_mask: get_free_pages mask, passed to kmalloc() + * + * This macro dynamically allocates a new fifo buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * The fifo will be release with kfifo_free(). + * Return 0 if no error, otherwise an error code. + */ +#define kfifo_alloc(fifo, size) \ +__kfifo_int_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __is_kfifo_ptr(__tmp) ? \ + __kfifo_alloc(__kfifo, size, sizeof(*__tmp->type)) : \ + -EINVAL; \ +}) \ +) + +/** + * kfifo_free - frees the fifo + * @fifo: the fifo to be freed + */ +#define kfifo_free(fifo) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__is_kfifo_ptr(__tmp)) \ + __kfifo_free(__kfifo); \ +}) + +/** + * kfifo_init - initialize a fifo using a preallocated buffer + * @fifo: the fifo to assign the buffer + * @buffer: the preallocated buffer to be used + * @size: the size of the internal buffer, this have to be a power of 2 + * + * This macro initialize a fifo using a preallocated buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * Return 0 if no error, otherwise an error code. + */ +#define kfifo_init(fifo, buffer, size) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __is_kfifo_ptr(__tmp) ? \ + __kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \ + -EINVAL; \ +}) + +/** + * kfifo_put - put data into the fifo + * @fifo: address of the fifo to be used + * @val: the data to be added + * + * This macro copies the given value into the fifo. + * It returns 0 if the fifo was full. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_put(fifo, val) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \ + __dummy = (typeof(__val))NULL; \ + } \ + if (__recsize) \ + __ret = __kfifo_in_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_full(__tmp); \ + if (__ret) { \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->in & __tmp->kfifo.mask] = \ + *(typeof(__tmp->type))__val; \ + __kfifo->in++; \ + } \ + } \ + __ret; \ +}) + +/** + * kfifo_get - get data from the fifo + * @fifo: address of the fifo to be used + * @val: the var where to store the data to be added + * + * This macro reads the data from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_get(fifo, val) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) \ + __val = (typeof(__tmp->ptr))0; \ + if (__recsize) \ + __ret = __kfifo_out_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->out & __tmp->kfifo.mask]; \ + __kfifo->out++; \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * kfifo_peek - get data from the fifo without removing + * @fifo: address of the fifo to be used + * @val: the var where to store the data to be added + * + * This reads the data from the fifo without removing it from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_peek(fifo, val) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) \ + __val = (typeof(__tmp->ptr))NULL; \ + if (__recsize) \ + __ret = __kfifo_out_peek_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->out & __tmp->kfifo.mask]; \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * kfifo_in - put data into the fifo + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * + * This macro copies the given buffer into the fifo and returns the + * number of copied elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_in(fifo, buf, n) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \ + __dummy = (typeof(__buf))NULL; \ + } \ + (__recsize) ?\ + __kfifo_in_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_in(__kfifo, __buf, __n); \ +}) + +/** + * kfifo_in_spinlocked - put data into the fifo using a spinlock for locking + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * @lock: pointer to the spinlock to use for locking + * + * This macro copies the given values buffer into the fifo and returns the + * number of copied elements. + */ +#define kfifo_in_locked(fifo, buf, n) \ +({ \ + unsigned int __ret; \ + uv_mutex_t __lock = ((struct __kfifo*)fifo)->lock; \ + uv_mutex_lock(&__lock); \ + __ret = kfifo_in(fifo, buf, n); \ + uv_mutex_unlock(&__lock); \ + __ret; \ +}) + + +/** + * kfifo_out - get data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get some data from the fifo and return the numbers of elements + * copied. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr) __dummy = NULL; \ + __buf = __dummy; \ + } \ + (__recsize) ?\ + __kfifo_out_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_out(__kfifo, __buf, __n); \ +}) \ +) + +/** + * kfifo_out_spinlocked - get data from the fifo using a spinlock for locking + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * @lock: pointer to the spinlock to use for locking + * + * This macro get the data from the fifo and return the numbers of elements + * copied. + */ +#define kfifo_out_locked(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + unsigned int __ret; \ + uv_mutex_t __lock = ((struct __kfifo*)fifo)->lock; \ + uv_mutex_lock(&__lock); \ + __ret = kfifo_out(fifo, buf, n); \ + uv_mutex_unlock(&__lock); \ + __ret; \ +}) \ +) + +/** + * kfifo_from_user - puts some data from user space into the fifo + * @fifo: address of the fifo to be used + * @from: pointer to the data to be added + * @len: the length of the data to be added + * @copied: pointer to output variable to store the number of copied bytes + * + * This macro copies at most @len bytes from the @from into the + * fifo, depending of the available space and returns -EFAULT/0. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_from_user(fifo, from, len, copied) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const void __user *__from = (from); \ + unsigned int __len = (len); \ + unsigned int *__copied = (copied); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_from_user_r(__kfifo, __from, __len, __copied, __recsize) : \ + __kfifo_from_user(__kfifo, __from, __len, __copied); \ +}) \ +) + +/** + * kfifo_to_user - copies data from the fifo into user space + * @fifo: address of the fifo to be used + * @to: where the data must be copied + * @len: the size of the destination buffer + * @copied: pointer to output variable to store the number of copied bytes + * + * This macro copies at most @len bytes from the fifo into the + * @to buffer and returns -EFAULT/0. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_to_user(fifo, to, len, copied) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + void __user *__to = (to); \ + unsigned int __len = (len); \ + unsigned int *__copied = (copied); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \ + __kfifo_to_user(__kfifo, __to, __len, __copied); \ +}) \ +) + +/** + * kfifo_out_peek - gets some data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get the data from the fifo and return the numbers of elements + * copied. The data is not removed from the fifo. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out_peek(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const unsigned int __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr) __dummy __attribute__ ((unused)) = NULL; \ + __buf = __dummy; \ + } \ + (__recsize) ? \ + __kfifo_out_peek_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_out_peek(__kfifo, __buf, __n); \ +}) \ +) + +#define kfifo_peek_locked(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + unsigned int __ret; \ + uv_mutex_t __lock = ((struct __kfifo*)fifo)->lock; \ + uv_mutex_lock(&__lock); \ + __ret = kfifo_out_peek(fifo, buf, n); \ + uv_mutex_unlock(&__lock); \ + __ret; \ +}) \ +) + +extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, unsigned int esize); + +extern void __kfifo_free(struct __kfifo *fifo); + +extern int __kfifo_init(struct __kfifo *fifo, void *buffer, + unsigned int size, unsigned int esize); + +extern unsigned int __kfifo_in(struct __kfifo *fifo, + const void *buf, unsigned int len); + +extern unsigned int __kfifo_out(struct __kfifo *fifo, + void *buf, unsigned int len); + +extern unsigned int __kfifo_out_peek(struct __kfifo *fifo, + void *buf, unsigned int len); + +extern unsigned int __kfifo_in_r(struct __kfifo *fifo, + const void *buf, unsigned int len, unsigned int recsize); + +extern unsigned int __kfifo_out_r(struct __kfifo *fifo, + void *buf, unsigned int len, unsigned int recsize); + +extern unsigned int __kfifo_len_r(struct __kfifo *fifo, unsigned int recsize); + +extern void __kfifo_skip_r(struct __kfifo *fifo, unsigned int recsize); + +extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, + void *buf, unsigned int len, unsigned int recsize); + +extern unsigned int __kfifo_max_r(unsigned int len, unsigned int recsize); + +#endif diff --git a/app/libuvdbus/src/include/inet_api.h b/app/libuvdbus/src/include/inet_api.h new file mode 100644 index 0000000..c49936d --- /dev/null +++ b/app/libuvdbus/src/include/inet_api.h @@ -0,0 +1,51 @@ +#ifndef INET_API_H +#define INET_API_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_HTTP_POST_SIZE (1024) + +typedef struct HTTP_POST_ATTACH +{ + char keyName[64]; + char keyValue[MAX_HTTP_POST_SIZE]; + + struct HTTP_POST_ATTACH *next, *prev; +} *PHTTP_POST_ATTACH; + +typedef struct +{ + char *pUserName; + char *pPassword; + char *pSmtpServer; + short smtpPort; +} SMTP_MAIL_CONFIG, *PSMTP_MAIL_CONFIG; + +int InetSmtpSendEmail(const char *pFrom, + const char *pTo[], + const char *pCc[], + const char *pTitle, + const char *pMessage, + const char *pAttach[], + PSMTP_MAIL_CONFIG pConfig); +#define InetHttpsDownloadFile(pURL, pPath, onRespCb, onPrgCb) InetHttpDlFileAsync(pURL, pPath, onRespCb, onPrgCb) +#define InetHttpsWebServicePost(pURL, pPost, onRespCb) InetHttpWebServicePostAsync(pURL, pPost, onRespCb) +int InetCancelDownload(const char *pTaskUuid); + +typedef void (*OnHttpResponse)(void* pData, unsigned int size, const char* pReqUrl, const char* pDlPath, const char* pTaskUuid, int iFinished, void* pUserData); +typedef void (*OnProgressNotify)(const char* pReqUrl, const char* pTaskUuid, unsigned char uPercent, void* pUserData); + +int InetInit(void); +void InetUnInit(void); + +const char* InetHttpDlFileAsync(const char*, const char*, OnHttpResponse, OnProgressNotify, void*); +const char* InetHttpWebServicePostAsync(const char *pURL, const char *pPost, OnHttpResponse onRespCb, void *pData); +int InetHttpUploadFileSync(const char *pURL, const char* pPath, void* pAttachInfo); +//int InetSmtpSendEmail(void); +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/json_struct.h b/app/libuvdbus/src/include/json_struct.h new file mode 100644 index 0000000..5664316 --- /dev/null +++ b/app/libuvdbus/src/include/json_struct.h @@ -0,0 +1,150 @@ +#ifndef JSON_STRUCT_H +#define JSON_STRUCT_H +#include + +#include "smart_sound.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_MUSIC_UUID (256) +#define MAX_MUSIC_URL (2048) + +typedef enum +{ +//****************************************** +// Player <--> Controller +//****************************************** + JSON_ENGINE_P2C = 0, + JSON_ENGINE_C2P, + +//****************************************** +// Configure Req & Rsp +//****************************************** + JSON_ENGINE_CFG_REQ, + JSON_ENGINE_CFG_RSP, + +//****************************************** +// Alarm Req & Rsp +//****************************************** + JSON_ENGINE_ASSISTANT_SYNC_RSP, + JSON_ENGINE_ASSISTANT_NOTIFY, + JSON_ENGINE_ASSISTANT_STATUS, + JSON_ENGINE_ASSISTANT_RUNNING, + +//****************************************** +// Work Day API Req & Rsp +//****************************************** + JSON_ENGINE_WORKDAY_REQ, + +//****************************************** +// PING Cmd +//****************************************** + JSON_ENGINE_PING, + +//****************************************** +// OTA Cmd +//****************************************** + JSON_ENGINE_OTA_REQ, + JSON_ENGINE_OTA_RSP, + +//****************************************** +// LOG System Configure Cmd +//****************************************** + JSON_ENGINE_LOG_CFG_CMD, + +//****************************************** +// WIFI Status Changed Nofify Cmd +//****************************************** + JSON_WIFI_STATUS_NOTIFY, + +//****************************************** +// mcu test Cmd +//****************************************** + JSON_MCU_GUIDE_TEST_CMD, + JSON_MCU_MATRIX_TEST_CMD, + JSON_MCU_TEST_GET_VER_CMD, + + JSON_ENGINE_MAX, +} JSON_ENGINE_TYPE; + +typedef struct +{ + uint32_t playerId; + char musicUuid[MAX_MUSIC_UUID]; + int plySt; + uint32_t curPos; + uint32_t duration; +} PLAYER_TO_CTRL, *PPLAYER_TO_CTRL; + +typedef struct +{ + uint32_t playerId; + char src[MAX_MUSIC_URL]; + char srcUuid[MAX_MUSIC_URL]; + char ttsText[MAX_MUSIC_UUID * 2]; + int skTime; + int plyMode; + int plyListType; + char adSrcType; + int duration; + int volRestoreTime; + char volBegin; + float gain; + char fifo[MAX_MUSIC_UUID]; + char channel; + char bytes; + int sampleRate; + char backGroundUrl[MAX_MUSIC_URL]; +} CTRL_TO_PLAYER, *PCTRL_TO_PLAYER; + +typedef struct +{ + char keyName[MAX_CFG_KEY_NAME]; + char keyValue[MAX_CFG_KEY_VALUE]; + int keyType; +} CFG_API_REQ, *PCFG_API_REQ; + +typedef struct +{ + int red; + int green; + int blue; +} MCU_TEST_GUIDE_CMD, *PMCU_TEST_GUIDE_CMD; + +typedef struct +{ + int level; +} MCU_TEST_MATRIX_CMD, *PMCU_TEST_MATRIX_CMD; + +typedef struct +{ + char McuVer[16]; +} MCU_TEST_VER_CMD, *PMCU_TEST_VER_CMD; + + +typedef struct +{ + char keyName[MAX_CFG_KEY_NAME]; + char keyValue[MAX_CFG_KEY_VALUE]; + int keyType; + int errNo; +} CFG_API_RSP, *PCFG_API_RSP; + +typedef struct +{ + double PING; + int tmSec; + int tmMSec; +} PING_MSG, *PPING_MSG; + +void* Json2Struct(const char* pJsonStr, JSON_ENGINE_TYPE type, int enBase64, int* pErr); +const char* Struct2Json(void* pStruct, JSON_ENGINE_TYPE type, int enBase64, int* pErr); + + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/app/libuvdbus/src/include/libuv_dbus.h b/app/libuvdbus/src/include/libuv_dbus.h new file mode 100644 index 0000000..e019b8e --- /dev/null +++ b/app/libuvdbus/src/include/libuv_dbus.h @@ -0,0 +1,232 @@ +#ifndef LIBUV_DEBUS_H +#define LIBUV_DEBUS_H +#include "smart_sound.h" + +#include +#include +#include "json_struct.h" +#include "config_engine.h" + +#ifdef __cplusplus +extern "C" { +#endif +#define SAFE_STRING_VALUE(s) (s ? s : "") +#define R16_TINA_KEY_EVENT_PATH ("/dev/input/event2") +#define DBUS_MESSAGE_INTERFACE_NAME "netease.ihw.SmartAudio" + +#define DBUS_PATH_HEAD "/netease/ihw/" +#define DBUS_INTERFACE_HEAD "netease.ihw." + +#define DBUS_MSG_MAX_PAD_SIZE (1024 * 1024 * 2) +#define LIBUV_CURRENT_TIME_S() (uv_hrtime() / 1000000000) +#define LIBUV_CURRENT_TIME_MS() (uv_hrtime() / 1000000) +#define LIBUV_CURRENT_TIME_US() (uv_hrtime() / 1000) +#define MODULE_ALIAS_NAME(i) (strrchr(g_pModInfoTable[i].modAliase, '.') + 1) + +#define HEART_SEND_DELAY (5000) +#define HEART_LOST_DELAY (20000) + +typedef enum +{ + WIFI_CONNECTED = 0, + WIFI_DISCONNECTED = 1, +} WIFI_STATUS; + +typedef struct +{ + int wifi_evt; +} WIFI_STATUS_PRO, *PWIFI_STATUS_PRO; + +typedef struct +{ + int isReady; + int year; + unsigned char days[366]; +} WORKDAY_INFO, *PWORKDAY_INFO; + +typedef struct +{ + int32_t msgSrc; ///< message who send + uint32_t msgDests; ///< who need receive message(not only one) +#if USED_SHM_TO_DBUS + uint32_t tmTickMSec; ///< timestamp of second +#endif + uint32_t busCmd; ///< command of message + uint32_t msgSize; ///< how many bytes of this message + uint32_t msgKey; ///< share key for copy large message + char* pMsg; ///< message context if has + int isBstMsg; +} DBUS_MSG_PACK, *PDBUS_MSG_PACK; + +typedef struct DBUS_MSG_PROC +{ + int msgFrom; ///< 0: Boardcast Msg, 1: P2P Message + DBUS_MSG_PACK msgContent; + + struct DBUS_MSG_PROC *next, *prev; +} *PDBUS_MSG_PROC; + +typedef void (*OnDBusAsyncSendTo)(int err); +typedef PDBUS_MSG_PACK (*OnDBusMessage)(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg); +typedef void (*OnDaemonMsg)(MODULE_NAME modName, int status); +typedef void (*OnKeyEvent)(uint16_t uType, uint16_t uKey, int32_t iValue); + +typedef struct +{ + MODULE_NAME modName; ///< Module Name + const char* modPath; ///< Attach to dbus path + const char* modAliase; ///< Attach to dbus bus name +} MOD_INFO_TABLE, *PMOD_INFO_TABLE; + + +typedef struct +{ + uv_loop_t* pLoop; ///< libuv default main loop + uv_loop_t* pUserLoop; ///< libuv user main loop + DBusConnection* pBus; ///< D-Bus object + MODULE_NAME modName; ///< Process name + const char* pBusName; ///< D-Bus object's interface name + const char* pBusPath; ///< D-Bus object's path name + OnDBusMessage onMsgCb; ///< D-Bus receive message callback + OnKeyEvent onKeyCb; ///< Keyboard event callback + OnDaemonMsg onHblCb; ///< Process HBL event callback + OnCfgMsg onCfgCb; ///< Configure message callback +// unsigned int uDaemon[MODULE_MAX]; ///< Daemon Service +} LIBUV_DBUS_PARAMS, *PLIBUV_DBUS_PARAMS; + +static MOD_INFO_TABLE g_pModInfoTable[] = +{ + {MODULE_CONTROLLER, DBUS_PATH_HEAD"controller", DBUS_INTERFACE_HEAD"controller"}, + {MODULE_ALARM, DBUS_PATH_HEAD"alarm", DBUS_INTERFACE_HEAD"alarm"}, + {MODULE_CALL, DBUS_PATH_HEAD"call", DBUS_INTERFACE_HEAD"call"}, + {MODULE_VOICEENGINE, DBUS_PATH_HEAD"voice_engine", DBUS_INTERFACE_HEAD"voice_engine"}, + {MODULE_PLAYER, DBUS_PATH_HEAD"player", DBUS_INTERFACE_HEAD"player"}, + {MODULE_CONFIGURE, DBUS_PATH_HEAD"config", DBUS_INTERFACE_HEAD"config"}, + {MODULE_OTA, DBUS_PATH_HEAD"ota", DBUS_INTERFACE_HEAD"ota"}, + {MODULE_WIFI, DBUS_PATH_HEAD"wifi", DBUS_INTERFACE_HEAD"wifi"}, + {MODULE_BT, DBUS_PATH_HEAD"bt", DBUS_INTERFACE_HEAD"bt"}, + {MODULE_KPLAYER, DBUS_PATH_HEAD"kplayer", DBUS_INTERFACE_HEAD"kplayer"}, + {MODULE_KPLAYER_TEST, DBUS_PATH_HEAD"kplayerTest", DBUS_INTERFACE_HEAD"kplayerTest"}, + {MODULE_SPLAYER, DBUS_PATH_HEAD"splayer", DBUS_INTERFACE_HEAD"splayer"}, + {MODULE_SPLAYER_TEST, DBUS_PATH_HEAD"splayerTest", DBUS_INTERFACE_HEAD"splayerTest"}, + {MODULE_LIGHT_MCU, DBUS_PATH_HEAD"light_mcu", DBUS_INTERFACE_HEAD"light_mcu"}, + {MODULE_BLUEKC, DBUS_PATH_HEAD"blukc", DBUS_INTERFACE_HEAD"blukc"}, + {MODULE_BLUEKC_TEST, DBUS_PATH_HEAD"bluekcTest", DBUS_INTERFACE_HEAD"bluekcTest"}, + {MODULE_MANUFACTURE, DBUS_PATH_HEAD"manufacture", DBUS_INTERFACE_HEAD"manufacture"}, + {MODULE_BT_DEMO, DBUS_PATH_HEAD"btdemo", DBUS_INTERFACE_HEAD"btdemo"}, + {MODULE_SKINS, DBUS_PATH_HEAD"skins", DBUS_INTERFACE_HEAD"skins"}, + {MODULE_LOG_CTRL, DBUS_PATH_HEAD"logCtrl", DBUS_INTERFACE_HEAD"logCtrl"}, + {MODULE_WIRELESSTEST, DBUS_PATH_HEAD"wirelessTest", DBUS_INTERFACE_HEAD"wirelessTest"}, + {MODULE_WIRELESSTEST_DEMO, DBUS_PATH_HEAD"wirelessTestDemo", DBUS_INTERFACE_HEAD"wirelessTestDemo"}, + {MODULE_MANUFACTURE_CONTROLLER, DBUS_PATH_HEAD"manufacture_controller", DBUS_INTERFACE_HEAD"manufacture_controller"}, + {MODULE_WIFI_DEMO, DBUS_PATH_HEAD"wifiDemo", DBUS_INTERFACE_HEAD"wifiDemo"}, +}; + +PLIBUV_DBUS_PARAMS DBusLibuvGetRuntime(void); +MODULE_NAME DBusLibGetModName(void); +uv_loop_t* GetDBusDefaultLoop(void); + +void RunUVLoop(uv_loop_t *pLoop); + +PDBUS_MSG_PACK DBusGetMessage(void); +void DBusMsgCleanup(PDBUS_MSG_PACK pMsg); + +DBusConnection* DBusWithLibuvInit(uv_loop_t* pUserLoop, + const char* pBusName, + OnDBusMessage cbOnMsg, + OnDaemonMsg cbOnHbl, + OnKeyEvent cbOnKey, + int* pErrno); + +int DBusJsonSendToCommandAsync(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int iSize, + OnDBusAsyncSendTo cbSendTo, + int enBase64); + +int DBusJsonSendToCommand(DBusConnection* pBus, + const char* pBusName, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64); + +int DBusJsonBoardcastCommand(DBusConnection* pBus, + uint32_t msgToMask, + uint32_t busCmd, + JSON_ENGINE_TYPE type, + void* pStruct, + int enBase64); + +int DBusBoardcastCommand(DBusConnection *pBus, + uint32_t msgToMask, + uint32_t busCmd, + const char *pContext); + +int DBusSendToCommand(DBusConnection *pBus, + const char *pBusName, + uint32_t busCmd, + const char *pContext); + +void HeartDaemonUpgrade(int iWatcher); +void HeartDaemonInit(MODULE_NAME mod, int msHblTout, OnDaemonMsg cb); +void HeartDaemonHblCheck(void); + +int DBusWithLibuvCfgInit(OnCfgMsg cbOnCfgMsg); +int GetShellExecResult(const char *pCmd, char **pResult); +int CopyFile(const char *pSrc, const char *pDest); +int CopyFileWithSize(const char *pSrc, const char *pDest, int iSize); +int ReadFileToBuf(const char *pSrc, unsigned char *pBuf, int iSize); +void SystemSafeReboot(void); + +typedef void (*OnAlarmTimer)(unsigned int tmId, unsigned int status, void* pUserData); +int AlarmTimerInit(uv_loop_t *pLoop); +int AlarmTimerCleanup(void); +int AlarmTimerRemove(unsigned int tmId); +#if 0 +unsigned int AlarmTimerAdd(struct tm *pOnTime, unsigned int repMode, OnAlarmTimer pOnTimerCb, void *pUserData, int *pError); +#endif +unsigned int AlarmTimerAdd(int year, + int month, + int day, + int hour, + int minute, + int second, + int weekDay, + int repMode, + OnAlarmTimer pOnTimerCb, + int priority, + void *pUserData, + int *pError); + +int CurrentIsWorkDay(int year, int day); +int IsHolidayDBSynced(void); +const char* DumpTimerRepeatModeString(int mode); +unsigned long long GetPartitionFreeSize(const char *pPartPath); +WIFI_STATUS GetCurrWIFIConnStatus(void); +const char* ErrcodeToString(int errCode); +const char* DBusCmdToString(DBUS_CMD cmd); +const char* ModuleNameToString(MODULE_NAME modName); + +char* GetCpuSerial(void); +char* GetCpuChipId(void); +char* GetCurrentVersion(void); + +void CfgFileInit(void); +int CfgGetIntValue(const char* pTags, int defValue); +int CfgGetIntValueV1(const char* pTags, int defValue, int* pErr); +int CfgGetIntValueV2(const char* pTags, int defValue, int* pErr); +int GetServerModeFromCC(int defValue, int* pErr); +char* CfgGetStringValue(const char* pTags, char* pDefValue); +double CfgGetFloatValue(const char* pTags, double defValue); +int CfgGetBoolValue(const char* pTags, int defValue); +void SetHBLAutoExit(int flag); + +extern char *strptime(const char *s, const char *format, struct tm *tm); +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/log.h b/app/libuvdbus/src/include/log.h new file mode 100644 index 0000000..118d79c --- /dev/null +++ b/app/libuvdbus/src/include/log.h @@ -0,0 +1,233 @@ +/** @file log.h + @brief + @details + @version 1.0.0 +*/ +#ifndef LOG_H_ +#define LOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __KERNEL__ +#include +#include +#else +#include +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef MAX +/** @def MAX + @brief 取最大值 +*/ +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +/** @def MIN + @brief 取最小值 +*/ +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define TIMEZONE_EAST_8H (8 * 3600) + +#ifndef __KERNEL__ +#define DUMP_PREFIX_ADDRESS (1) +#define DUMP_PREFIX_OFFSET (2) +#endif + +#define DEBUG_SQL_CALLBACK_DATA(argc, argv, azColName) do { \ + for(int i = 0; i < argc; i++) { \ + fprintf(stdout, "%s = [%s], ", azColName[i], argv[i]); \ + } \ + fprintf(stdout, "\n"); \ +} while(0); + +#define print(format, ...) fprintf(stdout, format, __VA_ARGS__) + +typedef struct +{ + int cfgCmd; + int iParams1; + int iParams2; +} LOG_CFG_PROTOCOL, *PLOG_CFG_PROTOCOL; + +typedef enum +{ + CMD_LOG_ENABLE = 0, + CMD_LOG_FILE = 1, + CMD_LOG_MAIL = 2, + CMD_LOG_LEVEL = 3, + CMD_LOG_NETWORK = 4, + CMD_LOG_SERVER = 5 +} LOG_CFG_CMD; + +/** @enum _LOG_LEVEL_ + * LOG等级枚举变量 + */ +typedef enum +{ + LOG_Fatal = (1 << 0), + LOG_Error = (1 << 1), + LOG_Warn = (1 << 2), + LOG_Debug = (1 << 3), + LOG_Info = (1 << 4), + LOG_Test = (1 << 5), + LOG_Call = (1 << 6), + LOG_Devp = (1 << 7), + LOG_Step = (1 << 8), + LOG_Unknown = (1 << 9), + LOG_All = (0xFFFFFFFF), + LOG_Close = 0x0, +} LOG_LEVEL; +/** @var typedef _LOG_LEVEL_ LOG_LEVEL + * @brief 错误值枚举类型 + */ + +#ifdef DISABLE_LOG +#define LOG_BUF(level, buf, len) +#define LOG_EX(level, format, args...) +#define LOG_EX2(level, format, args...) +#define LOG_TAG_EX(tag, level, format, args...) +#define DEBUG_CODE_LINE() +#define DEBUG_FUNCTION_BEGIN() +#define DEBUG_FUNCTION_END() +#else +#define LOG_BUF(level, buf, len) do { \ + const char* pFmtBuf = format_hex_buf("", DUMP_PREFIX_ADDRESS, 16, 1, buf, len, 1); \ + IHW_LOG(level, "[%s] - %s(%d): %s[0-%d]:\n%s", basename_v2(__FILE__), __FUNCTION__, __LINE__, \ + #buf, len, pFmtBuf); \ + free((void*)pFmtBuf); \ +} while(0); +/*! \def LOG_EX + \brief 系统日志调试宏标识 +*/ +#define LOG_EX(level, format, args...) (IHW_LOG(level, "[%s] - %s(%d):" format , basename_v2(__FILE__), __FUNCTION__, __LINE__, ##args)) + +/*! \def LOG_TAG_EX + \brief 系统日志调试宏标识 +*/ +#define LOG_TAG_EX(tag, level, format, args...) (IHW_LOG(level, "{%s} [%s] %s(%d):" format , tag, basename_v2(__FILE__), __FUNCTION__, __LINE__, ##args)) + +#define LOG_EX2(level, format, args...) (IHW_LOG_UNTAG(level, format , ##args)) + +/*! @def APP_BUILD_INFO + @brief 应用程序编译信息 +*/ +#define APP_BUILD_INFO(appname, appver) (IHW_LOG(LOG_Info, "%s Ver:%s (Build: %s %s GCC Ver:%s) With %d(bits) OS\n", \ + appname, appver, __DATE__, __TIME__, __VERSION__, sizeof(int*) * 8)) + + +/*! @def DEBUG_CODE_LINE + @brief 输出当前函数名,行号 +*/ +#define DEBUG_CODE_LINE() (LOG_EX(LOG_Info, "\n")) + +/*! @def DEBUG_FUNCTION_BEGIN + @brief 函数入口标志 +*/ +#define DEBUG_FUNCTION_BEGIN() (LOG_EX(LOG_Call, "+++++\n")) + +/*! @def DEBUG_FUNCTION_END + @brief 函数出口标志 +*/ +#define DEBUG_FUNCTION_END() (LOG_EX(LOG_Call, "-----\n")) + +/** + * @brief 输出调试信息 + * @param level 调试信息开关 + * @param pMsg 调试信息内容 + */ +void IHW_LOG(LOG_LEVEL level, const char* pMsg, ...); +void IHW_LOG_UNTAG(LOG_LEVEL level, const char* pMsg, ...); + +void IHW_LogStrWithoutPrint(int level, char* pMsg); +void IHW_LogRawString(int level, char* pMsg); + +/** + * @brief 设置调试等级 + * @param level 调试等级 + * @param iEnable 1 打开调试等级, 0 关闭调试等级 + */ +void IHW_EnableLogLevel(LOG_LEVEL level, int iEnable); + +/** + * @brief 初始化系统日志功能 + * @param pLogTag 系统日志标志 + * @param pPath 系统日志保存路径 + * @param bEnable 打开/关闭调试信息 + */ +void IHW_InitLOG(const char* pLogTag, const char* pPath, int bEnable); + +void IHW_RunLogService(void); + +/** + * @brief 判断文件、路径是否存在 + * @param pPath - 文件路径 + * @return int 存在返回 1, 否则返回 0; + */ +int IHW_IsFileExist(const char* pPath); + +void IHW_EnableLogOut(void); +void IHW_DisableLogOut(void); + +char* IHW_bin2hex(char *p, const unsigned char *cp, int count); + +void UpgradLogConfigure(PLOG_CFG_PROTOCOL pCfg); +//void LogUploadCurLogFile(void); + +/* Return the last part of a pathname */ +static inline const char* basename_v2(const char* path) +{ + const char* tail = strrchr(path, '/'); + return tail ? tail + 1 : path; +} + +static inline int dirname_v2(const char* path, char* dir) +{ + const char* tail = strrchr(path, '/'); + + if(tail) + { + memcpy(dir, path, tail - path); + dir[tail - path] = 0; + } + else + { + strcpy(dir, "./"); + } + + return 0; +} +#endif + +const char* LogLeveToString(LOG_LEVEL lv); + +const char* format_hex_buf(const char* prefix_str, int prefix_type, + int rowsize, int groupsize, + const void* buf, int len, int ascii); +#ifndef __KERNEL__ +void print_hex_dump_bytes(const char* prefix_str, int prefix_type, + const void* buf, int len); +#endif + +int HttpPostLogFile(char* pSession); +//void UploadLogFile(char* pFilePath); +int SysPointMarkUpload(void); +int SysPointMark(char* pMarkInfo); +int SysPointMarkInit(char* pDevId, int iMaxSize, int iPostTime); +#ifdef __cplusplus +} +#endif +#endif //LOG_H_ + diff --git a/app/libuvdbus/src/include/log_info.h b/app/libuvdbus/src/include/log_info.h new file mode 100644 index 0000000..cd24c61 --- /dev/null +++ b/app/libuvdbus/src/include/log_info.h @@ -0,0 +1,13 @@ +#ifndef LOG_INFO_H +#define LOG_INFO_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/monitor.h b/app/libuvdbus/src/include/monitor.h new file mode 100644 index 0000000..e5f8513 --- /dev/null +++ b/app/libuvdbus/src/include/monitor.h @@ -0,0 +1,21 @@ +#ifndef _MONITOR_H +#define _MONITOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ENABLE_COUNT_DEBUG +int MonAddNewItem(const char* pName, int logSaveTime); +int MonIncreaseCount(const char* pName); +int MonUpgradeStatistical(const char* pName, long newVal); +int MonDiffStatistical(const char* pName, long long newVal); +int MonItemLogout(const char* pName); +int MonitorInit(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/libuvdbus/src/include/ota.h b/app/libuvdbus/src/include/ota.h new file mode 100644 index 0000000..7d4be75 --- /dev/null +++ b/app/libuvdbus/src/include/ota.h @@ -0,0 +1,156 @@ +#ifndef OTA_H +#define OTA_H +#ifdef __cplusplus +extern "C" { +#endif + +#define SIZE_1K (1024) ///< 1K 字节大小 +#define MD5_CHKSUM_LEN (16) ///< MD5校验和长度 +#define MD5_CHKSUM_STR_LEN (MD5_CHKSUM_LEN * 2 + 1) ///< MD5校验和字符串格式长度 +#define NO_OTA_STATUS_VAL_TAG (0) ///< 状态默认值 + + +/** + * 系统启动模式定义 + */ +typedef enum +{ + NORMAL_SETUP = 0x1234, ///< 普通启动模式 + RECOVERY_SETUP, ///< 恢复模式 + SYSTEM_OTA, ///< OTA升级模式 + SYSTEM_OTA_OK, +} SETUP_MODE; + +/** + * OTA状态命令定义 + */ +typedef enum +{ + OTA_CURRENT_VERSION = 0, ///< 当前系统版本号 + OTA_CURRENT_SETUP_MODE, ///< 当前系统启动模式 + OTA_CURRENT_REBOOT_TIME, ///< 当前系统未正常启动次数 + OTA_DOWNLOAD_FILE, ///< OTA升级包下载状态 + OTA_DOWNLOAD_PROGRESS, ///< OTA升级包下载进度 + OTA_VERIFY_FILE, ///< 文件校验结果 + OTA_VERIFY_PARTITION, ///< OTA分区校验结果 + OTA_DECOMPRESS_FILE, ///< OTA当前进度:解压文件 + OTA_UPGRADE_READY, ///< OTA更新准备完成 + OTA_UPGRADE_START, ///< OTA更新开始 + OTA_UPGRADE_PARTITION, ///< OTA写入分区数据 + OTA_RECOVERY_START, ///< OTA恢复模式启动 + OTA_REREQ_OTA_NOW, ///< OTA请求立即执行OTA更新系统 + OTA_REBOOT_SYSTEM, ///< OTA准备重启系统 + OTA_SUCCESED, ///< OTA执行成功 + OTA_UNKNOWN_CMD, ///< 位置OTA状态命令 + OTA_ERR_CODE, ///< OTA过程异常 + OTA_DISK_FULL, ///< 存储空间不足 +} OTA_STATUS_TYPE; + + +/** + * OTA模式 + */ +typedef enum +{ + OTA_MODE_NORMAL = 9029, ///< 普通OTA更新模式 + OTA_MODE_FORCE_NOW, ///< 强制OTA更新模式 + OTA_MODE_RECOVERY, ///< OTA恢复模式 +} OTA_MODE; + + +/** + * OTA操作命令 + */ +typedef enum +{ + OTA_CMD_DOWNLOAD = 1234, ///< 下载OTA升级包 + OTA_CMD_USED_LOCAL_IMAGE, ///< 从上次备份的OTA升级包升级 + OTA_CMD_EXEC, ///< 开始OTA更新系统 +} OTA_CMD; + + + +/** + * OTA级包信息 + * + */ +typedef struct +{ + char url[SIZE_1K]; ///< URL, Base64编码 + char md5[MD5_CHKSUM_STR_LEN]; ///< OTA升级包MD5校验和 + unsigned int size; ///< OTA升级包文件大小 +} OTA_FILE_INFO, *POTA_FILE_INFO; + +/** + * 控制中心控制命令协议 + * + * @see OTA_CMD + * @see OTA_MODE + * @see OTA_FILE_INFO + */ +typedef struct +{ + int version; ///< OTA版本号 + OTA_CMD otaCmd; ///< OTA命令 + OTA_MODE otaMode; ///< OTA模式 + OTA_FILE_INFO otaFileInfo; ///< OTA升级包信息 +} OTA_DATA_INFO, *POTA_DATA_INFO; + +/** + * OTA状态信息协议 + * + * @see OTA_STATUS_TYPE + */ +typedef struct +{ + OTA_STATUS_TYPE status; ///< 状态命令 + int val; ///< 状态值 +} OTA_RSP_STATUS, *POTA_RSP_STATUS; + +static inline const char* otaStatusName(OTA_STATUS_TYPE type) +{ + switch(type) + { + case OTA_CURRENT_VERSION: + return ("OTA_CURRENT_VERSION"); + case OTA_CURRENT_SETUP_MODE: + return ("OTA_CURRENT_SETUP_MODE"); + case OTA_CURRENT_REBOOT_TIME: + return ("OTA_CURRENT_REBOOT_TIME"); + case OTA_DOWNLOAD_FILE: + return ("OTA_DOWNLOAD_FILE"); + case OTA_DOWNLOAD_PROGRESS: + return ("OTA_DOWNLOAD_PROGRESS"); + case OTA_VERIFY_FILE: + return ("OTA_VERIFY_FILE"); + case OTA_VERIFY_PARTITION: + return ("OTA_VERIFY_PARTITION"); + case OTA_DECOMPRESS_FILE: + return ("OTA_DECOMPRESS_FILE"); + case OTA_UPGRADE_READY: + return ("OTA_UPGRADE_READY"); + case OTA_UPGRADE_START: + return ("OTA_UPGRADE_START"); + case OTA_UPGRADE_PARTITION: + return ("OTA_UPGRADE_PARTITION"); + case OTA_RECOVERY_START: + return ("OTA_RECOVERY_START"); + case OTA_REREQ_OTA_NOW: + return ("OTA_REREQ_OTA_NOW"); + case OTA_REBOOT_SYSTEM: + return ("OTA_REBOOT_SYSTEM"); + case OTA_SUCCESED: + return ("OTA_SUCCESED"); + case OTA_UNKNOWN_CMD: + return ("OTA_UNKNOWN_CMD"); + case OTA_ERR_CODE: + return ("OTA_ERR_CODE"); + default: + return ("Unknown Type"); + } +} +#ifdef __cplusplus +} +#endif +#endif + diff --git a/app/libuvdbus/src/include/server_addr.h b/app/libuvdbus/src/include/server_addr.h new file mode 100644 index 0000000..9f5d473 --- /dev/null +++ b/app/libuvdbus/src/include/server_addr.h @@ -0,0 +1,49 @@ +#ifndef SERVER_ADDR_H +#define SERVER_ADDR_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + YUNXIN_MODULE = 0, + VOICE_MODULE = 1, + VOICE_AI_MODULE = 2, + SERVER_MODULE = 3, + LOG_MODULE = 4, + MARK_POINT_MODULE = 5, + TTS_MODULE = 6, + DC_MODULE = 7, + MAX_MODULE +} SERVER_MODULE_TYPE; + +typedef enum +{ + DEV_MODE = 0, + TEST_MODE = 1, + PUBLISH_MODE = 2, + PUBLISH_PREBUILD = 3, + MAX_MODE +} SERVER_MODE_TYPE; + +typedef enum +{ + VOICE_APP_KEY = 0, + VOICE_APP_SECRET = 1, + VOICE_MAX +} VOICE_KEYMAP_TYPE; + +const char* SvrModeStr(SERVER_MODE_TYPE mode); +const char* SvrModuleStr(SERVER_MODULE_TYPE module); +void DumpCurServerAddr(const char* pTags); + +void ServerManagerInit(void); +SERVER_MODE_TYPE GetCurrentServerMode(void); +void SetCurrentServerMode(SERVER_MODE_TYPE mode); + +char* GetCurServerAddr(SERVER_MODULE_TYPE module); +char* GetCurVoiceKeyValue(VOICE_KEYMAP_TYPE keyMap); +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/skins.h b/app/libuvdbus/src/include/skins.h new file mode 100644 index 0000000..1403813 --- /dev/null +++ b/app/libuvdbus/src/include/skins.h @@ -0,0 +1,58 @@ +#ifndef SKINS_H +#define SKINS_H +#ifdef __cplusplus +extern "C" { +#endif + +#define MD5_STR_LEN (36) ///< +#define MAX_KEY_NAME (64) +#define MAX_KEY_PATH (256) + +#define SKIN_MODE_NAME ("ModuleSkin") +#define RES_MODE_NAME ("ModuleRes") +#define RES_TBL_NAME "res" +#define SKIN_TBL_NAME "skin" +#define SKIN_USER_DB "user_db" + +#define CREATE_SKIN_TBL_SQL "CREATE TABLE IF NOT EXISTS %s"SKIN_TBL_NAME" (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "keyName TEXT NOT NULL," \ + "resType INTEGER NOT NULL," \ + "priority INTEGER NOT NULL," \ + "resID INTEGER NOT NULL," \ + "resReadme TEXT NOT NULL DEFAULT \'\');" + +#define CREATE_RES_TBL_SQL "CREATE TABLE IF NOT EXISTS %s"RES_TBL_NAME" (" \ + "ID INTEGER PRIMARY KEY AUTOINCREMENT," \ + "resVersion TEXT NOT NULL," \ + "localPath TEXT NOT NULL," \ + "serverURL TEXT NOT NULL," \ + "md5Chksum TEXT NOT NULL);" + +typedef enum +{ + VOICE_RES = 1, + IMAGE_RES, + TEXT_RES, +} SKINS_RES_TYPE; + +typedef struct +{ + SKINS_RES_TYPE resType; + const char *pResVer; + const char *pKeyName; + const char *pLocalPath; + const char *pMD5Chksum; +} SKIN_RES_INFO, *PSKIN_RES_INFO; + +int SkinInit(void); +char* GetSkinsResource(char *pKeyName, int *pResType, int *pVersion, char **pComeFrom); +int SkinUpgrade(char *pUpdFilePath); +void SkinIsVerifyRes(int isVerify); +unsigned int SkinsDefaultSize(void); +PSKIN_RES_INFO SkinsItemById(int iId); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/skins_res.h b/app/libuvdbus/src/include/skins_res.h new file mode 100644 index 0000000..742ccda --- /dev/null +++ b/app/libuvdbus/src/include/skins_res.h @@ -0,0 +1,319 @@ +#ifndef SKINS_RES_H +#define SKINS_RES_H + +#include "skins.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PLATFORM_CPU +#define SKINS_DB_PATH ("./skins.db") +#define DEF_SKINS_ROOT_PATH "/home/hx/MyProjects/release/drivers/skins/" +#else +#define SKINS_DB_PATH ("/mnt/UDISK/skins.db") +#define DEF_SKINS_ROOT_PATH "/usr/share/resource/" +#endif + +#define EMU_HTTP_URL_ROOT "http://10.240.84.163/resource/" + +#if 0 +#define TEXT_WIFIPARING_APPARINGANDCONNECTING ("接收到WIFI配置参数,开始连接,可能时间比较长,请耐心等待") +#define TEXT_BT_WIFIPARING ("进入蓝牙网络配对模式") +#define TEXT_AP_WIFIPARING ("进入AP网络配对模式") +#define TEXT_WIFICONNECTED ("联网成功") +#define TEXT_SYSTEMBOOT ("很高兴遇见你,我是如意") +#define TEXT_NOTRECVINGWIFICONFIG ("没有收到网络配置信息") +#define TEXT_BLE_SUUCCESS_WAIT_CONFIG ("低功耗蓝牙已连接,等待配网") +#define TEXT_AP_WAIT_CONFIG ("当前在AP配网模式,等待配网") +#define TEXT_WIFINOTCONNECT ("网络未连接") +#define TEXT_REQSERVER_ERROR ("服务器请求失败,请重新配网") +#define TEXT_BLE_CONNECT ("ble已连接") +#define TEXT_BLE_DISCONNECT ("ble已断开") +#define TEXT_WIFIPARINGSUCCESS ("网络配对成功") +#define TEXT_BT_ON ("开启传统蓝牙") +#define TEXT_BT_OFF ("关闭传统蓝牙") +#define TEXT_ALARM_REMOVE_ALL ("删除全部闹钟成功") +#define TEXT_ALARM_REMOVE ("删除闹钟成功") +#define TEXT_ALARM_ADD ("闹钟设置成功") +#define TEXT_AP_APP_CONNECTED ("APP已通过wifi连接音箱") +#define TEXT_WIFICONNECT_ERR_REPARING ("wifi联网失败,请重新配网") +#define TEXT_WIFICONNECT_ERR_PASS ("ssid或密码错误,请重新配网") +#define TEXT_WIFIPARING_ERR_SERVERCONNECT ("服务器连接失败,请重新配网") +#define TEXT_NOT_UNSUPPORT ("不支持当前操作") +#define TEXT_BOOT_DONE ("你好,欢迎使用如意音箱") +#define TEXT_WIFIPARING_FIRST_NOTICE ("请使用网易云音乐APP ,进入账号页面 为音箱配网,请下载如意音响APP,为音箱配网") +#endif + +const SKIN_RES_INFO g_SkinDefaultResTable[] = { + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// voice resources + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef RES_FACTORY_MODE + {VOICE_RES, "0", "v102", DEF_SKINS_ROOT_PATH"voice/Alianwang002.mp3", "c84ee8c2dade8b5d39e36d10ee8e3807"}, +#endif + {VOICE_RES, "0", "v103", DEF_SKINS_ROOT_PATH"voice/Alianwang003.mp3", "33c00781480680a9ea5ef6be1f7ac258"}, + {VOICE_RES, "0", "v104", DEF_SKINS_ROOT_PATH"voice/Alianwang004.mp3", "d8ee9527dd6635f7251b455fcf177723"}, + {VOICE_RES, "0", "v105", DEF_SKINS_ROOT_PATH"voice/Alianwang005.mp3", "87849f3c844a42d765e85631ccfca2eb"}, + {VOICE_RES, "0", "v106", DEF_SKINS_ROOT_PATH"voice/Alianwang006.mp3", "46a63182f73e242fff7f202fc621ef17"}, + {VOICE_RES, "0", "v107", DEF_SKINS_ROOT_PATH"voice/Alianwang007.mp3", "fc02f25d84abfe066fd4ae8c140fe5f7"}, + {VOICE_RES, "0", "v108", DEF_SKINS_ROOT_PATH"voice/Alianwang008.mp3", "da772f7fcec24ebcd85bc3d9fe323f88"}, + {VOICE_RES, "0", "v109", DEF_SKINS_ROOT_PATH"voice/Alianwang009.mp3", "22b8163a5956bb877db55d38f1223cb2"}, + {VOICE_RES, "0", "v110", DEF_SKINS_ROOT_PATH"voice/Alianwang010.mp3", "5d83539bcb59558dd53352b898512227"}, + {VOICE_RES, "0", "v111", DEF_SKINS_ROOT_PATH"voice/Alianwang011.mp3", "58de437b7778885481678cc48bc4b592"}, + {VOICE_RES, "0", "v112", DEF_SKINS_ROOT_PATH"voice/Alianwang012.mp3", "0e1d0afc6663a73c5aa5d9de0072b8df"}, + {VOICE_RES, "0", "v113", DEF_SKINS_ROOT_PATH"voice/Alianwang013.mp3", "f495927bf6b5c67991685e751f2fca40"}, + {VOICE_RES, "0", "v114", DEF_SKINS_ROOT_PATH"voice/Alianwang014.mp3", "06b0f3de13c21c60ab73253ee16f36b3"}, + {VOICE_RES, "0", "v202", DEF_SKINS_ROOT_PATH"voice/Ashiyong002.mp3", "e825e5c5b6989afb88d4084ffe1eff01"}, + {VOICE_RES, "0", "v203", DEF_SKINS_ROOT_PATH"voice/Ashiyong003.mp3", "d7245a20b4a3597894e6af8a83770044"}, + {VOICE_RES, "0", "v204", DEF_SKINS_ROOT_PATH"voice/Ashiyong004.mp3", "d546fe1b69f8ba62c14acd299ae5bc7e"}, + {VOICE_RES, "0", "v205", DEF_SKINS_ROOT_PATH"voice/Ashiyong005.mp3", "79df29d63ac4ea40546f0274b7dd3c84"}, + {VOICE_RES, "0", "v206", DEF_SKINS_ROOT_PATH"voice/Ashiyong006.mp3", "7f47f1796e125078778556d62bd573e2"}, + {VOICE_RES, "0", "v301", DEF_SKINS_ROOT_PATH"voice/S001.mp3", "eee1506b7ed801e5aa6a6ccc18c0c1f1"}, + {VOICE_RES, "0", "v302", DEF_SKINS_ROOT_PATH"voice/S002.mp3", "c90dbc04cda7bdb778a9cb196eb208a2"}, + {VOICE_RES, "0", "v303", DEF_SKINS_ROOT_PATH"voice/S003.mp3", "89340aa9f735d082d9404bae014d7bae"}, + {VOICE_RES, "0", "v304", DEF_SKINS_ROOT_PATH"voice/S004-1.mp3", "2a03648026864291cf0aad7bf6569734"}, + {VOICE_RES, "0", "v3041", DEF_SKINS_ROOT_PATH"voice/S004-2.mp3", "33cafc99de51b53afc97156866e82473"}, + {VOICE_RES, "0", "v3042", DEF_SKINS_ROOT_PATH"voice/S004-3.mp3", "0a1057342a661597730b521427d6097c"}, + {VOICE_RES, "0", "v3043", DEF_SKINS_ROOT_PATH"voice/S004-4.mp3", "c8061b90c50558c155ddc9ffef114e61"}, + {VOICE_RES, "0", "v3044", DEF_SKINS_ROOT_PATH"voice/S004-5.mp3", "97f94d1350bc09c9e974525172ad8fc0"}, + {VOICE_RES, "0", "v305", DEF_SKINS_ROOT_PATH"voice/S005.mp3", "2e7a489501b76c73e5aa4be4f7e7aa5f"}, + {VOICE_RES, "0", "v306", DEF_SKINS_ROOT_PATH"voice/S006.mp3", "437ddb3e99f77696d60c2f28c1b268cb"}, + {VOICE_RES, "0", "v307", DEF_SKINS_ROOT_PATH"voice/S007.mp3", "a6c6be6f702b5b47ddebad61d28eb1ad"}, + {VOICE_RES, "0", "v308", DEF_SKINS_ROOT_PATH"voice/S008.mp3", "5918f635de28b45f2d32e3eb4b05b9ad"}, + {VOICE_RES, "0", "v309", DEF_SKINS_ROOT_PATH"voice/S009.mp3", "f9039012752b3ed2a00f173aa305acf1"}, + {VOICE_RES, "0", "v310", DEF_SKINS_ROOT_PATH"voice/S010.mp3", "446ec757495bdf7aee31a41a9efe8bab"}, + {VOICE_RES, "0", "v311", DEF_SKINS_ROOT_PATH"voice/S011.mp3", "e9fa92d8929dcb2e134f42c1cedf4827"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-60.mp3", "61b24ec25307072464866da912d38287"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-61.mp3", "a231dc24277e25e6d762269efa9a1e07"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-62.mp3", "27402531c6aff9a9cfb5e418267fb41e"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-63.mp3", "f9487a6bf86f82961011920509ae0704"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-64.mp3", "1e67f62e7d8f38dbd8535355cb50fd81"}, + {VOICE_RES, "0", "v400", DEF_SKINS_ROOT_PATH"voice/B-h-65.mp3", "d2e6c99c68e981e6126306cfe8a8058e"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-66.mp3", "cb64153aef2ea8d5d9baeb0fc683fd54"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-67.mp3", "6661a903cd05fdab1ecd5193fb789e51"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-68.mp3", "db32f17dc439c25255d934bbeaec6275"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-69.mp3", "a93fea8d57e37a519f3ee0388cbd6e9a"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-70.mp3", "f91f277864c927fedfee53fb1e9d964a"}, + {VOICE_RES, "0", "v401", DEF_SKINS_ROOT_PATH"voice/B-h-71.mp3", "a4a4ff36d63fa47072c9eb181712e5cb"}, + {VOICE_RES, "0", "v402", DEF_SKINS_ROOT_PATH"voice/b-h-50.mp3", "017b53f7610f6dd99e21b546e6b35605"}, + {VOICE_RES, "0", "v403", DEF_SKINS_ROOT_PATH"voice/b-h-51.mp3", "422b4550253780343b7a9805ca7b629a"}, + {VOICE_RES, "0", "v5011", DEF_SKINS_ROOT_PATH"voice/a-a-01.mp3", "5d9d186ef50b603ab84a9abbfd348630"}, + {VOICE_RES, "0", "v5012", DEF_SKINS_ROOT_PATH"voice/a-a-02.mp3", "837a2222c961824e98c0d3751a234ae6"}, + {VOICE_RES, "0", "v5013", DEF_SKINS_ROOT_PATH"voice/a-a-03.mp3", "0ec34a1f19ee7cea6b139d214e59026d"}, + {VOICE_RES, "0", "v502", DEF_SKINS_ROOT_PATH"voice/a-n-01.mp3", "b1eb13ed8c9afaa2989763c3d379b39a"}, + {VOICE_RES, "0", "v601", DEF_SKINS_ROOT_PATH"voice/b-m-1.mp3", "820cf2c01e03726b95bc4346a2ce8f8b"}, + {VOICE_RES, "0", "v602", DEF_SKINS_ROOT_PATH"voice/b-m-2.mp3", "35a48b8ec586acfb99a612b4fc1ba57a"}, + {VOICE_RES, "0", "v701", DEF_SKINS_ROOT_PATH"voice/B-b-1.mp3", "993810d9cdcdc7ea02c5a069c9a66623"}, + {VOICE_RES, "0", "v702", DEF_SKINS_ROOT_PATH"voice/B-b-2.mp3", "2748a62323e3e004cdc54da7f50b2315"}, + {VOICE_RES, "0", "v703", DEF_SKINS_ROOT_PATH"voice/B-b-3.mp3", "5be4e22fb53180719b5385863a50a7ae"}, + {VOICE_RES, "0", "v801", DEF_SKINS_ROOT_PATH"voice/C-yc-1.mp3", "ea4268b86e2527f79a0f239944645cc9"}, + {VOICE_RES, "0", "v901", DEF_SKINS_ROOT_PATH"voice/IoT-01.mp3", "22a19c8fc7b0a07701d256dde5eb510d"}, + {VOICE_RES, "0", "v902", DEF_SKINS_ROOT_PATH"voice/IoT-02.mp3", "d1187715117c33ffd48788e53cefc5bf"}, + {VOICE_RES, "0", "v903", DEF_SKINS_ROOT_PATH"voice/IoT-03.mp3", "39d829772814e1bd36b3d68863dbb651"}, + {VOICE_RES, "0", "v904", DEF_SKINS_ROOT_PATH"voice/IoT-04.mp3", "3315787b7c9ce5ea3e9e77a4b27f7358"}, + {VOICE_RES, "0", "v905", DEF_SKINS_ROOT_PATH"voice/IoT-05.mp3", "f4e8806c84c532bad54a25a81f983887"}, + {VOICE_RES, "0", "v906", DEF_SKINS_ROOT_PATH"voice/IoT-06.mp3", "a214a9af112c9581353ebfa171f4132e"}, + {VOICE_RES, "0", "v907", DEF_SKINS_ROOT_PATH"voice/IoT-07.mp3", "50b80fb9b4fc1afd96c0118382a25282"}, + {VOICE_RES, "0", "v908", DEF_SKINS_ROOT_PATH"voice/IoT-08.mp3", "ea911086bfe0603256ef4b7b6ab731e2"}, + {VOICE_RES, "0", "v909", DEF_SKINS_ROOT_PATH"voice/IoT-09.mp3", "32461a940f695d80623a05c871a0dcda"}, + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// picture resources + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + {IMAGE_RES, "0", "p001", DEF_SKINS_ROOT_PATH"image/IconChaozuo001.jpg", "0d4aa6351cc71daf2c699e42c1b74cde"}, + {IMAGE_RES, "0", "p005", DEF_SKINS_ROOT_PATH"image/IconChaozuo005.jpg", "1ceca68b9e7d49c537376a08c07a2b88"}, + {IMAGE_RES, "0", "p101", DEF_SKINS_ROOT_PATH"image/IconLianjie001.jpg", "236dbc343bd1d0c5e651f33900a13c07"}, + {IMAGE_RES, "0", "p102", DEF_SKINS_ROOT_PATH"image/IconLianjie002.jpg", "c627364aec00131589fc942c902c65bc"}, + {IMAGE_RES, "0", "p103", DEF_SKINS_ROOT_PATH"image/IconLianjie003.jpg", "edb04af03cf7c7e4d29aee43c332235b"}, + {IMAGE_RES, "0", "p201", DEF_SKINS_ROOT_PATH"image/IconNaozhong001.jpg", "bd5e7a00b4902ca971684d6ee021fb06"}, + {IMAGE_RES, "0", "p302", DEF_SKINS_ROOT_PATH"image/Iconstart002.gif", "90f2b52b1399348debcec2f447dbd383"}, + {IMAGE_RES, "0", "p401", DEF_SKINS_ROOT_PATH"image/IconTixing001.jpg", "feff2fbedffc955b491e0349385ef6c3"}, + {IMAGE_RES, "0", "p500", DEF_SKINS_ROOT_PATH"image/Iconyinliang000.jpg", "a0c29ad20d51cf86e808c83ee90b6510"}, + {IMAGE_RES, "0", "p501", DEF_SKINS_ROOT_PATH"image/Iconyinliang001.jpg", "196ba4082358d3238d0dcb0035764465"}, + {IMAGE_RES, "0", "p502", DEF_SKINS_ROOT_PATH"image/Iconyinliang002.jpg", "196ba4082358d3238d0dcb0035764465"}, + {IMAGE_RES, "0", "p503", DEF_SKINS_ROOT_PATH"image/Iconyinliang003.jpg", "196ba4082358d3238d0dcb0035764465"}, + {IMAGE_RES, "0", "p504", DEF_SKINS_ROOT_PATH"image/Iconyinliang004.jpg", "d3157ec3c194e4cc6dbcbe683fd40d3f"}, + {IMAGE_RES, "0", "p505", DEF_SKINS_ROOT_PATH"image/Iconyinliang005.jpg", "3f857b11062aeddaa6061e7cabfde044"}, + {IMAGE_RES, "0", "p506", DEF_SKINS_ROOT_PATH"image/Iconyinliang006.jpg", "3f857b11062aeddaa6061e7cabfde044"}, + {IMAGE_RES, "0", "p507", DEF_SKINS_ROOT_PATH"image/Iconyinliang007.jpg", "64a461ee34bea341879aa5a08c717705"}, + {IMAGE_RES, "0", "p508", DEF_SKINS_ROOT_PATH"image/Iconyinliang008.jpg", "b932b0b1c7766c6a995ce3e63b2b7422"}, + {IMAGE_RES, "0", "p509", DEF_SKINS_ROOT_PATH"image/Iconyinliang009.jpg", "dce1278710e1831f02d8dd4fd5d0aac6"}, + {IMAGE_RES, "0", "p510", DEF_SKINS_ROOT_PATH"image/Iconyinliang010.jpg", "b9ac1d7469b34d2aabe04d849c4f1112"}, + {IMAGE_RES, "0", "p511", DEF_SKINS_ROOT_PATH"image/Iconyinliang011.jpg", "45e001edc7d973b15434334ad7f77771"}, + {IMAGE_RES, "0", "p512", DEF_SKINS_ROOT_PATH"image/Iconyinliang012.jpg", "c9c22063c381e5cb775c82b105dce0f1"}, + {IMAGE_RES, "0", "p513", DEF_SKINS_ROOT_PATH"image/Iconyinliang013.jpg", "6e06e51e83498185d148070c0643852c"}, + {IMAGE_RES, "0", "p514", DEF_SKINS_ROOT_PATH"image/Iconyinliang014.jpg", "6e06e51e83498185d148070c0643852c"}, + {IMAGE_RES, "0", "p515", DEF_SKINS_ROOT_PATH"image/Iconyinliang015.jpg", "694a1698c16539805ed4ee238f36586c"}, + {IMAGE_RES, "0", "p516", DEF_SKINS_ROOT_PATH"image/Iconyinliang016.jpg", "0e7e847191e429618c6684ae89d30ac6"}, + {IMAGE_RES, "0", "p517", DEF_SKINS_ROOT_PATH"image/Iconyinliang017.jpg", "a18f5107ada535d664b2483b02080e70"}, + {IMAGE_RES, "0", "p518", DEF_SKINS_ROOT_PATH"image/Iconyinliang018.jpg", "d64992577a379c0faed0078dde767fcc"}, + {IMAGE_RES, "0", "p519", DEF_SKINS_ROOT_PATH"image/Iconyinliang019.jpg", "58268a96482df75c97a177371d295bd3"}, + {IMAGE_RES, "0", "p520", DEF_SKINS_ROOT_PATH"image/Iconyinliang020.jpg", "81ffbdc7857790696e3a7e353bd86908"}, + {IMAGE_RES, "0", "p601", DEF_SKINS_ROOT_PATH"image/Iconlianwang001.gif", "9e18565313b6b1769b7c5979a248dbd6"}, + {IMAGE_RES, "0", "p605", DEF_SKINS_ROOT_PATH"image/Iconlianwang005.gif", "ee81f49fe49864d4cbc4f7f9a1ec52c0"}, + {IMAGE_RES, "0", "p703", DEF_SKINS_ROOT_PATH"image/IconZhuangtai003.gif","e2bdf79f8c2825c23ffbb0233328df97"}, + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// tts resources + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if 0 + {{TEXT_RES, 0, "wifiparing_apparingandconnecting", ""}, "", TEXT_WIFIPARING_APPARINGANDCONNECTING, ""}, + {{TEXT_RES, 0, "bt_wifiparing", ""}, "", TEXT_BT_WIFIPARING, ""}, + {{TEXT_RES, 0, "ap_wifiparing", ""}, "", TEXT_AP_WIFIPARING, ""}, + {{TEXT_RES, 0, "wificonnected", ""}, "", TEXT_WIFICONNECTED, ""}, + {{TEXT_RES, 0, "systemboot", ""}, "", TEXT_SYSTEMBOOT, ""}, + {{TEXT_RES, 0, "notrecvingwificonfig", ""}, "", TEXT_NOTRECVINGWIFICONFIG, ""}, + {{TEXT_RES, 0, "ble_suuccess_wait_config", ""}, "", TEXT_BLE_SUUCCESS_WAIT_CONFIG, ""}, + {{TEXT_RES, 0, "ap_wait_config", ""}, "", TEXT_AP_WAIT_CONFIG, ""}, + {{TEXT_RES, 0, "wifinotconnect", ""}, "", TEXT_WIFINOTCONNECT, ""}, + {{TEXT_RES, 0, "reqserver_error", ""}, "", TEXT_REQSERVER_ERROR, ""}, + {{TEXT_RES, 0, "ble_connect", ""}, "", TEXT_BLE_CONNECT, ""}, + {{TEXT_RES, 0, "ble_disconnect", ""}, "", TEXT_BLE_DISCONNECT, ""}, + {{TEXT_RES, 0, "wifiparingsuccess", ""}, "", TEXT_WIFIPARINGSUCCESS, ""}, + {{TEXT_RES, 0, "bt_on", ""}, "", TEXT_BT_ON, ""}, + {{TEXT_RES, 0, "bt_off", ""}, "", TEXT_BT_OFF, ""}, + {{TEXT_RES, 0, "alarm_remove_all", ""}, "", TEXT_ALARM_REMOVE_ALL, ""}, + {{TEXT_RES, 0, "alarm_remove", ""}, "", TEXT_ALARM_REMOVE, ""}, + {{TEXT_RES, 0, "alarm_add", ""}, "", TEXT_ALARM_ADD, ""}, + {{TEXT_RES, 0, "ap_app_connected", ""}, "", TEXT_AP_APP_CONNECTED, ""}, + {{TEXT_RES, 0, "wificonnect_err_reparing", ""}, "", TEXT_WIFICONNECT_ERR_REPARING, ""}, + {{TEXT_RES, 0, "wificonnect_err_pass", ""}, "", TEXT_WIFICONNECT_ERR_PASS, ""}, + {{TEXT_RES, 0, "wifiparing_err_serverconnect", ""}, "", TEXT_WIFIPARING_ERR_SERVERCONNECT, ""}, + {{TEXT_RES, 0, "not_unsupport", ""}, "", TEXT_NOT_UNSUPPORT, ""}, + {{TEXT_RES, 0, "boot_done", ""}, "", TEXT_BOOT_DONE, ""}, + {{TEXT_RES, 0, "wifiparing_first_notice", ""}, "", TEXT_WIFIPARING_FIRST_NOTICE, ""}, +#endif +}; + +static const SKIN_RES_INFO g_emuUpgradeInfo[] = { + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"android.txt", "8dc557037b69c69efd5615cdfc06934a"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"applying-patches.txt", "8d65812b01d64c9df1529509083e189d"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"atomic_ops.txt", "0d6a66d951ed4747aeee1aa7ab99d8d3"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"bad_memory.txt", "e81b536c2095eb53f9209e26b914f426"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"basic_profiling.txt", "1c70596bd41eb49077af5e91e16d2967"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"binfmt_misc.txt", "8936b928d685bdf98f83f1b3e86562a4"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"braille-console.txt", "4263bbce1595bdb3923bcb7885f866f5"}, + {VOICE_RES, "1", "v001", EMU_HTTP_URL_ROOT"bt8xxgpio.txt", "3a61d033e71cff3c75c778dad89ac565"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"btmrvl.txt", "f5ce90fb4a0ef97d23914fef37fba39d"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"bus-virt-phys-mapping.txt", "23fedac31d1b6ee5dae644ed86cc2c37"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"cachetlb.txt", "5db6b816869d89822759bca684024430"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"circular-buffers.txt", "3be2b7f00c13b160d5dba390b2ee8a54"}, + {VOICE_RES, "1", "v105", EMU_HTTP_URL_ROOT"clk.txt", "e60704c45037f922a73f49fc827b5225"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"coccinelle.txt", "379a83726bbf8f2ffbb12ba454788909"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"cpu-hotplug.txt", "e3676063c62c556a94ebf3b9296db82f"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"cpu-load.txt", "d9d096434110f5c017ab27ea397cee1d"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"cputopology.txt", "4ead2141d532dfaf1057cd2964ced3f4"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"crc32.txt", "644ff3d58c8ab6ca0c5c721dc78e7343"}, + {VOICE_RES, "1", "v206", EMU_HTTP_URL_ROOT"dcdbas.txt", "ad88b9a2d9b547a81ec3f28006a897bc"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"debugging-modules.txt", "c3b0d7040e83f85b5593dac628b3ffa5"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"debugging-via-ohci1394.txt", "a58d95e96be1ca24c5946c6636c4e041"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"dell_rbu.txt", "d5324f7ddcfbf19eb00e4c81bbb5cb7f"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"devices.txt", "8aa73c9268a9012eecbbb78fc4e4cc68"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"digsig.txt", "44b680ee0b743d63f9d0d2849e39d982"}, + {VOICE_RES, "1", "v309", EMU_HTTP_URL_ROOT"DMA-API-HOWTO.txt", "3225970a70a6a79c5112ff29b8f99ec6"}, + {VOICE_RES, "1", "v310", EMU_HTTP_URL_ROOT"DMA-API.txt", "3110d6930bd1c4c692c741f960310810"}, + {VOICE_RES, "1", "v310", EMU_HTTP_URL_ROOT"DMA-attributes.txt", "1ccc7f613bde5312a6a7452e8381d518"}, + {VOICE_RES, "1", "v311", EMU_HTTP_URL_ROOT"dma-buf-sharing.txt", "303f87732efc9effee0d6ed16e89ee37"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"dmaengine.txt", "80881dc6b0c7c9761be617a8f2e5eee3"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"DMA-ISA-LPC.txt", "a0b20e82cadca3595c95a9b7909a2120"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"dynamic-debug-howto.txt", "d15ef07d9fae98de0e096897da1e06ab"}, + {VOICE_RES, "1", "v303", EMU_HTTP_URL_ROOT"edac.txt", "a83b6d68f9e4c2d03ac619f912c13eb9"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"eisa.txt", "cae33ca2a108401d9465a0589503b845"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"email-clients.txt", "a1e6b9470ea752cf97a99ebcb9594aa0"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"feature-removal-schedule.txt", "e45405d2fac3a3bf87b26b3faeaad5de"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"flexible-arrays.txt", "03bfe3a8cb65aecdc96f710a140b8c27"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"futex-requeue-pi.txt", "684984d4f7026c76533ad7f247136ef4"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"gcov.txt", "fb711ca5323092e285f2e0b59a574009"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"gpio.txt", "13417a2589abd22672e8c109e5c57e8e"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"highuid.txt", "1c3e14d700b302d76b1bca29325a4a8e"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"hw_random.txt", "6c78af2ee2fab6ae30aca725c3970da1"}, + {VOICE_RES, "1", "v202", EMU_HTTP_URL_ROOT"hwspinlock.txt", "2ac1e75e3ee30099527e344287340b0a"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"initrd.txt", "c889974503df36fc073c891e6d9b8b0a"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"init.txt", "bdbcc42bf6ae739157092a7fa64aaaac"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"Intel-IOMMU.txt", "e693ef88d3d7d42c7a65a23f3975aa97"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"intel_txt.txt", "9dd22fd4de8b9e718fefc96c15b994c8"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"io-mapping.txt", "a7785b478117c65839749521fc020dc3"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"io_ordering.txt", "f7a404c9794d133f9167ff1a7e2953bb"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"iostats.txt", "4248f808a42956c73b79032686ae77bb"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"IPMI.txt", "8b8bc6bf4528e8d82017113c17d58a37"}, + {VOICE_RES, "1", "v111", EMU_HTTP_URL_ROOT"IRQ-affinity.txt", "d89c8d406a2618cc19db636ba81ce4ca"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"IRQ-domain.txt", "ec9bde5aa997211d7ded9658cfde4fff"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"irqflags-tracing.txt", "b8ca946951177d2cb8099feb9c4587e2"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"IRQ.txt", "0ef9f8f98b9eac9336c0ffb95cfc1d65"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"isapnp.txt", "ab111f0d42d1e748d9745c09e7ff935b"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"java.txt", "fbe28a3d11651fd214ad1d897700fd4f"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kernel-doc-nano-HOWTO.txt", "28579d296e40e460678d0587991e9d48"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kernel-docs.txt", "afc6fd5cdcc8b49ba794bcf5382ff2c3"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kernel-parameters.txt", "2dc9abd6790fd24c3e841f15d0d24a38"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kmemcheck.txt", "b301c758aed537468e98183bd04dc15d"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kmemleak.txt", "b5108533723c0a616e8723e009244d55"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kobject.txt", "d47cf170cd9ce2aaca082fa322b3c271"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kprobes.txt", "7a4c60ba6c646746ca64a311b24a7919"}, + {VOICE_RES, "1", "v110", EMU_HTTP_URL_ROOT"kref.txt", "e6ee109e7185aafc4efe67cad2576352"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"ldm.txt", "3492835c4e3f2340ef0a0d5af464b962"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"local_ops.txt", "809dba9261b3704813557cccaeb3d83d"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"lockdep-design.txt", "b5379d04c39758d7f979d8c6c459285b"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"lockstat.txt", "c672433097ed3823b84bea98cafbb921"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"lockup-watchdogs.txt", "36c72be9bf511bd0e76975f7987f97a2"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"logo.txt", "c12e6a02a126220ed420586143f96d7e"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"magic-number.txt", "2baed34f647a4dab43357718050ded53"}, + {VOICE_RES, "1", "v201", EMU_HTTP_URL_ROOT"mca.txt", "1ea3eab396d5433f30952ad1b30ab133"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"md.txt", "6cdd602644e47836f0cb357e910a4db7"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"media-framework.txt", "1f3f9ba9afc6c1323df2c03160b4db4d"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"memory-barriers.txt", "1b2369bd78d18c2f80c23ca3ab2fb8d8"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"memory-hotplug.txt", "e9bc23bc43814ef7fbe2bcd89692c55b"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"memory.txt", "c17ccb89201a46532f3b95fee4adc372"}, + {VOICE_RES, "1", "v304", EMU_HTTP_URL_ROOT"mono.txt", "da6d7823007522089fc4bfefc1752b16"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"mutex-design.txt", "278a8bef9b14c136939715738cc0f0e8"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"nommu-mmap.txt", "9f4e01823e63aec8b42bf523389664fc"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"numastat.txt", "bebd74fc4713e1500702be1a90113f74"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"oops-tracing.txt", "87f1184ede24989279c9a1dfa1ccfae1"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"padata.txt", "bd3486df46e488dd75d1e67b2bb52da9"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"parport-lowlevel.txt", "a7d58201239229037269d4fd7ba720ac"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"parport.txt", "fa8d7291a3e7d5c2afe5a2060a0abb50"}, + {VOICE_RES, "1", "v108", EMU_HTTP_URL_ROOT"pi-futex.txt", "492ac92f69716bfaa0c40a909c992ade"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"pinctrl.txt", "9b7c710bba0b9aaae7e4f3794a548511"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"pnp.txt", "a7338b790fd6b30b4071fcacbfcedc4e"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"preempt-locking.txt", "5b7ed3fd44bb218e897492667b316a56"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"printk-formats.txt", "8eaefbea3500e15cc155045b3d3ef39c"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"prio_tree.txt", "1b079f5eac72227ecee86a7693ae8f69"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"ramoops.txt", "b50016891d7184720439346f362083e3"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"rbtree.txt", "a35e53c01ecfe9fbc534425504b8f408"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"remoteproc.txt", "d9599a6eda47e17ade41491b1106db22"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"rfkill.txt", "d86dc1dc7f27a25692b40cb739a88a09"}, + {VOICE_RES, "1", "v107", EMU_HTTP_URL_ROOT"robust-futex-ABI.txt", "32be0a8a71053b3258c8dc13c8e3f981"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"robust-futexes.txt", "1ac8f369bc00680aa40e8dfd3bc766c3"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rpmsg.txt", "67b8fcf7e064b15d910e6ef41b944984"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rtc.txt", "51577c35a6c713e85bc4325dde78f1f9"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rt-mutex-design.txt", "25703f95e001b8ab0a92ec7e22f85527"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"rt-mutex.txt", "b449bdf78dad3a5ff62eb7a0853c0c99"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"SAK.txt", "bb81ce113927582c1513704f360129fd"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"serial-console.txt", "814e90de90e893f56eb12cc536dc7d42"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"sgi-ioc4.txt", "f4e0584fa5b55907435c3374c6ae6601"}, + {VOICE_RES, "1", "v333", EMU_HTTP_URL_ROOT"sgi-visws.txt", "0bb26ebbfc96a898f54126d5762cd3de"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"SM501.txt", "58ce960675582f8414019f33a27e1260"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"sparse.txt", "8bc3d0ada8ca01475d69431cd9cd4ec0"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"spinlocks.txt", "d903caeac016182fd7bb349af658bb1a"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"stable_api_nonsense.txt", "ca2acd6fd94048b5b03b213922d962b5"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"stable_kernel_rules.txt", "3948439142160832a55510a93746b738"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"static-keys.txt", "6d801dd48021a20394a7eaa82f0b758d"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"svga.txt", "ffc4306708801c3489dc575998ecca43"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"sync.txt", "381c9f8905dfc34f66eef3e3e486f0d1"}, + {VOICE_RES, "1", "v203", EMU_HTTP_URL_ROOT"sysfs-rules.txt", "84cfa60b3ba436be5acd54034bc15c84"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"sysrq.txt", "f24e71d4fed0257178078b820927791b"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"unaligned-memory-access.txt", "a5a387aeec918a0f528f85bcb76bc8c5"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"unicode.txt", "fd815b4b43d0cf5a85ca44d0db76dde7"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"unshare.txt", "a3ca54a1d655c512654510e56b4c8e53"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"vgaarbiter.txt", "802d04a400dfb5959711fe8088c62f01"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"VGA-softcursor.txt", "88c93a1b83277f3fc3fb07de148fd726"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"video-output.txt", "60ab68e5be73008948e8f1426db0941b"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"volatile-considered-harmful.txt", "8983aa37ffb5d56400e7f54ca9aa88d6"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"workqueue.txt", "6fadee709d10fbbdc4ed587020dbb9b7"}, + {VOICE_RES, "1", "v204", EMU_HTTP_URL_ROOT"xz.txt", "4c3cdd3cc9795936719f90c5998e444d"}, + {VOICE_RES, "1", "v904", EMU_HTTP_URL_ROOT"zorro.txt", "5afccd5699a870edbaeeb4842171e637"} +}; +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/include/smart_sound.h b/app/libuvdbus/src/include/smart_sound.h new file mode 100644 index 0000000..8a17142 --- /dev/null +++ b/app/libuvdbus/src/include/smart_sound.h @@ -0,0 +1,528 @@ +#ifndef SMART_SOUND_H +#define SMART_SOUND_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CMD_BT_AVK_OPEN CMD_BT_BREDR_ENABLE +#define CMD_BT_AVK_CLOSE CMD_BT_BREDR_DISABLE + +//***************************************************************** +//* Global Configure +//***************************************************************** +#define USED_SHM_TO_DBUS (0) // used shm for dbus transfer data +#ifndef MAX_PATH +#define MAX_PATH (256) +#endif + +//************************************************************* + +typedef enum { + MODULE_CONTROLLER = 0, + MODULE_ALARM, + MODULE_CALL, + MODULE_VOICEENGINE, + MODULE_PLAYER, + MODULE_CONFIGURE, + MODULE_OTA, + MODULE_WIFI, + MODULE_BT, + MODULE_KPLAYER, + MODULE_KPLAYER_TEST, + MODULE_SPLAYER, + MODULE_SPLAYER_TEST, + MODULE_LIGHT_MCU, + MODULE_BLUEKC, + MODULE_BLUEKC_TEST, + MODULE_MANUFACTURE, + MODULE_BT_DEMO, + MODULE_SKINS, + MODULE_LOG_CTRL, + MODULE_WIRELESSTEST, + MODULE_WIRELESSTEST_DEMO, + MODULE_MANUFACTURE_CONTROLLER, + MODULE_WIFI_DEMO, + MODULE_MAX, +} MODULE_NAME; + +typedef enum { + CMD_MISC_PING = 0x0000, + CMD_MISC_OTA, + CMD_MISC_WEATHER, + CMD_MISC_NOWTIME, + CMD_MISC_UPGRADE, + CMD_SYSTEM_STANDBY, + CMD_MISC_QUERY_OTA_STATUS, + CMD_MISC_QUERY_DL_STATUS, + CMD_MISC_CHANGE2TEST, + CMD_MISC_CHANGE2ONLINE, + + CMD_SEARCH_PLAYER_REQ, + CMD_SEARCH_PLAYER_RESP, + + CMD_PROCESS_START, + + CMD_CALL_DIAL = 0x0300, + CMD_CALL_ACCEPI, + CMD_CALL_HANGUP, + CMD_CALL_MESSAGE, + + CMD_PLAY_MODECHANGE = 0x0600, + CMD_PLAY_PLAY, + CMD_PLAY_PAUSE, + CMD_PLAY_STOP, + CMD_PLAY_SEEKTO, + CMD_PLAY_SHOWMODE, + CMD_PLAY_NEXT, + CMD_PLAY_PRE, + CMD_PLAY_SEEKTO_PLAY, + CMD_PLAY_SHOWLIST, + CMD_PLAY_UPDATELIST, + CMD_PLAY_PREPARE_NEXT, + CMD_PLAY_ADDTOLIST, + CMD_PLAY_DELETEFROMLIST, + CMD_PLAY_RESETLIST, + CMD_PLAY_VOL_SET, + CMD_PLAY_VOL_RESTORE, + CMD_PLAY_MAX, + + CMD_PLAY_AUDIO_STOP = 0x0700, + CMD_PLAY_AUDIO_PLAY, + CMD_PLAY_AUDIO_MAX, + + CMD_SE_PLAY = 0x0780, + CMD_SE_PLAYER_STATE_NTF, + + CMD_MUSIC_PCM_PLAY = 0X0790, + CMD_MUSIC_PCM_PAUSE = 0X0791, + CMD_MUSIC_PCM_STOP = 0X0792, + CMD_MUSIC_PCM_MAX, + + CMD_PLAYER_MAX = 0X07FF, + + CMD_PLAY_RET_STATUS = 0x0800, + + CMD_CFG_ADD_REQ = 0x0900, + CMD_CFG_ADD_RSP, + CMD_CFG_CHANGE_REQ, + CMD_CFG_CHANGE_RSP, + CMD_CFG_GET_REQ, + CMD_CFG_GET_RSP, + CMD_CFG_UPG_NOTIFY, + + CMD_MSC_MSG_CONTROLLER_RECOG_SUCCESS = 0x0a00, + CMD_MSC_MSG_CONTROLLER_RECOG_ERROR, + CMD_MSC_MSG_CONTROLLER_WAKEUP, + CMD_MSC_MSG_CONTROLLER_SESSION_BEGIN, + CMD_MSC_MSG_CONTROLLER_RECOGING, + CMD_CC_MSC_BEGIN_SESSION, + CMD_CC_MSC_END_SESSION, + CMD_CONTROLLER_REQMSG_INITARGS, + CMD_CONTROLLER_RSPMSG_INITARGS, + CMD_CONTROLLER_REQMSG_PLAYERSTATUS, + CMD_CONTROLLER_RSPMSG_PLAYERSTATUS, + CMD_MSC_REQMSG_MIC_CONTROL, + CMD_MSC_RSPMSG_MIC_CONTROL, + CMD_NDUILITE_FESPA_SET_ARG, + CMD_NDUILITE_SDK_REINIT, + CMD_YUNXIN_RECVMSG, + CMD_YUNXIN_SENDMSG, + CMD_YUNXIN_SENDMSG_BYPASS, + CMD_YUNXIN_SENDMSGCB, + CMD_CONTROLLER_MSG_YUNXIN, + CMD_YUNXIN_STATUS, + CMD_YUNXIN_SYSMSG, + + CMD_WIFI_CONF = 0x0b00, + CMD_WIFI_CONF_RESP, + CMD_WIFI_AUTO_CONN, + CMD_WIFI_AUTO_CONN_RESP, + CMD_WIFI_AUTO_CONN_OUT, + CMD_WIFI_STATE_REQ, + CMD_WIFI_STATE_RESP, + CMD_WIFI_STATE_NTF, + CMD_WIFI_CHANGE_VALID_AP, + CMD_WIFI_CHANGE_VALID_AP_OUT, + CMD_WIFI_CHANGE_VALID_AP_RESP, + + CMD_WIFI_BL_CMD_START, + CMD_WIFI_BL_CONF, + CMD_WIFI_BL_CONF_ABORT, + CMD_WIFI_BL_DEV_INFO_NTF, + CMD_WIFI_BL_CLOUD_CHALLENGE_SIGNATURE, + CMD_WIFI_BL_DEV_SIGNATURE, + CMD_WIFI_BL_CLOUD_SHAREDKEY, + CMD_WIFI_BL_DEV_TOKEN, + CMD_WIFI_BL_DEV_TOKEN_BOUND, + CMD_WIFI_BL_CONF_FAILED, + CMD_WIFI_BL_CMD_END, + + CMD_BT_NAME_GET_REQ, + CMD_BT_NAME_GET_RESP, + CMD_BT_EVT_NTF, + CMD_BT_CREATED, + + CMD_BT_RESET, + CMD_BT_BREDR_ENABLE, // 0xb10 + CMD_BT_BREDR_DISABLE, // 0xb11 + + CMD_BT_AVK_SOUND_OPEN, + CMD_BT_AVK_SOUND_CLOSE, + + CMD_BT_AVK_CON_EVT, + CMD_BT_AVK_DISC_EVT, + + CMD_BT_AVK_CON_DEV, + CMD_BT_AVK_DISC_DEV, + CMD_BT_AVK_PLAY, + CMD_BT_AVK_PAUSE, + CMD_BT_AVK_STOP, + CMD_BT_AVK_PRE, + CMD_BT_AVK_NEXT, + CMD_BT_AVK_VOL_UP, + CMD_BT_AVK_VOL_DOWN, + + CMD_BT_AVK_SOUND_START_EVT, // 0xb1f + CMD_BT_AVK_SOUND_STOP_EVT, // 0xb20 + + CMD_BT_LE_ENABLE, // 0xb21 + CMD_BT_LE_DISABLE, + CMD_BT_LE_NEVSPS_DISC, + + CMD_BT_AVK_CRTED, + CMD_BT_AVK_DELETED, + + CMD_BT_AVK_RC_PLAY, + CMD_BT_AVK_RC_PAUSE, + + CMD_WIFI_UNBIND_ACCOUNT, + CMD_BT_VOL_CHANGE, + + CMD_BT_BREDR_REBOOT_CLOSE, + CMD_BT_AVK_DEV_CON_CONFLICT, + CMD_WIFI_ON, + CMD_WIFI_OFF, + CMD_WIFI_ON_RESP, + CMD_WIFI_OFF_RESP, + + CMD_KPLAYER_START = 0x1b00, + CMD_KPLAYER_STOP, + CMD_KPLAYER_NOTIF_DUR, + CMD_KPLAYER_HOST_ACTION, + CMD_KPLAYER_CTR_NTF_BASE = 0x1c00, + CMD_KPLAYER_CTR_CREATED, + CMD_KPLAYER_CTR_DELED, + CMD_KPLAYER_CTR_PLAY, + CMD_KPLAYER_CTR_STOP, + CMD_KPLAYER_CTR_PAUSE, + CMD_KPLAYER_CTR_SEEK, + CMD_KPLAYER_CTR_SET_URL, + CMD_KPLAYER_CTR_SET_VOLUME, + CMD_KPLAYER_CTR_SET_MUTE, + CMD_KPLAYER_CTR_SET_NXT_URL, + CMD_KPLAYER_CTR_SET_NEXT, + CMD_KPLAYER_CTR_SET_PREV, + + CMD_SPLAYER_SFIFO_TEST = 0x1d00, + CMD_SPLAYER_START, + CMD_SPLAYER_STOP, + CMD_SPLAYER_HOST_ACTION, + + CMD_SPLAYER_CTR_NTF_BASE = 0x1e00, + CMD_SPLAYER_MSG_TYPE_CREATE, + CMD_SPLAYER_MSG_TYPE_DEL, + CMD_SPALYER_MSG_TYPE_START, + CMD_SPLAYER_MSG_TYPE_STOP, + CMD_SPLAYER_MSG_TYPE_SET_VOLUME, + CMD_SPLAYER_MSG_TYPE_STREAMING, + CMD_SPLAYER_MSG_TYPE_DESTRY, + CMD_SPLAYER_MSG_TYPE_DURATION, + CMD_SPLAYER_MSG_TYPE_STREAM_NTF, + CMD_SPLAYER_MSG_TYPE_STREAM_PLAYPAUSE, + + CMD_BLUEKC_POOL_TEST = 0x1f00, + CMD_BLUEKC_LOG_DEBUG, + CMD_BLUEKC_LOG_RESTORE, + + // 厂测 + CMD_TEST_GET_VER_REQ = 0X2000, + CMD_TEST_GET_VER_RESP, + CMD_TEST_GET_MCU_VER_REQ, + CMD_TEST_GET_MCU_VER_RESP, + CMD_TEST_KNOB_REQ, + CMD_TEST_KNOB_RESP, + CMD_TEST_BUTTON_REQ, + CMD_TEST_BUTTON_RESP, + CMD_TEST_GET_VOLUME_REQ, + CMD_TEST_GET_VOLUME_RESP, + CMD_TEST_SET_VOLUME_REQ, + CMD_TEST_SET_VOLUME_RESP, + CMD_TEST_BT_ADDR_REQ, + CMD_TEST_BT_ADDR_RESP, + CMD_TEST_BT_PARRING_REQ, + CMD_TEST_BT_PARRING_RESP, + CMD_TEST_GET_CPLD_REQ, + + // RF cmd---> + + CMD_TEST_RF_BASE = 0x2100, + CMD_TEST_RF_BT_ENTER, + CMD_TEST_RF_BT_ENTER_RESP, + CMD_TEST_RF_EXIT_TO_NORNAL, + CMD_TEST_RF_EXIT_TO_NORNAL_RESP, + + CMD_TEST_RF_BT_TX = 0x2200, + CMD_TEST_RF_BT_TX_RESP, + CMD_TEST_RF_BT_TX_2402_1DH1, + CMD_TEST_RF_BT_TX_2402_1DH1_RESP, + CMD_TEST_RF_BT_TX_2440_1DH1, + CMD_TEST_RF_BT_TX_2440_1DH1_RESP, + CMD_TEST_RF_BT_TX_2480_1DH1, + CMD_TEST_RF_BT_TX_2480_1DH1_RESP, + CMD_TEST_RF_BT_TX_2402_2DH3, + CMD_TEST_RF_BT_TX_2402_2DH3_RESP, + CMD_TEST_RF_BT_TX_2440_2DH3, + CMD_TEST_RF_BT_TX_2440_2DH3_RESP, + CMD_TEST_RF_BT_TX_2480_2DH3, + CMD_TEST_RF_BT_TX_2480_2DH3_RESP, + CMD_TEST_RF_BT_TX_2402_3DH5, + CMD_TEST_RF_BT_TX_2402_3DH5_RESP, + CMD_TEST_RF_BT_TX_2440_3DH5, + + CMD_TEST_RF_BT_TX_2440_3DH5_RESP, + CMD_TEST_RF_BT_TX_2480_3DH5, + CMD_TEST_RF_BT_TX_2480_3DH5_RESP, + + // varible extend---> + CMD_TEST_RF_BT_TX_VARIABLE = 0x22f0, + CMD_TEST_RF_BT_TX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_BT_RX = 0x2300, + CMD_TEST_RF_BT_RX_RESP, + CMD_TEST_RF_BT_RX_2402_1DH1, + CMD_TEST_RF_BT_RX_2402_1DH1_RESP, + CMD_TEST_RF_BT_RX_2440_1DH1, + CMD_TEST_RF_BT_RX_2440_1DH1_RESP, + CMD_TEST_RF_BT_RX_2480_1DH1, + CMD_TEST_RF_BT_RX_2480_1DH1_RESP, + CMD_TEST_RF_BT_RX_2402_2DH3, + CMD_TEST_RF_BT_RX_2402_2DH3_RESP, + CMD_TEST_RF_BT_RX_2440_2DH3, + CMD_TEST_RF_BT_RX_2440_2DH3_RESP, + CMD_TEST_RF_BT_RX_2480_2DH3, + CMD_TEST_RF_BT_RX_2480_2DH3_RESP, + CMD_TEST_RF_BT_RX_2402_3DH5, + CMD_TEST_RF_BT_RX_2402_3DH5_RESP, + CMD_TEST_RF_BT_RX_2440_3DH5, + + CMD_TEST_RF_BT_RX_2440_3DH5_RESP, + CMD_TEST_RF_BT_RX_2480_3DH5, + CMD_TEST_RF_BT_RX_2480_3DH5_RESP, + + // varible extend---> + CMD_TEST_RF_BT_RX_VARIABLE = 0x23f0, + CMD_TEST_RF_BT_RX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_BT_EXIT = 0x2400, + CMD_TEST_RF_BT_EXIT_RESP, + + CMD_TEST_RF_WIFI_ENTER = 0x2500, + CMD_TEST_RF_WIFI_ENTER_RESP, + + CMD_TEST_RF_WIFI_TX = 0x2600, + CMD_TEST_RF_WIFI_TX_RESP, + + CMD_TEST_RF_WIFI_TX_CHANNEL1, + CMD_TEST_RF_WIFI_TX_CHANNEL1_RESP, + CMD_TEST_RF_WIFI_TX_CHANNEL7, + CMD_TEST_RF_WIFI_TX_CHANNEL7_RESP, + CMD_TEST_RF_WIFI_TX_CHANNEL13, + CMD_TEST_RF_WIFI_TX_CHANNEL13_RESP, + + // varible extend---> + CMD_TEST_RF_WIFI_TX_VARIABLE = 0x26f0, + CMD_TEST_RF_WIFI_TX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_WIFI_RX = 0x2700, + CMD_TEST_RF_WIFI_RX_RESP, + + CMD_TEST_RF_WIFI_RX_CHANNEL1, + CMD_TEST_RF_WIFI_RX_CHANNEL1_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL1_RET, + CMD_TEST_RF_WIFI_RX_CHANNEL1_RET_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL7, + CMD_TEST_RF_WIFI_RX_CHANNEL7_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL7_RET, + CMD_TEST_RF_WIFI_RX_CHANNEL7_RET_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL13, + CMD_TEST_RF_WIFI_RX_CHANNEL13_RESP, + CMD_TEST_RF_WIFI_RX_CHANNEL13_RET, + CMD_TEST_RF_WIFI_RX_CHANNEL13_RET_RESP, + + // varible extend---> + CMD_TEST_RF_WIFI_RX_VARIABLE = 0x27f0, + CMD_TEST_RF_WIFI_RX_VARIABLE_RESP, + //<----varible extend + + CMD_TEST_RF_WIFI_EXIT = 0x2800, + CMD_TEST_RF_WIFI_EXIT_RESP, + + CMD_TEST_MCU_LED_GUIDE = 0X2900, + CMD_TEST_MCU_LED_GUIDE_RSP, + CMD_TEST_MCU_LED_MATRIX, + CMD_TEST_MCU_LED_MATRIX_RSP, + //<-----RF cmd + + CMD_TEST_RELEASE_SYSTEM, + + CMD_ALARM_SYNC_REQ = 0xF000, + CMD_ALARM_SYNC_RSP, + CMD_ALARM_ADD, + CMD_ALARM_REMOVE, + CMD_ALARM_REMOVEALL, + + CMD_REMAIND_SYNC_REQ, + CMD_REMAIND_SYNC_RSP, + CMD_REMAIND_ADD, + CMD_REMAIND_REMOVE, + CMD_REMAIND_REMOVEALL, + + CMD_ASSISTANT_STATUS, + CMD_ASSISTANT_RUNNING, + CMD_ASSISTANT_NOTIFY, + + CMD_SESSION_ALARM_SYNC, + + CMD_WORKDAY_DB_REQ = 0xF100, + CMD_WORKDAY_DB_RSP, + + CMD_OTA_NOTIFY = 0xF200, + CMD_OTA_STATUS, + CMD_OTA_RUNNOW, + + CMD_LOG_CONFIG = 0xF300, + + CMD_DEMO_PERFORM_TEST = 0xff00, + +} DBUS_CMD; + +typedef enum { + ERR_INPUT_PARAMS = 1, + ERR_NO_ITEMS, + ERR_GET_BUS, + ERR_DBUS_CONNECTION, + ERR_REQUEST_BUS_NAME, + ERR_SET_WATCH_FUNCTION, + ERR_SET_TIMEOUT_FUNCTION, + ERR_BUS_MATCH, + ERR_BUS_SET_MSG_CB, + ERR_DBUS_CREATE_MSG, + ERR_BUS_SEND_MSG, + ERR_DBUS_MSG_TO_LARGE, + ERR_BUS_RCV_MSG, + ERR_ADD_TASK, + ERR_UNSUP_EVP_TYPE, + + ERR_CREATE_MQ, + ERR_MQ_SENDMSG, + ERR_CREATE_SHM, + ERR_MAP_SHM, + ERR_MALLOC_MEMORY, + + ERR_EVP_INIT_KEY, + ERR_EVP_UPDATE, + ERR_EVP_FINALE, + ERR_EVP_KEY_SIZE, + + ERR_OPEN_FILE, + ERR_READ_FILE, + ERR_WRITE_FILE, + ERR_COPY_FILE, + ERR_FILE_NOT_EXISTS, + ERR_GET_FILE_SIZE, + ERR_UNINIT_ITEM, + ERR_FILE_EMPTY, + + ERR_SEND_MAIL, + ERR_NETWORK_SEND, + ERR_NETWORK_NOT_CONNECTED, + + ERR_CREATE_SOCKET, + ERR_BIND_SOCKET, + + ERR_UNSUPPORT, +} DBUS_WITH_LIBUV_ERROR; + +/** + * 错误码 + */ +typedef enum { + ERR_NO_INIT_IPL3 = 2000, ///< (0xF101) 未初始化OTA参数 + ERR_BAD_IPL3, ///< OTA参数异常 + ERR_BAD_FILE_SIZE, ///< 文件大小不正确 + ERR_MD5_FILE, ///< 计算文件MD5校验和异常 + ERR_MD5_CHECK_SUM, ///< MD5校验和不正确 + ERR_OTA_WRITE_BOOT, ///< 写入BOOT分区异常 + ERR_OTA_WRITE_ROOTFS, ///< 写入ROOTFS分区异常 + ERR_OTA_WRITE_IPL3, ///< 写入IPL3分区异常 + ERR_OTA_WRITE_PARAMS, ///< 写入OTA参数异常 + ERR_OTA_DOWNLOAD_FILE, ///< 下载文件失败 + ERR_VERIFY_PARTITION_MD5, ///< 校验分区MD5异常 + ERR_OTA_PRE_STATR, ///< 先前已经启动了一个未完成的OTA任务 + ERR_OTA_YET_CUR_VER, ///< 当前版本已经更新 + ERR_OTA_NOT_READY, ///< OTA未准备好,暂时不能进行OTA升级 +} OTA_ERROR; + +typedef enum { + ERR_CREATE_CFG_FILE = 1000, + ERR_CREATE_SQLITE3_DB, + ERR_OPEN_SQLITE3_DB, + ERR_SQLITE3_CREATE_TABLE, + ERR_SYNC_DATABASE, + ERR_SQL_QUERY, + ERR_SQL_DELETE, + ERR_UNKNOWN_TYPE, + ERR_PERMISSION_DENIED, + ERR_CFG_NOITEM, + ERR_CFG_ITEM_EXIST, + ERR_CFG_WAIT_RSP, + ERR_CFG_BUSY, + ERR_STR_CONVERT, + ERR_SQL_REG_MODULE, +} CONFIG_MODE_ERRCODE; + +typedef enum { + REPEAT_MODE_NONE = 1, + REPEAT_MODE_EVERY_DAY = 2, + REPEAT_MODE_WORKDAY = 3, + REPEAT_MODE_WEEKEND = 4, + REPEAT_MODE_WEEKDAY = 5, + REPEAT_MODE_EVERY_MONTH_DAY = 6, + REPEAT_MODE_EVERY_YEAR_DAY = 7, + REPEAT_MODE_EVERY_TIME = 8, + REPEAT_MODE_MONTH_LAST_DAY = 9, + REPEAT_MODE_HOLIDAY = 10, +} REPEAT_MODE; + +#define MAX_CFG_KEY_NAME (256) +#define MAX_CFG_KEY_VALUE (1024) +#define DATA_TIME_STR_LEN (20) + +#define GET_FILE_SIZE(path, size) \ + do { \ + struct stat st; \ + memset(&st, 0, sizeof(struct stat)); \ + if (stat(path, &st) != 0) { \ + size = -1; \ + } else { \ + size = st.st_size; \ + } \ + } while (0) +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/libuvdbus/src/log/hexdump.c b/app/libuvdbus/src/log/hexdump.c new file mode 100644 index 0000000..0217b34 --- /dev/null +++ b/app/libuvdbus/src/log/hexdump.c @@ -0,0 +1,326 @@ +#ifndef __KERNEL__ +#include +#include +#include +#include +#include + +#include "log.h" + +static const char hex_asc[] = "0123456789abcdef"; + +#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] +#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] + +char* IHW_bin2hex(char *p, const unsigned char *cp, int count) +{ + while (count) { + unsigned char c = *cp++; + /* put lowercase hex digits */ + *p++ = 0x20 | hex_asc[c >> 4]; + *p++ = 0x20 | hex_asc[c & 0xf]; + count--; + } + + return p; +} + +/** + * hex_to_bin - convert a hex digit to its real value + * @ch: ascii character represents hex digit + * + * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad + * input. + */ +int hex_to_bin(char ch) +{ + if((ch >= '0') && (ch <= '9')) + { + return ch - '0'; + } + + ch = tolower(ch); + + if((ch >= 'a') && (ch <= 'f')) + { + return ch - 'a' + 10; + } + + return -1; +} + +/** + * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @linebuf: where to put the converted data + * @linebuflen: total size of @linebuf, including space for terminating NUL + * @ascii: include ASCII after the hex output + * + * hex_dump_to_buffer() works on one "line" of output at a time, i.e., + * 16 or 32 bytes of input data converted to hex + ASCII output. + * + * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data + * to a hex + ASCII dump at the supplied memory location. + * The converted output is always NUL-terminated. + * + * E.g.: + * hex_dump_to_buffer(frame->data, frame->len, 16, 1, + * linebuf, sizeof(linebuf), true); + * + * example output buffer: + * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO + */ +void hex_dump_to_buffer(const void* buf, int len, int rowsize, + int groupsize, char* linebuf, size_t linebuflen, + int ascii) +{ + const unsigned char* ptr = (const unsigned char *)buf; + unsigned char ch; + int j, lx = 0; + int ascii_column; + + if(rowsize != 16 && rowsize != 32) + { + rowsize = 16; + } + + if(!len) + { + goto nil; + } + + if(len > rowsize) /* limit to one line at a time */ + { + len = rowsize; + } + + if((len % groupsize) != 0) /* no mixed size output */ + { + groupsize = 1; + } + + switch(groupsize) + { + case 8: + { + const unsigned long long* ptr8 = (const unsigned long long *)buf; + int ngroups = len / groupsize; + + for(j = 0; j < ngroups; j++) + lx += snprintf(linebuf + lx, linebuflen - lx, + "%s%16.16llx", j ? " " : "", + (unsigned long long) * (ptr8 + j)); + + ascii_column = 17 * ngroups + 2; + break; + } + + case 4: + { + const unsigned int* ptr4 = (const unsigned int *)buf; + int ngroups = len / groupsize; + + for(j = 0; j < ngroups; j++) + lx += snprintf(linebuf + lx, linebuflen - lx, + "%s%8.8x", j ? " " : "", *(ptr4 + j)); + + ascii_column = 9 * ngroups + 2; + break; + } + + case 2: + { + const unsigned short* ptr2 = (const unsigned short *)buf; + int ngroups = len / groupsize; + + for(j = 0; j < ngroups; j++) + lx += snprintf(linebuf + lx, linebuflen - lx, + "%s%4.4x", j ? " " : "", *(ptr2 + j)); + + ascii_column = 5 * ngroups + 2; + break; + } + + default: + for(j = 0; (j < len) && (lx + 3) <= linebuflen; j++) + { + ch = ptr[j]; + linebuf[lx++] = hex_asc_hi(ch); + linebuf[lx++] = hex_asc_lo(ch); + linebuf[lx++] = ' '; + } + + if(j) + { + lx--; + } + + ascii_column = 3 * rowsize + 2; + break; + } + + if(!ascii) + { + goto nil; + } + + while(lx < (linebuflen - 1) && lx < (ascii_column - 1)) + { + linebuf[lx++] = ' '; + } + + for(j = 0; (j < len) && (lx + 2) < linebuflen; j++) + { + ch = ptr[j]; + linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; + } + +nil: + linebuf[lx++] = '\0'; +} + +/** + * print_hex_dump - print a text hex dump to syslog for a binary blob of data + * @level: kernel log level (e.g. KERN_DEBUG) + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @ascii: include ASCII after the hex output + * + * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump + * to the kernel log at the specified kernel log level, with an optional + * leading prefix. + * + * print_hex_dump() works on one "line" of output at a time, i.e., + * 16 or 32 bytes of input data converted to hex + ASCII output. + * print_hex_dump() iterates over the entire input @buf, breaking it into + * "line size" chunks to format and print. + * + * E.g.: + * print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, + * 16, 1, frame->data, frame->len, true); + * + * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode: + * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO + * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: + * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. + */ +void print_hex_dump(const char* prefix_str, int prefix_type, + int rowsize, int groupsize, + const void* buf, int len, int ascii) +{ + const unsigned char* ptr = (const unsigned char *)buf; + int i, remaining = len; + unsigned char linebuf[32 * 3 + 2 + 32 + 1]; + + if(rowsize != 16 && rowsize != 32) + { + rowsize = 16; + } + + for(i = 0; i < len; i += rowsize) + { + int linelen = MIN(remaining, rowsize); + remaining -= rowsize; + + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, + (char *)linebuf, sizeof(linebuf), ascii); + + switch(prefix_type) + { + case DUMP_PREFIX_ADDRESS: + print("%s%p: %s\n", + prefix_str, ptr + i, linebuf); + break; + + case DUMP_PREFIX_OFFSET: + print("%s%.8x: %s\n", prefix_str, i, linebuf); + break; + + default: + print("%s%.8x: %s\n", prefix_str, i, linebuf); + break; + } + } + + print("%s", "\n"); +} + +/** + * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) + * @buf: data blob to dump + * @len: number of bytes in the @buf + * + * Calls print_hex_dump(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ +void print_hex_dump_bytes(const char* prefix_str, int prefix_type, + const void* buf, int len) +{ + print_hex_dump(prefix_str, prefix_type, 16, 1, + buf, len, 1); +} + +const char* format_hex_buf(const char* prefix_str, int prefix_type, + int rowsize, int groupsize, + const void* buf, int len, int ascii) +{ + UT_string* pLogStr = NULL; + const char* pFormatStr; + const unsigned char* ptr = (const unsigned char *)buf; + int i, remaining = len; + unsigned char linebuf[32 * 3 + 2 + 32 + 1]; + + if(rowsize != 16 && rowsize != 32) + { + rowsize = 16; + } + + utstring_new(pLogStr); + + for(i = 0; i < len; i += rowsize) + { + int linelen = MIN(remaining, rowsize); + remaining -= rowsize; + + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, + (char *)linebuf, sizeof(linebuf), ascii); + + switch(prefix_type) + { + case DUMP_PREFIX_ADDRESS: + utstring_printf(pLogStr, "%s%p: %s\n", + prefix_str, ptr + i, linebuf); + break; + + case DUMP_PREFIX_OFFSET: + utstring_printf(pLogStr, "%s%.8x: %s\n", + prefix_str, i, linebuf); + break; + + default: + utstring_printf(pLogStr, "%s%.8x: %s\n", + prefix_str, i, linebuf); + break; + } + } + + pFormatStr = strdup(utstring_body(pLogStr)); + utstring_free(pLogStr); + + return pFormatStr; +} + +#endif diff --git a/app/libuvdbus/src/log/log.c b/app/libuvdbus/src/log/log.c new file mode 100644 index 0000000..0802634 --- /dev/null +++ b/app/libuvdbus/src/log/log.c @@ -0,0 +1,1332 @@ +/** @file log.c + @brief 系统日志接口文件 + @version 1.0.0 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef PLATFORM_R16 +#include +#endif + +#include "log.h" +#include "smart_sound.h" +#include "inet_api.h" +#include "crypto.h" +#include "libuv_dbus.h" +#include "server_addr.h" + +#define SHOW_CONSOLE_RED ("\033[31;48m\033[1m%s\033[0m%c") +#define SHOW_CONSOLE_YELLOW ("\033[33;48m\033[1m%s\033[0m%c") +#define SHOW_CONSOLE_GREEN ("\033[32;48m\033[1m%s\033[0m%c") +#define SHOW_CONSOLE_BLUE ("\033[34;48m\033[1m%s\033[0m%c") + +#ifdef PLATFORM_CPU +#define LOG_FILE_BASEDIR (".") +#else +#define LOG_FILE_BASEDIR ("/tmp") +#endif + +#ifdef PLATFORM_R16 +#define NIC_NAME ("wlan0") +#else +#define NIC_NAME ("enp3s0") +#endif + +#define MAX_LOG_ITEM (1000) +#define MAX_LOG_FILE_SIZE (1024 * 1024) +#define LOG_PRE_SIZE (512) + +#if 0 +#define LOG_MAIL_USERNAME ("pv1_es2@hotmail.com") +#define LOG_MAIL_PASSWORD ("netEase163") +#define LOG_MAIL_SERVER ("smtp://smtp-mail.outlook.com") +#define LOG_MAIL_PORT (587) +#else +#define LOG_MAIL_USERNAME ("pv1_es2@163.com") +#define LOG_MAIL_LOGPASSWD ("netEase163") +#define LOG_MAIL_PASSWORD ("pv1Dev163") +#define LOG_MAIL_SERVER ("smtp.163.com") +#define LOG_MAIL_PORT (25) +#endif + +#define LOG_MAIL_RECEIVER ("pv1_es2@163.com") + +#define SYS_POINT_UPLOAD_TIME (600) + +typedef struct +{ + char* pDeviceId; + char savePath[MAX_PATH]; + int iMaxCacheSize; + int iEveryUploadTime; + time_t lastPostTime; + time_t lastMarkTime; + FILE* pMarkFile; + uv_rwlock_t uvRwLock; + uv_thread_t uvIOThread; +} SYSPOINT_INFO, *PSYSPOINT_INFO; + +typedef struct SYSPOINT_ITEM +{ + char* pContent; + struct SYSPOINT_ITEM *next, *prev; +} *PSYSPOINT_ITEM; + +typedef struct LOG_ITEM +{ + LOG_LEVEL level; + int isPrinted; + int isAddTags; + struct timeval timestamp; + char *pLogContent; + struct LOG_ITEM *next, *prev; +}*PLOG_ITEM; + +typedef struct LOG_BACKUP +{ + time_t timestamp; + char *plogFilePath; + char *pGzFilePath; + unsigned int sendTimes; + unsigned int tolLogs; + struct LOG_BACKUP *next, *prev; +} *PLOG_BACKUP; + +typedef struct +{ + pid_t pid; + char* pChipId; + char* pChipSerial; + char exeName[MAX_PATH]; + char logFilePath[MAX_PATH]; + FILE *pLogFile; +} LOG_PROCESS_INFO, *PLOG_PROCESS_INFO; + +static int g_bEnableLog = FALSE; // 是否启用 Log 功能 +static int g_bEnMailBackup = FALSE; +static char* g_pEmailBox = NULL; +static int g_bEnLogToFile = TRUE; +static int g_bEnLogToServer = TRUE; +static char g_strLogTag[32]; // Log 标志 +static unsigned int g_LogRdPos = 0; +static pthread_t g_logThreadId; +static pthread_t g_backupThreadId; +static LOG_PROCESS_INFO g_LogProcessInfo; +static uv_rwlock_t g_uvLogLock; +static uv_rwlock_t g_uvLogBackLock; +static PLOG_ITEM g_pLogItemList = NULL; +static PLOG_BACKUP g_pLogBackupList = NULL; +static int g_logSock = -1; +struct sockaddr_in g_logAddr; + +static SYSPOINT_INFO g_SysPonitInfo; +static PSYSPOINT_ITEM g_pSysPointArray = NULL; +static PHTTP_POST_ATTACH g_pLogParamsArray = NULL; + + +static int g_iMinLevel = LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info | LOG_Step; + +/** + * @brief Log 调试等级转字符串 + * @param level 调试等级 + * @return 调试等级对应的字符串 + */ +const char* LogLevelToStr(LOG_LEVEL level) +{ + switch(level) + { + case LOG_Test: + return "T"; + + case LOG_Info: + return "I"; + + case LOG_Call: + return "C"; + + case LOG_Debug: + return "D"; + + case LOG_Warn: + return "W"; + + case LOG_Error: + return "E"; + + case LOG_Fatal: + return "F"; + + case LOG_Step: + return "S"; + + case LOG_Devp: + return "V"; + + case LOG_Unknown: + return "U"; + + case LOG_All: + return "A"; + + default: + return "?"; + } + + return "U"; +} + +#pragma pack (push) +#pragma pack (1) +typedef struct +{ + unsigned short logSeq; + unsigned int pid; + unsigned int timeStamp; + unsigned int nanotime; + unsigned int logLevel; + char logContent[0]; +} LOG_PROTO_CONTENT, *PLOG_PROTO_CONTENT; +#pragma pack (pop) + +static struct HTTP_POST_ATTACH g_PostLogParams[] = +{ + {"CPUID", "", NULL, NULL}, + {"MAC", "", NULL, NULL}, + {"Version", "", NULL, NULL}, + {"BuildTime", "", NULL, NULL}, + {"SerialNumber", "", NULL, NULL}, + {"Datetime", "", NULL, NULL}, + {"content", "", NULL, NULL}, +}; + +static void __initPostLogParams(void) +{ + char *pMacAddr = NULL; + struct tm localTime; + time_t timeStamp = time((time_t*)NULL); + + GetShellExecResult("ifconfig wlan0 | grep HWaddr | awk \'{print $5}\'", &pMacAddr); + + localtime_r(&timeStamp, &localTime); + + strncpy(g_PostLogParams[0].keyValue, g_LogProcessInfo.pChipId, MAX_HTTP_POST_SIZE); + strncpy(g_PostLogParams[1].keyValue, (pMacAddr && strlen(pMacAddr) > 0) ? pMacAddr : "00:00:00:00:00:00", MAX_HTTP_POST_SIZE); + strncpy(g_PostLogParams[2].keyValue, GetCurrentVersion(), MAX_HTTP_POST_SIZE); + sprintf(g_PostLogParams[3].keyValue, "Build: %s %s", __DATE__, __TIME__); + strncpy(g_PostLogParams[4].keyValue, g_LogProcessInfo.pChipSerial, MAX_HTTP_POST_SIZE); + + for(int i = 0; i < sizeof(g_PostLogParams) / sizeof(g_PostLogParams[0]); i++) + { + LL_APPEND(g_pLogParamsArray, &g_PostLogParams[i]); + } + + if(pMacAddr) + { + free(pMacAddr); + } +} + +int HttpPostLogFile(char* pSession) +{ + int ret; + struct tm localTime; + const char* pFileName = "/tmp/backuplog.tar.gz"; + const char* pLastFile = "/mnt/UDISK/backuplog_nand.tar.gz"; + char* pLogServerURL = GetCurServerAddr(LOG_MODULE); + time_t timeStamp = time((time_t*)NULL); + + ret = system(" /usr/sbin/backuplocalfiles.sh"); + + if(access(pFileName, F_OK) != 0 + && access(pLastFile, F_OK) != 0) + { + return -ERR_FILE_NOT_EXISTS; + } + + localtime_r(&timeStamp, &localTime); + + memset(g_PostLogParams[5].keyValue, 0, MAX_HTTP_POST_SIZE); + sprintf(g_PostLogParams[5].keyValue, "%04u-%02u-%02u %02u:%02u:%02u", + localTime.tm_year + 1900, + localTime.tm_mon + 1, + localTime.tm_mday, + localTime.tm_hour, + localTime.tm_min, + localTime.tm_sec); + + memset(g_PostLogParams[6].keyValue, 0, MAX_HTTP_POST_SIZE); + + if(pSession && strlen(pSession) >= 2) + { + strncpy(g_PostLogParams[6].keyValue, pSession, MAX_HTTP_POST_SIZE); + } + else + { + strncpy(g_PostLogParams[6].keyValue, "{}", MAX_HTTP_POST_SIZE); + } + + if(access(pFileName, F_OK) == 0) + { + ret = InetHttpUploadFileSync(pLogServerURL, pFileName, g_pLogParamsArray); + + if(ret == 0) + { + LOG_EX(LOG_Debug, "Upload Log Data [%s] To Server [%s]\n", pFileName, pLogServerURL); + unlink(pFileName); + } + else + { + LOG_EX(LOG_Error, "Upload Log Data [%s] To Server [%s]\n", pFileName, pLogServerURL); + } + } + + if(access(pLastFile, F_OK) == 0) + { + ret = InetHttpUploadFileSync(pLogServerURL, pLastFile, g_pLogParamsArray); + + if(ret == 0) + { + LOG_EX(LOG_Debug, "Upload Log Data [%s] To Server [%s]\n", pLastFile, pLogServerURL); + unlink(pLastFile); + } + else + { + LOG_EX(LOG_Error, "Upload Log Data [%s] To Server [%s]\n", pLastFile, pLogServerURL); + } + } + + //fprintf(stdout, "Upload Log Data [%s] To Server [%s], size = %d\n", pFileName, UPL_HTTP_URL, fileSize); + + return ret; +} + +static int __logNetworkSend(PLOG_ITEM pItem) +{ + PLOG_PROTO_CONTENT pLogInfo; + unsigned char *pBuf; + int ret, totalSize = 0; + static unsigned short sendSeq = 0; + + if(pItem == NULL || pItem->pLogContent == NULL || strlen(pItem->pLogContent) == 0) + { + return (-ERR_INPUT_PARAMS); + } + + totalSize = sizeof(LOG_PROTO_CONTENT) + strlen(pItem->pLogContent); + + pBuf = (unsigned char *)malloc(totalSize); + + if(pBuf == NULL) + { + return (-ERR_MALLOC_MEMORY); + } + + memset(pBuf, 0, totalSize); + + pLogInfo = (PLOG_PROTO_CONTENT)pBuf; + + pLogInfo->logSeq = htons(sendSeq++); + pLogInfo->timeStamp = htonl(pItem->timestamp.tv_sec); + pLogInfo->nanotime = htonl(pItem->timestamp.tv_usec); + pLogInfo->pid = htonl(g_LogProcessInfo.pid); + pLogInfo->logLevel = htonl(pItem->level); + + memcpy(pLogInfo->logContent, pItem->pLogContent, strlen(pItem->pLogContent)); + + ret = sendto(g_logSock, pBuf, totalSize, 0, + (struct sockaddr *)&g_logAddr, sizeof(g_logAddr)); + + if(ret == totalSize) + { + return (0); + } + else + { + //LOG_EX(LOG_Error, "Send %d bytes, need %d bytes\n", ret, totalSize); + return (-ERR_NETWORK_SEND); + } +} + +static void __cleanupBackupItem(PLOG_BACKUP pItem) +{ + if(pItem) + { + LL_DELETE(g_pLogBackupList, pItem); + + if(pItem->plogFilePath) + { + if(access(pItem->plogFilePath, F_OK) == 0) + { + unlink(pItem->plogFilePath); + } + + free(pItem->plogFilePath); + } + + if(pItem->pGzFilePath) + { + if(access(pItem->pGzFilePath, F_OK) == 0) + { + unlink(pItem->pGzFilePath); + } + + free(pItem->pGzFilePath); + } + + free(pItem); + } +} + +static void* __uvLogBackupProc(void *pParams) +{ + SMTP_MAIL_CONFIG smtpCfg; + char gzLogPath[MAX_PATH]; + struct tm localTime; + const char *pFrom = LOG_MAIL_USERNAME; + const char *pTo[] = {g_pEmailBox, NULL}; + char *pMacAddr = NULL; + + //const char *pCc[] = {"xajhuang@qq.com", "xajhuang@163.com", NULL}; + + memset(&smtpCfg, 0, sizeof(SMTP_MAIL_CONFIG)); + + smtpCfg.pUserName = LOG_MAIL_USERNAME; + smtpCfg.pPassword = LOG_MAIL_PASSWORD; + smtpCfg.pSmtpServer = LOG_MAIL_SERVER; + smtpCfg.smtpPort = LOG_MAIL_PORT; + +#ifdef PLATFORM_CPU + GetShellExecResult("ifconfig enp3s0 | grep HWaddr | awk \'{print $5}\'", &pMacAddr); +#else + GetShellExecResult("ifconfig wlan0 | grep HWaddr | awk \'{print $5}\'", &pMacAddr); +#endif + + if(pMacAddr == NULL || strlen(pMacAddr) == 0) + { + pMacAddr = strdup("00:00:00:00:00:00"); + } + + while(TRUE) + { + PLOG_BACKUP pItem = NULL, pTmp = NULL; + time_t timeStamp = time((time_t*)NULL); + localtime_r(&timeStamp, &localTime); + + uv_rwlock_wrlock(&g_uvLogBackLock); + + LL_FOREACH_SAFE(g_pLogBackupList, pItem, pTmp) + { + const char *pAttact[2]; + UT_string *pTitle, *pMessage, *pDatetime; + char* pMD5Val; + + pAttact[1] = NULL; + + if(pItem->plogFilePath == NULL || strlen(pItem->plogFilePath) == 0) + { + __cleanupBackupItem(pItem); + continue; + } + + if(timeStamp - pItem->timestamp >= 3600) + { + __cleanupBackupItem(pItem); + continue; + } + + if(pItem->sendTimes >= 3) + { + __cleanupBackupItem(pItem); + continue; + } +#if 0 + if(g_bEnLogToServer) + { + __logHttpPostFile(pItem->plogFilePath); + //InetHttpUploadFileSync(UPL_HTTP_URL, pItem->pGzFilePath, NULL); + } +#endif + if(pItem->pGzFilePath == NULL) + { + memset(gzLogPath, 0, MAX_PATH); + sprintf(gzLogPath, "%s/%d_%s_%u.log.gz", + LOG_FILE_BASEDIR, g_LogProcessInfo.pid, g_LogProcessInfo.exeName, pItem->tolLogs); + + if(GZipFileCompress(pItem->plogFilePath, gzLogPath) != 0) + { + LOG_EX(LOG_Error, "Create Gzip File Error: %s\n", gzLogPath); + continue; + } + else + { + pItem->pGzFilePath = strdup(gzLogPath); + } + } + + pMD5Val = (char*)EvpMD5HashFile(pItem->pGzFilePath); + + utstring_new(pTitle); + utstring_new(pMessage); + utstring_new(pDatetime); + + utstring_printf(pDatetime, "%04u-%02u-%02u %02u:%02u:%02u", + localTime.tm_year + 1900, + localTime.tm_mon + 1, + localTime.tm_mday, + localTime.tm_hour, + localTime.tm_min, + localTime.tm_sec); + + utstring_printf(pTitle, "Log [%s]-[%s]-[%s]", + g_LogProcessInfo.exeName, + g_LogProcessInfo.pChipSerial, + utstring_body(pDatetime)); + + utstring_printf(pMessage, "\r\n" + "

Summary information:

" + "


" + "

" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
Items
%u
Process PID
%d
Process Name
%s
CPU ID
%s
Serial
%s
Mac Address
%s
File Checksum
%s
Log Level
0x%08X
Datetime
%s
" + "

" + "\r\n", + pItem->tolLogs, + g_LogProcessInfo.pid, + g_LogProcessInfo.exeName, + g_LogProcessInfo.pChipId, + g_LogProcessInfo.pChipSerial, + pMacAddr, + SAFE_STRING_VALUE(pMD5Val), + g_iMinLevel, + utstring_body(pDatetime)); + + pAttact[0] = pItem->pGzFilePath; +#if 0 + if(g_bEnMailBackup && + InetSmtpSendEmail(pFrom, pTo, NULL, utstring_body(pTitle), + utstring_body(pMessage), pAttact, &smtpCfg) == 0) + { + __cleanupBackupItem(pItem); + } + else + { + LOG_EX(LOG_Error, "Send email error: %s\n", pItem->pGzFilePath); + } +#endif + pItem->sendTimes++; + + if(pMD5Val) + { + free(pMD5Val); + } + + utstring_free(pTitle); + utstring_free(pMessage); + utstring_free(pDatetime); + } + + uv_rwlock_wrunlock(&g_uvLogBackLock); + + sleep(1); + } + + free(pMacAddr); + pthread_detach(pthread_self()); + return (NULL); +} + +static void __logColorOutput(const char* pColFmt, UT_string* pLog) +{ + if(pLog == NULL) + { + return; + } + + if(pColFmt == NULL) + { + print("%s", utstring_body(pLog)); + } + else + { + if(utstring_find(pLog, -1, "\n", 1) == utstring_len(pLog) - 1) + { + char* pLogArray = utstring_body(pLog); + pLogArray[utstring_len(pLog) - 1] = 0; + + print(pColFmt, pLogArray, '\n'); + + strcat(pLogArray, "\n"); + } + else + { + print(pColFmt, utstring_body(pLog), '\0'); + } + } +} + +static void* __logOutputThread(void *p) +{ + while(TRUE) + { + int isWriteLog = FALSE; + PLOG_ITEM pItem = NULL, pTmp = NULL; + + uv_rwlock_wrlock(&g_uvLogLock); + + LL_FOREACH_SAFE(g_pLogItemList, pItem, pTmp) + { + UT_string *pLogStr; + struct tm lTime; + int logFileSize = 0; + + if(++g_LogRdPos % 100 == 0) + { + GET_FILE_SIZE(g_LogProcessInfo.logFilePath, logFileSize); + } + + localtime_r(&(pItem->timestamp.tv_sec), &lTime); + + utstring_new(pLogStr); + + if(pItem->isAddTags) + { + utstring_printf(pLogStr, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld] [%s] %s", + lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday, + lTime.tm_hour, lTime.tm_min, lTime.tm_sec, pItem->timestamp.tv_usec / 1000, + LogLevelToStr(pItem->level), pItem->pLogContent); + } + else + { + utstring_printf(pLogStr, "%s", pItem->pLogContent); + } + + if(pItem->isPrinted == FALSE) + { + if(pItem->level & LOG_Error + || pItem->level & LOG_Fatal) + { + __logColorOutput(SHOW_CONSOLE_RED, pLogStr); + } + else if(pItem->level & LOG_Warn + || pItem->level & LOG_Unknown) + { + __logColorOutput(SHOW_CONSOLE_YELLOW, pLogStr); + } + else if(pItem->level & LOG_Test + || pItem->level & LOG_Call) + { + __logColorOutput(SHOW_CONSOLE_BLUE, pLogStr); + } + else if(pItem->level & LOG_Devp) + { + __logColorOutput(SHOW_CONSOLE_GREEN, pLogStr); + } + else + { + print("%s", utstring_body(pLogStr)); + } + + pItem->isPrinted = TRUE; + } + + if(g_logSock != -1 && GetCurrWIFIConnStatus() == WIFI_CONNECTED) + { + __logNetworkSend(pItem); + } + + if(g_LogProcessInfo.pLogFile != NULL && g_bEnLogToFile) + { + if(logFileSize >= MAX_LOG_FILE_SIZE) + { + fflush(g_LogProcessInfo.pLogFile); + fclose(g_LogProcessInfo.pLogFile); +#if 0 + if(g_bEnMailBackup) + { + PLOG_BACKUP pBackup = (PLOG_BACKUP)malloc(sizeof(struct LOG_BACKUP)); + char path[MAX_PATH]; + + memset(path, 0, MAX_PATH); + sprintf(path, "%s/%s.bak_%u.log", + LOG_FILE_BASEDIR, + basename_v2(g_LogProcessInfo.logFilePath), + g_LogRdPos); + rename(g_LogProcessInfo.logFilePath, path); + + if(pBackup) + { + memset(pBackup, 0, sizeof(struct LOG_BACKUP)); + pBackup->timestamp = time(NULL); + pBackup->plogFilePath = strdup(path); + pBackup->sendTimes = 0; + pBackup->tolLogs = g_LogRdPos - 1; + + uv_rwlock_wrlock(&g_uvLogBackLock); + LL_APPEND(g_pLogBackupList, pBackup); + uv_rwlock_wrunlock(&g_uvLogBackLock); + } + } +#endif + g_LogProcessInfo.pLogFile = fopen(g_LogProcessInfo.logFilePath, "w+"); + } + + if(g_LogProcessInfo.pLogFile) + { + fwrite(utstring_body(pLogStr), 1, utstring_len(pLogStr), g_LogProcessInfo.pLogFile); + } + + isWriteLog = TRUE; + } + + LL_DELETE(g_pLogItemList, pItem); + + utstring_free(pLogStr); + free(pItem->pLogContent); + free(pItem); + + if(g_LogRdPos % 100 == 0) + { + break; + } + } + + uv_rwlock_wrunlock(&g_uvLogLock); + + usleep(1000); + if(g_LogProcessInfo.pLogFile != NULL && isWriteLog) + { + fflush(g_LogProcessInfo.pLogFile); + } + } + + pthread_detach(pthread_self()); + return (NULL); +} + +/** + * @brief 设置调试等级 + * @param level 调试等级 + * @param iEnable 1 打开调试等级, 0 关闭调试等级 + */ +void IHW_EnableLogLevel(LOG_LEVEL level, int iEnable) +{ + if(iEnable > 0) + { + g_iMinLevel |= level; + } + else + { + g_iMinLevel &= ~(level); + } +} + +static int __getCfgFromCfgFile(void) +{ + int ret = 0; + g_bEnableLog = CfgGetBoolValue("Global.Log.Enable", g_bEnableLog); + g_iMinLevel = CfgGetIntValue("Global.Log.Level", g_iMinLevel); + g_bEnMailBackup = CfgGetBoolValue("Global.Log.LogToEMail.Enable", g_bEnMailBackup); + g_pEmailBox = CfgGetStringValue("Global.Log.LogToEMail.EMail", LOG_MAIL_RECEIVER); + g_bEnLogToFile = CfgGetBoolValue("Global.Log.LogToFile", g_bEnLogToFile); + g_bEnLogToServer = CfgGetBoolValue("Global.Log.LogToServer", g_bEnLogToServer); + +#if 0 + LOG_EX(LOG_Debug, "g_bEnableLog = %d\n", g_bEnableLog); + LOG_EX(LOG_Debug, "g_iMinLevel = 0x%X\n", g_iMinLevel); + LOG_EX(LOG_Debug, "g_bEnMailBackup = %d\n", g_bEnMailBackup); + LOG_EX(LOG_Debug, "g_pEmailBox = %s\n", g_pEmailBox); + LOG_EX(LOG_Debug, "g_bEnLogToFile = %d\n", g_bEnLogToFile); + LOG_EX(LOG_Debug, "g_bEnLogToServer = %d\n", g_bEnLogToServer); +#endif + + ret = CfgGetBoolValue("Global.Log.LogToUDPServer.Enable", FALSE); + + if(ret) + { + char *pIpAddr = NULL; + int udpPortBase = CfgGetBoolValue("Global.Log.LogToUDPServer.UdpBasePort", 10000); + int port = udpPortBase + DBusLibGetModName(); + + if(g_logSock != -1) + { + close(g_logSock); + g_logSock = -1; + } + + pIpAddr = CfgGetStringValue("Global.Log.LogToUDPServer.UdpServerIp", NULL); + + LOG_EX(LOG_Debug, "UDP Ipaddr = %s, port = %d\n", pIpAddr, port); + + if(pIpAddr) + { + memset(&g_logAddr, 0, sizeof(g_logAddr)); + g_logAddr.sin_family = AF_INET; + g_logAddr.sin_port = htons(port); + g_logAddr.sin_addr.s_addr = inet_addr(pIpAddr); + + g_logSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + } + } +} +/** + * @brief 初始化系统日志功能 + * @param pLogTag 系统日志标志 + * @param pPath 系统日志保存路径 + * @param bEnable 打开/关闭调试信息 + */ +void IHW_InitLOG(const char* pLogTag, const char* pPath, int bEnable) +{ + int ret; + char strPath[MAX_PATH]; + + memset(&g_logAddr, 0, sizeof(g_logAddr)); + uv_rwlock_init(&g_uvLogLock); + g_LogRdPos = 0; + memset(g_strLogTag, 0, 32); + + memset(&g_LogProcessInfo, 0, sizeof(LOG_PROCESS_INFO)); + + if(pLogTag == NULL) + { + strcpy(g_strLogTag, ""); + } + else + { + strncpy(g_strLogTag, pLogTag, 31); + } + + memset(strPath, 0, MAX_PATH); + + g_LogProcessInfo.pid = getpid(); + if(readlink("/proc/self/exe", strPath, MAX_PATH) == -1) + { + strcpy(g_LogProcessInfo.exeName, pLogTag); + } + else + { + char *pExeName = strrchr(strPath, '/'); + + if(pExeName == NULL) + { + strncpy(g_LogProcessInfo.exeName, strPath, MAX_PATH - 1); + } + else + { + strncpy(g_LogProcessInfo.exeName, pExeName + 1, MAX_PATH - 1); + } + } + + //fprintf(stdout, "pid = %d, name = %s\n", g_LogProcessInfo.pid, g_LogProcessInfo.exeName); + g_LogProcessInfo.pChipId = GetCpuChipId(); + g_LogProcessInfo.pChipSerial = GetCpuSerial(); + memset(g_LogProcessInfo.logFilePath, 0, MAX_PATH); + sprintf(g_LogProcessInfo.logFilePath, "%s/%s_%d.log", LOG_FILE_BASEDIR, g_LogProcessInfo.exeName, g_LogProcessInfo.pid); + + memset(strPath, 0, MAX_PATH); + sprintf(strPath, "rm -f %s/%s_*.log > /dev/zero", LOG_FILE_BASEDIR, g_LogProcessInfo.exeName); + ret = system(strPath); + + g_LogProcessInfo.pLogFile = fopen(g_LogProcessInfo.logFilePath, "w+"); + + g_bEnableLog = bEnable; + + __getCfgFromCfgFile(); + +#if 0 + LOG_CFG_PROTOCOL logCfg; + + memset(&logCfg, 0, sizeof(LOG_CFG_PROTOCOL)); + logCfg.cfgCmd = CMD_LOG_NETWORK; + logCfg.iParams1 = inet_addr("10.240.84.163"); + logCfg.iParams2 = htons(10000); + UpgradLogConfigure(&logCfg); +#endif + + __initPostLogParams(); +} + +void IHW_RunLogService(void) +{ + pthread_create(&g_logThreadId, NULL, __logOutputThread, NULL); + pthread_create(&g_backupThreadId, NULL, __uvLogBackupProc, NULL); +} + +static void __logTo(LOG_LEVEL level, int isAddTag, char* pMsg, int isPrint) +{ + PLOG_ITEM pLogItem; + + pLogItem = (PLOG_ITEM)malloc(sizeof(struct LOG_ITEM)); + + if(pLogItem == NULL) + { + return; + } + + pLogItem->pLogContent = strdup(pMsg); + pLogItem->isPrinted = isPrint ? FALSE : TRUE; + pLogItem->level = level; + pLogItem->isAddTags = isAddTag ? TRUE : FALSE; + gettimeofday(&(pLogItem->timestamp), NULL); + + uv_rwlock_wrlock(&g_uvLogLock); + LL_APPEND(g_pLogItemList, pLogItem); + uv_rwlock_wrunlock(&g_uvLogLock); +} + +void IHW_LogStrWithoutPrint(int level, char* pMsg) +{ + __logTo(level, TRUE, pMsg, FALSE); +} + +void IHW_LogRawString(int level, char* pMsg) +{ + __logTo(level, TRUE, pMsg, TRUE); +} + +/** + * @brief 输出调试信息 + * @param cFlag 调试信息开关 + * @param pMsg 调试信息内容 + */ +void IHW_LOG_UNTAG(LOG_LEVEL level, const char* pMsg, ...) +{ + va_list arg_ptr; + UT_string *pLogContent; + + if(!g_bEnableLog) + { + return; + } + + // 检查调试等级 + if(!(g_iMinLevel & level)) + { + return; + } + + utstring_new(pLogContent); + va_start(arg_ptr, pMsg); + utstring_printf_va(pLogContent, pMsg, arg_ptr); + va_end(arg_ptr); + + __logTo(level, FALSE, utstring_body(pLogContent), TRUE); + + utstring_free(pLogContent); +} + +/** + * @brief 输出调试信息 + * @param cFlag 调试信息开关 + * @param pMsg 调试信息内容 + */ +void IHW_LOG(LOG_LEVEL level, const char* pMsg, ...) +{ + UT_string* pLogContent = NULL; + va_list arg_ptr; + + if(!g_bEnableLog) + { + return; + } + + // 检查调试等级 + if(!(g_iMinLevel & level)) + { + return; + } + + utstring_new(pLogContent); + va_start(arg_ptr, pMsg); + utstring_printf_va(pLogContent, pMsg, arg_ptr); + va_end(arg_ptr); + + __logTo(level, TRUE, utstring_body(pLogContent), TRUE); + + utstring_free(pLogContent); +} + +void IHW_DisableLogOut(void) +{ + g_bEnableLog = FALSE; +} + +void IHW_EnableLogOut(void) +{ + g_bEnableLog = TRUE; +} + +#if 0 +void LogUploadCurLogFile(void) +{ + UT_string *pFn = NULL, *pCmd = NULL; + utstring_new(pFn); + utstring_new(pCmd); + + utstring_printf(pFn, "/tmp/%s_%s.bak.log", g_LogProcessInfo.exeName, g_LogProcessInfo.pChipId); + utstring_printf(pCmd, "cp %s %s", g_LogProcessInfo.logFilePath, utstring_body(pFn)); + + __logHttpPostFile(utstring_body(pFn)); + //InetHttpUploadFileSync(UPL_HTTP_URL, utstring_body(pFn), NULL); + + utstring_free(pFn); + utstring_free(pCmd); +} +#endif + +#if 0 +void UploadLogFile(char* pFilePath) +{ + int fileSize = 0; + + if(pFilePath == NULL || strlen(pFilePath) == 0) + { + return; + } + + GET_FILE_SIZE(pFilePath, fileSize); + + if(fileSize <= 0) + { + LOG_EX(LOG_Warn, "File Size Error: %d\n", fileSize); + return; + } + + __logHttpPostFile(pFilePath); +} +#endif + +void UpgradLogConfigure(PLOG_CFG_PROTOCOL pCfg) +{ + switch(pCfg->cfgCmd) + { + case CMD_LOG_ENABLE: + g_bEnableLog = pCfg->iParams1; + break; + + case CMD_LOG_FILE: + if(pCfg->iParams1 == FALSE) + { + g_bEnMailBackup = g_bEnLogToFile = FALSE; + } + else + { + g_bEnLogToFile = TRUE; + } + break; + + case CMD_LOG_MAIL: + g_bEnMailBackup = pCfg->iParams1; + break; + + case CMD_LOG_LEVEL: + if(pCfg->iParams2 == FALSE) + { + if(pCfg->iParams1 == 0) + { + g_iMinLevel = LOG_Fatal | LOG_Error | LOG_Devp; + } + else + { + g_iMinLevel &= ~(pCfg->iParams1); + } + } + else + { + g_iMinLevel |= pCfg->iParams1; + } + break; + + case CMD_LOG_NETWORK: + if(pCfg->iParams1 == 0) + { + memset(&g_logAddr, 0, sizeof(g_logAddr)); + close(g_logSock); + g_logSock = -1; + } + else + { + if(g_logSock != -1) + { + close(g_logSock); + } + + memset(&g_logAddr, 0, sizeof(g_logAddr)); + g_logAddr.sin_family = AF_INET; + g_logAddr.sin_port = htons((pCfg->iParams2 & 0xFFFF)); + g_logAddr.sin_addr.s_addr = (pCfg->iParams1); + + g_logSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + } + break; + + case CMD_LOG_SERVER: + g_bEnLogToServer = pCfg->iParams1; + break; + + default: break; + } +} + +const char* LogLeveToString(LOG_LEVEL lv) +{ + switch(lv) + { + case LOG_Fatal: return "LOG_Fatal"; + case LOG_Error: return "LOG_Error"; + case LOG_Warn: return "LOG_Warn"; + case LOG_Debug: return "LOG_Debug"; + case LOG_Info: return "LOG_Info"; + case LOG_Test: return "LOG_Test"; + case LOG_Call: return "LOG_Call"; + case LOG_Devp: return "LOG_Devp"; + case LOG_Step: return "LOG_Step"; + case LOG_Unknown: return "LOG_Unknown"; + case LOG_All: return "LOG_All"; + case LOG_Close: return "LOG_Close"; + } + + return "Unknown"; +} + +static void __uvSysPointIOProc(void *pParams) +{ + while(TRUE) + { + PSYSPOINT_ITEM pItem = NULL, pTmp = NULL; + int iFileSize; + time_t tmNow = time(NULL); + + if(g_SysPonitInfo.pMarkFile) + { + uv_rwlock_wrlock(&g_SysPonitInfo.uvRwLock); + LL_FOREACH_SAFE(g_pSysPointArray, pItem, pTmp) + { + fwrite(pItem->pContent, 1, strlen(pItem->pContent), g_SysPonitInfo.pMarkFile); + free(pItem->pContent); + LL_DELETE(g_pSysPointArray, pItem); + free(pItem); + } + uv_rwlock_wrunlock(&g_SysPonitInfo.uvRwLock); + } + + GET_FILE_SIZE(g_SysPonitInfo.savePath, iFileSize); + + if(g_SysPonitInfo.lastPostTime == 0 || tmNow < g_SysPonitInfo.lastPostTime) + { + g_SysPonitInfo.lastPostTime = g_SysPonitInfo.lastMarkTime = tmNow; + tmNow = 0; + } +#if 0 + LOG_EX(LOG_Debug, "iFile = %d, MaxSize = %d, upTime = %d\n", + iFileSize, g_SysPonitInfo.iMaxCacheSize, g_SysPonitInfo.iEveryUploadTime); + + LOG_EX(LOG_Debug, "tm = %d, last = %d\n", tmNow, g_SysPonitInfo.lastPostTime); +#endif + if(iFileSize > g_SysPonitInfo.iMaxCacheSize + || tmNow - g_SysPonitInfo.lastPostTime > g_SysPonitInfo.iEveryUploadTime) + { + int fileSize = 0; + + GET_FILE_SIZE(g_SysPonitInfo.savePath, fileSize); + + if(fileSize > 0) + { + SysPointMarkUpload(); + g_SysPonitInfo.lastPostTime = tmNow; + } + + if(tmNow - g_SysPonitInfo.lastPostTime > g_SysPonitInfo.iEveryUploadTime) + { + SysPointMarkUpload(); + g_SysPonitInfo.lastPostTime = tmNow; + } + } + + if(g_SysPonitInfo.pMarkFile) + { + fflush(g_SysPonitInfo.pMarkFile); + } + + sleep(1); + } + + pthread_detach(pthread_self()); +} + +int SysPointMarkInit(char* pDevId, int iMaxSize, int iPostTime) +{ + LOG_EX(LOG_Debug, "pDevId = %s, iMaxSize = %d, iPostTime = %d\n", pDevId, iMaxSize, iPostTime); + + if(g_SysPonitInfo.pDeviceId != NULL) + { + if(pDevId && strlen(pDevId) > 0) + { + free(g_SysPonitInfo.pDeviceId); + g_SysPonitInfo.pDeviceId = strdup(pDevId); + } + + if(iMaxSize > 0) + { + g_SysPonitInfo.iMaxCacheSize = iMaxSize; + } + else + { + g_SysPonitInfo.iMaxCacheSize = 1024 * 10; + } + + if(iPostTime > 0) + { + g_SysPonitInfo.iEveryUploadTime = iPostTime; + } + else + { + g_SysPonitInfo.iEveryUploadTime = SYS_POINT_UPLOAD_TIME; + } + } + else + { + memset(&g_SysPonitInfo, 0, sizeof(SYSPOINT_INFO)); + + if(pDevId && strlen(pDevId) > 0) + { + g_SysPonitInfo.pDeviceId = strdup(pDevId); + } + + if(iMaxSize > 0) + { + g_SysPonitInfo.iMaxCacheSize = iMaxSize; + } + else + { + g_SysPonitInfo.iMaxCacheSize = 1024 * 1024; + } + + if(iPostTime > 0) + { + g_SysPonitInfo.iEveryUploadTime = iPostTime; + } + else + { + g_SysPonitInfo.iEveryUploadTime = SYS_POINT_UPLOAD_TIME; + } + + sprintf(g_SysPonitInfo.savePath, "%s/sys_point_mark.log", LOG_FILE_BASEDIR); + + g_SysPonitInfo.pMarkFile = fopen(g_SysPonitInfo.savePath, "w+"); + + if(g_SysPonitInfo.pMarkFile == NULL) + { + LOG_EX(LOG_Error, "Create File: %s Error\n", g_SysPonitInfo.savePath); + return -ERR_OPEN_FILE; + } + + uv_rwlock_init(&g_SysPonitInfo.uvRwLock); + + uv_thread_create(&g_SysPonitInfo.uvIOThread, __uvSysPointIOProc, NULL); + } + + return 0; +} + +int SysPointMark(char* pMarkInfo) +{ + PSYSPOINT_ITEM pItem; + + if(pMarkInfo == NULL || strlen(pMarkInfo) == 0) + { + return -ERR_INPUT_PARAMS; + } + + if(g_SysPonitInfo.iMaxCacheSize <= 0) + { + return -ERR_UNSUPPORT; + } + + pItem = (PSYSPOINT_ITEM)malloc(sizeof(struct SYSPOINT_ITEM)); + + if(pItem == NULL) + { + return -ERR_MALLOC_MEMORY; + } + + pItem->pContent = strdup(pMarkInfo); + g_SysPonitInfo.lastMarkTime = time(NULL); + + uv_rwlock_wrlock(&g_SysPonitInfo.uvRwLock); + LL_APPEND(g_pSysPointArray, pItem); + uv_rwlock_wrunlock(&g_SysPonitInfo.uvRwLock); + + //LOG_EX(LOG_Debug, "SysMark: %s\n", pItem->pContent); + + return 0; +} + +int SysPointMarkUpload(void) +{ + int ret, size = 0; + char path[MAX_PATH]; + + memset(path, 0, MAX_PATH); + sprintf(path, "%s.txt", g_SysPonitInfo.savePath); + + if(access(path, F_OK) == 0) + { + unlink(path); + } + + GET_FILE_SIZE(g_SysPonitInfo.savePath, size); + + if(size <= 0) + { + LOG_EX(LOG_Debug, "Upload System Mark Data [%s] Is Empty, Skip......\n", g_SysPonitInfo.savePath); + return 0; + } + + rename(g_SysPonitInfo.savePath, path); + + fclose(g_SysPonitInfo.pMarkFile); + g_SysPonitInfo.pMarkFile = fopen(g_SysPonitInfo.savePath, "w+"); + + size = 0; + + do + { + ret = InetHttpUploadFileSync(GetCurServerAddr(MARK_POINT_MODULE), path, NULL); + sleep(1); + } while(ret != 0 && ++size < 3); + + LOG_EX(LOG_Debug, "Upload System Mark Data [%s] To Server [%s]\n", path, GetCurServerAddr(MARK_POINT_MODULE)); + + unlink(path); + + return 0; +} + diff --git a/app/ota_r311/Makefile b/app/ota_r311/Makefile new file mode 100644 index 0000000..a5e3c43 --- /dev/null +++ b/app/ota_r311/Makefile @@ -0,0 +1,52 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common +include $(TOPDIR)/rules.mk + +PKG_NAME:=ota +PKG_RELEASE:=1 +PKG_VERSION:=0.0.1 + +PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME) + +include $(BUILD_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Netease + TITLE:=OTA tools + MAINTAINER:=Huang xin + DEPENDS:=$(MAKE_COMMON_DEPEND) +endef + +define Package/$(PKG_NAME)/description + $(PKG_NAME) PV1 Device OTA Tools +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) -d ./src/ $(PKG_BUILD_DIR)/ +endef + +define Build/Configure +endef +define Build/InstallDev +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR)/src \ + ARCH="$(TARGET_ARCH)" \ + AR="$(TARGET_AR)" \ + CC="$(TARGET_CC)" \ + CXX="$(TARGET_CXX)" \ + CFLAGS="$(TARGET_CFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" \ + INSTALL_PREFIX="$(PKG_INSTALL_DIR)" \ + TARGET_NAME=$(PKG_NAME) \ + all +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/app/ota_r311/src/Makefile b/app/ota_r311/src/Makefile new file mode 100644 index 0000000..c0b48f7 --- /dev/null +++ b/app/ota_r311/src/Makefile @@ -0,0 +1,24 @@ +include $(TINA_BUILD_TOP)/package/netease/Makefile.common +TARGET := ota + +commonSources := ota_r311.c + +local_CFLAGS := +local_LDFLAGS := $(BUILD_COMMON_LIB) + +OBJS = $(patsubst %.c, %.c.o, $(commonSources)) + +$(TARGET):$(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(local_LDFLAGS) -o $@ $^ + +$(OBJS):%.c.o:%.c + $(CC) $(CFLAGS) $(LDFLAGS) $(local_CFLAGS) -c $^ -o $@ + +clean: + -rm $(OBJS) $(TARGET) + +install: + mkdir -p $(INSTALL_PREFIX)/usr/bin + cp $(TARGET) $(INSTALL_PREFIX)/usr/bin/ + +all: $(TARGET) install diff --git a/app/ota_r311/src/ota_r311.c b/app/ota_r311/src/ota_r311.c new file mode 100644 index 0000000..c19fceb --- /dev/null +++ b/app/ota_r311/src/ota_r311.c @@ -0,0 +1,1067 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R311) || defined (PLATFORM_CPU) +#include "log.h" +#include "libuv_dbus.h" +#include "crypto.h" +#include "json_struct.h" +#include "config_engine.h" +#include "inet_api.h" +#include "ota.h" +#else +#include +#include +#include +#include +#include +#include +#include +#endif + +#define MD5_CHKSUM_LEN (16) +#define MD5_STR_LEN (32 + 4) + +#define GET_STA_CNT(s) (s & 0xFF) +#define SET_STA_CNT(s, v) (s = (s & 0xFFFFFF00) | ((v) & 0xFF)) + +#define GET_STA_CMD(s) ((s >> 8) & 0xFF) +#define SET_STA_CMD(s, v) (s = (s & 0xFFFF00FF) | (((v) & 0xFF) << 8)) + +#define GET_STA_FLAG(s) ((s >> 16) & 0xFF) +#define SET_STA_FLAG(s, v) (s = (s & 0xFF00FFFF) | (((v) & 0xFF) << 16)) + +#define GET_STA_ERR(s) ((s >> 24) & 0xFF) +#define SET_STA_ERR(s, v) (s = (s & 0x00FFFFFF) | (((v) & 0xFF) << 24)) + +#define OTA_PARAMS_PARTITION ("/dev/by-name/ota_info") +#define OTA_PARAMS_TAG ("OTA163\0") +#define BOOT_IMG_FILE_NAME ("boot.img") +#define ROOTFS_IMG_FILE_NAME ("rootfs.img") +#define OTA_TEMP_DIR ("/mnt/UDISK/ota/unzip") +#define OTA_FILE_DOWNLOAD_DIR ("/mnt/UDISK/ota/dl") + +typedef struct +{ + char tags[8]; + unsigned int otaStatus; + char otaVer[MD5_STR_LEN]; + char bootChksum[MD5_STR_LEN]; + unsigned int bootfileSize; + char rootfsChksum[MD5_STR_LEN]; + unsigned int rootfsfileSize; + char paramsChksum[MD5_STR_LEN]; +} OTA_PARAMS, *POTA_PARAMS; + +typedef enum +{ + CMD_RUN_OTA = 1, + CMD_RUN_BOOT, + CMD_RUN_VERIFY, +} OTA_COMMAND; + +typedef enum +{ + FLAG_NORMAL = 0, + FLAG_EXEC_OTA = 1, +} OTA_FLAG; + + + +typedef struct +{ + unsigned int fileSize; + unsigned char md5sum[MD5_CHKSUM_LEN]; + int reserved[4]; +} IPL_DATA_ITEM, *PIPL_DATA_ITEM; + +typedef struct +{ + OTA_FILE_INFO fileInfo; + + char pPath[MAX_PATH]; + int dlStatus; + int retCode; + uv_barrier_t* puvBarrier; +} DOWNLOAD_TASK_INFO, *PDOWNLOAD_TASK_INFO; + +static char g_otaDownloadPath[MAX_PATH]; +static SETUP_MODE g_sSetupStatus = NORMAL_SETUP; + +static unsigned int g_IsOTAMode = 0; +static uv_barrier_t g_otaBarrier; +static uv_loop_t* g_pMainLoop = NULL; +static int g_isDownloading = FALSE; +static OTA_PARAMS g_otaParams; + +static void __ota_print_params(POTA_PARAMS pInfo, const char* pTips) +{ + LOG_EX2(LOG_Debug, "%s--------------------------\n", pTips ? pTips : ""); + LOG_EX2(LOG_Debug, "tags: %s\n", pInfo->tags); + LOG_EX2(LOG_Debug, "status: 0x%08X\n", pInfo->otaStatus); + LOG_EX2(LOG_Debug, "version: %s\n", pInfo->otaVer); + LOG_EX2(LOG_Debug, "boot_ver: %s\n", pInfo->bootChksum); + LOG_EX2(LOG_Debug, "boot_size: %u\n", pInfo->bootfileSize); + LOG_EX2(LOG_Debug, "rootfs_ver: %s\n", pInfo->rootfsChksum); + LOG_EX2(LOG_Debug, "rootfs_size: %u\n", pInfo->rootfsfileSize); + LOG_EX2(LOG_Debug, "params_chksum: %s\n", pInfo->paramsChksum); +} + +static void __printfOTANotifyCmd(const char* pTags, POTA_DATA_INFO pInfo) +{ + if(pTags && strlen(pTags) > 0) + { + LOG_EX2(LOG_Debug, "%s:\n", pTags); + LOG_EX2(LOG_Debug, "**************************************************************\n"); + } + + LOG_EX2(LOG_Debug, "Version : %d\n", pInfo->version); + LOG_EX2(LOG_Debug, "OTA Command : %d(0x%08X)\n", pInfo->otaCmd, pInfo->otaCmd); + LOG_EX2(LOG_Debug, "OTA Type : %d(0x%08X)\n", pInfo->otaMode, pInfo->otaMode); + + LOG_EX2(LOG_Debug, "---------------------------------------------------------\n"); + LOG_EX2(LOG_Debug, "\tURL : %s\n", pInfo->otaFileInfo.url); + LOG_EX2(LOG_Debug, "\tMD5 : %s\n", pInfo->otaFileInfo.md5); + LOG_EX2(LOG_Debug, "\tsize : %u\n", pInfo->otaFileInfo.size); +} + +static int __otaRspStatus(OTA_STATUS_TYPE type, int val) +{ + int ret = 0; + OTA_RSP_STATUS oStatus; + + if(OTA_ERR_CODE == type && val != 0) + { + g_IsOTAMode = FALSE; + } + + memset(&oStatus, 0, sizeof(OTA_RSP_STATUS)); + + oStatus.status = type; + oStatus.val = val; + + LOG_EX(LOG_Debug, "Rsponse: %d --> %d\n", type, val); + + if(type == OTA_UPGRADE_START || type == OTA_REBOOT_SYSTEM || type == OTA_RECOVERY_START) + { + ret = DBusJsonBoardcastCommand(NULL, 0xFFFFFFFF, CMD_OTA_STATUS, JSON_ENGINE_OTA_RSP, &oStatus, FALSE); + } + else + { + ret = DBusJsonSendToCommand(NULL, + g_pModInfoTable[MODULE_CONTROLLER].modAliase, + CMD_OTA_STATUS, + JSON_ENGINE_OTA_RSP, + &oStatus, FALSE); + } + + return (ret); +} + +void __onHttpResponseCb(void* pData, unsigned int size, const char* pReqUrl, const char* pDlPath, const char* pTaskUuid, int iFinished, void* pUserData) +{ + PDOWNLOAD_TASK_INFO pDlInfo = (PDOWNLOAD_TASK_INFO)pUserData; + + if(iFinished == 0) + { + LOG_EX(LOG_Debug, "Request(%s): [%s] --> [%s] Response: [%u] OK\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else if(iFinished == 1) + { + LOG_EX(LOG_Error, "Request(%s): [%s] --> [%s] Response: [%u] Error\n", pTaskUuid, pReqUrl, pDlPath, size); + } + else + { + LOG_EX(LOG_Error, "Download Error Code: %d\n", iFinished); + } + + if(pDlInfo) + { + uv_thread_t uvThread; + pDlInfo->retCode = iFinished; + LOG_EX(LOG_Debug, "Cleanup barrier\n"); + uv_barrier_wait(pDlInfo->puvBarrier); + } + else + { + LOG_EX(LOG_Debug, "pDlInfo == NULL\n"); + } +} + +void __onProgressNotifyCb(const char* pReqUrl, const char* pTaskUuid, unsigned char uPercent, void* pUserData) +{ + static unsigned char preCnt = 0; + + if(preCnt != uPercent && uPercent != 0) + { + preCnt = uPercent; + __otaRspStatus(OTA_DOWNLOAD_PROGRESS, uPercent); + LOG_EX(LOG_Debug, "[%s]: %u%%\n", pReqUrl, uPercent); + } +} + +static int __ota_read_params(POTA_PARAMS pInfo) +{ + uv_fs_t uvOpen, uvRead, uvClose; + int ret, rdSize = 0; + unsigned char md5Buf[MD5_CHKSUM_LEN]; + char md5str[MD5_STR_LEN]; + + uv_loop_t* pLoop = g_pMainLoop; + uv_buf_t uvBuf = uv_buf_init((char*)pInfo, sizeof(OTA_PARAMS)); + + if(pInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + memset(md5str, 0, MD5_STR_LEN); + memset(pInfo, 0, sizeof(OTA_PARAMS)); + + ret = system("sync"); + + if(uv_fs_open(pLoop, &uvOpen, OTA_PARAMS_PARTITION, O_RDWR, 0, NULL) == -1) + { + LOG_EX(LOG_Error, "Open Partition %s Error\n", OTA_PARAMS_PARTITION); + return (-ERR_OPEN_FILE); + } + + if((rdSize = uv_fs_read(pLoop, &uvRead, uvOpen.result, &uvBuf, 1, -1, NULL)) != sizeof(OTA_PARAMS)) + { + LOG_EX(LOG_Error, "Read Partition Error: Read %d Bytes, Need Read %d Bytes %d\n", rdSize, sizeof(OTA_PARAMS)); + return (-ERR_READ_FILE); + } + + uv_fs_close(pLoop, &uvClose, uvOpen.result, NULL); + + if(strncmp(pInfo->tags, OTA_PARAMS_TAG, 8) != 0) + { + LOG_EX(LOG_Error, "Check Magic Head Error: [%s], need [%s]\n", pInfo->tags, OTA_PARAMS_TAG); + return (-ERR_NO_INIT_IPL3); + } + + EvpMD5HashBuf((const unsigned char*)pInfo, sizeof(OTA_PARAMS) - MD5_STR_LEN, md5Buf, &rdSize); + + IHW_bin2hex(md5str, md5Buf, MD5_CHKSUM_LEN); + + if(strcmp(pInfo->paramsChksum, md5str) != 0) + { + LOG_EX(LOG_Error, "Verify MD5 Error: %s --> %s\n", md5str, pInfo->paramsChksum); + return (-ERR_BAD_IPL3); + } + + return (0); +} + +static int __ota_save_params(POTA_PARAMS pInfo) +{ + int ret, wrSize = 0; + uv_fs_t uvOpen, uvWrite, uvSync, uvClose; + unsigned char md5Buf[MD5_CHKSUM_LEN]; + char buf[MAX_PATH]; + char cmd[MAX_PATH]; + char md5str[MD5_STR_LEN]; + + uv_loop_t* pLoop = g_pMainLoop; + uv_buf_t uvBuf = uv_buf_init((char*)pInfo, sizeof(OTA_PARAMS)); + + if(pInfo == NULL) + { + return (-ERR_INPUT_PARAMS); + } + + memset(md5str, 0, MD5_STR_LEN); + + if(strncmp(pInfo->tags, OTA_PARAMS_TAG, 8) != 0) + { + memset(pInfo->tags , 0, 8); + strcpy(pInfo->tags, OTA_PARAMS_TAG); + } + + EvpMD5HashBuf((const unsigned char *)pInfo, sizeof(OTA_PARAMS) - MD5_STR_LEN, md5Buf, &wrSize); + + if(wrSize != MD5_CHKSUM_LEN) + { + LOG_EX(LOG_Error, "Error MD5: size = %d, need %d\n", wrSize, MD5_CHKSUM_LEN); + return (-ERR_BAD_IPL3); + } + + IHW_bin2hex(md5str, md5Buf, MD5_CHKSUM_LEN); + memset(pInfo->paramsChksum, 0, MD5_STR_LEN); + strcpy(pInfo->paramsChksum, md5str); + + memset(buf, 0, MAX_PATH); + ret = system("mkdir -p /tmp/ota_param/"); + sprintf(buf, "/tmp/ota_param/ota_%s.params", pInfo->otaVer); + + if(uv_fs_open(pLoop, &uvOpen, buf, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR, NULL) == -1) + { + LOG_EX(LOG_Error, "Open File %s Error\n", buf); + return (-ERR_OPEN_FILE); + } + + if((wrSize = uv_fs_write(pLoop, &uvWrite, uvOpen.result, &uvBuf, 1, -1, NULL)) != sizeof(OTA_PARAMS)) + { + LOG_EX(LOG_Error, "Write Error: Read %d Bytes, Need Read %d Bytes %d\n", wrSize, sizeof(OTA_PARAMS)); + return (-ERR_READ_FILE); + } + + uv_fs_fdatasync(pLoop, &uvSync, uvOpen.result, NULL); + uv_fs_close(pLoop, &uvClose, uvOpen.result, NULL); + + memset(cmd, 0, MAX_PATH); + sprintf(cmd, "dd if=%s of=/dev/by-name/ota_info bs=4k conv=sync > /dev/zero && sync", buf); + + ret = system(cmd); + + return (0); +} + +static int __otaRunning(char* pCheckSumFile, int ver) +{ + ssize_t rdRet; + size_t rdSize; + unsigned char strMD5[MD5_CHKSUM_STR_LEN]; + char dirPath[MAX_PATH]; + char basePath[MAX_PATH]; + const char *pChkMD5 = NULL; + char *pRdLine = NULL; + char *pChkSumFile = pCheckSumFile; + FILE *pFile = fopen(pChkSumFile, "r"); + int ret, i = 0; + int step = 0; + + if(pFile == NULL) + { + LOG_EX(LOG_Error, "Open File %s Error\n", pChkSumFile); + return (-ERR_OPEN_FILE); + } + + memset(dirPath, 0, MAX_PATH); + dirname_v2(pChkSumFile, dirPath); + + LOG_EX(LOG_Debug, "Step %d: Check OTA image .......\n", step++); + // check download ota file + while((rdRet = getline(&pRdLine, &rdSize, pFile)) != -1) + { + char* pToken = NULL; + char *pItem[2]; + char pMD5Val[MD5_CHKSUM_LEN]; + char pMD5Str[MD5_CHKSUM_STR_LEN]; + int fileSize = 0; + + if(rdSize == 0 || pRdLine == NULL) + { + continue; + } + + if(pRdLine[strlen(pRdLine) - 1] == '\n') + { + pRdLine[strlen(pRdLine) - 1] = 0; + } + + i = 0; + + for(pToken = strtok(pRdLine, " "); pToken != NULL && i <= 1; pToken = strtok(NULL, " "), i++) + { + pItem[i] = pToken; + } + + //fprintf(stdout, "md5 = %s, file = \'%s\'\n", pItem[0], pItem[1]); + + if(pItem[0] == NULL || pItem[1] == NULL || strlen(pItem[0]) != 32 || strlen(pItem[1]) == 0) + { + free(pRdLine); + fclose(pFile); + return (-ERR_MD5_CHECK_SUM); + } + + memset(basePath, 0, MAX_PATH); + sprintf(basePath, "%s/%s", dirPath, pItem[1]); + + LOG_EX(LOG_Debug, "OTA File: %s --> %s\n", basePath, pItem[0]); + + if((ret = EvpMD5HashFileV2(basePath, pMD5Val)) != 0) + { + free(pRdLine); + fclose(pFile); + LOG_EX(LOG_Error, "%s Check MD5 error: %d\n", ret); + return (-ERR_MD5_FILE); + } + + memset(pMD5Str, 0, MD5_CHKSUM_STR_LEN); + IHW_bin2hex(pMD5Str, pMD5Val, MD5_CHKSUM_LEN); + + //LOG_EX(LOG_Debug, "%s Check MD5 Info: [%s] need [%s]\n", basePath, pMD5Str, pItem[0]); + + if(strcmp(pMD5Str, pItem[0]) != 0) + { + free(pRdLine); + fclose(pFile); + LOG_EX(LOG_Error, "%s Check MD5 error: [%s] need [%s]\n", basePath, pMD5Str, pItem[0]); + return (-ERR_MD5_FILE); + } + + if(strcmp(pItem[1], BOOT_IMG_FILE_NAME) == 0) + { + GET_FILE_SIZE(basePath, fileSize); + memset(g_otaParams.bootChksum, 0, MD5_STR_LEN); + strncpy(g_otaParams.bootChksum, pMD5Str, MD5_STR_LEN); + g_otaParams.bootfileSize = fileSize; + } + else if(strcmp(pItem[1], ROOTFS_IMG_FILE_NAME) == 0) + { + GET_FILE_SIZE(basePath, fileSize); + memset(g_otaParams.rootfsChksum, 0, MD5_STR_LEN); + strncpy(g_otaParams.rootfsChksum, pMD5Str, MD5_STR_LEN); + g_otaParams.rootfsfileSize = fileSize; + } + } + + if(pRdLine) + { + free(pRdLine); + } + fclose(pFile); + + __otaRspStatus(OTA_VERIFY_FILE, NO_OTA_STATUS_VAL_TAG); + + LOG_EX(LOG_Debug, "Step %d: Save OTA Information .......\n", step++); + + memset(g_otaParams.otaVer, 0, MD5_STR_LEN); + sprintf(g_otaParams.otaVer, "%d.%d.%d.%d", + (ver >> 24) & 0xFF, + (ver >> 16) & 0xFF, + (ver >> 8) & 0xFF, + ver & 0xFF); + + SET_STA_CMD(g_otaParams.otaStatus, CMD_RUN_OTA); + + ret = __ota_save_params(&g_otaParams); + + if(ret != 0) + { + LOG_EX(LOG_Error, "Save OTA Params Error: %d\n", ret); + return (-ERR_OTA_WRITE_PARAMS); + } + + //print_hex_dump_bytes("IPL3", DUMP_PREFIX_ADDRESS, &g_iplInfo, sizeof(IPL_DATA_INFO)); + __ota_print_params(&g_otaParams, "OTA Finished"); + + LOG_EX(LOG_Debug, "Step %d: Waitting for reboot ......\n", step++); + + return (0); +} + +static void __otaFromLocalImage(void* pParams) +{ + int ret, reTry; + int step = 0; + char buf[MAX_PATH]; + char* pFileName = NULL, *pMD5Val = NULL; + const char* pMD5Chk = NULL; + int version = (int)(intptr_t)pParams; + + LOG_EX(LOG_Debug, "Step %d: Get OTA information .......\n", step++); + memset(buf, 0, MAX_PATH); + sprintf(buf, "%s/ota.md5", g_otaDownloadPath); + + if(access(buf, F_OK) != 0) + { + __otaRspStatus(OTA_ERR_CODE, -ERR_FILE_NOT_EXISTS); + g_IsOTAMode = FALSE; + return; + } + + memset(buf, 0, MAX_PATH); + sprintf(buf, "cat %s/ota.md5 | awk '{print $2}'", g_otaDownloadPath); + + if(GetShellExecResult(buf, &pFileName) != 0) + { + LOG_EX(LOG_Error, "Get File Name Error: %s\n", buf); + __otaRspStatus(OTA_ERR_CODE, -ERR_READ_FILE); + g_IsOTAMode = FALSE; + return; + } + + memset(buf, 0, MAX_PATH); + sprintf(buf, "cat %s/ota.md5 | awk '{print $1}'", g_otaDownloadPath); + + if(GetShellExecResult(buf, &pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Get MD5 Value Error: %s\n", buf); + free(pFileName); + __otaRspStatus(OTA_ERR_CODE, -ERR_READ_FILE); + g_IsOTAMode = FALSE; + return; + } + + LOG_EX(LOG_Debug, "Step %d: Verify OTA image .......\n", step++); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "%s/%s", g_otaDownloadPath, pFileName); + + pMD5Chk = EvpMD5HashFile(buf); + + if(strcmp(pMD5Chk, pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Check %s MD5 Error: %s --> %s\n", buf, pMD5Chk, pMD5Val); + __otaRspStatus(OTA_ERR_CODE, -ERR_MD5_CHECK_SUM); + g_IsOTAMode = FALSE; + return; + } + + free(pMD5Val); + free(pFileName); + free((void*)pMD5Chk); + + LOG_EX(LOG_Debug, "Step %d: Decompress OTA file .......\n", step++); + + pFileName = strdup(buf); + + __otaRspStatus(OTA_DECOMPRESS_FILE, NO_OTA_STATUS_VAL_TAG); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "mkdir -p %s/%d/ && tar -C %s/%d -xvzf %s > /dev/null", + OTA_TEMP_DIR, version, + OTA_TEMP_DIR, version, + pFileName); + free(pFileName); + + ret = system(buf); + + SetHBLAutoExit(FALSE); + __otaRspStatus(OTA_UPGRADE_START, NO_OTA_STATUS_VAL_TAG); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "%s/%d/ota.md5", OTA_TEMP_DIR, version); + + reTry = 3; + while(reTry--) + { + if((ret = __otaRunning(buf, version)) == 0) + { + break; + } + } + + if(ret == 0) + { + ret = system("rm -f /mnt/UDISK/ota/*.img /mnt/UDISK/ota/*.md5 > /dev/null"); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "cp %s/%d/* /mnt/UDISK/ota > /dev/null", OTA_TEMP_DIR, version); + ret = system(buf); + + memset(buf, 0, MAX_PATH); + sprintf(buf, "rm %s/* > /dev/null", g_otaDownloadPath); + ret = system(buf); + } + + if(ret == ERR_OPEN_FILE + || ret == ERR_MD5_FILE + || ret == ERR_MD5_CHECK_SUM + || ret == ERR_OTA_WRITE_BOOT + || ret == ERR_OTA_WRITE_ROOTFS + || ret == ERR_OTA_WRITE_PARAMS) + { + __otaRspStatus(OTA_ERR_CODE, -12345); + } + + __otaRspStatus(OTA_REBOOT_SYSTEM, NO_OTA_STATUS_VAL_TAG); + + reTry = 300; + + while(reTry--) + { + LOG_EX(LOG_Debug, "System force reboot before %d seconds\n", reTry); + sleep(1); + } + + while(TRUE) + { + ret = system("reboot -f"); + sleep(5); + } + + return; +} + +static int __isPreDownloader(POTA_DATA_INFO pInfo) +{ + UT_string* pDlPath = NULL, *pChkPath = NULL; + + char* pFileName = NULL, *pMD5Val = NULL; + const char* pMD5Chk = NULL; + + if(pInfo == NULL) + { + return (-ERR_FILE_NOT_EXISTS); + } + + utstring_new(pDlPath); + utstring_new(pChkPath); + utstring_printf(pDlPath, "%s/tina_r16_ota_%d.tar.gz", g_otaDownloadPath, pInfo->version); + utstring_printf(pChkPath, "%s/ota.md5", g_otaDownloadPath); + + if(access(utstring_body(pDlPath), F_OK) != 0 + || access(utstring_body(pChkPath), F_OK) != 0) + { + utstring_free(pDlPath); + utstring_free(pChkPath); + return (-ERR_FILE_NOT_EXISTS); + } + + utstring_renew(pChkPath); + utstring_printf(pChkPath, "cat %s/ota.md5 | awk '{print $2}'", g_otaDownloadPath); + + if(GetShellExecResult(utstring_body(pChkPath), &pFileName) != 0) + { + LOG_EX(LOG_Error, "Get File Name Error: %s\n", utstring_body(pChkPath)); + utstring_free(pDlPath); + utstring_free(pChkPath); + return -ERR_FILE_NOT_EXISTS; + } + + utstring_renew(pChkPath); + utstring_printf(pChkPath, "cat %s/ota.md5 | awk '{print $1}'", g_otaDownloadPath); + + if(GetShellExecResult(utstring_body(pChkPath), &pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Get MD5 Value Error: %s\n", utstring_body(pChkPath)); + free(pFileName); + utstring_free(pDlPath); + utstring_free(pChkPath); + return -ERR_MD5_CHECK_SUM; + } + + if(strcmp(pMD5Val, pInfo->otaFileInfo.md5) != 0) + { + LOG_EX(LOG_Debug, "Download File Chksum Diff: %s -> %s\n", pMD5Val, pInfo->otaFileInfo.md5); + free(pFileName); + free(pMD5Val); + utstring_free(pDlPath); + utstring_free(pChkPath); + return -ERR_FILE_NOT_EXISTS; + } + + utstring_renew(pChkPath); + utstring_printf(pChkPath, "%s/%s", g_otaDownloadPath, pFileName); + + pMD5Chk = EvpMD5HashFile(utstring_body(pChkPath)); + + if(pMD5Chk == NULL || strcmp(pMD5Chk, pMD5Val) != 0) + { + LOG_EX(LOG_Error, "Check %s MD5 Error: %s --> %s\n", utstring_body(pChkPath), pMD5Chk, pMD5Val); + free(pFileName); + free(pMD5Val); + utstring_free(pDlPath); + utstring_free(pChkPath); + + if(pMD5Chk) + { + free((void*)pMD5Chk); + } + + return -ERR_MD5_CHECK_SUM; + } + + free(pMD5Val); + free(pFileName); + free((void*)pMD5Chk); + utstring_free(pDlPath); + utstring_free(pChkPath); + + return (0); +} + +static void __otaDownloadImageCb(void* pParams) +{ + POTA_DATA_INFO pInfo = (POTA_DATA_INFO)pParams; + DOWNLOAD_TASK_INFO dlInfo; + char buf[SIZE_1K]; + int ret, reTry = 3; + + g_isDownloading = TRUE; + + // Notify CC Beging Download + __otaRspStatus(OTA_DOWNLOAD_FILE, 2); + + if(__isPreDownloader(pInfo) == 0) + { + g_isDownloading = FALSE; + g_IsOTAMode = FALSE; + __otaRspStatus(OTA_DOWNLOAD_PROGRESS, 100); + __otaRspStatus(OTA_DOWNLOAD_FILE, 0); + + if(pInfo->otaMode == OTA_MODE_FORCE_NOW) + { + g_IsOTAMode = TRUE; + __otaFromLocalImage((void*)(intptr_t)pInfo->version); + g_IsOTAMode = FALSE; + } + + free(pInfo); + pthread_detach(pthread_self()); + return; + } + + while(reTry--) + { + uv_barrier_t uvBarrier; + uv_barrier_init(&uvBarrier, 2); + + memset(buf, 0, SIZE_1K); + sprintf(buf, "rm -rf %s/*", g_otaDownloadPath); + ret = system(buf); + + memset(&dlInfo, 0, sizeof(DOWNLOAD_TASK_INFO)); + sprintf(dlInfo.pPath, "%s/tina_r16_ota_%d.tar.gz", g_otaDownloadPath, pInfo->version); + + memcpy(&dlInfo.fileInfo, &pInfo->otaFileInfo, sizeof(OTA_FILE_INFO)); + + dlInfo.dlStatus = 0; + + dlInfo.puvBarrier = &uvBarrier; + + InetHttpDlFileAsync(dlInfo.fileInfo.url, + dlInfo.pPath, + __onHttpResponseCb, + __onProgressNotifyCb, + &dlInfo); + + LOG_EX(LOG_Debug, ">>>>>>>>>>>>>>>>>>>Wait Download Finished.............\n"); + uv_barrier_wait(&uvBarrier); + uv_barrier_destroy(&uvBarrier); + LOG_EX(LOG_Debug, "<<<<<<<<<<<<<<<<<<otaFileInfo.md5) != 0) + { + LOG_EX(LOG_Error, "Download File MD5 Error: %s --> %s\n", pChkVal, pInfo->otaFileInfo.md5); + dlInfo.retCode = -ERR_MD5_CHECK_SUM; + } + else + { + break; + } + } + } + + if(dlInfo.retCode != 0) + { + ret = system(buf); + g_IsOTAMode = FALSE; + g_isDownloading = FALSE; + + if(dlInfo.retCode > 0) + { + dlInfo.retCode = -dlInfo.retCode; + } + + __otaRspStatus(OTA_DOWNLOAD_FILE, dlInfo.retCode); + pthread_detach(pthread_self()); + free(pInfo); + return; + } + + LOG_EX(LOG_Debug, "Step 1: Download File result: %d\n", dlInfo.retCode); + + memset(buf, 0, SIZE_1K); + sprintf(buf, "echo \"%s %s\" > %s/ota.md5", + dlInfo.fileInfo.md5, basename_v2(dlInfo.pPath), g_otaDownloadPath); + + ret = system(buf); + + LOG_EX(LOG_Debug, "Step 2: Save MD5 File; %d\n", ret); + + g_IsOTAMode = FALSE; + __otaRspStatus(OTA_DOWNLOAD_FILE, 0); + + if(pInfo->otaMode == OTA_MODE_FORCE_NOW) + { + g_IsOTAMode = TRUE; + __otaFromLocalImage((void*)(intptr_t)pInfo->version); + g_IsOTAMode = FALSE; + } + + free(pInfo); + + g_isDownloading = FALSE; + + pthread_detach(pthread_self()); +} + +static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg) +{ + int err; + uv_thread_t uvThread; + POTA_DATA_INFO pInfo = NULL; + + if(!pMsg || !pLoop || !pConn) + { + return NULL; + } + + //fprintf(stdout, "Recv: cmd = %u, Json = [%s]\n", pMsg->busCmd, (const char *)pMsg->pMsg); + + switch(pMsg->busCmd) + { + case CMD_OTA_RUNNOW: + if(g_IsOTAMode == 1) + { + LOG_EX(LOG_Info, "Trigger OTA Now.......\n"); + uv_barrier_wait(&g_otaBarrier); + } + else + { + __otaRspStatus(OTA_ERR_CODE, -ERR_OTA_NOT_READY); + LOG_EX(LOG_Error, "Current Not In OTA Mode\n"); + } + + break; + + case CMD_MISC_QUERY_DL_STATUS: + if(g_isDownloading) + { + __otaRspStatus(OTA_DOWNLOAD_FILE, 1); + } + else + { + __otaRspStatus(OTA_DOWNLOAD_FILE, 0); + } + + break; + + case CMD_MISC_QUERY_OTA_STATUS: + if(g_sSetupStatus == SYSTEM_OTA_OK) + { + __otaRspStatus(OTA_SUCCESED, 0); + } + else if(g_sSetupStatus == RECOVERY_SETUP) + { + __otaRspStatus(OTA_SUCCESED, -1); + } + else if(g_sSetupStatus == NORMAL_SETUP) + { + __otaRspStatus(OTA_SUCCESED, 1); + } + + __otaRspStatus(OTA_CURRENT_VERSION, 0); + __otaRspStatus(OTA_CURRENT_SETUP_MODE, g_sSetupStatus); + __otaRspStatus(OTA_CURRENT_REBOOT_TIME, GET_STA_CNT(g_otaParams.otaStatus)); + break; + + case CMD_SYSTEM_STANDBY: + LOG_EX(LOG_Debug, "System Ready ....\n"); + break; + + case CMD_OTA_NOTIFY: + + if(g_IsOTAMode == 0) + { + if(g_sSetupStatus == SYSTEM_OTA) + { + LOG_EX(LOG_Debug, "Current System Mode: SYSTEM_OTA\n"); + } + else if(g_sSetupStatus == RECOVERY_SETUP) + { + LOG_EX(LOG_Debug, "Current System Mode: RECOVERY_SETUP\n"); + } + else if(g_sSetupStatus == SYSTEM_OTA_OK) + { + LOG_EX(LOG_Debug, "Current System Mode: SYSTEM_OTA_OK\n"); + } + else + { + LOG_EX(LOG_Debug, "Current System Mode: NORMAL_SETUP\n"); + } + + if(g_isDownloading) + { + __otaRspStatus(OTA_DOWNLOAD_FILE, 1); + break; + } + + pInfo = (POTA_DATA_INFO)Json2Struct((const char*)pMsg->pMsg, JSON_ENGINE_OTA_REQ, TRUE, &err); + + if(pInfo == NULL) + { + __otaRspStatus(OTA_ERR_CODE, -ERR_INPUT_PARAMS); + } + else + { + unsigned long long uDiskFreeSize = GetPartitionFreeSize("/mnt/UDISK/"); + unsigned long long uUsedSize = 0; + + g_IsOTAMode = TRUE; +#if TEST_OTA_SERVER + memset(&pInfo->otaFileInfo, 0, sizeof(OTA_FILE_INFO)); + strcpy(pInfo->otaFileInfo.md5, "78bcf3236f54543301ee1a2f74282917"); + strcpy(pInfo->otaFileInfo.url, "http://10.240.84.163/tina_r16_ota_2.tar.gz"); + pInfo->otaFileInfo.size = 57106052; +#endif + __printfOTANotifyCmd("On OTA Notify Command++", pInfo); + + uUsedSize = pInfo->otaFileInfo.size + (1024 * 1024 * 10); + + if(uUsedSize > uDiskFreeSize) + { + LOG_EX(LOG_Error, "Error: File Size = %u bytes, Need %llu bytes, UDISK Free %llu bytes\n", + pInfo->otaFileInfo.size, uUsedSize, uDiskFreeSize); + + g_IsOTAMode = FALSE; + __otaRspStatus(OTA_DISK_FULL, pInfo->otaCmd); + break; + } + + switch(pInfo->otaCmd) + { + case OTA_CMD_DOWNLOAD: + if(strlen(pInfo->otaFileInfo.md5) == 0 + || strlen(pInfo->otaFileInfo.url) == 0) + { + g_IsOTAMode = FALSE; + LOG_EX(LOG_Error, "OTA Information Error\n"); + } + else + { + err = uv_thread_create(&uvThread, __otaDownloadImageCb, pInfo); + + if(err != 0) + { + LOG_EX(LOG_Error, "Create Thread Error: %d\n", err); + } + } + + break; + + case OTA_CMD_USED_LOCAL_IMAGE: + case OTA_CMD_EXEC: + err = uv_thread_create(&uvThread, __otaFromLocalImage, (void*)(intptr_t)pInfo->version); + + if(err != 0) + { + LOG_EX(LOG_Error, "Create Thread Error: %d\n", err); + } + + free(pInfo); + break; + + default: + __otaRspStatus(OTA_UNKNOWN_CMD, pInfo->otaCmd); + free(pInfo); + break; + } + } + } + else + { + __otaRspStatus(OTA_ERR_CODE, -ERR_OTA_PRE_STATR); + } + + break; + + default: + break; + } + + return NULL; +} + +int main(int argc, char** argv) +{ + int i, ret = 0; + char buf[256]; + DBusConnection* pBus; + int otaCmd, otaFlag, cnt; + + //struct tm *pTm = NULL; + g_pMainLoop = GetDBusDefaultLoop(); + + pBus = DBusWithLibuvInit(g_pMainLoop, + g_pModInfoTable[MODULE_OTA].modAliase, + __dBusOnMessage, + NULL, + NULL, + &ret); + + if(pBus == NULL) + { + fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret); + return (-1); + } + + g_IsOTAMode = 0; + strcpy(g_otaDownloadPath, OTA_FILE_DOWNLOAD_DIR); + + memset(buf, 0, 256); + sprintf(buf, "mkdir -p %s", OTA_FILE_DOWNLOAD_DIR); + ret = system(buf); + + if(__ota_read_params(&g_otaParams) == 0) + { + __ota_print_params(&g_otaParams, "System setup"); + } + + otaCmd = GET_STA_CMD(g_otaParams.otaStatus); + otaFlag = GET_STA_FLAG(g_otaParams.otaStatus); + ret = GET_STA_ERR(g_otaParams.otaStatus); + cnt = GET_STA_CNT(g_otaParams.otaStatus); + + if(ret != 0) + { + LOG_EX(LOG_Error, "System setup error: code = %d, flag = %d, otaCmd = %d\n", + ret, otaFlag, otaCmd); + } + + if(cnt >= 3) + { + LOG_EX(LOG_Error, "Reboot more than %d times\n", cnt); + } + + if(otaFlag == FLAG_EXEC_OTA) + { + g_sSetupStatus = SYSTEM_OTA_OK; + } + else if(otaFlag == FLAG_NORMAL) + { + g_sSetupStatus = NORMAL_SETUP; + } + + SET_STA_CNT(g_otaParams.otaStatus, 0); + SET_STA_CMD(g_otaParams.otaStatus, CMD_RUN_BOOT); + SET_STA_FLAG(g_otaParams.otaStatus, FLAG_NORMAL); + + __ota_save_params(&g_otaParams); + + // Make sure continue last download task + __otaRspStatus(OTA_DOWNLOAD_FILE, -28); + __otaRspStatus(OTA_CURRENT_VERSION, 0); + + RunUVLoop(g_pMainLoop); + + return (0); +} + diff --git a/res/system_resources/Makefile b/res/system_resources/Makefile new file mode 100644 index 0000000..eec6c19 --- /dev/null +++ b/res/system_resources/Makefile @@ -0,0 +1,34 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=pv1res +PKG_RELEASE:=1 +PKG_VERSION:=0.0.1 + +PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME) + +include $(BUILD_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Netease + TITLE:=System Resource Files +endef + +define Package/$(PKG_NAME)/description + $(PKG_NAME) System used sound, picture resources. +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/share/resource/voice + $(INSTALL_DIR) $(1)/usr/share/resource/image + $(INSTALL_BIN) resource/voice/* $(1)/usr/share/resource/voice/ + $(INSTALL_BIN) resource/image/* $(1)/usr/share/resource/image/ +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/res/system_resources/resource/image/IconChaozuo001.jpg b/res/system_resources/resource/image/IconChaozuo001.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ebb781e24bf6999c83dfae28cd9bb6b74f6efd41 GIT binary patch literal 1280 zcma)6-D}fO6u(*3Z6dPh)Xk@msi>IGCd~({V@+2qqdMk5ee)){TSJ!*lhk&576e~p zZ$9}q_~agZaDuNs`YniW3Zmd2V7zIYwn!N}kZ|rf=XbvDIXC%`d;>E}ZD$>TYV|Uh z00T;X0hp^ZNAo-SiT#w^G=QuB7q3xT9wS1Rr!+;Z5o&)m>?EqR06jLVJ zaJ(Y@`^8I|a_k~~ORn*?z(959+IEO;ZeL%swi}ja(+gLr`L^D60~f`RYP*|Wq_>N7 z$GMLARLs#-$0TkP>BTfEb-T7g8GeW;nJq9DUr;DTV+C1JB;^Vv@`B9qc`na0VqTYc zT@tAt(KuRYuj{MjN-q{Z73p44tyYU|(6I9}vLk--*BwB^OH&3MsV=An!t zD|CX`@jWW_2u;5k7ipYnw*)t+)%uP{cFT3sx;oZTyov^CjI@r{wgSYhqR4NC7Q*Ip z85s9&|3IlB&PKlxI`~rHX4$uzF7o1PxkzITYdf}X79c``$TKR$KS@*tM$1b!15F4E zrmZNVBxZg_;rWtKQc8l6&&#qPEUBeRMO_lhLcvfM4OLSzY}Jcm=vgR>?cmrwY-wMt zZiEQNez@lQo7ohs)cx3x>V7~OM(5V4i#2FDUMjqlUR1a4G76ph$gYIGOLaP}J0r3< zSO>azd#HomNyQReNsuL^<2H!0D5;EMYAPcLipiLgw9eSF43TLS@&e>(4yVYa!!tBY znFvp4%Jx?SANtFMJiJjMUY+C@INn(ZVDI4-C6dqJ0U!=eV*|?dsRth;2&~0lUvW?- z*#qPRm;{qKf&^nEkt2!ZHMo-|Hh5lAZu02=5&)(EksBKyGCTuLojy4}eeV2`3p2B4 z$stYGS@H=S%MmzEjsy$f&G)D8V*ReP`{(P_@`)$jm!0XqJFo2B=kG|ZJkN*HFu~3Bo literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/IconChaozuo005.jpg b/res/system_resources/resource/image/IconChaozuo005.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7e882ad021a463d859132cc7fd63c5fee07c9b89 GIT binary patch literal 10999 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

MVA&f1Z@AuQU0Ako`=Yo-vlsobxNh;W zCHYG>E$y-Nm8Eyzq~1L8R_>jC9~Eq_=3eak`B!L5ff4sHJ?>zf^i z`ybwUBnOq6>y#_sN6%HahMUt3ULx;@lh%?Pl!& zF$`i)y|0uiaPKazQb4Zj(`hadh*{#8DT0y7|`Idvl^sUu?ncb42pE%~36T e-ltwY^F{4Miy-{K#O?R*Uw!J5dDAcL-~9{pr+ef8 literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/IconLianjie002.jpg b/res/system_resources/resource/image/IconLianjie002.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c64910cc96c2139b1130f08ba2fa1876b52c34b2 GIT binary patch literal 9258 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 literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/IconLianjie003.jpg b/res/system_resources/resource/image/IconLianjie003.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4dc834b4c1debacf9328820123e3b61a5661973 GIT binary patch literal 9224 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 literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/IconNaozhong001.jpg b/res/system_resources/resource/image/IconNaozhong001.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fe96da0f0f43f0f969cc59255204db91d078017d GIT binary patch literal 10988 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 literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/IconZhuangtai003.gif b/res/system_resources/resource/image/IconZhuangtai003.gif new file mode 100644 index 0000000000000000000000000000000000000000..5d85a05c324258b766194683e1144fb0029fe151 GIT binary patch literal 4818 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 YQDj6|i;(Av*cN?G@6__7Y)%Gi0C2FZ-~a#s literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconstart002.gif b/res/system_resources/resource/image/Iconstart002.gif new file mode 100644 index 0000000000000000000000000000000000000000..ca8bd3d12306cc10d6e83a7c81fd7bf3b6ddb2b2 GIT binary patch literal 2552 zcmbtUdt6g>6u)BwHpXjCaw9v2! zweTPwbR2;wiW(jsE-ES#3WXUN89W|ue0;pTyc|W*zP`T3#>S40j+B&?iHV8+{{H0T zWXto6Q~>87V9* z=H}*sfr0MsZmCr2a=9P~0)*iA|6k$>{xZFJrA}L-S4!n<7GMNRYfL3DZgE?{fBq5= zWwEX&+;AmPWp`>MC-?1_z;>HPvO32kH&HsG+HP#1iIok@%+`kWR@5e0aw(keQF|Pe zgK%45kE7PO>nx#;w!JRFKr!NVJM%&h@OL4<=Ebyg~RJ+}jS|+Qnub0-Vq$FJh zd{I;;SIU&iEP%*zZFIUVo-C&;HNb!qE-P)P+;-9lGmMr>vd*oM0HsqYIH(y~r%O7S zj?_vzWF8A8Q%L1ZN&%qB^xsg2V+QSVml9|61|@cxH&TSGlyH%Cw3PtxR3;Rq*3pE; zP10tPtPNDLq?&Y-u4$FrDHC zkC_1=oS^Gz(B7e)0ME*k>m`{p911 zKK$VQ_uhTy?YEBmj~#vUjnN~oj|>kTKJ?nF2VXhx@=JsJUwq;Dea}7n%+pUj`NTkf z-`>X`d-Rcq_dL|Q`@vlg+~0Gb@7|r=U7a2G+Z)~w&01->`l^cZvMaAxyJq#}tIR7) zSClMYW-7j{sL;67pvQFuT5QRsn*7CTbWvVzPPR&^kjtc5nHlK|kxLd_oR%sP!xyC_ zCtWx{@q+W`i4x8e3gY8pW1{&{JZ@w}IENhu4hivTPBV zj7UzWHW$#?`m#96TJ9(IEiC;S;b4R#N=}ZGTE9 zCqM$XggFGDI&Xa(7e(sndXj4-W0eBGkLr8$~cW#LF6(%PI9m8Dsym8=(Sl_*luCgdH93_(~L6VzSRVa-d&%lb`)&9*I6Vk zg&g~wPGgo7L%*wt6D^EFFR%$?5E*KRh?j*rP<2f!R7pUH9fXd9EY#qvi+6h#!q`Vv zuVX+s=ycqHyNi1R%kJ5}>6%UKFv$y&P}by*MD9f_yf)VBXN(j)JK+4dnS#ABFL*xY zsod|+Z(V*gA~Z^BT)&2$8xz?A~q@$t5f|3_vQ-$!ZWd=QuPyj0MgB6V3Qh`vjv0=FjApAJLE@w4FG!Ky>P=!imJ=@pDO8t=S5VtcsVqs-u zV_-sJphI_79#bb41VUm&GUp^tTNG9NlC9tWec%7O|9Ac=KLIy7nYRl-uXhJj!Kvim zL9IP@MhAccmzdcFAU~-*AEs$!$#RfL#0_mKIiW9SB$A<|$Y7(HMZ_7=l(*@g7c_*Q z?>`8<=Qe~Lqp$R%79DyI4rBWG@Zq*|IC8KnH1F{nnU(pGPgBBY{(g{HSwomQx0qg- zWr3eU(osXWUqt1f^tbp{7*pPmOwmzH#3L+010fyVYAdHbU;tjSc*=z4s&Uepra5kyT!YYZ%ge=W4R72J4BC>H^gb>-Ht?SI2VGwFN zrUr>3$Sg&<7@jl3RGQd?7V2U(*vDeIXuviqW~-C`0N1Ar0o)_DqFnwJJOkYS%gU)# z7BZ)=a2z{j&*I>JmHY_Qs$dnYR=65isd1GWmmh;ck=W_)g=tlA^&bl}u5p07d=9pH srJB9Nwewtt$iIMV6^;d{)Ibw_{IhoR_qUfjFJAq6{pRg40L}dKUoQSd;s5{u literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang002.jpg b/res/system_resources/resource/image/Iconyinliang002.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6816ea678e4e596ed53dcc22e4a3536d8cd5bf99 GIT binary patch literal 1247 zcma)6J8aWH7(O>3Qh`vjv0=FjApAJLE@w4FG!Ky>P=!imJ=@pDO8t=S5VtcsVqs-u zV_-sJphI_79#bb41VUm&GUp^tTNG9NlC9tWec%7O|9Ac=KLIy7nYRl-uXhJj!Kvim zL9IP@MhAccmzdcFAU~-*AEs$!$#RfL#0_mKIiW9SB$A<|$Y7(HMZ_7=l(*@g7c_*Q z?>`8<=Qe~Lqp$R%79DyI4rBWG@Zq*|IC8KnH1F{nnU(pGPgBBY{(g{HSwomQx0qg- zWr3eU(osXWUqt1f^tbp{7*pPmOwmzH#3L+010fyVYAdHbU;tjSc*=z4s&Uepra5kyT!YYZ%ge=W4R72J4BC>H^gb>-Ht?SI2VGwFN zrUr>3$Sg&<7@jl3RGQd?7V2U(*vDeIXuviqW~-C`0N1Ar0o)_DqFnwJJOkYS%gU)# z7BZ)=a2z{j&*I>JmHY_Qs$dnYR=65isd1GWmmh;ck=W_)g=tlA^&bl}u5p07d=9pH srJB9Nwewtt$iIMV6^;d{)Ibw_{IhoR_qUfjFJAq6{pRg40L}dKUoQSd;s5{u literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang003.jpg b/res/system_resources/resource/image/Iconyinliang003.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6816ea678e4e596ed53dcc22e4a3536d8cd5bf99 GIT binary patch literal 1247 zcma)6J8aWH7(O>3Qh`vjv0=FjApAJLE@w4FG!Ky>P=!imJ=@pDO8t=S5VtcsVqs-u zV_-sJphI_79#bb41VUm&GUp^tTNG9NlC9tWec%7O|9Ac=KLIy7nYRl-uXhJj!Kvim zL9IP@MhAccmzdcFAU~-*AEs$!$#RfL#0_mKIiW9SB$A<|$Y7(HMZ_7=l(*@g7c_*Q z?>`8<=Qe~Lqp$R%79DyI4rBWG@Zq*|IC8KnH1F{nnU(pGPgBBY{(g{HSwomQx0qg- zWr3eU(osXWUqt1f^tbp{7*pPmOwmzH#3L+010fyVYAdHbU;tjSc*=z4s&Uepra5kyT!YYZ%ge=W4R72J4BC>H^gb>-Ht?SI2VGwFN zrUr>3$Sg&<7@jl3RGQd?7V2U(*vDeIXuviqW~-C`0N1Ar0o)_DqFnwJJOkYS%gU)# z7BZ)=a2z{j&*I>JmHY_Qs$dnYR=65isd1GWmmh;ck=W_)g=tlA^&bl}u5p07d=9pH srJB9Nwewtt$iIMV6^;d{)Ibw_{IhoR_qUfjFJAq6{pRg40L}dKUoQSd;s5{u literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang004.jpg b/res/system_resources/resource/image/Iconyinliang004.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a5a51994ba84ceb6e85738425206036b6dd2c213 GIT binary patch literal 1311 zcma)6O=#3m5PsRUb?g5sg5o8l2ep_@UjE)DbS-wbixpO-7VDvxm*mxkHa{d;oAxGn z5IlJDq*oCBL{ZV|rHJ4`^y)#4FWdd8Qi=l!lX>6FH#2W0>AQ3l92iTS z834w|hd=@JB>f7CwWc+<2pF)1nr#5m)%^9@I1UU!@S+m7eUp?d-xU%Z2(TmyV0a`6 zur)_w)+84luflzQ^n_y_yTVPW4Y3ha$*gm7DJ18XPET4(bCzy%Bgfg{#7Nx0B{60b zcixMPq{6j=8&uEC0>`!>@mz&Fk+HHD8fV$69}-qAX}l$Bh(&q{st76Q7%PcT6+~H( zMP8B(MKlzNZ3{=)LVL!TsMXtC^sBt=Pe&`~@=dTDHkjwTlaB219T zZ-y43@WGBV?cL@?8IWdUoCzIzDR{o-TTPdE@p!Gm(UX$x*oLWLLZBq_WlUd+REE4R zD>jc!j5X6nNK&LuoQ?b?gmfe#MHxkP2*=80eN3;bqhpFTs?}s&?)Z*-QH(u{bhsVL z-S(9?^);#?!Lc7s`u==p3eL{@u^-L)0b8xMZk;{Sz?S1>#-rIqt<_y4p>v7Y_0V_O zR;LYTgDjv0A;dc2Efwj!f>g+3Nt@wqiy%#fvZfQAYx~>lI=D8e)Iuu>ItdxFs!FP) zlzC+8WgbFg@}{EDXsU{dX=yUVA}7!kg=~1%4O7QNCp1&Lt3f}y%SAl8Q6XKO^c&dK zS_oh-(-mdX58w)5{$FxE$#Fo~7|1h4kSj9zB9lG^Q(0oY z-wV|W{oDSrP~#quvG((>8O1jS284{9-+y!>uL*JAevE38T_)3(lBQi00nx8*#aP0&)%MiB46h?H!L8_GjPH594e4LohTCFaM|=L~IIC1ygd^L4+BXY6x}0lvI=VccAtH8qPFK0^=1dhGZPju0I? zb8e`|C8il%Cwgk;7`h3GW=qW3l$E|(zeJb40Ml|oVNG69X;mvgSyd(VG%fH@=6I14 zc~%g0iPt58ZV5x!0&7YitJGRttCboS?-7rF~iQC*Z z;cofz+xqI|0HeqY#yxMYJq4F$yvPe@JfAL?o3~D%tRvHQQ{$=hqBiQT;K06ytydNxLo2cnss?LF5{V|u2pgs%Lc}v1Ns&v3XVWmXO=Ln-wX+)JqqAJtB^wox)k(gC z{mq2{)-qX9D)|U*0BYxw=}NXEE%yvXkyG+?4tA;}%OIZv{h&Wf2`Old*OM7mvz7rq3mh}l`@&r5ia7B50WNzP`+{C>ry+dn<;??^v`(>8O1jS284{9-+y!>uL*JAevE38T_)3(lBQi00nx8*#aP0&)%MiB46h?H!L8_GjPH594e4LohTCFaM|=L~IIC1ygd^L4+BXY6x}0lvI=VccAtH8qPFK0^=1dhGZPju0I? zb8e`|C8il%Cwgk;7`h3GW=qW3l$E|(zeJb40Ml|oVNG69X;mvgSyd(VG%fH@=6I14 zc~%g0iPt58ZV5x!0&7YitJGRttCboS?-7rF~iQC*Z z;cofz+xqI|0HeqY#yxMYJq4F$yvPe@JfAL?o3~D%tRvHQQ{$=hqBiQT;K06ytydNxLo2cnss?LF5{V|u2pgs%Lc}v1Ns&v3XVWmXO=Ln-wX+)JqqAJtB^wox)k(gC z{mq2{)-qX9D)|U*0BYxw=}NXEE%yvXkyG+?4tA;}%OIZv{h&Wf2`Old*OM7mvz7rq3mh}l`@&r5ia7B50WNzP`+{C>ry+dn<;??^v`0v>V#4^E6E0kWoW zOq=+Mo0xk30$%rkV$B%UfUr?RN@#o9T#?1z|EIF+>oRiibXgNmlf+Au8&P~ioMmjqUn z3|TN_k!}-1qJ?(Dn5c}kW06ydX%{s+JIl>VoF87{p|0z^Ao8Nf5(_q(^J0{+UUa16 zp@JhTbb{FNJv#GpEVyTdtec)v}J_3EWF#UF)bm7hrw@NB&G` zVPbxy117!OI8bItvN6tv4!IOGUGc3M7klw|rNj^oXFIlGst98!3TzRPpDY$3t4p%Y zA`>Civ^7nX#g3o#@N!Wqm&;W}9@WMmtQL!URUcDEtFk((RwP~OV8^{EMxKQ`u^ke- zjg>dV8s!k9*bnQzKi!#vb4@??qoyCw<#OxR>7zAdIbJ3_mR;0p-4z@nb+Oq>G?100zNeo+^M`fyx)C^aZ$_CDwah z2shBb?LP?-?gCUFmFw?W_UHSyY~2g?~Hho zZ*KVUflnV7@`wL`CcAJc3|36Ov2EFWYutR!(|2#A;QZvX*LM!ye=yWo+V^s$UJsXU cES~+j^T(^tcjgXV`@8h(&6lC;)V=iGKle^$$p8QV literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang008.jpg b/res/system_resources/resource/image/Iconyinliang008.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec7406d50fda524e0f95dcf3857a457dd5b6c096 GIT binary patch literal 1316 zcma)6OK8+k6n&YgwiQuFw2FenxKU|7FW*UUEOus!U5uYPP{q|t^2P~mJ|wA4yYYj2 zm#zd??%Z0%g%w@6b5ZcSv51SJD1st_5MQSADN;%=B;0rJJ@@zSed*hD8SJknP6L4P z@#A0s^eFub3Y8gaY7S7KkBDsm(&hZ^W*i3w&wCMvY~RG3<-2@>0v>V#4^E6E0kWoW zOq=+Mo0xk30$%rkV$B%UfUr?RN@#o9T#?1z|EIF+>oRiibXgNmlf+Au8&P~ioMmjqUn z3|TN_k!}-1qJ?(Dn5c}kW06ydX%{s+JIl>VoF87{p|0z^Ao8Nf5(_q(^J0{+UUa16 zp@JhTbb{FNJv#GpEVyTdtec)v}J_3EWF#UF)bm7hrw@NB&G` zVPbxy117!OI8bItvN6tv4!IOGUGc3M7klw|rNj^oXFIlGst98!3TzRPpDY$3t4p%Y zA`>Civ^7nX#g3o#@N!Wqm&;XM9@WMmtQL!URUcDEtFk((RwP~OV8^{EMxKQ`u^ke- zjV*47HOe7Iu^-lbf4VaT=bC=(M@>JV%jMRs(?@H_a=c76xrjCeAXvTI|gB-fcg*~!SAz7XD8`#lW z2w*Rg6{XS-;1-}ZPq`lDyVQo~D2iyw*HvtmNf$w301Se`JXHX>0+laN=?icm?(EtDd literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang009.jpg b/res/system_resources/resource/image/Iconyinliang009.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e35602a1a036c26c5288780819da8e7273fe335f GIT binary patch literal 1316 zcma)6O=#3m5Ps>l+Da+r=D|aVD77@3y!>uL*W&JW?Fy@IVowT+-aP0bzHIkLrHBIwlX>6FH#2W0>6>%|?3zlP zc>rp)F)#>vl70bnWyxx+01EUIvkgGHk-NGO$AQ7~UX(|+Z{ob=yL^HI9_9reOiU&L zvKlyMOnlbyitM*1&sfH>i|h%dF4TiEUT~&YLws!Y$egv>uymW9JitsOM&br8juDf% zi(X_TMYa{(AbMuzS*8Vv8%6eD#>$+m&oE^_#Eg)dd==StQOnEA`DH2Zhi7@H>pCxpyeM)6!9^=xj1ta^ z_H-gtaAbu}5IerdWD$|+FU3WcWV%^`8`SIFz*~09b+fu!=qR4Wy)?E&M{_Fy=4Wx_ zFNGE+@I4)8(z|~XWk8aRaWr(urJ%)%Z!Njli))o4OHT5(V;iQ5FovSQ6%cvJVgYix zB-Z-XtCM~O zBdvu1c9X0qmA(g;0QLXU*OOdV+U|W6MNY}nJ@{WGZ321_41u8>MT0(?%F$H%9Gu7! z>-}DcHn@GqUlwBA38;R;*#q|H2DWVngMCBEBc1*;00E`%z;KQtEIArXg0-LA{;~77 z??1gvuN}C#@7|-)AG4*`wIdUItA`(aIl+Da+r=D|aVD77@3y!>uL*W&JW?Fy@IVowT+-aP0bzHIkLrHBIwlX>6FH#2W0>6>%|?3zlP zc>rp)F)#>vl70bnWyxx+01EUIvkgGHk-NGO$AQ7~UX(|+Z{ob=yL^HI9_9reOiU&L zvKlyMOnlbyitM*1&sfH>i|h%dF4TiEUT~&YLws!Y$egv>uymW9JitsOM&br8juDf% zi(X_TMYa{(AbMuzS*8Vv8%6eD#>$+m&oE^_#Eg)dd==StQOnEA`DH2Zhi7@H>pCxpyeM)6!9^=xj1ta^ z_H-gtaAbu}5IerdWD$|+FU3WcWV%^`8`SIFz*~09b+fu!=qR4Wy)?E&M{_Fy=4Wx_ zFNGE+@I4)8(z|~XWk8aRaWr(urJ%)%Z!Njli))o4OHT5(V;iQ5FovSQ6%cvJVgYix zB-AUf=FO_k|LiC&u_!jF_8())b47KkM43|k8D&(Rww-m zMp_F2>?T=JDt!+w0qXyyuP3>#wB7qCikyZE*XJzbwSK6Hxtxvj^_py00K(if#DoQSaLL&1ZzLJ{bT2E z-+y|UUORAe-@QkpKW0m>Yey#bRu4b;bY^Y+&iZik?yH9f>F=+vG|tyw9$(*my*55F g${ZS)o|(D&Ve<2>8>g>*Ou?xOkH5dT2%72JU%%00egFUf literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang011.jpg b/res/system_resources/resource/image/Iconyinliang011.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8780f8cebb4d7e127a2b1a2a3e099632b7c1e861 GIT binary patch literal 1304 zcma)6No&L>##GX8x`}CoAD*|S$spWi)TwMSP+z(;RCh(>G_6Bs2xVkBi6&EL^k$Pe@THz@jLC;gK{%_8d-F z3tw^lGWYYvD~@%YGIv33h>fs{XWg^Q5k9|sZpvPsvkiwEIn55IX6l6=P7s@V^L}im zWv=PmBzkTZIJOB%=E~feJSscgm|&|xgjuzy@wTYxtZo#cs_Tk=ij_pD3Zg8?A}`6N zBASZCwuB?mB4@^&tc|u}k*_k>Dr#|YvA8G~gXoF?4Z{#bNsuI-AozI6Pf*JH@le}C z4aaumhKU>aZ0-?R!9r5zNTypQcwwW_alB)t0C(y|w{bhROJcXU z#y`1cHNq$fqNyO5Z%@I*Y>));Y!I^5YV+3F;|*lHer`OGU({CJH5|EDu`?P49^34+ z>F$sPv>}AZz`U*M2CwKU%V1sM%ooyZ5np9#Tm4xktOj%VWRZ>d4 zZW$#WLfzsmMIqi)6=BQPWQasgASnv@@N65Vwuww=u69;~d~}uz`(&dcvO3uhu&=og zz*!|LN@btGbwK^U^mK*pNQ>S>QRI|7orC{XvQ@woKtJfGDF*Z~6wOfC8*njCtowT* zT4DE|zbwQ!06-s2_jQ4T2M_HofCIg|j`Y)q)29aWrxOCqK7ze8MIzA*7y++0?pbdc z^ySvKmHUrYn8!Ej`!7%U$DZFcHzyzJU+)ZUyc{U(y-lw@fY&ar75eDSXTPvCoPp2d O?=DS00fR@g55EB#5L=}H literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang012.jpg b/res/system_resources/resource/image/Iconyinliang012.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2a5ab73abe86067dd8235d1e43d1d6591f15ae5 GIT binary patch literal 1304 zcma)6OKa3n6uxO%JC!0vt9EBhH!5b5o985SEOus!U5qWYpioe5lG`@4d61+w?M`s# z!lLL(H$K3h-~&|9om;`zs^~&QbSJnd@n$-YDy8&5!pXVccV73LWFNA1Fj!07Spdez zPl5vINcICT)g^mj1yG=ym>mGJb^6A9l7yxp_;C?AfrX29;0Y-T1y~dXFg%im$X>t+ zYvDQ9FLS@1zvNigDRURpx>ye@c-}p`8sYP+=cet|1>11Ak<;vOYNlT3;RLa%x9G=a zTIL$gO`_*!fnytxWTDKR$)mCt>yvCHh%l=bHQp9Aoz;yZRCQg^PqC5+RY8;mS>z?z zR76ve*rsqKTI9@{Q`NC%Eb>+6nnf)yFBg~PVi3&<&@c=^lmtoQ34)JT`~;=E9}l%W zRB>!aZkV`%&*mPH6)YuXj%2!7f*027ZO7Yo%k%QO8t6Eg!ksj>MaR=CAr_`^94tjP zCh(yane=YwKsk_PV@^aaxfHZm4eTWk`^k8<%#o9#<2t6LA&j9U@+CxGid2HUAuA4# zEQB=6(RE3YT7I_UYnnC+H3*eaeGI}{sbtiQF?F=2Xro$HHsls}+>aCF+qf0mC9#`a zaYwFMi7-lnXgUZMTT?JOA0$CMAB1eB(ztc@cpcfUpBqo)7qwY;6-VwB?2JW$$2K}` zy4z#{Z3rPUFmJ26!7I87c_eAGyklcsQ=zOG*x;IcXG;e+CzV)8C1EQeQ&v?;m6Q^% zTSke8P`7wXQHVEHMcA@686uGrNQy!}JX?mTWg-)rtL@bwAMNGBKG~>}xCp za9)uWrLxc98lZMBT^*s@(xi7$6geeN`(U?9_6jfs&ThEYHAs({s2O`5esi95^@- z`^cQc5pCcJ+buFbp1)vd+bS|=GS4r-dl@d76ZEJ3j0j2oet zb;I7KhcXV$!1g2CbLrG0GQ8=i$dF7|OK|*3rR8|tZaGd`R~;Qjqqv>My6A9h#>dVvH3|S;7MNww~+|62gq38+qx$+nRl+0HFp-5?V`?a^{=bHh`z1hx@yCYQ~D0dW1>o&CEn zz4^T|$G$pzd+EW4Kf7+t%QsHejxO9h_jh6W@xt8IxBX8Jtdy@j`7A%$w|Kv6yU@Gm j@~QW|&+gvq+gsT2_v_Dh)=UC^9shXY;d#)NO+Nht1kq+J literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang014.jpg b/res/system_resources/resource/image/Iconyinliang014.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ddfbea119d41da58055379726e67f2ee214987f5 GIT binary patch literal 1316 zcma)6OK8+k6n&X#Z7ZUVptuYvNG)cPm+vGvRy)&T7o$?^2NdKbdF_NYAClBb3nHQ$ zsZa!$x^iRHjffz+P((p+Be<}(3vs0jsh|tdO?;Wor${NikZ^O~IrsPOO|qDL0egpH zdmMm~k$%t(+LC++x$?9*IRhxrLCh8a$(QVWHHv(lThEYHAs({s2O`5esi95^@- z`^cQc5pCcJ+buFbp1)vd+bS|=GS4r-dl@d76ZEJ3j0j2oet zb;I7KhcXV$!1g2CbLrG0GQ8=i$dF7|OK|*3rR8|tZaGd`R~;Qjqqv>My6A9h#>dVvH3|S;7MNww~+|62gq38+qx$+nRl+0HFp-5?V`?a^{=bHh`z1hx@yCYQ~D0dW1>o&CEn zz4^T|$G$pzd+EW4Kf7+t%QsHejxO9h_jh6W@xt8IxBX8Jtdy@j`7A%$w|Kv6yU@Gm j@~QW|&+gvq+gsT2_v_Dh)=UC^9shXY;d#)NO+Nht1kq+J literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang015.jpg b/res/system_resources/resource/image/Iconyinliang015.jpg new file mode 100644 index 0000000000000000000000000000000000000000..19f3c6f4234d47fe5e8cc6d46f268f045cc35d69 GIT binary patch literal 1319 zcma)6Nodqi7=G!rIu%i;xPcyGyr`H-Ue-x47H7jjMr$o7;=z~X)rM&nlGLU}P}G~C zcv1ACc=zA}Djw{?n;;%Us-Ak$izs;V7GI{bh?LSF68`ru-@m;7f9Ybn1a{UEXA*!$ z;{eEmKBYfEp*mx=<^Tl-iP#1pUCP~>isL}%I4>$9+c$C1@?9=L0SAjb2M&!U0kT>+ zrcHdo@eJnI>o*MT*amZ2Zt~5bf~TCL^C3Ppe|*B4Z&{knj2@;BC3@lpE{+kMxYJ&w zCkE37*9o7AIfibV#4Uq4l0~J@G{@+QA7WZADy+pTDy?coD66WZ9;5{x${a6pBF_q< zF7dh~&>dn(w9uZ^$E)>DEOIiKPEoV7v&C7l=!X|LsA(F<3!EUZ#Db0Hyci{{7wzpL zRB>d5P7pi3M`wu0^k-s&A(<|h;0DcR4|v6Hxo%ch+d7KJaX*a}t)q##0CVFw@@GN| z6Z5@YXVSaX17(IJ8~sG+kV`?+Ro|L%u@^V0217JO+p%?1K^Q}UXG@6uB%uUZO_XdF znFuMSt*U|~ba7Vl*J|~0l~)9*tkxl{l}cJotIOq@q?DDasEJ+Qh8M-ivv4=ILt-n6 zQicjFt?H{+LX2WRobdhW?i7qo`LQ2O`2k(2v~Qi>*F=`%Wy1a0MJ?A|#i4T%+x5_Q z>2{}eXN4@F1tCNlW-VFOSV@&3iv(qowJoeFG87dJYfQ)A{-=Y>lS(9{lAxQAF3PeX z3sQ+yO|8U2sG6)PNd!%n5jHJFgotN2k|LK4&p*S|6_E+e*xqW8LvOjTM>Z-XtCRi& zo7xKj>;>Lq7eFBohQV--Du96kl`Bx`TX2>n z)_+|xF2CV_2>@FF7#gI8`j)xDp>^xQw*2tcfsyUWORdmXb~i|~FFLbgkpKVy literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang016.jpg b/res/system_resources/resource/image/Iconyinliang016.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fbe9353156a141be424745dee1c827abca8623d5 GIT binary patch literal 1319 zcma)6OK8+k6n*KmIu%i;_yb+UxKS~aynH9YSezdYGFodv5f{EBuQp8cAxUjo1V!Bm ziW@~YihCD+K*fb!xD&*MNYzz0x)B9e?&8aIJ|d;`Lc)Fb-gAHN-j^<>OJHX$aV7z1 zG!B3~=u`Rw6sj{;YYtFgkce#n(xu$3sW=XFj`N}-vV9X5E#Ku56mYP}bKuZu5+JLE zW7@cj%_ffG%;;hIP@*Sp;Nlq3i978@ zdSWnb=Q`mtF~`ttlelFtN3y8&ndTT>@k30@MTNC^MWt1(2xV23)PuCZLz&}6PUKlZ z)Fob*1iC{Ei5A+E`gpb8iA7EZ(VYytl8t^MbjYQk>8fwdxY&yuRf8d#qV3qasUVD@z_TSpev(jvtR_k} zi%f(R(^geM61sj?!fUm9xymbwR95Q{)=DLc;oAP5nn(_m>Qfc2hy|0NZ$IFEKvx{1;yNW~SBDU+H@6zo~ z>&^;UKnp^MG|XDEs`YUkS@xyAPZ87 zRZXqLLa3UoDM`eeEF)}MiU<+Ua3n=88=ilLsVgEAnz6mrAcx*^VUKK7NLDBP2{yGC z0@w>=MXB^FxDKeb(?FkcJ?g**D2iyw*Hf&ONf$sN4~D^Tjw*nG0+lOJ>05A?B-Vdj zGA_U2e+d9v02msihWeJd!J&2Q!M6PH)`5}j$xE%!S9QFlU%4kH5?tk3!YGnHI-9N_m=jUF?R~~O{T-~vF>}jq13_RR*DFwGn^tUHBPd>V~dw=W4 hfqi@KsUObgw{HIP{r5Y;NWrHE?_Zk_!Pw>W^IyhxV#WXf literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang017.jpg b/res/system_resources/resource/image/Iconyinliang017.jpg new file mode 100644 index 0000000000000000000000000000000000000000..949048b74045054cc63c8367dcfa3b9b0541f2df GIT binary patch literal 1314 zcma)6J#5rS6duRn*dPSA0tBUH8bEmM@$Zh6B}(=OR=VXU1nwj#7~7M?+W1GdmpJK= zuDJqHLIDL76civK!QBbzE)rBUC*A4ztw7Kq1RYQSX1v+mAQYiI$<~`U@4fH+PWC8! z26og_cN&0Za}Owh70Osn`J^d&ZudO_If%p$JQo z2u8=!5Zi5%a2ADw%Z;EJoz$;=w6N z-zI%*mtyy9(RXdlYD91nL{mX9*PnvJvq2KXvq8vJtKF`1yIR!Kj0+#h@!Lf;X{EQ485h_;9{*zwgid=FakzcrU-_L3|nNf zd*C?;gC@2fqf#&cJ?7E>5u)dJ~fr{TapfA!Bu#sgb2wMbW;OvWS z+EMNISMRSpIDh~2$#!a2O=)p-cZNoMXlB`X86TEm3 zk9yF99z1wZ5PTtMK~G);#rH|ki-_LTgBmB>-K|Iwe@OV}pa1{A|2f&q>@8S7l)7U8 z)a#o;0nAhO2^4EByEzRQu!xEs0J692nTaF`O;PmY5_STMl=p&DB_S%R7!C(sJ95Ls4SX*5h^?TNRCpTcTnb*;X!IN}SS`=X^J;6y$q1PbV?phBbUGyB2#JGM zWD}~sp=(TQ_ivzFkw#a)1NArp@0xx8y6a*q>dI0`(j zU1`%@APQ(h2r(jptr61WQ$^H%-IDvULSwi5F>zVm>^73{zJ`Cp2e!t3eOF54Mh8*maZ|4)7M#P+CT-p4TXmVUj9|7EgSP%MCc(9beO&{t&GB9lD?2WepQ zuS?Dqmi;XOU=^UCEMR+@i}?2cBNM*$m&^*!5uJt0T{@-8^z}-`cS?tB=9=Pfl$4 fK7P*ru)a`U`RmS)>tA;~{^|Z~y;%pC+3eMCQdnr$ literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang019.jpg b/res/system_resources/resource/image/Iconyinliang019.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b0ecab9a7ce5248378c10418231dc159295382e GIT binary patch literal 1257 zcma)6OK;Oa5MDPRQiKq>aa_3;ymrR<=llpckCgT6aQU%t$1nx+H?-Ru&OwNKN}D{(^tc2+>i1`k&+L}(7j;e0NxDJjX`G2pHuoYbZqOtg#SUfgrIO5gcYdG( z$g(llVvk)4*|kDvDY(filwi@hXwp=t|8x^zF$$x{ZlZ628AzM){{|24`?*CG0i zs@a=GTsv)K?EEXZQsJ2YN)5EY!S|mp*7zqsUX4CN09qejKU#jCgO{UETTfYAzWfEv C6G@@~ literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/image/Iconyinliang020.jpg b/res/system_resources/resource/image/Iconyinliang020.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6208e158b2aaab89406accaf9f07d51cdb27bbf8 GIT binary patch literal 1257 zcma)6J8#oa6uxdiqzEChFXB?6pZk61bfH zEU<74Ne2yfrHBf*dh4(i#ssRo#yO&h1yL4ck&|Ro5luyc6Jcqz z*xfcatj;7B{c5n2qDG?;Ka%+{-Vu;t7=kDXlEhI2m+S{A&bT01Dm_>vabhn@y)b}< zM{I|~w87F$PfGBkUT^AnZnu2DsB4T)(hV|8V=g+`+>eN`L6UG7JA}fQN;2);`GE=` z&Bk1dJ$fm4*9x7XPlB{-HCTGWyPj*>8YTouB3H-srAT$e8M5MX*v441U0s(Hsq{0C zztU1=OI$(9s@_4UU9TH$qoc026>U|sWJ4~w-5^PE;E*!5M`KU8;<;S26%(9>@n#tA zmQ%3a57RK|hY@VG#P=NK zu^mlDSY!p7qEHOasbMNjbV3Vtx*GIjx?Cin8x_;l$^U@s$rG zYW8-~sGT)ZcK!`qt1#4mr3RYd@W-#0YwXjXuZN!?0L_nYo-Dt}!K>ltt!K0?U;hD? Cr%8+e literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/voice/Alianwang002.mp3 b/res/system_resources/resource/voice/Alianwang002.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..da381f8e48fdbe103f01f6e5d51f0282f79191d9 GIT binary patch literal 99097 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

i$H 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 literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/voice/Alianwang003.mp3 b/res/system_resources/resource/voice/Alianwang003.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ff5a6e3d4087df1d027d2cfcdb529d35d26ae63e GIT binary patch literal 77972 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

^VlFFla>tTr=&U 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

  • KuYqBB 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 OIb59-;^;o0UIPFxd4wYX literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/voice/Alianwang004.mp3 b/res/system_resources/resource/voice/Alianwang004.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ed4f40f1293917ae1f36324dbb6ccab476be364d GIT binary patch literal 46868 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%0D;KxIww5kQPCoHiDAp|3>6LcKNsr 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�^Hcwg1dKDjQWljgHaEwE65{DB$g$|t>O12I_MB}K)a%` zLC{mUb27)T|Fis7-ofv@{O|Aj-I)uev$B$tqGj1{)e6EaQCA94Y-knmaE^H@brCRE zNGNsW{15(^1Sc#h00{DVp|Xc>c@V#6p|0NvN|hD(kU2=k6$ZI~6-%+s6`7JQvp=c) z7Lc%>KSe#tck;4koN)DK5LF%w)ZBt21#%AxCQh()jw0N35XV}uDiHs<*qK5n~fC147D#aL>C3|>P}HEKhi}i z6>K-B(sS%`ql?6Lic292lvTnl$!nNa}Iqb9P)+Iq-$};EmcB0jRwlH@PbQ z*gpDnFPn|n376u}rr2h@b{H$f6&K6!7)%32l@bx{Ti7b&to~-N6Bw$PqqENz40kL= zEHrlop|emL7bW((7`MNW39Ne3dSG1d(q=I24 zJ-6dpWhNeBWhMPYSz@aa=dN|?VeyauFa%D9zv}BlApCD88gTystbhA#(%Mp7lG$=#*cHmFeDj;@I z-n8zMwF_G^&lf3J`OI#dNZ~0QyqPI6YHV#|t=Ge{(-fH_?L_JFrA#I=UT!MB5&9*Y zdz(|Ty^}dDKeS&u(Fnado9#8tronm&ZUgwD^J`Whta|WfW9Y z%JzoP5ybcE-+v=`u&ZN&w_=HiBp&CFD7AJ#wQO_LGUFUm6mkI_`!dk!pA1sSc=Jw~B z2)-+jcgZR&pHTTaD(%QkmnUDli7GGT=a7R$E>w}eK#+*R2_FQz{NvvRfkmP(J_6Q% zrj=WHJ=8UA{<)|8Ohv0L5VQ82h`_4#PC`9oX5)x52Z&!#U=?ylo0XWKNG(|Aq^OB3 zcX)a1ssj<$*8u}`1VPJ{03FY{il;L@`H_;7EKTi9SOXm`Mc(J;n*EmUOaV5mw!gHX zWtRyen`8eY@@lidnpi)$7_G+DP3jD@#5D>4cI}o#2TqaGO@8xMeOg;37H_;kET%*y z*~5#oj+vEx;LbU0A*Pmy%oBWz4)@mWG0)fnilRkian1PKgUC zq)Doys1IhyXkLo$SgCI$kzZp)fn|3l(?=7>UZXzA^i}8}+`CK)_sB;VUP0ZkPTgL+ zi!V>G&f_2d5eT$HdC8Hki-MH$vVZ;qJ4v<2ulIxdKaa~?JagJ6JzXhFNz~%@WRgmj ztXx%|c7ri-p-P0yUezfw@p{96>__zW)*H5BYGI?7CNF0l8K?YB$0kQ=tRN5gd z0-4@Urk2S|4YehO&6!2IP*eI@``g%urI9c>N0qmuZK^4*7%$C!=^U*G+^I8mua%E| zzNNkHxT9{@nly{RyZj#v1w+LmA_y|&Hs^IKa)1ejh;uR!W3N+nLe-H>H;{hDR6KNV zF}&Xs76B9j;2wx@2X_V=BiAc=Q9x{dSDv>7?UBI8v;j(dx$t`kYQ}s!`6|aB%w;?d<+`;}cfPy(@T8^}?=3#zJ8@I#)An?L3=|*cIl>$DSQ=mZ=Gt5 z%Y}YG>&mj}X1%J*mVG@BV?4v6I;K@VHIhUzd7#nI2px2-D?$z$0)#oLpWvmEHS5O@h>?*6jsL;O#n#m>RW(U6@zWS(TxWAsayFM-DvkrM+>jk z4DTZ*WP-mt6P<5#$t=y|hU5FxKD`v2iHMedFzm4KI?-5SryeY>-w_>k`eWEuJwuNp z+^gD)u8H`+Q>w5MteZDJg=x+^5EezDBl0D31X8CSq=7w#ClVC^Di9hOgHQMFNX)iU ze(gd-CbUw*%T=m^=QmY+W=5${4aKHP#)swQ)tVf|gR8}4q9yzCaMiwIj)Pn+)7O;? zSKm&1uD)?hdkneGqks?owx*g?=)c#9{)oc2$8@ew+>q4fc}DQ7{^NfXh{+SAT*Y!x z-_1zo`<}OMaW524$6&ePL|3IKPqu5>w#EEvVCW z<%}x@Q0^4=iwZF|`De#~s3zhJ8m3}-a#0&?)r3B&wpK2)RxAZv1;@;?>tW*T8}XQq z)K-bkKnSPy?id0_(2Pj02)?c}ysY|Vf#CSWYP@0Z0zx)U-Fvxg&)Nb6G5LlA=bluW zOnq=oSk1EF<+vS?X7m(Zp`qFuT3F2B(=_l@d)cmb%);D0zO}ZfAyeOa5=h6B?ZG7Q zJ!L(8*kNtk@Z+QBwMWn~^XP2f0ngj_TS++=hKITAoL62LK}Z#Ea+8+IQ}y9vjjUfg zPLT`?UDtp8=c|AEtN;2x?KS`Pf9eS$g;Dl@znWc-@fZx(4!D0b-t*Zceap|BKqN)8 zyjI_o(e~rX)pFQY$#?{{$u%#nW$N&_l~ik#RT>NM$qMUiGD6vpk%5m|PO^gZB0|ks ze2Nj^c9v62KObSA0!k@wT>C+grvi43RATV4)Z}qFpH38e$+`CL-X+f(ue7O)n$jc@ zbCHEhD>FAntIf?6`c}D$WwkG305vo*O~oX?X6PVR1QuI9Nc#8B3r>6X9?mW3pea=) zndGtl{TT^DRkwi8IDnt_9e!1!hub9<0u#*Ygr-jt+5WHg0%2ZBEzJ@PSGCWP0gUy0^oHi95UBnQ;0XmNjbAJcr$ZrlpP)%*%yYI`z06A!UdMIN;3wZxbG zTIIQ?N>?r`c+vcsQ{t%)zzX%_4}H_Rbmm(f^?>_fR!Yy?K(ljc-2E`#)+s%`LvB;t z8^x12{g))#{*01!@%DNK5vQ!3?c^CMr>Isj(zPtyjup!n&J0%67infZo5kGUBZtof z$5iF?JJTka?w}ugHyP#QRxSyaz2m8RrRGbYFtFTb4z(eI~FbuB;wze`}G<6_hc>)fnRluhl2#Ey(tUIDex{9d#eHX5#fH z4<*{d=vR7WUVd`ngr(N^)MsAqSbrPCF%7~CG+E_#o3~2lagl}E{&Bn;C0BS|64m!J zDQ|-PZKEq074;`uv=mXWkUrY)26q?_a}G0n7n1N9#?p19tf%a(fBbJCh&X~|&wCgO z!Tz88x5kYOC{}Lk+J`*Lh`Sv}N8|(BqHN$C4n?y_&;;J11vXb!c(r6E%Xp&__MP>& z!C0Ln;`G2!2anX<&TvBNC84%qg6O;UDv%oHLEc@vxyp}D<(4xlZpD5P%qCXVD5;8L zviJoH%8F3eqlbn{YA^g~w#OXzafafl11WhMuT+aDe%*%7=t>n{fK}4r1k=u8rgxTp zPwaN{h`a(3bT6&s|@hYDnX|H9?FsNJ*3uTzxT19FE-A57?B>*6?qjBIG{cy>@L zKko&P1+PMZf-)7nq@)dhosT!zW#ccKtYffI4{+btfC{AlM>Hf`I#Ow=B)bVS!tg>^ zb8B^wk0F)+j&5L~Ol@1kZkTcS$`#RF(NJ&eEY)T69lBXlhaDnW zLtPE*xA>2LPaxJwfbt07BKV`$#_P_wRYwyU$};DYdNqkjLSvrZWSu=G#=$pbJ)9@W zt#Lw(p%%269VfdojN~p>xNX zV$2;4lq_k7pChd%O-^EUm|Eg#?VAlH>Rc7fwTSRQ3qELlZG_?ze_IkUnK zbq7lv*C~uqJICXQwr=;M!G*)?A#KR-5G>`>r#5W3t7WQug-54XSdmez1hwwmIP@ju z1-X!;uINyl#MN*>@k>})J7+!ajvmVpxHwxX*OvuLM9VzCcp)D9+q|?fMxR(!x`CmqZ^+?i~1~Dn<$n$bLors3K<#yLz_`mV7=#rfQ_4=y$y8XdU*DvKz)pNL~YFWsNh* zbL1n1e0nGC)M>2>?24tsMbtZINgH1_#FSEnZ2^wr2|5*wV$DY7$WzB@u1|L{DG0$8 z_#-JMU{mQX<4f~JxZexdi!|@u9F{Z9e?;0aR~B)Ims&uYx;ijamX5 zwzu<7x@p)GY9n31_S)q+4gr6Cl}HzLkWL<}s15GeAorew*Y3vJVtg*iY-U!*khT8@C&NwslC7 zdUbRWcYu0?iveMFq0SsI*5W>3;WvD<`vLy1+kvdO8_)3w|L8cf@L%y2Qgz~Tvip^HJNlzl`V9tN_-w%NSGL}9D z>(9%|O5a+#>Kw@DqZ-Cn!*@w>ytoxDTG|0<{;kz1%#5=Wp*%T3yd_~UiJ&m6`PMpt z^7B%ooW3R@8yr~ngH{ps&_6BO>J0#$43~+D5_H>Q3C8Im(zciOb$Ulgth@1NaaW4w z@wa~HmrUzh=rGa(a=@&)nNLDHPU|QdCfEQe(bj$&(!#m7CS}M^hux&8?u#|krqiRq z{yyr*gqxJ~u*?8Db-N0n6n-2|;+XXGJ${+%cgoLQ>|<&b#!}ziq3#1+Uv+z&L=96V zt|mTH<;D>)?AEVG1^#0;4dNSzQWuO=aL-)f7paU>>e68_A#S0Yl|m=wW9HX1-!YW; ztCN6DQLu9-k#oQJeaO%^ZM2Aq;quf>Kt2oX(3%J=0f?EbCldpdB{yFZE>1a z?NyYE7e>w4=^$f-2sp7tp;?gE4>HmwB9FRf_(6JXxFfLqgGWN8 zU0nOX-@ZmY)q7#eo`nEYru=j@c39uRQ7YAdZ;`6}wL)7|RqlG)+?kpwT0$DLd})wg z`JJpglmD+pPL^&brX6U3k%i(BO zxui#fD!#_Rb}J118)n!y&Ei+6i~8)q;i}-bvbJC;RzFN>$M(q3Dv>2!jF+hI-iB@R z0rVdN9%P2_-nrw9#}5rF?uG~r3IrmAiU0Vo24W}+DeV8uDK zPOC+6qNRPb3;n&?RZE`I9;(fQ-lfq8q{qiWlrmCItJ|M@q&+_loEd+z0L7S|s9jNZ zT|pO>95#ajUK*P%!pRL*ydJ6bYGj99wrP+5s)dA|dtg+_pEiT%y(t`<>*9dcRAEax zk0kqxEuops>?|e0Rou%hs*bdyPKLrUHZAQQ6S|c@jHj+4J!^_{R2u*BKZL;6_mzzW z=f6ypm)Ab*w!GDqwfDR7?p3C7t8$jl+>55bt2S_nTkuZoDk)=*pA1<6+A?%}@rQ2!03SRLVpEX=@w>369&L=crZKib1m zlp>wvQ5#`!D#>JJpr3=VA_XNlXZ4KtGEk2a$#pBS@6Cx<}MHaD0abKb5KmB;cA*>l$Ui*>)VeY~X0?7&e7 z4T3L$2RH0X<*FKoq3tCLLa8gQ<$}3Ut9jw;{ism74q|ojOgf+|(yo$0aunKrs(-o! zn4lgRVIOg$*1MRkQqg*W#X)6=aoQe9+>18Ce6)*)uQrA~+jIM_NLvG*=jOR5w>vwj zTJEN*t~I6?|M>5N{gOI#DA&RH(Lq(%q-kXjsx)$h{_-9_1Q(K3 zbSyfr61c53t;fcYVCwjNCi4>0&NbZ;f0=p2`ySN&dAQB7RFU*Isnz7nH^=Uc0s3bZ zG;=8DAz_>c`S&67$_M+ee#1pUSoGYFQayHpaEO0j zGx!#d0WfLgj~hN9K~%tv8bv4;sqMx-j)uxtI*jJG3(QlZW4s}!6N`d`wk8pg>xw&s z(MFRzZPQU4G|d<_ldEx1A_y1d%XA(<{9=Lwx+7;$YfmKLquX51<&WqjiQvV0lZv%u zI?fu9I}3ms56Hi?v-0KlQBiyDhVL?LMJ1_RI|_gQUK;+M@gooRuzSL8c?!8YKj_jqi>)qlF{A`0fuK))H%Z@9H!XxJy?Eb?UJuv(r04zw*kUY|A>+;as%iz8_G0(Lx&`3!%l2r5<&|u`*JtHZ$VDis4 zjXRTHWLyV*OM~@IC0>JJmw(M3-p1de#E~!q#3i(~NG@jzART+e{X$lB6g0LuKW}d0 z^uEFiUM)a7q5b$O? z4?62!4d>F)SeoE%owb!BkbKNUNhYP0>f!ESr%FFpY~bLo)^5oDXzyCY>z{N)ibjYg zbCH`%z7>TUt#>?v;Tyl?pd-+l5FsP&nf;yB^P%hhe1)g66nkHmM^t6N_g%35SPzzr zrnHV8sFL_2w~6B95mJ^cB2(nAHrX(3&brC;Ydtokxb_Qk2+89&<;=v+RHc9Qe*l4x z>nmBck5rLGd+H3n|1HssoY>jzF-;_6iwVh=5BRv=?|0dvLH0iRbUk|Qp|vFGN~$7= z6G3vY%{GXUl01%fAL!vC&d3I&njN~kqiM)AxGw>{+alK#csXyI>UQmU=n4A5$wpcG zS?mm%Ka^dt$~s7+*|R4%j-q0Tuu{6+c1`tpvxB&PSe)c3TyNNPQ|J}AG2bwh`Uq>K zehZn!JPC4e`mUJ<`SukX3N`kOe`S|SPhqg`aYRFQZ)$SHB&a#2x!tDYtmaNLoyFt41=OhX8%0W--4(|6L-eajF3h*z$PR&K7>Da449$iyc-ntO z`iG(6%O3sEZO)NGx<3$812_9DMx`IcU+X?|i${)0n3SM#bD89jGX#oFzt5<>jm;Nx?g4drG5#qj%op)D;mI|8$Be6mFoLj2t z(vUHu0V?y>37%LK)A%HLei=CHN3ZJmP!|-vr4mfl8NAu3rpUSCNgR%+XP}9=*B0k> zPp9Nynu(9=Q1D?qeq?pg^4I7}JqYqF`|8xC!bP1D1eH;3^3=BEh5+k{76_)%G5aWJ-VL%3oDROGEwIYiz>+ zADO;>dylS*T(Wk5O!zlN$5LXb!3iqq9R$Tw9^OMj#2A(IrI7AQF2DX%QZ8JhWQi^t zoTkTsDo&FJ_*R+|0|ZQUIEYGR;rtcoGHUMyduG7y6&X*<9EAE1y^iniC8t6Y>ib#% zsB-cn--^+7wY9j8=nkFvMQo1AvvYIE*dFfEvfKpkL69-6IGhF})#$aIPUz*CucmJ7 zT0tEh1ZSvfocd||h zOfXH*_b`2IZZUM;OuYOzuy^?q2YNF7-sa;+jQ7z~+$}NO2x;dDd-FS*>W^@4^7lQu zHPa+3+Jbj?g0n)uZ3l%al4{;e!3>O{AuU6>K4U3@l4pYM=|Y9?>J8-#E>eiXey~FTh*@@Ay!S#dY7%um^n!e% z(ZQ{_plNEL5A?UCt6SY>ec9FD@e0+Rk+d=$)5-o-`sCof_EzAkedx+&AGekZg*-9K zL1JH;=So}4t&pis_#n;=t&BLeP2ERaOAo8`Db^)<7Ij)qX?FRTQ^OW$9(HG?v^cD$ z)5tt;&OfFu)4j11!iTmoTBB#KCIS3y0Rn-Y%7J?rS^CW~sw}w@F$wQVmH+9V4DV+dUgg7`#J`u)ilo|8Edq{9D~N=_%ouE|K{$tHBgZK-cnhlaVuf!COw(t8oAyI z#0n!%)O#33jYu1I3H0e=#ImaV*)>njg=FwzZv9b~H@v;5Aigq5agtbKS&x#_;K_d=FkbQuUhWMoE(jK=X ztvEwBS{ZFZEg9#3{=lS!qP(Gj7(LluJzPBk+j z$j+w|h~u(^xeqcGG(3g9{>F0lO`-Bp?bpZud;;NUWz7;Avuej+$(7<;f;^+PrOgT}18( z@enYK`kb^)3H9#KA%vPEz4Y74o_LF|8ZLq9_k_i|M&I`&rXziu2#UdHb>D zetmo35@<|j%-dWVeW#Z$S2k6rO7TY_g}l}ys1a=>|K-zUvqN%+3OEUN0`tuj8|Fr&(zi-va-Mv6FEb)3%BTiit%v4w1 z(Xof&|Kj`q^a|&o-?CwAma6kpM6;9xaZ=d1d+eIVno)z^XVz-Lnm)ki@!TtU2pr{x z*gnaqpA@dk#~4oDdmxkI=NQG1QEBHG;QN8Iv-14$UAOoZ&yf>Yz!xYr+f-OuTZJ7a zBaCFeM5+j*AQiLwOmBt$8i2(?GJj1lhBzwG9ro2NN^rk&V|RWnw%DWg=(=xes418o zLCC+In^`EVVrOMU6S%`~rc?=w(DOWEPSgeI9F{b=%MRI1J!0>3^Po70h zkHh+LbabTCz{b@%qi9Kz*8BSib`bJBM&v6cTm_5pNV?pU=w?L1GV)n1!h%%dPXd;f@7v#)>0bvm!% zR{bUUDQ?25eMqezA;0(p z9jWn5j9-iZO*E$~%IAbd}D%_Yohcz zSaThEK}2#aawnqd z(8M1@G;V#^1e~C@8`2UP4LPifOxpSm+mnhmlRrR_m2O6MG!+ z@$1&!@~9< z>o=P(%J;nYlAncgz5>3#(MqTUw_#q+u?g@30q-G-#G^rY% zY08b4m@l$RLnI%+HT6*nr7;J+=i(kIu`TzxQ?H1Fhg*o60$;(Sgj8ftm;Ki(Df{aK z{h&M=Sjae|cg*WW+YGX0|LEsGXU+y*+3r$^h^OoZy-LQ)1lP$>psj@d~OZzMNyhPfde4N77oYd%A)iu>uaC zed|-$WzUE2`+PIN`tZZmFNR;q2n9|dV9S7hO2Hx>) zJ*19|0tMcMdqci;;DAv0ktxP#74LQk%?vwnsXVBMC1Ek@YPPS56qzzCyJtA zn23k+L2)K{qHXdat(U7du@y~^FwO6bct9Lwg3f5I5+NB!!15AWcqwaPPm?Yn{o&v3 zX7WqOs9TD2Cwb8;<6X3$(nqQ7S#s8 znuCsLVZJZT>>xA6E`~Jp<1cg-jL07Y7Wf;yQ=Knh_pNu(uUombL-&dqii42WnC36j z$TndQpN#+U2j?H9XsgD8=P!0?ZT{6ilhayCZSMNUWL@#?5xMxZ7Unn=rfL&qe z0xcq6)&IHt{oh~SrNzLxc#`;zpTr)`x=0aGtH|X(X$?}Zh82rCnKLJv(L{ZXN-Ia` zG1KfQ!tZjhvrLfrQ4BZQ?LaYj;tk=IUb1Gl*&6N=IroYjSqz@)v7>;8Df}JpxrUvJ z(L8b2csDsC`$s`N;1!kNM#kX&!`fM&N6AEQpH(?e1?-yjdyl_buwYfA8pU1%kQgt| z?@zwwX&NyrZ|O^!ImG8*L7n)?_v#)z!IxcuQjT8;6J5<&GM=&to3F&TKA)9{(ZI)a z$06Ik(Lr59R-+O^@0z@J&hg!Z0Klm{M<$0{n%(?XGJ%_G3S53;)!^vnNOEi-vc7ue=>!S=1V|B{|MTYDVF-=?hJsQuw@)Aq`8gz z*4@nX@QJ&eLw7xO!D_VDbogU|=VhA?hNFR2Wb;Q0H1svE(()f?)7F_I4G|Tp60Z}Q z#wC-%D9I7i%)_Hw@u%QEDjMkR9Vv)p8HIp1akEbMcmQF+nL$)Snbmc?^}ERw3bXj4 zkmUPpDz@xh+|7(u0jsD}7hZ86ND(*Eip>H-Y}6dJ9;>%v+`CC_18SzZddPSq2H z>a}OoV3@?OvGl6pJ=Tf4x0>#oLo3`JqY4{dw<<*mr$OsNbsJ;PbkD|gz3kHbh?A3F zmFMbjQOkiB`%JOMjspL4{hyMT2JyN(0Ewkt;-)^j-I^n zbYWgS_rGb=UlSAUC&&RsIS?M?r2GmNQ9kj|Nm-ild4G)*uySb z|1N7{K89SNt_+unFBkL>Df6YpR6AJ2Cjk@CIFF9Lb1z z|Ja}kI8_o)W_d_;RzOp*yx33roBfZj%k~*Fp0U5kQjo@k1RdM%?_2?fs9jEtC4idi zk47(4M>H+ePQUTB)X?kyYugqDu3odtYv$?p-gjc1Yg~I*U3F`Xow5J3q+g4o zEsq~Qv%k@p@7r;yFtaVp+%df$B(HQR-^_)c{~#Xe?G7CO-*iADv*eHMHo<*`LejIV zJx}ZmU8%Hx>vyj(8?HQ+eJpMkAxF55L$ZLX$?ZwzQkm);3hW;Z&ATpnt#?vURIGZ| zqM4VJx3o|u#80>E|JI4m-kkY!=3EZzRwj=kL#O}O3VZ(4|3CJ9ZTab}xtMEJyG z-OOfjr%rRInk!ENwm;1oSQbr?K9VtQVoSlRXFHp8lYbO6%gOh1Kj>ztz9M&^VZx$d z4S{)ObIr50#)!&&JRBRnGX)7RAv-Am8#Zd);=!#eQ*EI zwaQG{p3pMrRG4SpwcE;hp^DOu0TE62{WGGT_O55!?{YILv!%9M?~HRHzg51kxpUyg zl@B-XICRahCyPxXa_{36z8mGw)_a|gudR>C)7`lL|MjhfY@f;}ENhI=@6K8>XVbDt ze(W3B+#6a__#c-%Ne?qoU!=F_%+HWwi&ea;1*a0?ftvz~6J1IqSwE)o1PeX3{p@{B z=+TW$$5lQUi~ZR9blS)Fz~j5Sg2R4YzgG9s>;J0kSM#R#@~Ga;y&kFDyS;$lDbvQH z>Bkc@E>lTGh9?ucFHMVAOK`f#VzP6s>a1fa0y3{R%I)Q~2z(t9eK$6F&8E{^zUMp) z*UOiWIQReh{dM_K^}um7-W`GFCM#DQ*>hxPRoz^j8xLr;pPPrlM=?HLlKsCY*ANTi)n%!JmRq8gK@?3i}d3tIko7P>Fr_;%MJ1MvKd z)Yo8-i_0f%{;_fU{;Gp(B+UPR4sX?&c1+LN6s`P+bN~77y1i|i+a%~4hW4br zd$W7qRhh^VTM-wRg9|P_iwx2_uw-lHDb1f((^8DYt2e)&zpDNFgr0ZN5B@PKR)1kU z@woSE(CSE00ZsqN4DU&;Iwv{3xIUIm;V3A!)O0^FTmAS_-hcyXj0_z!m>5|jSeS&D zO`PvCX_eRZlL8a8N~CPK<%F6RDTHh&P1x`uWJ8&fjp{45Zu_>W|04g}9@+NkK0G*x zXMp=(5`R6Nmp^>Ft9$M8(jHY{b7?q&e++{VK+?Z%Or~^?%}Jp9R1YvPunaw(koGB*EPY(rDxEkl^mF!5V1XHAo2V?(WjKTS#zs*8~j^AVBbtzRfSc zea_zJ?DOv4cf9-ldA~InjP6ylYF2&bch;&^YqhKd=TkV?!GWxzCaVPphXwnrqo@KW z^vcuG#LNcdN?{7J1ltP(PCL2*6ku~@)R?;x@wlU*32fPwN z7V;GEv~#orxtdUT+S%H>2zUwuOw1ijK?1PPkEdAy6n~hw+6V(g9}6g8&M3qkoIw=a zES$_{Z0zh5JUlGyT--c7>`W9KZ0sDYY_LBbW_B(CZXN*+UWz{tfCw^$kh8gkfSQEV zpUz<4gaKBru8sn%tR5a7EFPRJ4$hXW?EL)vkBx9}FvBdEUA*jFO+1VV?C1)1u%~!z)5O%l%~coxfR$7H*|;gl6L#j$*6m$b{umaEnS&jxsfPvYV<{^; z3mfa-SAn6BQ2gh0U`2nJOL*Cv*n!OyLFQl>o4<1hGx#5Bn*6T$UyK$1Cr5vp+u8j? z^DeHE?*GGZJpZiWqT%HTVpRjVIJh~Rfh65Q_O4Wa@6^Rr4fLP9|AELqZvtli4-J@` z{l^F$-JEUzh?Th+E65gP2lM3uD&yR2g9Gt;09h$g0I12+*oE<1M92{(2{^-wt zDTcWLIfLxYK*9hwNp)FmQ3-xtTNBtJZS&vFVF8ygafO+}l*Y%*#>LFe`A>~Bz;-Yr zmUSg_$c~64F9pr!Wq_p+8;`>;NoM0 zg@^TDbE)oTYGw;|{NH+%wO4j?{TF=-u|CdGe;c(B>wm-Y2nrTT8L$g1UA+E|lsd@i zpLY9?=|I55>~R7V2Dq5GgUtWdm)}L;ePU8k2L$Ia{muw7Y7Sh z4-;pQs3lB^f4fqM!sPJB3@xtCLqV?%wl{b1Z~^{fKh3O6>@7jCs}$?w)#fqH{)a&Q zpN;rmNu&Q5#Q)bL{@X}@%j0jM{zD%BMGSxHLjvRshDBP+*}?9QjQL|m7x+I9_3!%T z|7-&Jm!$H${+|>5|Je-kM^^p@@ORgAnC5?-#q@Dj{a}D zprH86$-l+-FI<1&`nL%DTgHE>>n~jY7J+}u_%C(+zlIC>KleF6_ONB62W%JPaXaL% z<1Ye#5%`P1Uj+Ul@E3vqpAmrGCw+v2LzZwu2~CrQPe3=_`H@ahT`Vh6sj13Jgcz_% zet3&HSY|Azq!>3Ed-@hjX3$TT0IEGLL0>O`34fJ^lLW_i-#v%L=htgOkVHp(j*vK- zq*QRo_X4R8;c5rzs{<7JD_K}m{t19k0q#naa5)XvYT>ns1Ql9yu$vsG@H{Q|`8zb) zMi(L9hg?72Uydu!ji``|vTajv@<`FqQJXK*^Rz(Wi0|Uf=%&srpJypnz80U3l5DvC z%37!|{6aH)y_|%*&c8*c5upz5DaJM&Tt$0DhNh+?1VP4fh_P+J%yUL2c0vGh^%Fm^ zKX|oR2NF@T>wZXt?~-t!oo#s{rQdX+|0{ieKSzgp5W`DUD(E96eFbiv_(!P?h8Ct` zhNxnxNaR=T1GWj!9|x6C=;2jGxu#yNCjJb8!V0P3pjpP`=ai9873i5+y-m3sbd#f- zYAeS-c}`2AS4XRZn=N}MCseC!qd6ibm+P9Bv&=Kz=?vT>MS4aSkNh>^P~k?2XsK<) z1RA!@FPK}!a=Frk++6laM@#EB)k)*;lx6m&J@pU@ei!4O-ZTae2^YB>&1vz6L zx|mycU#CI&Qi!~C*mR}!>DwUg#}`l45)k3OmOyFP+eI94 zuZyj-C5vrTBg%T2DR;u=Py17B!SwjdEncytcf|s|gr-5SU^~cdBC$*PE|T z=EYetDe{)s{{VgWd%pt)ZYkHkpt;cX{=F(BiBp^s3r|y19i_h3?-$0LEK^6C*H5cXivpx{Q=zfglJgz``|ybDMO9628H@f zU1XX1n*Fpn^7n!2y#H+ZK&}myzBAhx=ap)(6BR0e7eFyT3*ci!(*quyw2emlz zJ6Y@&t=Pm{>Q80dztE3a8Voj$ZEY_%xXX)n=hw>|8k@Q}(Dgao>A7v19)e_r!&hwa z!9~3GZQZQBrD0M}D*|u&KHlthOznbinM3Iv^KGRoSqzzya~WEv6UT_SEeH+ab(Wd5 zSP6#fc)aIqkJ>mn+jMUmCr+1LY&?II)j#sjfWvlk(i}`bPI${w?weXyi=(L_sc)ac zU(u+8An9HTWC2#24BCQ)gk|QeX-K$jo#)4IrV{((-Ou8d&NMGpncPp0Ib7RO(&KhY z_1~@>H=_<@C>qEOc=h;;ITkxO{PKq`o<0l{Gu@SZ(4i7`R+^{qFT<4fb(6jG)ti>yb)c701Y%%6aPauQ9MHHTFjrnZWK> z$z+WeKvw?rbj?${;GWs-kDvO@ot8ya+!S3yaydC)U92u|a@5cN+-K>yjV$g({4|jW zucAwlf*TF@F~?^AgiRpjCP{=|kRfr|uSThHG`eol*N0vv^R<TG^fl|6k_%5 zviv6_XmEL$@KgXm0(~(x3KUZ#Pqs;gwxf%UU$j{M3OYM&(IMGrQtZopcywOe;=X%vKwh5F zceh`)cieAmFfuO3l`kVHOxX!IK>^k%U7)qu`kxL2k3K(rglS`Qtq0yijjPF#(2&az>Gq4L4->vJ-BfurdXs#d2eP_1^LQ*bC3=arR4Jy?Ce6938o5Z^dgV zFaZGUwUpzM`TC$0q;Ki)*k^%=I8XL@@y@HHI*2C(^f?hw)pYekKozAX-jSNpMf%n$ zr+9Qphgb9Vl8$wc{Djdc9E+zjHV#M7 zUyKH3Kjp64?l(7}w;M%kR+Z8wue1u>a}`MrW`FF7ty6-i;=RS+&hXp(JV}fFEK(87yq2ontb5o6E#;Shbuz@Y++0ZX;pN`t%0=@45Nts^`=TvL0>lNicdB0aNyo2aP{exzNYS?($S{+qJDp+V%-)K({)q7nUCbS@t$!%AknF0r&=D3 z6)(w0{z1Y}Aj{j>TF*nU)wrc^wO546U(|wv<`{ngEa>n|pE1zyM*{0gU7J>bByd?{ zBz3T@rv{^;hq5I5?Ji?XCZ&Yo@I{nAbo1(w{{kHDuCFqTe?(m^@FBFTu@UNdS=|JM zoUHxj+zNl9QytJ78>|-7jrnRYosQ#4W-$_5)m14Zs~>f(az;(?OqxBUN35I}&0UOPzSrDl@Pf3v zuWA$A32De+3DPKSVIKx)j*THrwdsR^PFi*urmZv}R#gRK{_ASn$6#W+ z0iP(%bg_|-*KI}}6JVsepOa;G9Sedh534iHkv?B;irZ*c<(U_aepOMv7j@=ZR!4j1 z62qrHgcZMBsTZh?S?5litd%03n*G&>@S}moB0k!$61#P!4&Ji_oo)uxSzWVIyjCll z0O=%9zXi3M{W5{=h?a+P=?9mV^!^JBEZ|e!4WQxMRlVxU?x-Wxy;KxV>PP-x0&th# zDMMiT&#eWzrFJ!@U3LDN%n=K!=*?^yCyv-ysV=lpBdv(O`~}S1lhO4>XRTSN%eB(2 z&NsdDtn+BOov2?Y#zEEHI7ArN)YUaid8m$KcB6kja`*}~lQ=DYpCPy4AR8g%VBsJz zc#fSDtT+X-nngAwf?SFA%Gt-(7<%3C`wJ_WwqRwcw=HhtmoVg92d{SBzl&Gq&=&(dBk6_ zvc=uRfroJg+SrdEZI&fWw~af{jk%LZmd#(vlL|j)_xx-oqx}f|+EfAn8sZ!PeWw-igX=hd9qxx9P^_r%!@nFGGU(Mdl#r0aIEpk&>|x@vlHg zuLRap#pl|yzH`iZ7ELtj#Ju?UdJwWo3W};tt-s4b(*pvEB%>&uF#CkQOJ_x3Lh-rE zZEdxlElEwCp*RXW@;?p0YkMaT`Epz^S$P1v{x(g{F11G7k@+{&G7wLgvxhu6F8k`) z`FU7FSox0!exFAt1 zI9b_Y%r7)A=QeybdAzsrQBJLu+t#j*6Q1mqhiB8Fb8F5afKUPnch*<~<#5@4$~5L9 z<8zx~bg)9AzgZYlC(K_IYu}Q*V5Vo0$|I@wh@K`Rc7R4 zFK)qt?JZuMPf0dg-pTDTYXFOSC3q}rmS0#W2XzzeeyM7_(`aihn`c%)0?LeyOO6v~ zi}&5G5avpnWQ3QGUWhkRj=wg`3OnD*(v(o)q+EUE{{xPYQdNGx>$nn&4fyuDt9JE? z+c0UB-~tsr(QMW3S<^c-uzDpqB{Sk#u=_B#rLBWH=dsqU(I+&Iik{QF1uF0Q#D!>$ zapOgv^|Q>Aj;_w8o9+#f3&kx%3CIyPau@(h6>~@eP7|D#!kILQdMU@lFtbPEZwy`0 zC;3VgbatL;)JZpuN{$$s67-`2zSWrJ^#q@Wi3c8mz()QaW?f=!XxR`lWJHQ3Ih27= zwLIc!(uM}G@4*P18{)jGk4;)4^-+z6VF_ZUP1zzrdKgShfEWMnPE;h{s;BPAC8C-$ z2+u~pqi%h|Ze|+bwJm9Kc1ecImlS!RueC|ky?%V%{?iOU*Xy19EE#FsZgjdk27NLj z0tXhJRz;v(L;}`b4#xMS>tI?Ze>pW$q!*%woIUcFs@SbEjDT! z$(v8FjM)w{VmB?w{F}*kzgf_@j(tz2meaQfU0H?3A68nt<{%q`gx{_auBbBfe=!w( zq05}iB#3EkLv zq>T1C4Rm5K#Z%34j~ShM$`FU7Qn@)d9KA0Fex0h6U>bs?1DQIZ=wcft z5dJEj17#5fM{aPxf&-?~DZH|rl+B_ukpQc68z>%&Lb!n&%%`qcYrf}$4! z#VTD-a?0_{HBe}3O?CRuploECV4h%B;husg6TUZdvwgh845=-KLd~N5i+|92I zrc+9~1MIV}P3W&#H5#T#mj~k!iKmdZt|#EqV0&(?0=ypiAHw0+z0-&BPpDyKxEbuK zH%hj%6;qiv?N-KOS7owi4oSLEXG|;DquKK4c3dqqLWyQZ&WN^^4Aq(Muj)qefe>%; z4i2u{MX$&&;$3Z25d+rj`VwSInTpd%(w~ONx$%f=c`h0g7;TztOi!wb1`O>$f{`W1 zoK0~tNtD#R;#k#ehPSjr8c;8iG>TLfbh->CvOR;c5e_uM`80-hc*bK3YAj-k3dr)5 zTWOzhirVSLRCxf7^+rM!k(vfkCpbu#e97V=a|Ka%cd)FfsxFyKNrLeC+30K7#`F!A z(7C=NA$I0O!kt(~e$*e#|#vHV1qUssL4g%NXaz6I^L8=4cz+;>g;qlEU^J zQd%G$tHqsEi#lN_lD{H|*`!K~-M3q`G0Ui~-GsNU@wLv+WVbC@`9Xhpq}QTW%f&J9 z$o~X3|M;kub{z+Pssc8pb~P~?gvdrzze)-i4cVD3aKnpKr_b8y#ZPa^)+aX{nBL!b zHPN{;@yqXn|Bq_3+65~7Uv+64WQy=SYhYdyS$>Y{Cv@+_08vNT6#2@;RX#2FR$;CV zkdaJCqMUIfQGvNQqRe?4ElcUh?X4D7vTiAJPg6lZ+jFcDG|EPOZJ-8l80V!(RLrF* z<-OiOC|XREu3hrBkBvQnYx>FOfr}YCsg*A6k~Xt}a6o(LEh_xy#OQo3^|I;w1(x20 zHqRt8aRLGuc!s_iG1e%ftuHwljn`OlLbOMXfst{7m6(#e!^= z;G%ShSIH{^2Ks-mZU9*8y#(SRbWVI@I zA_lstNweW`4#=yy?+b$AIj(PGVsH!XYDU)Am;dzbq>x7piWe)@ zrZtCE;D7pLYQ>3UE2D8~g1ud4n*^Si>cIwfn*%$(A~kRO|7t#EQh`6J0>q4od>1$a zCq+YPH6wbF9UOhd z6QaSWOjox9#rL5H^KclZ6|geBvj*h8du$zs+ZOf&z-Nm;naix*9->m=1{~wwi&|jt68qdk=z%scs5lgG|@ z!`hloY3P;YD|$Yp#iCtdGvFU?!mkmxUki6_oBxFW|MRIU1?WR_^U#bFbtwU6?q>C;{$3Li&@@KeN29ns?d9$p0y2WcFU=2GEp0lThcE(&%s&Tup7V#q(FdNMzJMcUWYU*Z)!rWR5WLqI8gkkIL-eqgjBCv{iqkkWN*{flx%(5J(! ziMew`M;Ky4?YdNw@-iP-Q55}JkUBwXMdCg1b-{swswt3Bryd7!#;l!nwt3e*-8S3& zLC4mVq+yJ8Ek8Z8lMJ_aorj}0c+A)-Kj_qeRVb5hgbG7|?QQ+B$MTy&Sa>OAs zUh_<)N-##*EJ|cOV)6~@s{c}hB8%@yjZ=(wVl9bjpJ-d3c8i>%-2`v3|34%32Y*t` zTS>^5qjm<;uiR1W_W#W;jK0FE3@lS18}|fLNI6;8C^Y|MZG(I8c!xAQR_8g~>!%bU zDDND_iMVBwO1nQi0F~jl``B6%>)nOTnX(fbS;j2V9q7zSy@!_t1tx+`>*BXZ{5w^* zpAae`eTpm04%i_HFn9tdgZNQ=NOz&eA1!Cz3(~Eea_%lVnx1F%5*f|#o;Vs+ixDpt zSUKood+5SYpztI)x?XNX|rLOajoWkMk1V`eEOjz8m)3-(oh?WaZbJVg{)xU zsA^&y3!1W=aky31hu!&dtq-nm&HE#zl(A!_Un-BQ3_++9UmwQPl4x;N8gUyO|JFZl zHat5-n6ZJNs`Te|S5s5*Bt)d`N8d6(TavkwhF0_dSrS9-PnAmNm^P$i2f1R8 zVM^hjfjXlFWF^Q_Idc?mRSax9k_NmMcus-JM(;R^jp{iEiZga~wN=J8$-g}~UkkRA z#6usyhg%mM{kqfGvNm5E zk9wOPF4;Jdt@0@mJt3US5z$mempa&P9xo%VGH|mV?BA4nAIZ1C>vDN^Q8}37O!%^fIFBc@dDz^JpH@pCxI!X){}SPvD2R(Cr7+2}KXOe&D`eZ3 z(RdYSpvvjG>qy6;WGo;@4zGU)Nkz3q81)*}FK3Cr2Aix9#3s;yFAgo^1B>%Um#RCXd*+R_PX1<;&Pm za+(zsM%e7=Fg)eh=w^A?_`>fXbhvxhVwScv`aHTPf*)fif+c@9@WsbZ)9ln=T77v6 zzXP;*J3v;gk<|!%H3a9;m2GIUwy^^DX?v<)L(TXt+akL%8-gbLXktHfSd10Oe72;^ zeK3pBVz0Cjo_%}Vadp5OZ2jplIWLG-J;DEcRZmHC#}$!9aD=6Avz#BE(=Q*JTw23) zOPmCYDbPlQ`T8EDcGZUMWWp5aqgZ_Qu ze512>{q0P3digBWm$AS3<0qSF!mhvdOOOh;(l5>O-D?73b3DZQo}oH?MqkAL|Kc^SD`9cnCS2F zIoN7P-?>pSzjPu$$Z_eub+}Ba`*q%l!?<%oJaO$@GO!+g07*>}n$FJvhc_WgeJOuk zr3bI8@PSa`U0fZ44LG(}4iZR@ObVV@)AQ!Ek8wHc@FAYdNZ&iz#mTJ#&U-pz6jpw) zALMY`x0BdSshpTz>Epp6ylPec`Z_>8foDsi_@zEV6E9_WZF%B-0~?Ms3N%D?e_vCjt%CP@M8S`(~>!WbEBdA87F1{SvH;{d=L%%ew`i z$`~S#Zbch+ucRDeH>|EPCC#F%M!H1;YqiM9Ii6j1JPc7l5)+4=7>CjB0Jbk9PE(LQ z_Xish=k=E!_kzT0?7#UFfJ_vlnUCwc%Ynj0UmE?K1*M7X3V9FQa?VCiRC<}S6X!Bg z)p3fs_t)2I{vjGaUa-hFuj<>)D*SlbYFDdwh3$^{jmZ*N!=c+o!tF{%g_}%;nIg3l zpKfb^dGhLH`-of5=GFq$Eqh;!20uN-j8ALdEtZ6&+W%KBRMBDUe(`qw;LTYJ-g?el zHl^Yro|xe{k|hh=vn2B$38l}A^~9vv(0a`A6O(U?%@F28v$j=8v-!t9939qF+%0M? z>WmIF?_GX6jNp$+_M!gJ4Lxwk__^pTo+&N%)x2b_6E84h%pkRm5kQ3+0_M3YQ%VR^a!a(e@41O$0QI!Ne*5pV(C1TWhTKYgPM?@T3 z=Zl$3>+#B~hbl|36_lA}-;ULA=}-P=;<6Akw0a1ntSL*lX<-i1B^gt&OX|F4oYOB9 z`wztb{V#bL3=O>>R)$F;o*-hHe8xg%LBhleP*4;`fmegzg5xkzzb8IxA-)~p%d@~b zw*og7rN~{|5X;)OQ(1oda=Xh-9~GvR(Y6!PqUzs0zF@^c`4nM0QUxdoV5Q0T8Eu>RcEBO0@cmcJ4W!AkUn*}08C}js%4`$n;9IoPLkv6{ zcZ(ZrcFl}79L|5NLN89o(%wBUl=tq_U-6>lAV#%R_zVzJ;%@Mj8vN!*&tRwgwMOcH zkM8&S2P7)OTE@lt!uBBZeWYSbH-IYiVJ zM*_*kHSC3PBmG1##VySN#~!%yU9Hk2C+_Of?&Q)e2&jm z@_kv_NYvau%kxpsDfw8?nNCTS+*+{+H-~CspOjyDvp4j{C$b+@uKXeqVI)IT8B}n} zF_9VC$V(acrLUlG=M}rn|kv6-Mp6Y|PIioSq zL#!#K5GY<#%cf4!QcfNiI$B~rdV_f8G`;k;IBJuOGB5q_9q z7WC9s%9#pZl;R0~eja6;{D9@) z{mY7&4$Kh4o5HZqk^t7VZ$EZv=r|W{yB2zO3f<}bsz%O+mAJn*WYcP$e5try>UCp- zfBL+a`WloHrzq~I_yhJm)rL>O(i6uR3#&)PX67E^m|vcLEzWNi zR5G9bnxRCA@8lRVG<5sId#i>|*Fw|Q0J9l5QA9B-6n;q2)pt1iGr0Gy60Qv3hJ{9_ z8Lf7Rb|^oPV>AQNIST({0!E>Lr?OTwWow>i-rJ4i3>0d5JxhnEpxpLIL5=SP;I~lE zrQn7c%c-R;d)g(k6*St8^~NTlcUqVF>iS8u6Pq$#xx9TZrgs{Vj0GY?N$M6*$S94O zi$3I~c$jm-Hl%CXvRI0Cptz0glDJ=@o1g0GuzocIhtGnKUEC5o`3Yx$c$DG^9|a2u_Vob}*w z|C7uNeDGOrjbte<&|4lP5UZX{9OZ=L^u2^15eQ<+6-tsICZW~j(WqXoZoJgr@X# zN=z9fe_kdtawYzYvu``gX1UVQ*z{Civ;06OX{5;O1rwmJ(nwG6q?LDNLL+bn==V}R zT9)J65)<{jue&Qg_Al00b|>1Xz3=CtIic+I17|<|OEAsZ!H0DXMe%(H&pWA;SY7bP zBLF9^=_*%g7WpHNT^6%8VtWZKc6+OC7B4rz%!(g3$32d8R^BTZ_By&Dttm)0CiOQw z%NQ>Wx+i!~y!4@^OI8`&aU5(uRFWx+9Z$mt=5y}in1vu(w@yb;=g-u}FsGwb zdK{a>ZM?kt<)yqEw+rV|P2mwy=05)I2IsM&=wjC!iFYL1?zfB8l{MWNE4Ws??;V7N z49y(P^ay&)i`JYL*9~T}WAucwoyBxsH7#$v&b%3~QD`1erkspCLZy9Q^URnz6P1(V z3#alxVaBMXT(rs?ZRYso=kaUVQMM$I7c=RY3KI!i;UFQM94Se5QEgS%U|>?=Oc1en zunB36T-FQu4B~1#TfedDtPlAmowt=KM5 zJl9Vl3oGk(oqMYrP1n%LiK_M)cb6JU5LZ#cN&B$-s)I~hPh$M3i3~29iDc>B@PYSi zRgi7vF&36|E^BRafJl$XoA+v4y19dtC(Mvjm9H2Y$iXWI?ErO&fURum@-%In-9|;t zlhGdEcAV5V77)2d+P71d z*X`ZMnRv|8*&@U+x0IgUNs&D6X<2x2U&a0Gi@o{0d?s?SwX!H->y&xUHi|(t(F%rY zyPBO-!#&0HXQZx*`kCogtAKO-EUi+Cwqg7^)9m$z>-KG^vcvW1la>LJoWYbvd>i&#Av+uBCG=+Ae}RhMwC=Lpj#{^3t{H6r>rgu(m zS67Qz*xn_`L!z0R>3G2=#s9$s0IxU%{Z$RBz+NE3)0CXIR{*#luErf74DuSWGI&s9 z>SvBBN9~Bz4g=b;iA)k8MH3NRpIS1X?v|)}=jbazoB8BVhP4)0)^Vv-GWT`Eg6I?i zrzcBSOtT`;H+mM%1&X<@BmjatiObuqYD1<@)L*YvCLEhOM(ruZY*a$}CC#@Ggke(y7CC;rzv@;oc+{`U@2CGR|i zQWm2GP1s9sUnFkp1wujw&T2Y~xeqe1lUg*A9kcO5MW4z)Wncs?Zw{T5O)Df6 z5WNbP(kUvDr!7<4wWVl`t%Z`r@%cs;iU78}x=CQf116KIyfPT8S3DnzmqcR0toXZRblJ@LWF8?Q)pKc${~C@AgFw1xW7D0 zT_(`qBYbhFg8Uq~dg!g29<5gC1-kNhCZpl|OrV+3z4$#Ni_yTq!}lXy04L+hOhSv0yN#SB0kayFGcTC1l`jEmRBK+LE__y0~D`#as2pr=+;KQc>+? zQ4fxk7$tUs;;0!mmbvo}#V_(v9pi6i_k*M8sa|Hqfw)I#_qMyxgllWAK3|d|81+vb z3)R|CMR%~SReQ4?^^UW3B7c9A*z*;yU`9R8}O0;b^w0Amn3Ze zp<=d{p6j}+F-3c7fntPBB86gKd@fHN{|rSvK}9zU?uK=zhe}}AD3mXCd;Wz2;}{QL z@b?{dvOz?!-X=REjahIIhzv$Kj%j+Yrd^bCnrY7s3KCwiq{1=)witOhwAf{ zuV(U;MnU|#o_*J)aqzVUXGqWItbY)uXw}o1@X&I_!h)yHOxUN-6qS#Y{Ll-jdX=Qz7qONAyE&iGFI_=aCz2}Dq;WmR(D7MzvXGF4hx)R%xa$Rziw$l){ zXYSw2GbR;y1O~~&W?dXM`PQDoe{|x#{p7c6|FdmB{hf_`aoSp(JdJZ?QqvcY+O&eA znsUXL5lPF?`S8Um!pz)}rh^g2l^*R&dYWX`%?;N!UtxJ2je&2$ZGGPRN5;XL;v8_8 z@Olj&$5bk$o*1hC=1)BR?$!R6D%0elijTmzNZGluR^oE< z(4ifJSCN;l5^yXCdfPxJ=bCS<$&Kp4v?Y8EPW4SY2o&~hKc$Q)*^ zrV`2MSa%XW%RbB~zQ&jRa$<0j6iUuUrN~$M$NK*R9HHtv)yMZA)@qI(*Z&$ESn!(G zWcei;Il(=|{Em$sL6ZvdVa>l<(lZ4^#`#zL2o9V|oOi@Xml6vRyp{JySJh9y1g>6zkYdPaI9tkBv`q$&uq0hdeM+L6^e zeJ`8-QR-GVclAt}sy}(3_&AyR>6Q6@`XZ;M?&ffcQXZ=x%C|;5!abQZge+2;pcbYI z^FRtX>QcIwq4X^;>994kKbd6DSv4%;4U`iQhI+~rd)<|2XJfA3wJPPO12u_H;8}`3 z(2#Yr%9wnv5HOdFd*50IP$>%+i#Ne7lqk^6oSD=d!F`*iBCMVdv3ntJ@}VOm7He6$ z5_4a2WII-ZgteK0lU(nH|mspiwb-8gq>c2Sv z7mXSA{zG)eN(}?-{j0i2jm1vA>-gfxZUYf3dt?YG7d@ajGN(eSiit2L?au%fs->UuSZA6l_&8Em` zi?{aT*p5u#lEevJdYA?f!^3l%d}QEjH}`z0VlzWq_(9pTeXx7oqs=30`}Q){q0Mw9 zY5p`_3-1a4HfUZGwNFyBB0pC41NE@;G^)N~WojjrtDss==KBjNL{|%!EI-yl5+$yB zY+Bo+ss;w7$ zvIN_F5WWVm9mR%U1a0S$|HlA4Fi7)J{{;|+o9nKIbHje57#~Lc62p3K7Oca4Y)}a` zMV_!?zv?icO0TwOpj?)dR(X+&yDCr;yY1s$%sFjIFh@wcOTKOXmeo+Nc*wWXT_RG0 z*uB+FEz5v=;z9eIsL_dC$$FM#yVQK< zH|vq>iQ$u@gr^AFqb;t>*)7A0TR554J z69m$cp{ukfT^qBKzH-{5q;K4sk>&b6bj!E%18e$)RP<3}A3t{>PFim0F#*sbvS~fG zU}C+=ufclKa?f(l6}qRFYoj-@NH?&PS5-=4heO?BhhB#DK1H|Sj_#W`C0>epN7{pk z@u(NWvMpy*ZNCXcM3W%!t_PJOE}6mH`G6_U7b$(~k^dMRzM+fyfbelf33K_+>$Rfk*i=;5jTJQWWq5v3lP;lM04*u9OVhnL0Dk*yqYlXR)!ry8CN7 zAGGx+Yz!Yx_dcxlK@`FjhpD>TyXbFdunKB2<*THG=DxlJ+WPKgt6b`AJrvVCA$4OQ zz?6yU_YMv|BzEEfAZUo|y;m!-mt`N>t@JW0S81|ATA6~aG6X?Bg8IO_Y-bmn_ng)^ zPng1zV6WP>ld5iMDiX^aE}^pPv5ki*=PQG4gtX`od?F4~WUFWPpDgK~*;(o6$(%Bx`sUK!e-c+CN{p{Nqh|H71OE@X=&&x-1vk4 zEF8YDmpttLHzK35q7L@{LyM$9lV0|FGOd!Glo|}(qUDfXwC2p}ChvR2Fvq%$VTGQC z2t}q?CaQ-W##b^QHOt-zy|3W0ZuK?TK0Wn>)UP1A{DR)zLJxJ_^bS{>N`jlW61H5m zphpkY<;H3@Bj`b;$6m{}L=A)Kg|d5OD>2nh9W@`e+_pIOMe|yzimYspOCe3=L~dV} z71FahCf{fBll4d@p%DfuV?`yGKiDtKRa6*(DXGZ%`Abg?bhc~j`6XkyGq<*w%^q$W zIya~p`%_5#C@mp%Wy34cN1fUb1=+tXksR z7jN$&y6g}ewr`(o{Bxtsh^r{{DI{Ry=cNwkm+K6x)_6_jJP=;YnQN{d$w*M~`nz8E ztgK;JgF-?_oH|eBQ_Cmsl=>G(f;qW$F)Eg5sh+dJ(l=F9w0QQa|BaAkhUIZuBH!fT!hv$s*2bBC zmk07&(FvzFzYY$3m5b!;<@KG1GE=lrAv~n7Tsjq)wFBc*K96~hoyGg`N0xOldb}?$ zE6g;pXJ?qCkZY1?9NRL(MDhN-`&68TQEAtD_L4j6d#7qSg}Hsf+gAJV_;}nnG0$Bp z+&NuKcCH)`CK5pSkGL*cw~TmDIvKBiiRT&COT_%o3J7aNwjr@ktVXr6?s*zWcSac6@mSU<> zBVF)qgR(438zL|EH`kUK9j=ffk4qa?_TfuqLmQ*b!{sw7he!VVu;1VLYeHb}Uv1V{ zUuKCmdoJEr6)bOG+@VU*K@@9oLK15If!g+?XY%Y@egM_Tl#C~} zJ^YuHz_L1Kf>(Z1B2_+zx*hd|_g$+N>>P3lx@IXuYZJL=i)RL~xZx&0a9QWYo;fqt&YLkHhEb`PMj9oFpe5&t5?BIX37^0zC6tb|RU#d% zE6m_(c5H9!Y;e|`U8gg4>K_pe)STqD!@_gOnb(zZ_2?xoOwN+GFdb4vsgdfP#;PcDJd`HhMTg zZR9yT;>|~m_Ms94&&cmTVBZ>CEU!Sq@^;Wo(Om*fP07&tpXBIqC?fA@u;!!lv|V? z90}qVM7}gFVJQ)sdC*-*CuvYdpZ@-f*ZXt|>>dsrrnc4x*qc`XU)REa{WL7fcQup9TFZmUTf#qWNP`C2|S%7tlaVEE(FJs_T$k&Xjmr5j!(Q(TG z6hOgJ@(@zOabbOr+cxux_S=x0oU}XbP45LtzMuOd?NIVJ+uAh?XU9=3JrXW#@wt#y zyVbqDgJk*wV|m$~r;hVU0x<=|Y-*4Ezr*1p8S29Jf7*L$7%pM^pNx&dduF+ZN$gb5 zHvJZTv?mm#l8ILrNLXKvq9o4gXOVp>)F*K<^V6lO0#4aZJNO>?Lk)BXyg|%w9-viY z$p{oFX=8f&k;vDboEOY`g{U*>pAHSrV@OcaDWcrTEY3#qUpJJ;;2t5j?QU16x)*mm zbK>-Ne&U>Xq%qD6QR9k8)wz3o2zTH<>3P${t+&cs$=1py7>v&K9Ic_QTzAZ3ml{Da zF0c>G_bM`orab;~j)C*62j73dK}JLyh2cwAb&U*1Guug z%zOF2^a$k-$1_8SYQZpUW?EU;T?2aAPn*e{Ad9FUCPy3~WNDL8cI)9sOUty=7EfQMay12oOAYaCdiicP-rA-7QFP zcXxNEa0%}2?gR)HENI=zcTS&se|Gm6-D?c0_74VCJbUgXbG`Fj#ahn*y0yH_kYUM{>MR`wK6K;f&jq=vMi{hVWsjul5*jk#IQ@0myR;SY6SP|B>r z+H5L(w1TF-)myYMj5zrF2Ee1Y=X3wql^iGu0$$T!Sk2SvX_qMBXpI#Z1iE>03g~vK;uptVoP&oJ=`akmQ1f0K z<_pF`<=~>OP;2=K1j|dmKh<|Gp5lRUmvngq>Hu5k&6_E|exO=;dBxWzajv?+e-6nn z`<|$!wIhyp-r{UBzV9eX!$gywhxQuHN~#?@)Oze^jgs*%0iP7H0 z;V|RKo6{Dz%U8uJjxV+7i!M3egd z2l4-li+Axh+mhP})E)@XG;pB9g+zhl(kwS4D(b3g_AOlf1a4_&SD zoZMxfHm-E4Hz0^u1&0bXF6vq}U2aUlHN^DfUO+YMm0xKXT^zZVXi1H}?L?9L$Xb&eNwX`@#cQy$}ix ztTzmNb)~&qAD+!SCFj$#o+Ij7{>IDLyvx*azotzz{pGmnv(%oo-`&bZ&9|9J`+a`% zvB?{~J@acy-wr6bA%lh=W!qFjGcsgnLUs%{ibHJyZ84&1a!C9WioyJzrTZb=^7k1c zXK>!uSNG*iL62TIP;g>zv+j$@gwM;nOzhQjs5DNmeSP;KV1((NCTf%2(KN0#mp7*)<@0Sv5TaA6L4F=-_l2JeHEEybIltfLUyL$h{;FQDctNLs z@ec|lhNGaU*+;6Z%rWCgBeDL|I5^b!3CglcpHk@m&YhT-*nNDmcLz3+LYE1W^dkC@ z;ZDFih~GdXJ=mglCCWT2AiA#`;@=zWUbl4!G!4vS!P`OlM-CFWGCKY;)nx8_ZSL*^ zfnKLU9}UNX?Agt*F=7aHgsx__pK@A4oP1k#U0J)(6&Q}pzS32Yn{$K}svodun{DZc zpKV#HXCvyr$4YmFb!|}q+NbP6mN#N&ET1M1Z`z)nlofULUcM)O`}sYwuiUJ>52W7; zoMaRq$fycDJBG_UAxS|lP$XCQ+eSgmqNc+B!uh@S>Gp$6Y>Aveb%OT` z?e6;L&VbYHBI3D?b0lA3IWjthVv8D4Uw{ zq1d>!pxL3;%DJkoCCS=fw@HTn^sf6FbeDSicfa3WqMS_V?tkAD@pO+(UArV1R+a>A zOakr^`^2(Hto`G4!Co3-h);nP?TALm?49y8&0MN1ddwvzO0T`3i`Oo{(fmB2S7KaXCV&-2RebwY1QWY;BG9$*mz6VbkZGlsdMiBrPiwl6_IKX5hdhCH zIN8gOE?x5U<%EpWnw<1`;xcqz#>V9aD-3SdIj8%5h&0DSUx`)p9Oi*7(TBrsxZ^r_8;_ z6FDT0epy(JVSVpRiLLfb=;0!xXKcE(uBoy~6VT8B?MD;4<2B3MpE-!QC9b{Xc-ZEr8Fes4nyT%hj0K9DZ`L;Yz$ z{(Dz9%W)>qZF~FJL-{xg8){7>)k2KNoRZDqHSnHWnU|A_gmp1Di{*$r6R{LUHK=7c z9;<0BHwc-q>^&?{c%OEMeDP<`gRIM zlg5G;Hk%H799F@xUsPvO#+GPe{lIY_#)wa^)-g+HUzdAjJwz~LN|b|g#5Od$iN+p~ z1`5Pc{eA*642@p?bwa08Hi<~T-B&;9b6lOmxK%nW52dYdMM*8{*k3>_wbaG0-yo8jr_t z(o3s6!waWaH#h~}IF->;LNU8(Qh`&L7M|)ypg%f8dio6-GkK~REWMOhpwVc$F)`!f zHyJPE6Vn()1rE5NR=i*aRq0%~r#~a8R0fY&OO=Kz-fm8`t`Yn4ZGh_aq<}PqOW-HH&VM6|dz`Z;FLu#z`3o%@Y;G-s;w4 z>+x<|6Z8Sd^g1$Ae`UyBmT#W+=DNn*!aO@8CEnp;HyAqV&uXq9qLi&XTN=AKz`P|4 zLXe$AL0UFpe)GCQwD!(KRyIg~H2-Ck@o-YB@E656sOz$|iH{Xfg=-}KAN})wAf5!+ z|G|=>*@E$$BWAx1!Z1Wh57DiH!U>2qaW1D#%rigULRnT=AHD{M-BntoZe}C5`l(jL zX(&I5S6h9nB=s0k)M0(&pra+f6}8GjPXQrj{h{NN#^;iW^|2W}Z=d6qpeJmvQ=-5o z)fNs`@k*QJ<$)KnWc;s5TQw8?CzQDt<^@wW9?9)vj~8Y4_tXn@VnydF{lQS`#{1j5 zwq~(25y*u!c96+RS|t*Ue{b@kT&V5D;AmuOE(RO;1_@J{xmQVkZ8=!)wBmMY_?~#D zET8E|vjq?=aTPla8&=JFG_LGyk36v;^~jLHeU(845*~_+g~TC2{KOVz7jT9jCf>)W z;4jpC$r$wZ-B>P^+if&r!HSIV^0!ao!Y2tVh24jZ{M5de+zMF5g*9LjOUQs*xOCOP z(mculVBhOc6HMQGJyieV8*#0_^fr}`sef?h#3`C3V?7(s?p3!Zk=V;HOW=&)W(kdO z8fb_L4L9tELPJLR7ymsF=rpKuHOA46H(>p3OrgiBm6IN6T2+&ct3uC_+y5SH|3A1Y zh!*SWY6XsMI5W3PMlDUi{wC&th+1ed)Y`GxMh)M!aY_}2L=u@>6W1nRtu2mY85+3P zlO66V?~vlXeMOQB(5a5>+|8FbcBtx;dn!4l2#aO)+l0JiM%IADVsn+3PNWHr(YM!6 zq2T~fK1Pu*jGK!Wt5h7;o{zLFB~uAPV8ZI+1P!4pGp; zKnl{Mo|;wmzAt-B?f-y91R9}!9t}kIK_x3tB2uVhES&at2EtujglK%EgD3meZ5RX1Dufa$N+#>@vm}c0KmMnI zI7ep;zxizo>v502Hv~crWOG9yCIww0VHSXNPMa0mL&QzHd}#l+5wu=A7gas5}SA`4=I>~w~afGj)gH7t4OUGUAmF8p=5 zSW^`tN)DAI<3cVIJ;0eKsB*25Q^YncSRe7X)cP8YpydojeyZKQhVpOxvQzA`j`*mK zBq{pIIo7>Q=;6AERWxnP4UupV$tYj33%>bAqsvJ<^CrgdP$zR4#u1^pH$T;o3+#q$ zQnJ^fWcnkd#(-OaBG>5#t~+jps(Wj#=nLZ2{D^l^2+J8@5?bpdj#n!&%6lC@m18(# zZ(Wx|IkjdS-bXTG-?D)+l){jUP13md+{UB)F`LUj9oLeDCC5=SS$M=8K!%1UO~HdV zdaf0dw&J$Qnh8YM==qQS2NXz7;47vbi-L~EOdF7Q13{p>ayv6E6JuixB~;%)uHS}R z8dhF_Bk#g~EbP4FfEQTGsuj&3MXg3x$Qg!4ZqhyX6))3qKDRBjR(<=mVWBnbmdiBg1x#UmvM(2Vm^cyAX@wVaEUyKnvPr?b%oU!fEi;A zOi#t$2CXjr+0$q7gH2x&7(`;s=v!yvan`@;`_&dvgFk*6P{~?g8pAVMW}5;fsn4&& zineBJy2SwVxR@oOsxCF040%IG^ZW`_Gc8ja?$mh)jrk&~T#h^1+4)Lv{L^@JzZ-U# ze{NfB(CB^Ky1djdnOtF9>sydvKIC|D4A&lni%Dc~|BL?t2<&lpC9wV^>Vv_`?M7q{K=w zI;)o5kyE>*03UvPSdP}}ujR~H#I>_b{K8Nf3;i@MZpMvztrEWmjAfNng)4#LP^bQ- zRwfCjppIW$U_{m}aivyV-1i10Ty=hHYdJOdZg4$$qqUxDa<^-&)!LS3vyN8P`@rPM z*=e}H=G$cECsPPx2K#Rhs=7&Xy7nVm*%s&~jIl(?lcEw2%7zb7YR|YVyH(AAlt$8p z*elYBuo>NOD1PNA3#P$ec}3dr0_wc|i@Oy_vyS84{y^@dCeLl(l!lfuC{ivqomGxj`ZnWs%U!#F z{96JsCFI0ndoGI-tLVV>?`H15*%M9%wzL(jsM`EFlED(;c!;#h*pI@1r zc8fjeqcNs43MR4PxN}5vB)QutpydMA?tcn8%+4 zM7N59;D&=3`=7aA?xboY9=jDdSz^_$cD08;TAy=4uDv+%3X6(tmH^^*rx zGF03Oic@LCg*3g8@5|D2I$&X|P`#|nMw6fZu^$)gERnO+T{*J-f#8`t!Qt3`Yue6o zD%FoYOX`o}|3$@BK<4&~bZc}qPecNC=nNmZm%PnbIlqqKyKMkqn+9Caa(y^>=fF|A zy8`YZA3ne@(UL9wL1|}L*YJg*mZWNGLmAbI zo*cLX3Dn%s!7BxWtk5qUJ%$&~Y^l=}-`B<7kV6CaxfMK*`;mUGU`i$^Aqcmojs~}y zYi-r4Hw`M4w|r2v%7JPu4JbWtZ#g~+&t-?R(8;a5n28Wc288A&DB8%YTid+d(z|a` zG$_-IggbyKE{OJ}^qswl&5o05{^@)p7*X5a`-~`yP|q|GvaPYy(u;fVBy!0e9(xhu z)x(#F>zgLgY^Ub_^zG0Q?M>@`TV<#OCpUw*3CoOktClu9h1+b`VFpggf}+|$);VYx z+nO=MzIws%yZ#<4Gc$iUUL~83B9x&_fS)7|!s_ACi1t7H=L0ePMdW_>To#kp(>R0c zACu)|2|!G~Q4BNBk$_V)--DOhfXj~ERnRJ?uk_}RO*Oe6G=NMo@num_1FHBRTjPqj zVmxrZZP+%$x-kuT3x1MqyF0f&4(m(YoTWRfhaUdW=V!A3e+0FKuC~?y(D#n%VhfoS zfBK|S;5tQY$@X%bJ(hE@KITS=N#%LN+!}N4z!Y|CsGmk`g|)LXg*x4Y3tD(u zM3bsNdhvuLQdX$cklvUq)h4#VEma;uEU=B)^~a1_ss+-m4Y< z#s6F&`n0@ z_nN0hbS^6gvuLa)vQiC`f05E6>sMUoa(f20fFu@zS8E*8x!4) zX&kLI(V>8&!lPk!nk(rbR8&$@+CC8Nmy#d2(js(HrI>#jxr>JqQo=IozNvU2HHnKs zZSz-3RU-|Z`7%T;`M6l4JopOaaa61#!tlV&VPhO?kNfp%BHX+`@1 zEb@;q;2&)H$Nw}CQ~Ft`#`vO1B%d6te|B>q=stTMI7V0t#T~k)(+aDP*>U^86Yq&I z)$(Y0k1#yGQ6Jfe^uzof!}~I_<8*mJAC5X^Aa;6Q7I2Z6tPFvcEYpD-_V+%HRBsy% z9XM8#bQyW>UYXe8k-z0IYCBtzxO_^=U1EGZA(31IL2NTT<(yqN&3%mz_~8^zbUB&+ z%coW+9GRm`-8Uw~UR+9Wy5vP*A4K-hHcM*CW`gfILwhe|=XAJ`<*Zh`!uBbVaOeH2 zk%J@$`#AK(ZwJpLg+3$89-}@zj;fc$i}#*MjZzJkgNFdf>3FAEjywy@);<`?4EyCgYU20Xd63W7wg1ol7dZcq^n(YiKb$yYrn(3FzYWCHL{hmp z$Aye)D4;dCX6oiq6Awfj)o3*KrQUOSbz{lOdbZPU6x+;IdUkAOZfWvvK(qN=Ic8h( z1S#xvM5}e#SV@bLk{2a8=p~m!d-r#cRIbr(Huq=ElP*|!SlAkUpUiM-gC}g7*@>9M z!_-hu9RI|NqP)mdGA|sMT1xea1WQXZx3~~F4x7coOCOU`EvS<_6ghKjqBR&V1y1|+ zSX6z?gp*B8E!q_-b~cx-u_6<{>Sb-g7vQsBkJE$!J7Y&hd#3zyflhk!ii{L9zujlA z$rsAEx+6t-Qf4P!LvQ=F=b9d2I!(_4QE%F6xvp|w616`9`x8`A>vx$Sg&%&TDzdE# z2K|naRva~RO_e@BKV?CmS!r0LH`?`)O!KDB<_^g77In~UslolZkR*?oq!ia_$vB&T z8$lmvO#N~U)ZwBJI{>FD_=(;x*hDK){Ba@~2}z&^s~cN2HB*hqb3`yS`TxcLHMssO zKux`**pE9v{32a`Ju5cf@a8K;_!rQO!BXo1zru9x%RHrK zB&4Fa>7I)33A!XjWiFvDniCFrp6|3D2^9`OD5zHA!fR7&yOuWOTe+ot;IzL!j%ui8 zpIx7lltA0R#mAO4cim)6xvV&L6S`j){HEZ`YTVaLNUH^)qnAAxc8lgfpDp&BQNl~P zEXQqCtTjnIJU!>GlNk_>LA}S>klF2XSlB{$=D|EH%UE#=J{k3=-kln&F*1wPy6cOK zzF_ye(is`)5uk&FX|rVRUwS2hZ3ln8x7XXVv|7);`N2m!{xzZgXwF^Ynk^eIYg zt&;YtL#9e}dQ?_H|M*`8Vt6a@g!jZo^;Dlam-n;~&eeZ9XHoJs|E@dG<73Z8)w4CfRU$xrX*EjlblY8}vAs+0V|THiu6;6 zG;0k<5qTbuF!V1-1%r0Yf&$w0Fs%-(SqF5R20y)ReGV90-)kAF-;3=HM2Ml%wt#Kq z);uGDtweh&UIbk<^X9Y+7)hxoo5&J43Z?DXW`Q&PhFh`F=&s%`;U>5x^GlQ#)b;LI zo1u0;hdo=>OxNm8mMwv&zLtvvLrnJkmI7onD}XvCBf6R76ZlWoS|=V0)t39bOe4=M zf}4o!RrdrMWPqrW!apO2t&0xETs%F_%Wb_6+{@qo@qdB9dJY2n|6CSzg8d)B{miL~9Loq^`f_);tA!N5ko)bR$>O8w z*N8g4F*v|nCDqhKDZ*;8`D$V7^S#GPj!C<`u5*rG1Z$#Yn)mu5dP4jf1yIhStSjUI zE{G}+#{E;Tp>N$H}n5 zb2@ct$wO5h`jL9ct;awH-R0MMhmt8DPR67dYnM{xwLNu}tXmeVKEk|?`)sdg(9b0+ z#~f>gQ?F_AMG%~KENM3V7quwi2}V(;P{QH;J5*os6d2)GJ5xidE2$++J^O$B!TayW zw(8|z{X=sDo!c7=@ZHk4n|iA0eWl5i`Sz~H(TPy~aV|MH8yX&Ln*TrTS#i4!uFL`{$8niGnqaSdpd6p(o{EN>&y8|;ITQ@cPS++g88cIY z9>#i-XF3Tf4>6-#My29Ow2}#73|=UX$>ZHOX(=z|>H~p@K=Df52W<5)F za-Re7DP=ya31yGQuf7JdlAN^!v|^)(PLH}tB( zrh%B+2*56+z4Xz0XgY9D`Hw&QD282upK{b6O241G$|H~f`PK^RAWlBG=a1BsemfN= zv@$6+w}wJ#HPS}>fUgU3@CpVWk2@wq7P%mwha^@7+4xWyK*IYa=%u$epnewwdN=B~ z52}ASV`^r_8Y^}c%FM5Wd~-{Z(8+`}+(Jb0gLsr1QOT&LH>=gMtcx4b;@j>@!D$r8 zTlvQy6!=YDU9$$P|M^K{%K_G(Z2Tyvt1=dQtJ;F~k{L=`|-X_fGU_U_t)h8$6R+uyxNx}$d5+>kc+4CE7qYx?qLYJ)4PIzU2ful<+ymWnh8d>7>1n9ogc{9 zL5w&Z6GjzoNhwA zfwSRVDp^YYax3(8J}XY3Sd-|#_+#;y|MQ>eJYuR6h>>Z#>RUZ@2OZ)Fndo%1trYIv zXGt|^(t;~D|DQHUeXuc{U2J(UerWDRDPYq4Qz<$W#wQ5LhpePDoLAIw z3H^yu_V~9WQ63)}yxdB)dtqe_s)PnK0H9i=YX+62WL9ZU2-RjRzJ9c{(teuD^&UCKi|Yn zYQ+&l;eq%dGdqx^9aa*^G8D4Z{~4;s3jZ(&jPQ6cBleoNP5m-Za1?XoZsdx z$rL$Xmy#2g)&dHLXaL3tI18n!(r0?I38m<=5^B)=@tqk5YE)U%=Ja6REnw+baIP@A@?D~!-xrgJh9jcn8JZ&;v+eUzGz&B)_!saPJ} ziM*PwzS^t=u5472Z_-TCg0jp7(hoy{xi<+HIK7cS#hARQ`=sGzoGWy1zoOFwowT^i#O0Ar!Q+VW;T#^(9A%IQMG-2|RcanDYlO zxOn1XY$^+--=LZiu*k#{X*LO8=f-Oy~^rTMka0kHhrJy0Ep0Hg~N1H?W~vNfH*mI2fu{ z+1*$7PHG2*gwg(g*kdO@YjG zEMWgt^hSPfEONl1tqp#J&}eX=UZk-b6>T|gu|i`eYl*)m-{6$= z9T%k-mP-q!Gjw@}-04<|-UnnOYRW$^mvF&C z01Cd|8gR?=ch$kJl1qnKd3^@Je!3&Omx4J{WMFBL&eC9~v1}q7nmHKgi|>2-=w`Su zXkSw3PQA#s(;Y6#+)RcfVwemH#c{@3H?Z*vWtO5e<8}@e4HQSb#g`+EHCH(%?Ody6 z>z*DRFUm@ySt?Z%j>IfOv=Lu^cg;1(*Dl}vcnoR-?nCS#lv z6bMW8tY4*wW#tiGwfVjQtZlaQE^e1{YdJUr3@qh_Z0Ze0w89>Dm4|nnd**zR#i&(0 zW3Ktf|2z;g)L#?a|5uGR(6)vNv{gq#;UOK z3#eyiY7;W%SQ^FW>S~p8<=^&2ufQDTyBhFKifvGkA0^4)Dagp;hm~D^3oQduzv{RW zrDINiugpd+Jq#UAL{mT?y)*Ig9CJ;2IkQ%acnXEPCmUB30cfN%8?0!njo!{+7Hk8m zwNmCCb!-oP{({bT-z;^jxBbo2wSXUVy`Ai->LEo*Q;G)HGLs~~L&eN(KmS_(_62Q6 zb`q}0iw-{%V|?Ws5e#jnx|c=^mGyGA;Bc+2T-Eyp_ikOIj^nrC?~Uz^Zfl(`Ke&a- z#~r)$!Lw3lu6|>=p|~LF&pNUGMym&_?jz8VO>9DReymz>dm5;utV2^9cFIqe4Iym9Sb`K2=olvpZc@PQNId$EArHI zc5wM-!+fn1(EPkLmw=zPX%CdbFOyQSFc8;MKKv@k@H@9p*CJ8)cZWObVT$XpPNKP8 zCQ2U9TFSUiRm%&mxojAM)va9J8;NR!l7)cQBKpls1D3?y42@H6)A4|=!*jn26G zZ}v}fy`Mos6J#HE=TIy=MUuc%F9iC6o$V(R^03%o6(Wa;CGUI9qE^2tG%NX;UKpNq zJ@2kGe^k~A)g%y@%Us|xLph0e)$RUU7i6&_XcRJE(uPcckHLDtrGQsHxzezrD<|9P zgd#>e#dUks>`2Fi#JG(G>g3;c3Ybx#E-PoX(Q9p%F?bYz2t_k=>#Ty!3hTl0GSFQ& z=sMPr>(&321 z^KbuaoNp0+XyCY~is9GT$R9%l&E1!0(4qQD8|Z2H_S45Q{7`d_zpYbsl^5!SqOQlP zE_u@L3JE-g2gEXE?Na3o1sF;h_b!I~*_21~xG2{UUhL|zBSX4X)(&>;|Q5tb+gQfTOqQ99_WF<@#Ufr2KYsP2GWUvo4+;;c= zW-;glZq#CtTg5fJeyd(TSTTYs+iDu8i|uG7B-HD_!y*zR2X;5Qopi$eREfB_UP<670<|4itf@ zo3lJcrc0Rd?uyUMv}|IOg+~X5LZymaQ5@ujt-XI_l}C#H7d;4*Gg@fHS#(v#jKIYx zW>&|~|Kk5H5aSG7e*vEVk2BM@g6ogCbxIGNf0j$OEvIE_z~HzpB|9`+B3ZWl;;~4A zts-bLxvzRCyC~sv=-B1OCg}HDe|7TQ5Z8ccmWk=Dsgeu0T02?-v99PH$549P9O2>h z$QWq4jOfm~U%M4$+mCI=CY4vt-4BZ~G6!a8$+E-3v@BrR&h5-eJ4jR-S<5l%MVSFa zBWrN45`^cDI<*x{(zxW5aLnwBjbnvx4V#(LHd8Xq$BdAhWiGPm@N974Fe0sAr){fs zR)7!o{r=LjRV z4bKc6vk%-ze0Qv&L&O-=0}UvhS;|8j4yLo}@z8=(+fJXownEfcLs*01SA@vh^6QuBil! zxkP+S6Ay^##uPb)j}Wk!@U_qj1|BW_5Jf&im9{p~A9M@PHG6KHfZ{d4$Xn=5InhLG zBOR)=6u`d3;=jSZlyW9rbRW(=e~Ruo)d8>IGiVJ&$RXg!b7FzxN@)^K3v_Te_@&>@ z8b$4XQY&&w4WXDQik zuW`4mJHNkR5ZJz|Zf@T`AZdkjS1l$SOaeFA@J3Nt=xNs)+;c@itW#xXfV|>`NJ|SP zoU#~;rv#3tFzL9jhQluY7P=}PFL7$>Z37RMx7yZW(KLRy{K<*QQDs&03E4kN*|~X0Ej+6}bMZ zsFv34sizH>pF*Ih+~+W9lu}!PqA)MP)FB@({XK)NHB56*g&wibdSEo!dsYpT3Ogvr z*42@o4=a+XozVg(?NClhL)X>QEUm!C8&JpnA@pdoXt33Lxm9_W=IPP!VbE%@nvCa2 zEeuCvpQMfEiixHEo8~7rt}sA9k=#>d8A^Xf#fq2gOATx5;WzDWSN5It^;xf9Ir!;6 ztCcVlOPHQWRcDR+O`Vnn@9Sf0&KG)j`aq!ghYS|to*y#SpdDRb427H@EzXg&*+g13 za$LYcbn-%fu~Y_W-}MxLCX1*(M^kN5ndPRMc&5YpNTX%LX3o_iLArDqRv5qj<635( zphZ5qp?bP*?BN%RKqIV^UEP-0Nfn+Y$xP~#$sa3rF=l0kcQwf8wPobgv;*P;?sR)R z5;Km5^*Od2(`HQNjZD5v2kkW)l#TGboviofk{q=XBYl7WD|_&eYY2MEQF(>Znw2Oy zBM#I0$NwY{+uvRj9RHoUbyXZ;0zkiXuGbwBgFAiLPh&z!v?dzi4I(ywxMW~%no5R= z=AYX|qJNZevL-oFi(n7|Yf~vtv)XYX2RkP}Wi zw0x}KG(Ebk%;CzyCP|t!IRNya>-LKUnH&}slPV;~ArKZrSWJA2egIZeaMDdxI2aH9 zS3RsOPe{gTqNr0gZi(Jj6n1hnmFzvz2!D~7NXNl9;^6^U|0$cU2V3`Vh^X>s-;GN1 zspGVzD{OSBU<)%3<{R~d(Ew@VWRW!LMU+UQqD4x&fO8aCOks-fSm?pLmQAm_%CnIV%}XK5qBNoiB!mq;g{i1vis=agKux9cPk#85>pk%$ZuKQvHSk~zZhRvw zJ+?$HdI|KSgT=?w0F!1JGBW?GK$VW1#N)adq`m(&mE9Fufs zX%{oqq`S*-7NTW?Q{WSCb6ep^P!r|jWP6-<-z#{eua*qHP1Wuhop#yU^PruKoTE2? zH+ZY&Uvh$!anaf`D!DPYK3);uQG-mTk~=9V2VALEg^l#6AtIWx1)ctCs!wrLV}5U2 z&}IlfJGijA!}BD?qFpn-xEStX}h|8;E1TNX;1U>3;54J1b*RsD%Tj| z$5F9h5VDHYJzrH~PcIxq9Ku|*R~^|9fOT=<*fJ6@>B3ryLpT*<=E6L2@t?rz`Jj2K z&)q%Qb&H0~_`5o+2cS>mEpF;DE=iJg0UnyuFe<8)8AO)CNMfnfG@0q>X%vjS=M;@4 zD=X@AWolTg;Y+{fk16o`xSnuHzi(Kua4;!Eh}+OqPRQCSU@j>opGK-;UHmk5ToLf^u+dx4W1S=Dd4?l{IXXvVVrNC`KlQ(t5LlOB{`;3rKyd#b(*q=o z)bBMQK~*;=5rD%vKon~vRw+W10aT4^v9BZJTQ&R+fBrUm6e3-%8M}8G+^{c|MDI;H z7%Ewrp|O9^`O#-T2R?>#=7j+QQr6)k?bcx|e(ij3n8cB09fyo2i1&fwh;p1<>yyX~ z6#EOl7dK&4*r=E8!kJbv-j~RB^7Hvl!>Ps8C{>SgdRS|GITOs{8#i2vcLT=?wUcoU zKIJr1qkz6-uilTwT1W7r^`rH5$NBE@QDd<(WQ#-`2TBiME%l4NYBAD{R}EIC+n6q) zf*~R;9IKLe$V^$nM6=)Pfqzkflz+DAj;WcSM}OF#)8ZlatHJD^$n49utM&sBh;1~K zl%!C$VNS!lI2d6VK{^dlQOEMBfvJkF71yk&v)6*LS?(YbSMDn!{sST~bfxa>YID}U zgkhammmBHUznbIMk_+~agNI_0Dh;d?z?q<}Oe=RerlohWnZR)Og3fH(`i{q@UBJKi zzk&Fc8uYLJwCS3e7M%Y9)|hl`7m1cN%kZxbS4>%Fl-X2F`63bH5#tpr+yr9>TNtj2 zMZ}~B4}5vR*?L&Wyt_*y$Kij?BPe2O7Sz)5yGAaqB#?^tzq&RV|Dx0i58`OS`tA9# zs?osF&b0~wK|^6EXE)d{@avv|mgp5@KU<~q80sTcICkS?ki66sarA6aQ_RK{D360` zNJwva#*9rl&{D{WjP?_ba_VMy0pByn_=G2b=oibM5yQD79Towzm&-J;8VWrCbocs9 zUY4zCdl@mZY@0a|FP>!F&8&7Da>6QAh(rTD4~O~1D=a8yn?XHjLLKsE2VFuZj$^+! ziO!_ez;JQ$?5|2%^g&P}@but(V&#G0P_Fjy4V15YsKO3Ap}^5=7ReyM(Pr zuiOFrUkuZDbL8Q`6@tN4*xwvwyl$Ps`YdWKO9=+!Lf7&5|szZBJ`MXZdW zK5$Bwi=E`W^a~D>UK@QwqmT>5`Ib9js)VQ2hT<(k_ICi0Tw&ds`{ zmkS8(v(G~%ClSgAB2mykmY&W8eutgaj-39M4!(KB>+d$=JCv^cjij`+K!JyTW;LOS zU0YkPPG3nqBjJl0l4WKcvCEetdw?Y<^cUp2!=bxMgq3dq#mCiBO9MU~*2+7@387Pa z8g_yL5T2ieZ?y;ku2?xeJE#2B=qj3gOC+MtSTrQIN1X!e_OLab*6l;BK3_Ju9pLY~ zu&9GiYlyYn>UbRRP0hGAFSd5CBuTGL&VELL)|et=K#}T^ut|wCiL>Gm@&=JnYAT|Wk#Ml|=B}>pT*p5=IC^Q!^gd;;;`BNS z>`v9$455`KZMrwf*AfXE;m%6ip}NxmhMvnzDKEaY7`md)7r7C$D@o#D8S@sYlKzdh zG&Mam89Y3jgrP4KkiLsX`@VFS3SSbdvUwck*A*Yo_is-92I6<`d%si7N-LSWzx1Bu z>(F6fG-v%L5jH!>oarVB)2hJON*Fq-7hXY2u`78j$y_|bA^yO>Y8D6RQ=STInF>?q z8hh*`y!f+v-T840{+p`-y4AThb~mY-BdzS!!i6PUN#o>ka;!iIRqHtH18zrjx-D-c z#Fr6?!?IayW~V>^V#xlU2n_`4nk?`7@ToZ&^>}G&wd~n)1x5BZ7Cq>D%P&^@Y@2_c zuC{ZuWk#`09h}hg=A zd|^xqH7V~MBs0nwqH0nrk*TYOCuy}}1ym-xBU^te-vUPvqY;9Sq_Fk8w2I_=ov4D7 zOeD#BZ1Hdu)1nm%lo{>sj3k;(AeJC8I9MsmH1y&`R)t<9Y`bF~5dnp{*F59dj;cwo zOn4Vr)?4^P&BU=Qd?l(#Bvu9wAf~i6gN<38?5Qgje4pjblKE$C`ySd67D)~6x2F_?|P;4dzWXzUZ8UP`79IslaqD2`T(RAtyB>gBPF#lbC4ez z5a3w6%FaE9LR8%3h~pf;!y!HR$`6YOyU*$zk>G6JFGDR+xvb|&y`#UZpe!i^o14|(yRsj+DkTH{T4HJi; zgchI49WC7Yrvh5aQmyybb+3d}7O1c9QAdUC*cN-}kY9;_^V2KpHhbLE#~-kPT0uncP>S>7%zom)c6RFnae| zzuTK$cO?Z}bYCZ&R4CF1=}cZk(?4$favSnTIDWX8N}Rhz50CshA@zm4tH!{qXFxm3 znfM+r2bPy8)WWWRVE^cM|CSW1zpcDxJk5wzZ^v-^f7V|of#~yXQlpu%2Tsh??RP9K z-mQ&|5B?mM)gEOYbA|IWc0#rAg=$P^AK3rb%j#a_A#kZf%bS-EPpVC9I+0N-0ZcUlTy2L-M!PUrA_v@5B9w*_HOGjU6wNhL0%JZ5z z8!D>GrzkF2#B^4_H8+;_evOe>cC>YE_td0{cp3cP0O1Xp1BxZP)VDyz;Ns&NS@;5d zGwN)zkO}IvpBAhuR(EJQV$#TmW>COjBwLRE#oJj&#nr6o9u4lU!5sp@-Q61+m*DPh zL4rGtdvJGmcXxO9009C7xa2!$X3br5X03DP&fNV^@2*w5SNCtfU0wawThEiVx*8B` z2LLE5=J!b8h*G53M}>3cjyGWA(?tSmo6{Z{jQxV)gN%bv-CO9!7Evh?MBC&BlL45q zyh1MD?cFEk{>1;QA5M<1_)$SrKvl&F*Uygn;f<}I$98qEG5?PFpE-Hjr6rT8EfXi$ zBVhv5hcp;fDIkR9i8Ig{)s@JrmHPO_T%JO!1{L2zl^h~vgI@#NICd=&L`zzUc?$T- z(%-)mtj^TMR5b?3BB!I4s=sp+C}6}lI&al>a2VS%`NR&tib9!^s683;Emwr2LIWjD zCZ*nS)zGPko`2ng>$JZ7r%X<%xL(86y~n-kikmmeQm0kAj?R4rSjjONCjYC{adEsw zewqa>t%7~c7ch5lA~YaYq_Aik9~1b697+Oi@qx(K@cVpGFAp7w{@fb-w8-yarqDhg zN6TyyClLso`3#AiQ8+n$}Jv^>SUolF8f_BK3D%*nP{s>0*b$w!9NyUevbjjkcfh1WPRC9`A4M7|+5zIH{o()Sho@{HJ5<1! z>(6lf<7Z91{M&t$b@vhVKSTZB`|Mzmu>q}`HZRsnduf+WN<|7rxiSDf0lKv_MXREK zBrE3R-F+@Gc0#?~Ugd#Igy7C%M+3shhpsGRU@nS zmG;*A|GTQUiB7@i&4yyi0Sl&%GgB17AaH4`JDnoE1pG8 z^Jv)y;F>njN@d-tLGeNR*~G4-1zz7v)ybw`sl!ZafmD+Z)QE_NWAyNM{-lbE75p}(A$0VA{KqMkul04!U2-c*w$)hj|DEtZ zI5`#vlLw|{|LSyaBRaJJs6*w>ixA|cc{q4x zJ$eabd{=aJq8?aH2{>sy)F7u5OF=h4*A3alC*S#6$jOVIcId=&LJA;oRe`!~^v#ZfU5`;b#*A z*UU1{!pyLa%G0@!j&nEy9(1O7HnjIW5|wQ>TL(6HbndGfk*fx>wQ2b2KUZ`MR({NN ze6&NjE$T(^_6xsrRNn|_WXKWA^jGjKnS^vu!D7UpKqn{>oBmo`7wWKE{mHsh^oxLL zTsYO1HuG2CySMkOsNj-SK&r#nXGC>-h2rfZqe%lMnlAWiC-?es^MxpEjAdB4vZEmD zBZhdUbgXbnEA0X7zwyTzk$+$Rips4mq34g}uUDok>(Hz_zAFnJd69w-jKMYZ{Riy- zy(u0Hpv~B{);^n=h@zK!<3v#k$@@7lT#Kp#?LA`=H#tDsK;6hp&WUhk3$d z3(X3a&4X49Mk^xoU)fyFfQ{*w0_Rt~V;&x@Rt~)wbE#(AhmgBTR9xZB1aEd+I^FUB(u>i?^D!8+Qzw3P(kmhYHS!EqU`zWM0*lKMCOdbAJu} zUe7eXj$2;tdKGC3h5|=HRslwMWCiRK`T+RKOvF@guZem12WsOS4IFYJ@SWu)3zox$ z#rTB8l-a-LpYQ&In$nu*{O|tn6@TXc4O4DuAsMQKA_5>uMS979=ll;(UZla&Eh*y=TWYQ|O-~kfH(Pb(-gc^)7U+ zjs-l47{he_Y{qstAGn|=vZ6i8eO8m67E8RBxSkj5n&I6UWIQXw`i)QH9OL77vO^2~ zs<-%5j(Sj;Jr5D{>6k?~VpJyW~~QeBa)> z{H6LmUea*)x0xEpT%Ubu4aCKTR<#xH_Aj5xTrmht#}BmGr-J2@O~gW2S43TG_mpQZ zsoeWy*`XuGkjwaX`mZ?qadKf5~X3s5zO3gUpkP;v*g>Ht@_YU>x4EE%{XPD78w;=}Dfi45-4irJ(!`^*hMKJUEIO{LS963e(QeJ6^>#`2!Z4^xB@_ua!}BYI+>hHRLc*{Q}cH>AwD_V zNQ8?lqC*#N)-Z^KDj}l`j=%F+Xszu494>$3$v9j+2oi}??Fz%5vCCZA6I7=7@$x`C zDOcMlV%Q&g!Zc<{mWG7!%RZa($Ag2YoSE9!?=!>R#V9Nel*l3p+tg7HV$F5qm4fPH zVU6Zu{Mt4|X%y<66nLtni6(3bac?iGa|V>hcb2R)_*})x1E;bFnE;aUQDFsYjE)>A zFUs6XeXgi!E4Z3s>DWWj4!x6g4SyYLm?kLh$7g(TK>kI^s$qR;x@x_06Gg0B(#?ds z`og=N45Gz$^@zt8k&2uShjH4Kr1=^1iokvcqSD+|X#-+to?`LcYL+IhQfk3O858Yv z*?hhZ&N3WeE!k z;k4Ykw#K!!hM56+%+iemLGpn~z1q_sd=|fg?{u;Z6q&Z@lWSafXepRT68W@I;(u=1 zg}ZJ{(vi%1%cp7X4t(kSh!Zh_lA`6@QB1X%k#&`tnwpuJdi6N9*|1o@1axMrYcjA1 z{cQzSLV8kW6>pea{(Ochfh49v;_QGbE7@pb>>;u=V6`~jL&yppkDmI{8DN2$l(|5o zENP4v{xTG^;8T9E2@&L)>!l&%c<$*@{elGXuj z);(m<2>U>}UkCA4Nm}?bdukq&jzMprDZHPOC2=f3;3F)hES-REa#Gu&scvTK>Q_yx zTj^x8)PRM@&Bdsn&14lHwe83K3XmHun9obeWKwz!esw~Hi8U^3vs%=X{*6CAG^=Ff zd;Z^&^4RBH|0)NQ+9z^cI$d@@7-1dkA7cKm8h@MGUR5+w#mSpgfqg<0OG!b8u@B6( z*z=>e#7Hd1|FA=#ENY-M<08Fm4N!g9-cS>o4QO@DaIw-aHO;o@1FsWrolCWvq@Ngg z7lvG(mG5t@+-9M#lc1+|5om9I+Hlh`!%*Y+q)~G#1zICkk8ALpo8wqVeu}>sq~|!p zzU(y#~Sfva6E@3j5ZZimyil+_2vQTFM$CXCh=vE33 z2o5gaQf$%?Z~SD?o-BcBNz3 z=bO*9P2D0_J1uv*xx-q&_A2#NQsC>^zQJ$lFIL(~$Ss`aD7B_MU9~`peS3I&0!%GW z{iW#mpSb;P{(nu%{%8JUle7QsfA_zu`0)M?Uc3%0fI?dm)X}1m6&D4JPZu7*6A8%S zl;2@0OBKk-S@`2{Lw3*8B5VlJw)hXUZEJ#!r72pxBVyy8!DeL-Ypnc66GlEh&#As$ zQ^{w!m&`rA5r9kK#*QI7@w@ljHSXtAn0Ij?-nIh{Ab{^|HQ@=`awfm@QM)+Reb^vE zPO#2-mvot23Wn}ug?u@0`H}T{ORuBmhYuQBN+X{@1?^SXzR)s~_4d1Dxp8oieyKx~ z;kbOv)mdQH5M13hN!3~}`MiiLjqz0mt&#Z+pw*3wllvK1pMjvvDWnoi@~g7{#QDE! z_=`Vr${Im=2ZHc2;qE~ap80>(_kXYbssoq+hQtMx*rqTCJE>(s1gErbKmT(fXSM>z z%1DN$I*^;>jINndw1?Cm5;@|%1`>8IY^(G73>M+DhlDcj+z>@#948yQ-1m#k#s}o7 zPoBjxdKlX@nBy$Z4R+C7VTW=;s<|(GWeBP=V^YB$}gP zV#v|WV48_itLduRi>0QAm(Uiid(VFy>HnDCU;Igi4R8>5Xu;#*a}ScgZ~x<-|C_Dz z7HrD;_c?Ky6~m(RdAYgybOVpaU14>NT(LFRhJ;=a%=t~?v1MNUOwj#?Q|5?2oY5(8 z1iWip%Eu|Jqf81E^U+Eq#Q{W24p%@(+07ca4q+pd$Ii6YR`a`x(Aut|rWfB?<;FN# znbL~UZTPw+lOk>>tKP)VjpCwuoNQ0~DY=Z;czmE-@n%)7{CbkuGHhcS_iZxQc!(>S zBUPH4a7%#doNUg3nXV}S&4F23l1M~R;P7=J2Aus?(6&miGRgP(YxaKw(ck&&<1z5l zf`cNB7()_C{u?jz-@fD)Um8=f=NFhC;lXZ@e3G^xO0PKi2gvaj$~&gJ)B=y-?;i-e z!ahE@R20Pd#-uxG3UG3C*ade!U)aayf79|WsHBY1GX7@M4~tz$XM?QXn*3y#QtMLN z0oy(9LU1laI2_+)tedD5Y&8pDo1v5`t^D4D2O|#vs5sXLkPhR>z+3oo$ z)f-lt85^$UkTfSP+u>`w5xV1s6LJ!#ZbLgbI!MR>^R#U^Y1Sn*QC>Ob*}yZd99v5{ z;j6J>l`&xd;gc?<{}ZOM4U0@w_VEJZdf;?l7zxw-OdmF%4Q_+J@)-V2uh z(x3eC&YzzeJSxU;`yTKAYyAITH*sqfILpw^nE#s&CY4t7_gU@dML&bd>-5XVf=>&> zKeQsphh7gi+I*WI7}ZtBfd~S6{E;T+eEsdJ#m?&lC|rHr(T+wdfgPL~^Wj3YL$wC{ za0>vt)F$=Ix68Z}1vZelOlegft5g_y9IMs=pdaK{Y@1E-Y|*B`5h@4UHyxJs@=!2@ zDHEK6kkcI-XIGOz87!OV?u^KPw7PN{5c(x!6rbtGHXo`;zLGpVTN9el zl9>sf#GOX1f#J!cBtK=epvlV7bfbmL!$km2C~>`E@tKjJS=F1C0MK_Hz&1+> zD6PcwThq^S=KA zkH5t~nESN$(s{{P;!I8_W}A_S3#04|MX(=agpvgfyr{#7@Kqao>m zF2hO*3JXO%FxU#GeN~2YwfGaS_>z_OR(V%Tk}?>>GGaBsFc?>lniDbVhVrN9hy+S;UY|-0jS3w#UH6jeQ&j5Ai=}JVD1Il|P%mpYaJKOs{O<&yCQR$WlnOppT z$Nl1PE!tua?p$1kBMPo^+^pmzRSKqTu|UAZhDbs~2;yeCi7-;zgLOPj*Yf&#c~!x% z_O67tNWeId#C?HD0F`$5|NmZM_@iz!HN7Rw{h0XYr!z-une~4LQSUU9r?Za z&qD{1t$%G8`iuWZJ_{V`_7U*D$UK&in*VM7&$e8%iUmLivuGgx7sZ5)L0@7n2BrlV zCGL!}9j&kG33UXwXjE4WvOPD9yQa_5^+6l0x-+|ZP28pDuN$vAuU}uS9xgl&sgBXX z#6U-|X%iik=p^<9pT2~bF{vVDW77>no5i*{N`1JZI!m>C?vm`f{~9G&?kY*H;490t z<%AUHI5&eo9B&i7j^FFbjs4c?jc}mteu3lJTkW-EVkbK7G8(H> zchr9|&130m<#lS~?RDyH?jL?J{^C#UY==YL5eB{@CT5!!-OE@g=jB+4Iy|PJEP@G3g4qAH>+qnnFjM z_&G@3C$mH4!RzpL(T$puw#rxSdN5w=$QSsHd>$7yO!AvVni3Ng7E{hHSWg}c$*%*g zw$&eVLeT~EfY@tbad1HN6MjcU!C(8o-uwu3(Fh_ttO5kljaVWLXkHKVmY&#LeE;DM z`;U#!VVoE?gK=Uh;bh4ToPY!HzIj9IyRxQ%TEr4g)r>AYf2E4gZXQePu6mI8}i7~=;J7trc=U)(+#1}3xe4|piAwkzUDMZwNGj679RL1`4g5!WgS9ZC@fop zrpbG*8*Y(TzDM|8zS+&;Qq^|&NS|8xPrSCUCRkW%x*fph6vC!Su$929;3A?^KDX(} zHy|J@N%i~K&YV9HC$ML#zD8dT&F`EZwyIL0j-x~R>D`b8%AC^X)7u|h+ z{*(U*{%_}3kInDwL1K7R2&4FPHzxUMawMdb3z2-n$^<4G1N#%HS|ycgiQs~ls{YZ) z=w*QJok+0eYF`4^gr|x~+^||g!K4^M!M|0o&22C&c%0iPEEU#48gZ}1 zo*$eXJ2v>JPra!ZWDX^>$6VbWq|vkD9Cw}X`CqJd+WiGTvL_L)b zuTi*0&^?B20sd%bL^Ct0PAIKIrK}D;Ov8hc(6>EQhw;VurYyLVoy-! zu-KFE_+cW)mm!U9*$^%~+UU`(*@E)GB0G(h+)$-jF$0*20re$bNi$i>gbZNJq(k<( zpMFf|=lzN+io%;PkmVlvsKQb%UBpRck*C!XA{9P#-%q5l@?qi!C`HZq$a_D-?u$X_ zMewf)c8JH24}|zNdu;tn>s+hRSg-}cy#+!D7V4|}S;wAH*)l$(`Y)q3^h;V5j&H@^ z)}EhC+?ml;{AAL;kx0zTgfUP@AkmEk&f*Xv_X9zwJBniI@%#p{sG-IKuz03OcF?gJ z2tT3frC?mZKb_%P(rLWnS#(405+G5?M(5BXn_tl;^fn?IL!_={YUs0aGY?O-UL9Q~ z7T&enu@6PBC9nFzvr^zHaBnr(R2&gAosho>57ymkP6z*;{{b{kq!~iMY|i`m!*5@$ z7J@J3Tr7+NhA|eNY&gehp*DSG_vUt4;d`e3pMFMOyX}k6mGk4Mwj)bcHFJNE|C&u4 z219_YRVEqQp)5U7>5s~VjH2jJ7T7^^oYighhi7o3QAL7fqM)e3f*>ZrDrUq*x3prK zA<+f8j3&*opX?ST1cs?|&`_tu8lUD{hm0X3=dU|GOAN-Qgf!4eBrt@_s>EYAw`mRdlW#uIEp&W*p1QhM-g-MZ@oQXQti%?c4 ziD!JzxW!o{Q$7`;MSUV3ltk{9ubV@8Ai7VhUtfUIhm)5YIOYgHV9#2s8W;54{K|E- zRkgXav4-7w5%J45806ME2>S58h~sE>@Q44q{|-M4-k=_=;m%i;E`lDj3 zGc3Os=NxJ-p_I^&DZ<&B9s(X71dHZ?D$|37eu$8PZVVDPMZN7FMJ=r)C>>Z;sUAyK zVGpi&mvXp}U#)ONE*zydC1odGNY^~$KWOh<`ux;3Imrqt^)5FH9Mn!vJ-71J|2R1e zCWaU<#zTp39qN8Pv*Sv|L`lO3h*vF6 z^_Y=jLMNfH=YTeH2|*J6Myf;`Mvt+)y%B3La@@fxYi2|TNepEl$%C+fE&Cdn^-e1E#v+D&3-ZS(HZ)%~KA1A3KFGbvAvYUnXw=eC8Rk z8+S?E#_#}lp53IAXSgxy2NW`E2?bD~VN(FO=o~px7B#heZ6GW~4tVOM@fpqS7k}t# zcPegw1L=Cz;>)~W>j!2c9P zBRvn*_gVP`iu^`SzJOS|D5iuGWr*Iz5pHyo-#MWO@5}JlvJ$bPeoSfAR7kUzFYq{U zJW>5oiQ{wXrwil+f_s=>SJv(@Lv20Y8H`AlkYnq%~(%4@tteiT@sT3+- zI%F^zv0N$vi(|`VvGU{j35gqJl9G$hg=vXETX>KqPY!oRHIC90jJ)rD7%)^<9i;MI zMoylLCyHFz9R5>>$YT!|jnJ>JY(FT8?cot(w0cwqO--{<(hNi;phe|ALo@f-lNX&b z7HdGoHi#4?3-6Yb=nMm=avu{?C9LAHAG8;Sbz<)G{*CcJetd4#Dy{r`{Ci*EFtE@E zv{Ub12eVX5+#f?t=!6pjGX3x1(_ep^xR+siUx-P7q7Dwq%=FybMTun zKtN`De(rDl(T>gVsPji4ZE}o^e;e3~y8o0vYM_Y|OjhR+?3Sx_UFRgPy_o5#_$p0O z1KxaB*@IXsXz`ZZd9_)%^Q^8r+IWD?9^~b*o&SQ z{J>CQEGx$w41@}e&sI3~##IPeHef=hyzSbnaTk4Na%fPGE7PjePvs~OBGM)C|q ziHE>jeo%XB4t6tPFVLQ0Ag7oQ#CcRfRh`1mI4p%LC4M?xlTtJJN{fvW%Dp#?r?BPhFES9O@OECcgW|g{E<YK%i%7^1h7*@3QS9EVfPywcKgh{#%5)N*;T+DQW zVae~Qu^SMu1W0|W5+6zPQ>(0eCm1t5EF1tySX0ry6WqA*N-FH}ks~dcuGIuul#D`} zmYW-lvLwJgTe;LXGYKIQ&Q1R$!*Y2HN^1O~QW*(`olI>ZQKR+`|0OWo34i6GWTb#Y zW;(u~9W^rj^Rw!L@kny!g^9(MzD|v=@~FYt%VZ0Y3})n`5bp)$l#yv^ayUTQObHLD z2Hg2pzF3wu;WhwxN9AQE#F2nO(zB8mn-LbVblOo|BGuQEMKF zaqao@n-6m*c@yR$7dD$4d14R8sY12>hdoG}CCdfD_&F>_s>Q z88tdZ0>F`*?s%a)vXIa)J)x$pc5I`iV~ml&DRgcyCKaPv8+R{@lBOjCrTQ}HI49D! zy=DlJ#qj@>AcR|$dXE8VVd_)T;D{uPP}r#`y(42@Q^ zaO`5CWh7aBzD_90c_xh`va?63leOIhwx&^Hf8`iKgl?M0~R^Z3cRuM1X zVgWYuZMAX zu|jmIza$P&TvJ9TQV*C^<}+S>Z=dxRPI+-Y*HxOBPP9`UJdhK-iz8;oO&WEzB+r+z zn7LM|WoA~Wz4+q&z#?sH+|+Jt@&G6Vxi%Xa4S5yVaU3jKWN+}7Jv@a}VR-sT8<%0k zLt%hI~h|+!WG- zvkKr07GlTfy$XZ-+(IitPO%3?NaOxfrGWt^SHZ_+{2kqL!9k$U0ZN-!4*d^F~q_(5OP9j@UcP zto7IQFV`l&48?EC2nk`QJ1qTNZ|EX+{xw^Y6r4VK0J+jMOlW3gcWxNhq^Tk$EA_r?xvo=%Ca>QxLeu_mkHg8Xed!PXDL;%C&G-7- zi`LeP(z{^(rcEZ|3!PK&aNh{&QeDNke)1l3B*$ke`XttEOutBxx^K4o5RA-ir z_zW270me$r1qhf?JR4uM5wGqp&g3r{3Ew4E%bYA4B)9M;uLa+RpDHFIWR|ffQX)!* z&B{|3lspB0orjo#hvuWqdvm7va_ndiL*k;^p zG_#FwRnw|KagGhJ+|x7Ml+qvfV-9J8*J&R?^V0q_MwWTV4U-J;bh(PB!U zw6-yYvvy2~B(7GndPcQqZ2K0iMM13N!kDY)2%CfZ$2z10KVgURU}GKeY@bDUj}$&| z6c+tRr3i69|HFU74;#)O7|C)`JNBvc?!EpQ%R}<^MX2m6WtV@L>k<=NYlz!pz5B%c zIPWYIrF!=H)p{6QZe{dp@3sMvcyszVkZ#$=S&MM%L-}YF_3=(I8hhIs?f~n1;+CaJ ztbK7f_0JYUP&!C!AH;F+ZC?xx%wOTdg}hf@x-e>%UBaZi7zG=$sx4mlylZv}ZI!yK zehTQ)$`qY8g@<+2xNzhiHz_u`GB05+m+3s%9UC1!iY^F#xH^m!7Mz>`EE$ZtH!ojI zH3*4R4RG5mbs~|xp9hVqZ5ldSET$pyAz-`v7?l)tH!N8s97u*&EauXTz%15Q9IA$A z4zw;i%ZgY;&S_u3fH|U$(ONTy66O*4f=Q#zkGlQDB%?U|d)8E>wkUMG@&-d{(?> z-TI3AhvlnX>+g%i7HZrpX`I{Z>ed0GBe*~Ocl@wYW&hHDD=V>b{!Q8V>PsbEmx+OJ zl)8%ilj|#rKSgjD(P1Xp{W`Ze;4_LLx^M2Xf+*ane^2a9r{#gvXuq06hxf(qZHCR< zZ>_lO?tZ+wjxEo0pg2Aqb}F5;&7w5Dqqb~sQoHC@9x<@SP)o-ZNNuYi?eTeYKJefz z`++`@H~90f`G($DDw*omK5_pv4C|L#>7~?K;fbg&Z+*Tlge{aen<~!KvcB1}w4c;!2|_fG@qPO>qo~oMuDmR z-+Om@6P5@nTq0$QEm>-GV;1c9Z%#8Q36@4l&!s6Nv^AsW$86-})nbMF$2a~5 zv2=0z^FW!dc_Is^ci!H7VbY(9V#sHqKY2ar3*rU8?gW5Sa#O@Lu1a4hr1A;Ha3T~H ztHI;R6Zq>pTUn35;8B&0?b!wYZ~)i%3H1enIg!}Ji1xcITFzI6u{Q4e@!|FZI4heA zo7b*pv#$i@ujPl{6Z)%~X_i*N+R?N{?V;C-EIW5IVTj(mxK&T7U^MvZ->aPU>?93= zX28XxjjiV?Ep$F!fb9Xbtx zt@!arvX3|Qi%vg16E>E36Rq3Et#_WD2`EyTwxnGauOi^dcx!|I`nA#6$hP{=5z6&;IwFMqklM6KH*A$u_$B15LcV;*JkO^$o}r zyK_9;0t_%>;^YKu3H3PD3c$~E3Fi~j1Qo4ITu*~LrlHUdNqhL%K6z|I{kLmwQO(sA z_>n(DBFwC3Y{AfNM$~2PPt8gua=#5FP9k@1jLFu{*SfCl$*XWG1~p5DZ|_)fs|Lt; zm6K9*7%VZjenlL_sWS0+ zyCv2K+*5!ye$ zztJ86<%v5(u4$o_SwuD_QSKYr9b!KFCz$gt0q`j&1Z!t+*=dHXbUiantZob6EW3?7 zurBhNb}~H%8KlxD8!F7W*VCZ_*KC3Fn`vbV`lQ%hNlhW*)@58D#DkdD@#nR{9I{Go>3}1d>RNt{_ z6(q6rtvM|!EVg5OriTAy{DTSvd|2%Fz1G@IwGXv~2Nx((nK&_y#XlV@Ij?3{iw>PY zV;kX8gu{imn@!0KiZT{yx@^H7D^UkQsl}!R&{jB31y6MMUs*FIGORzs86^6Fb-h+5 zo}0!%cL(mv+jqo`2MWoLCggQ)?YOh95e=f-^7g(mktY_Qs3kv@>3=*Zxr(ea~8^zStqLVBS% z+d`Kh$`wev-Ba=QcG$UG$l5yQ7Q2r0`LdON4-bYk@+*@6xP-`W`Ek(?wCi#Zv(PuH zi1`Av!!irV@)Hr95qRgPWQ)3 z4@KYYE^t=KAI5JfvZe?LQN7RR=d@v&0-3mw%FGSwV|6}3-zYZ$UDk{m=g>;ph4Z7F zDsyq6E{-<@qo`E2$a+J0ARk*&4>g@6DvV|k5xb+EAK&eD@6ujuXD_F}v__~=4G(&3 z=V98wSUPWrmx;rXcK^j64BNsV_^v-zyIuXq|Em#06t^`3UaAhz!(@4Q^L6-((re$Z zx|)_6aw38$V2!?w$QYX$4sn@PzHS-fjWdW}ad1{!eJSjHYr{_d>4?Au1mwzmT(;Gj z*SLNJeRhLDEjY)1Llc3t%(x9!tBmw9hrDLuLsFoLDdcsh*Ov3SL ztOFSlhBBV5mV++R0;4+3jb?=k1fR}(4)NKH*-+3Sd_9oJTqcM@dw3?v|6{*#D;Z=) zHJlL%yO_CXy21=QDn{U{dUKtazlFYNGCY^vO2TFCVq?@R-91I^kQa1kL;@nL0?_ML z*Q{@XTns4P=1L%J;5nvk`qPJzm5mF{=zZshO_Mf5R10Ep&2of@g=nwf1Vo;JbCIxY z&Dg$&h@@fHfNzIZm>Xu)QleNL1lscK7gF%=DO43DcUc+Oi+bZ#E{JbdUx6ST8|BW1 z(xczccB{WOk&WpHj;FCuvbiy4F_57s9%s!(sz zZ1u-le8o;nj1$lB3FNZ%i`MIBV3y7Od1M6NAfsE(m5Wc5fB%}2dkzOnvW&Lo| zrderC!!6}*X|OJ3KDeP^ZfV-#e1n(?yY=_UK{pB2M&k;(P2n>tcnYS>fG0XqjD^yQ zBn_C*hZOW>PenO~kko8;+7Tb=HI9=*e1ro;!5DhEgGXaohI8eHaqClE(=AF|X(oeK z+7=h~=NlT=CGHNZA8%WNUD5bM8B^{rlqpf{5zTW({OpEcJ%dU>e|e{Mq91?wpZQ@$ z=_TaE- zwX7v9?`ZpsWxm=mn6Z>3ebgFq8Go+2dh@-D8m}!!AF&ysu$7oqATk{MAlAc!#KWnk zqNW|68{9<8(Py3zwgOzhC8sv{0KXqqEODjUL-E}pkG_7>kV)wd9k)WgbO}Z$Y_KlV zg1gXFioqd1I`x8`V0{Mu+Y9kmJeV9lRd;x zQV!cHypz}EPgZOpf1d4o1WS?lB>`yFRoAYM(SD)jnO3RR36yK7(E%mO+)73ZKBt+B z^_}<3dh935X$0F>3!5fYI=hxGP#K3e-wBy$Z= zk-aV`N@sH*T7iF!s9l19&5LbTR;xqeKNnzSftIN-A^ok>bj4-xD{5?O*kLJ@9nPA- zlGqB_*zjHLh$eb@{?#c3ps^5bnbl>rr?r5TesgXD+@+(756#Pe1_Yk?Y4@|Tt2VR} zimQEnGg9Rca9AKD_$ZCoN&1?aW3GyXaNE|2_gZ&Zu9KvAv~lJzG6v`ry>(|_RI6H# zI49cGLQ!>C%eIYfg0@;)-lc%49b{K^ zNrDmp2z19+xsbBadViOt54ae&xGj^Ef`xP_cf5;S7$^l;1DlQH@sYH zxUXJK1s=?eV8|cvV{cG&v(I^Bq>XfYp*{ee5_C_cO$|I-MZ%OlarXTVm@3WdVs|@T zNA0RW`E~FF;J3Uka3hoee1&)2s!zb$Vm&RqTvvM4l3iDjI>l~tQ_h%dUMdhrQEPXC z;wq1;)2i^=WR9I)n%q!Lqb=y{`eDxs*!bGv;v2ddLgZkdY#I^*Ad{iw{w(+5=`mn2 zxRj~XA^e`I3R&Uq$Y%4oi13*n`TOU_hwWE-&X11C?aDYiwe9hoqq7aJPU|;+<=-a3 zu&@1rLlqYRu}pNo`uOY8+6K~*Z!A5C3gGb_QO%XsbtpXtjP4%e@tR~6oai%j)(r-Q zSx;Tvnf0Ct3iI0x+q9M)=r7sS}&K! zu?=qa+!B8i;QHHg#8KpD#E$krf^iX=<1p9QvH+BA7m6R6Iiq-3h$ z%`~V^A8j`KZ0E&zTZ{77{Aa-rlLaV$RC5s?R$TnTH!5-Ynk&$QKn9L~3pXZ1VR=L6xUR7IP`v? zr%C)Rj!6)k=*lx$^R+VN^w5l3hNNHjYYTAsA+~^P~^KIfWl*Eve zP5Y1j0f7=AcXQ#~&MK9L!1lCw7sixClVD!>Im(pf#!~2#o9OBk~%ZbkO>meWHU=!VfkD& z#LE#ueLq_LFva>6mHQ95(r(Qg`7?IOBJdl2-uI`>yCW({(HEzXNTX=@9i3;@IV9z< z2GZ2?EHoRKsO9#vHHHDI?|BaNiQo%aW|7FlOvUU(691|{JORVJlb5Y{-+!G}VsZDb zzj2n}!|%dh@>*zJiN}7_mF}|a*>#2as(5-+OO35w1o;~Zv}X-Ux70B4M}~059W(Rq z6|c6vv^~l3xpG;0tLqAN8QF@#BK~O+!?h-3N7>RNw~Iok$p}+5T$A2mY4F^poU7AC z*6=jOIQQaV%V|oAcSKTV%DsApSPOXV!vp~#O@8n}^{hD7wnyC6hLKivDmbw}+z@t7 zWtXUy-1{?0(jK)D)n#=d8$3ECR%|`G?P%YmM!Iewe{SEMdwh6kO?bX+Gb2cGYq=u2 zdiXuRA$U5OKY+Rq%FU>lAl5VnBb4n+!5J04NRkHxf4GYJt@*0^Iv`&@*dN@WfSMIk zfV29<0jm@$r_*wB%_j?Bm?2HU{z7y%Gj`Zf^aA3*E%aO8gG+T%uTG~HFko#g(OH(D zEwrOd(?mZO`)X2@aCFiiuZB=6r5H9dDS^d*N90EX#8`-gw&N>vGa@=gQCpn97NB=6(ArIyucHpgaN#c$JwwIi3Y5et+*YxxkO zj?3{jP4vI}b#orp_?6L|e_L1cx7H~5WY42nHE+GhdVRY{0%lqy=aNR-UE;C1yQ)U? zPL(dvTjsfz8F?=Rrz`IUn~~2vecC#^deMwNmCkZ4H)th1Un*##w|uyY_E#6dg+woi zWLi9q?+MbHoA%x({6F2j1yEeww(m=@KyY_=Xx!c1t#J*m!4fpMyVGcJcXxsXhu{vu zoghIHpkF87w{M-==k9m*JNMRmx85wO8oGO}p8V$QvBsQZtnuGA4BJ7r!`}FWU?@MB ztd*h@shziw^L+7AUpNNo`bz!l_3T!SEJ62_uL9YJmqwTDmoL3Oi+-1o9`Ao(dNdtM z%UNyNt6%?FUGPat#eu!QykV%V#n%IIYxS~EEB$1DE3Z36mFQBl8f^@x#GdXKGp~U* z*-rS-r8v*=c8hG{O%~1f2Q#+3MLY15y}%kX`ri5t=Z@w4W6;R*jEz8qTYhxtNCmB( zBX(cxD;qUb3wlLX8Sd>YYb*I<7n@X#0Lk>^lZ9x>h)eJb)xyoF0j9!l{@?&yuRz7$ z`fKa8gi;6OKu>wO8n=tjaB>t+V+88N-Ag#h5_Hk*43m zuht*LfyBL!4GagYtm9Q|)xLnyZ*H!X&l?HsL-vKNtN-GUU#zSQ+5ap^ zqi66)?{2E65OD_iX~qoy`Zd{T)jq(2)f%IV^bhbaVj+__+SM&mC9&nfY^XPQ7N||< za(3_wUhDZ2OFoAUb=tedO6ijML+tFQV*XfMO>izhg51~dCL1j83biwTxVku6gk4|J z+PW;_s+}A&xbh<= zq-`c-g9S_E5(X%+Amx?6DHgEYrvqlX55G-0Ki=OAJjQw6r?HG3zoa#-yD}(Z_#IPx zQQr#qBv*pIfbu|5BWdR}hxOH4&;{-~^`gTdjIs#*lon>-O~RylAKG4A7dv*!`XatT zL3Yzm`TD&LA@n1uZJ&iBXGMm6r(dmf<@CeOZxmYEu}fRSMZYf+d?eoVn%m7goT$)l z&6%)Ct`bRUT{!ScH?#DAuo=cHb=RWpkZ}Yge0#H{$jM~*3x|jjI<*)gi|QwQU7E*D zXcI{j<1zLF@UcQ+_kB<1CNG0!-3w@46lGFLO-Q+L7meRZLX73nhstHevp*Q&I8ec{ zZ6+bNCaIqBYotq6re&x&(rYn6L6ecsXwq+03(Y|vZL>~r=MbeF%LhM2qC^;eB+JV4 zqf+O$z#$K^RA&7Le}Bm{it~bPHo6Ch|4+E|Y3bMN$`sb!$FyJX^AMheeLPQ(8Tex_ zX5Z$qbz0TB^=k543OtxrIvn4HdvH?Vlsiksc=R>V%jrFYF>!5Q)m+7tD{mI&b~Jsp zuLPDU!NKOlGLTJa`3onurV<$5oIQJ%&9t+nevTZ4j^8W7 zCXDHI{sEIPo2yN14&}tU?__~gPlRXYJI~$Nj=AWa9_`V|0i>-%jH7td>2#T*ZCL@S zGf75E9+fcY7}#?0^Se)d__{k*xv!nZWm6gnx$8FIqV z?3ahmEi_4V_+JO50#!?)||>Kk^4Fpp+(!7Q6#lsD|%~n=JkEGCAKQ zG~UA6V*9Vg6@@MQs(SD9>*NEcrq>k4=gX5ITFZ4^-t4_f9bkC@&~sirmc7PMFTy+p zwt(wxF6EQAW|fM8A&Kngx9qwTFd*2l;>f@4&#OS`FY&+izZm##&FWn7Z#M)}0fQKR ziD?4GGUYyGOReavtcb1>a~xw!5Z*@ zA&3PCJ8`>oUvfzFb0oG8tk*6m2~tr|Co=HO%TGYV+hoe=uVKN$>(rZn>BM@$V{Jd^ zcouY)eY(J4EN3g48S)FGuvDeFfsXl}Go((Qp{WXp1SG|ec_3`F$h@)&15HoPnYBaW zKaC_ga_@6kl%qrVau`a~jeruGCps65c07`j8t2E-JSWScX6=~*`+OC#VGtq2F1sp+ ze87DZ*$1yeL%sY_z51IsONB>k&2)>cAegnTxN^2oNls1-C@9=8I(oG)^rNGbP75CQ zw9B#-l>_}notI2F=J)}mR6<7pB&cuLD&s}oC5GLn(7-nvk!JWM3Pa9`L5Ln)tGKE^ zVBZcYY^xX&Eq%mIrJv8bk6}iU)ex_-nNNG;HF_Bz#huSKPJ`rT{-^%ZVF0d&v*s6w z|6c^Cc!K2r`16aI$1MJcrQgZROp+%gKC4});uY?8dOmfq^~jcnI$rzI>eGrRD}gWGsfPEW{zQ@@I5`-=!nJ*WSijhwlorRZ6$Ub;XRMRZj{^doSY*%>0#;wWm1J1$5Ppjv zGh+V+G&S$-&2G!JUcjMVH$SXte}|W#g|=pk=&qad*~Ry4-^>*en0~B!ZmEAB}GXY$lX zkbIOPz)@4>Qn2U@d%k~k)I5B2D?D^oTC`5igy^jm`UKuGBKg>K78n^`e$)7 zsJ?{JD>GW<_x!&Iz(Mg+|B`>6v{G^G3DIA+UBqpx+tD~G`1mN>?Xn+=4E5sN`apCVQ)*3O!VgYJJwy7b3U=+}_g zDS~dNjYU^g2&PyJWShu!(Bp}au|@5WuRe0tVg82SMudeBC95sfFFxCUbf8KSTpCle z8>TEFuQXl^%;e{P|COtvs^KkcZ=-&7ra{$0Bkei2{X*FhFM@}i_U*aDXNHg&tDwM3)st>)1-0HE*k#$9mxxywrr08%?uC~GMSYI7GE>0Asdh$65Ih4~-H3Ij? z9X&nvXxZrS2^)9d?t}?m!om*qI zuk1Re@2Zkh*piYckLwV z!z_4P%eaMe{$$|11k8K$#nHyzGZ4UtpL!J7HXNv??x-KeNjYu4&Mdk2B(7U&^x>-qID8Aa+XF8^xv(w3Lv2nl3 zEWxyBFUkMes6@Bc(|SF0vFpK_xFCL*(_hAL;5@5nCA2gv9EbLtoVqe>QGvH)hVC&H zXm!{G6wJ|Br()E`I$|@|PtZp~V)Aa~D4ma~D7jZ(ry7o@`4EOk9oLbEp?%V9Kor%@ z^{89ThqU6(eB_;jJ6t0;GkYD0|7w`QdGNnP&gYd z%2n*=1yeN@KhnEftV(*PM0#Etqn<97rraVtk^#=l03N}ej41Qo|KSCVYHaj&`t5C& zo5n@?gg&xbbeH(-Y7o`s_VoLBU*=t)1w(=yD3OTj<_u@bpQzGl_Jw#8XLi_S&aX=i zu*%FPl+%&4qsvx9Tb#$X0SgGt9H<_Y6bP<{ ze8VcGGxOZ|6J;PGa8VyQ-d|uINS@m~viD|s ztjr3fJPXSUKyVPn28xb4iJ!`rZeoX2FRa*D36_~)cYs4 zjmq?bg@@Rtja3ycVYxBxQT?Y9&CZ}2@ML(lxP z&kOS({TDD4?z0DEhyT3eODzK=|EHO|ig2;sm&V;jy%os|q8w)ynThug?*H@{iP<>N z*$aMl>{7J2^B9gK(o-!mYHdfI=J?Vu+n9b+^XkR2mJ#uBxVC;O3cVkm!8XiwyO3ip z_8loDvQ(k`yBHwFH)JLR_9}uPR6@(oP(`HSD0G@9bJX4{xQpE0>|bY8;`i*iaPi8Q zU2b?NpC0$7Ty*b!_vOxKws`BAh$$L(rfG7ofg-s*>cc%R+uBcp2QMIqUYRI=@x8Li z$A>r>c+bk}4|~1tHm!gpdFnX+qzIE{_*%e;e!m0WJ65~__)Iq(iQcV)PL^01TVn>P zr#FY{`EOc99WzP#le{_B_?QU_8(WU?!&f@Qk`3j^6``cGGAQKYaFZBRI(_pgM&t*d z_E?Vx3Jm3z$6FSBm4EiCPb-W1`}6~un8^A}i-;MfK8#_tpFT9XvBqPJVO_kMab=ji z?aM@K`pf^p+xJl}Ek5t4r9bq8@PAyS-6M!WacfJ>v;H=7qe|yl%o3b|KPYQRe-Mf+{GsLxDNz7bGqaSrI??qAqab5#2q&9WeXkQM<)SK4>Y4KN ziu$OG`w(b9;_y|y#T}woN{~!zrvz4h4*>Z{LP;GD&YQjvsIE0JT&+Su6@wkpeaaMh z7N;r8A1k4?nHyFNsX=O4AM}9%NK!zYfTDnFGee+wGo|;0+R^IXEA;yuH<2w0q92%=#kyO2;ecc>$(XbfoUL@qhuIg(|2b5cwQix zk1*;;#3>p)o3hBnMA){++W+(Z@AVhHrGaqixARKln!|d?{u>%5_xn_DH&I7R6`lCB zp@d#<)y**2V0Z(Wx&gD?{b}c3g;}qv=Jzh&&=CmhC(C+3AT4qX3Jk`UZY0w^8=hDm ztap9x!e&tT;`H1AKTM8gi$QBsejKZa7ZR8>d@!&QLtFJ&zzgnMfy$^LG~s#@F!OjM zlDq%i#akyC5_ZGgL#3%>lB9{!!u>V3Ri#?_7@d=dsODlb7=R4Hr)@(djDk|2Kvc6_ zLbC0?J9i|-ocAPYW6|2%J`FLufHh7h9gx}75a&bdT(@kA2X#wi`&%#A!2$1VHnEg@ zd12EQ4Gc^yu4G4E3Y1qPXS4jdWaEu~)NvB1>J>JaeN&!JN~;NCWysV*MKDTAm3?1uPsWUUc;EF1PX&{BI9HWF^B9ec zyZls!!6lM7&wy5;;2xmIM3jb_g0^!;kA2FIL;r`e4_J3&ce#!zZ7F^Cnut39n__fa^N*-IENulCi77O)fLky0w?R zSF?%h)F% zWwPhHx1dh-rT=&RvX>rAAl-^{9f!c^swK5~k9HfBrYU|aF$;Xv2;(&>&LhR=kD=Sy4 z-~4|D;N+9YA9lx9Ojj@nJqb5k^IDs)39sH6&lmc`@Whmfbvplp`@ejAnV*OVky>?Z zS+}n&OOeMvc31njvQt5WGuJCVSULA=Ena|6LMuxjAm6cF}+2I=+fLvbtMTVPT` zYNk2)R8$%e9syRq<`E;?*YF>ySyeukyPnJ<8;sX@xBhIjv{vTL3a3jG-UR_Rvh+rB z80~IyB-@=Rt)C72djuB1Rkte~V?sJ;tg1KFcPa%3m=A^^UG6 zsVFc7_FVamd4g%!NJ{6Oig7~^bVIYv5tK*YR|M0$k<_a*SYX$c2OL?nn_oQ+aoA&_ z3Qo&%Gx^Yi#>U=}^FYHB_KF{z^jVgDM}8YS>j#&km9Jhv)xyzMQ{Aab!>a7-Ydsk0 zDCPlN8@(jc^DHhlAl?gWj|Xa-^UGt@aHY4{3Z>R=aNo!Nk|+|Q!u{L+5D?h@;UB?R zE)4NMjnYdm9P5oQe0_bMz>0?(;O@eq0Kro7NSJ?#|DRqsQi_q1Qg7K$vbMEZBc22lr1n*7KD zx{p`)R&biFXz=Ov4JT}#M!dS{;_ll@$?5JPnatAiXV1`15!~^Zk94@F!<@L$udf2>FdLR;b#g?4osQdG(`~HRA4qK)sb+?C+>jt z&8IAEMum;ta|L{RI1Tk#jI(d)>^ax44W4$@kUcmP8Cn8j~m%q?~9IUr~QV$8|ZgKC@U@ ze{#+D%Or?9(A%57Cj;MLT|_jbz4`0K#FPlEuy zqokFSiX?VZbSV(8Kx?3#4RPP?5x374qnOD+X2;UVIb=7z8p{wVeSXod6N)PHMV6P|D)zEIZf#Q9-!yfK@%#NmapX1;67Aoj)MDjG~{tLIoPy}=pvNHy-r zc@e&{U86zNGF7@XOs;`hkm3@rARXVbu7jNa8KZgrOg6ZTU4^S&LQ<2OS{>< zE`3W2wxDDzMfa=Cb$rqxau6w}dQ7#1&EChV;p2_nHw>o7(I2FU8)QXLba>elbQD^I zckK?M!^0qn+25xj)wJ=KY_bjwHqLoOmxfF4lZ0Jh{LyP`O}cgoYHPF$i<`><^Vy(1 zggm_2?We{tRzN*F;ZeIwlz*o$gcAXn%oVtl^=JJHslO4cr+N6zv4FqG&KF|;51P2j z7&Arx8Rvib_je_=gh>5Ut4=R0u}K33Jnxg%5eGFa=nuF%N)Z>fr>k=;v3T6DD*GYa zTMId6##6e&crUg;6D6m1404JKx#&Zm;}Rv#QgbEU&(XJsrp@OjtwtxD*D^3%?xF&Vrw1OPUb_~uMF2nm4>f*_`BX!3E7$a(SL#H zUqqT|oF z_nhxNqA#}$3YXuz`p7bU9_qIKQOtz#z{WR3t(DeJg-A!FCSPa0{~^hfW@(K=dUNWa zJ7E}Wd)Ly;#nFSnN`J}gVY9w!=u69Xcg(t33MHvQVQT~Kp2mL8-Rcj_qcQn#S|;f! z|9^B4yjc(L<>sT2UW|REmvSDaUD5xO)Z7kWDaq819XZr;GttygZ{*1pimN2mG`q$% znCH2{NlMC1^`KgKX#AJ`A>emYhVZWlu4VY`|C2Jemy@a*?P@~o=l{d@Xj@9tAlL82 zS8*D`<3r_$uJ~^E1vQSN`0i)49;aksJwNcAUG$kK*$?!%wZ8wu!5f-Mx7`jtP<{79 zQnkfb8okZ;{(pVu`Wi;umLLHNi3J5*7CLUiQ_w>8XA?Ozq^)D`w)}RZ zYQ7>G-;IT8~ zqpbuK z49E%g<5#X$&cIKCV**NBoL_AVq>j#8pSc?4k{SKY|2R;&3X*^8R148RWo}tz&YdM8 zZWYcKTg;W3xE}o1V-Um!EAt`tZoqG&X#eBjY+&+Jr+!LFbb1sbY?Li6Rw;I<0Xe^~ zN>;CVQ%y_VK=0N-`psEEF7=6axRFo2=R)>00ey0rKTIsUde!AxH;>hSXdj%v)?d~W zV{5EQPU`6kAwb>4Ww4P#1yct7dM!bj^qpKl1f}l*SJ2SCcPHvD5^QEZRb?pUP} zN|!*!P~RXT=A2_vIgQT(G`9>zk;X4dnRWFaGCF`CR<}DUTOWa))_P5`yll0q)gzVh zHXOeR$^4a&A(2OxP$Ze&x(_gY@~kr=hUT=;Q6pN1j6pCRod!BmA?)z0+@KKZtdi1S zSe`G}zvTCjA@uL?QN)jAVW|?E!^4l@pe9lv!%OtV@Da%m+{C3DX;R#cmDq4c7U>SW zjmAXnb}yL~>dKt{i$C6HKjpLH^NNN#M&WGsCf3a#Q?vWbu0`Me4EDdq|DRuJl4ocY zy{M@)hvw%j)1%QYQHo5tNSkcapgn~0Ac&B8>bj0%d_7y$LubI?N5?EpS1~uOUFQ%pB>JZP01b!6Ab@DqGS1M0zFEri6|I+hXwhZ#~1L+S@C8A?f^<58D?ZeQ0yBT z5?Ri@KJu7r^eQ;=hpIp##Nmr28Mz9sIb(SR#wq9#9c@Fog(^(fesf`_*5{)@40I`J z`<9N=XTKsc6OUi8xC@Oi3eCFthNw-{-TXvOD_Z;P z8vgP1p)*+y&^H0}UH70^qmgq<0w(CEqjW%p(|F#!gO`aO{onI{-wSg8onwa+!>LOQ zO)GO(+Sl!*+Pj{&+y9yHfBno8L^j&(+5Rm_iiAh!j}ArcBQ1;M#_q@f zNlPdhyH|d?uG}3OoY`mL{AcTtZ#8jakdC|~%L74n)uCOpmDmXHz6nH>xk%?+(;G?l zE`gu^xMWqA@2E@4l^-PKWNPHu_y{B`G2zz}Lib-7K z*Y+b5D~+18tg`Z#Xqi+>cATQ);$@3xy#rkdXf7jb_dKS~{!CPXqyY5lUiLOc`1ucQd59G1&*!hFn1xYQJ3l08ifc zR$Y38jfQ*M7hC|0dKw94o=@M@+eTWpU{RvahLRLaBR>_LEdkgPuge!=+(cc2QK4_{ z=$pK7h5q7C=phKv-#M=^EN1$xfBLw=(3|P((K;+TJizEKT+fE zw;0s4ddHdGE&8$DQ%8w_od&|<^j(!nXyW=w{J$w5vCDS&E`zpqui1}3EpqU6ncO_;~&m2W| zvPB^7td?J4)^<ooWo9P7NZ+Tv_WA<|4H=)i054^e_JS zko zX7!j>2MGb2GDaAqYy*Z;Kvo6#0nKKK#xh2Ui7#DWmZ%CMF@ur+SOK#ytJ{B7&S&Mw6Zknc8Fy{?Yi5OF#6_8n-b2X6S{~BP>apkcdY#xs<(sOJV5$Sj)Cs!5)twq zxRw~ahOK)0-y2EF8iinl>Z#E0q~DaYQ@`fL1p+kupL-Wv;B6LbJidwdgGN<8nVSdH zXbTExmYTV;52S=s6o-xqlX6DuOE)6`r0C@pZKa&4vE`^jax2(>ceek~a+G^Xu<;A%WCwJU%T-DpoP%D5Iu9wh~4Vh}8}6!>eTAE`Er3 z8#0xq1`WR7U5}zbJpWh%CIkfrA}Y=PWu{U zs7R&|LHA_B>3deE=`5vD_f${5hZ3t6enTla4AXw44`*B7U=TjTc*me~^v<*XZ5+qr zPwqomBqHPYW|d_t4i8nP6~pHo@2$Gd67~a1Gy-7@^c_c>QNJDoaTH%)2gWjmdqQNS z1vXFPk@|&R87T$su{jkr0e}>ksVfY&-t$+v3B=9>d>YiRKI6Mk6C{UP4w?~$=AKIT zABUptduYMIOun(1+=;8rKb?#_lquF@ifY_UsBQ&mC;b>KAuH5Z#}o#^dl+Tl`yfJz?DT!B(EDa28LblBmDQ5 z0JqdPTsLrvaTMNr2iPopjuhfa;;0x5 z1>vYF)|fI0C1y9r8IVv5Jfb>fc1(?mgpyRjnM(@cFZv*AxZtrko&%w6{q%%!;44FT z-1P!&ck+n$Fc?s9_TbMA%#{sqYUImBU0u?IX6MuWL1BEuifo5bjZ$e%m55vcu5gSq z<$HQZQB*;8XzZedMQ++?G(#35h8d5q#wj?VJl;T4vgId6Rv96jVg^klm1~t{$*T?N zV(5>NFs=y#87iW^9Y(o}wsrCxH9{DI{^Z|2LJ_bBN|x5g1~s!n^dF1sIEIE85(1CL z!xNwkk@Q@xlqYZK%zBn-*% zD=Ot^2JNIRF^v$A)0vt{QE(n6DaIcs70+QWlqK#VZgP~3+n_~gJADrl{nSxrp}~$@ z30`5RF5YLcrJDm(UAL)hz-1WTSCGS|eMw4jKgQ+o(DU=nQq?voR0Br?SQRsk)irgl zI~ERZ)ueJh?+#<7D6r$$DRQYu1UZt++on=09S6H9CQrg~>%h%NWBF)ls7)g|q60l=_xpR%(|6~7epm6j3DK7_L&JR=(mw-h)U2g()*?wR;X5hG-J7?b+x=rljR| zYO`qL?w97k4KaA9DEI5(_p60ir0gl#wqp@zM*D~QwSX8j>P@x$LY2m8b-!XdWI?N7 zh%!hFS~N5jm8c-kNyoB^EDv$rcxT11y3;0iG5^Xu!4{X#Qh#(^r|9kEMjsxckvpog~!YhKe)-ak-};+TZol(?ikot)-@Ey9@Pkg2emLKjwDh6I;ZK1Q9y%B)KlElM7jmSxbKNh{Z`PFN&QhT|<_nNd186q2*D4Z%a}>AijyeGhR$3 z$z|bH(B~rrlrYWN<+Rc_4L$aw0s%1_tD03V(meO6vK6fPz~C3i*&TefE54G6*w01p z?}=d4lz$wm+IVq>;Sg|DVwec^1-7ZO;>31;O$yJ8^$fbWq6R^1_g*Ec#ps`$E%E?}B&{)UbRMF(z;G)@rOJ(@2@fx+XT!1Lc8o#+SSs|BgQr6#L0m z)yGDCD5>a%)IZ7g?92swll{BY|MUB{p^%eCnP2NkjPiL$_Z?I*Zc$eE0y=oj5*nG10wvkv&^`3Tr0eFY`I4UoDls32OY$h2 zJ6CCdW@PG}LrLCw3zoa~=Siq@PVM6dC!)qSX&2oWJ`i!v3R6kpb6PH*Wrftwwr%i+ z9mG$jqxC<$cW9`m(QT?yVyg6FqPchQc#Dg{%Eu8fOz-yd%p8lkuS-FNzb&R>9u1)C z(Yl=aH#JE71sp(_Z>d)WiNEO5+TGrFH~(j#|J`SbC?U?9!~-s+4_@&XPhi8B-+GM-&|dyaOE@>j}H*}1rXQ0 zo04c|KPj19=xAngDDJnk9V{?RSA2gr^I#e=s6MU9w#FmB4uy~bRCXlN5^#umXH@YC zq4Hfzi2gnUBHYe?^AqjbLV&k?W02qDZsd+QbAgr)v34PDm3Ep`_eZpZbQ_~$Bd-%) zMPrcui;8pokGJFln_BM^DctSw$uPbF#C04O+hY|h27)vwhc?f&aTfLTcN*rc!B!ju zBaqC)zuF)EM4x#f^#@`rxM)tfA^L0oUD|&i_o!yKx?+rQhe?D6SMX^mu4s| zB%{MU9=)YM+{1dW`g~>dY=YBVn=v1Z$%MIm_)egJqI&G0%n7;L!J*1gbtNfkmM70N z?eRmo`7A6Si(u#SrV+Hd$z{_3P}&j|br2mXO%SsF4TizxQ9K!#UpQq%EdIXmu=2QZ zml6;%KOHx3w@zrE*i~l4d2U;kQMpNht|Zy?gA#rG)=--YCGH48Mo;51Pe#65dJ<(0 z^L^(O-BK3L)|a36o1BrhOcRskhmnXwN*0v_(W4@krbhcE+UD59;hagdE_JHY+6R1U zXV-A|uaay(wK+kGP%5wX^!~m6b>Y-2?T#%lreWNB5^jNTeD?DPKR#}9X57Ub=>EHE zV%Jh2$A*pWwebv_R+{pXyRnSh)#NUaI*p(=OREnytCN$5?I>CEs>_bZJH;%a8*ApC z+tp7o=d5{|r|%8#Cnm-l64+@$ar>~GFBi-xm1ETQu-12ek@tod8Cy%g9yT4T6j4*s z(N4RYIa-P33pC^n-zr1TjT5<qp#KOk)eCgW~#{dD6x8&GSxi)TYrZj z((zCI2X9(N4@myQL-K!7y7FIqL7tP6lh&A*My{cFb1CC00I*nTH&5RUKB#ZR)WDVE#r@yGvf;1I6 zT@v3GP)WE1RYe#o&y#ynEqv8kta<;LZdp=2ii)DTT>nQSi-Fzj;F(KuMJgB0Tv7|g zbH}F9??{%x@JHT=8S{(GtrnKWtIzrqebq9=3cPqU*jR(TW$MMF)DqejW#@FzJ0EDU zDh{JO>Ng6PyC>#qXO;$sN^=CbU6cgFwE2I9MN`}>BC=9U%1 ze&f6kd4LUrnkMGDu1?#UoiQdCQw0#>>cELD+KI%wKC5K?daLQIb?q(H(Q9ujk z(KtaFEhSszBW8;XYz!Cec~nJz>|QRe#ft6SY=zd}_D7yd_4oddIrR}F|E&oHqPhOx zYES9ZY0G<&)JEE*XbM^xfE-(yE%d%Q?h2?VW%L%iTqT7;=D~9{nnI?eK%f*x{jv)O z9Z(+QCq;NrS6#YiI3aUAdO_5=z&IhLmk0~Jd3m9826fTGA~&Qr&X8F8Nn5D*;5@l$pRWdC%-j@LxEy5c+7 zt`*{Xbl_(PM>p<1_Ayc`mjEkN?H|9AT z4CNU=Jxn@|3>K}fT%1lo|ocIPgQT7CZFbd{j1Q;!F6X3^u=1ah{9)Sg!_4 z8Mzicu(Iht*c6uFBwZ{Vl(1whM?cg(3WGjMj`zOwNG)da-p73J{TuL~>n}k&gJcXO z{^CJd3c3IE{eO%7|H?s-aZ8fhbu0?uVKWs3mGOQ3;>%*DnSO-S7y9~w$}D15rNYvP zvoBR?b8t4lUQvWELrVdMDo~5w(GZ9UB+<<;8{0`Pim1n;&gSl$aj>DLf(FedQC0~^ z!HiU!YRbmyB=vwl$t6HRK?lBu`LmDxztY|RoyY#+Pu`BmQ1uO|JO#b*M|knSTmSig wXE**|IM)-@|AFl<`@^jJ8b25TiXIAzrVk1V_W!_s{{OX0TH><*pZ;tA7r1<>rvLx| literal 0 HcmV?d00001 diff --git a/res/system_resources/resource/voice/Alianwang007.mp3 b/res/system_resources/resource/voice/Alianwang007.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..cc02636abe54d13388820d615dea1673711780c8 GIT binary patch literal 54932 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əM7jX1MdRES9qL3AFxR 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 z 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%0ADM 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