mirror of
https://github.com/openharmony/vendor_telink.git
synced 2026-07-01 20:44:02 -04:00
Added OTA.
Signed-off-by: Dmytro Kosmii <dmytro.kosmii@telink-semi.com>
This commit is contained in:
@@ -72,6 +72,7 @@ _attribute_ram_code_ int32_t gpio_handler(uint16_t gpio, void *data)
|
||||
|
||||
void AppMain(void)
|
||||
{
|
||||
#if 0
|
||||
UINT32 ret;
|
||||
UINT32 taskId = 0;
|
||||
TSK_INIT_PARAM_S taskParam = {0};
|
||||
@@ -101,6 +102,7 @@ void AppMain(void)
|
||||
GpioSetIrq(SW1_3_GPIO_HDF, GPIO_IRQ_TRIGGER_RISING, gpio_handler, NULL);
|
||||
GpioEnableIrq(SW1_3_GPIO_HDF);
|
||||
#endif /* TELINK_GPIO_IRQ_SAMPLE_ENABLE */
|
||||
#endif
|
||||
}
|
||||
|
||||
SYS_RUN(AppMain);
|
||||
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
# Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//device/soc/telink/util/util.gni")
|
||||
|
||||
b91_firmware("ota_demo") {
|
||||
explicit_libs = [
|
||||
"bootstrap",
|
||||
"broadcast",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//build/lite:ohos",
|
||||
"ota_demo",
|
||||
]
|
||||
}
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"product_name": "ota_demo",
|
||||
"ohos_version": "OpenHarmony 3.x",
|
||||
"device_company": "telink",
|
||||
"board": "b91_devkit",
|
||||
"kernel_type": "liteos_m",
|
||||
"kernel_version": "3.0.0",
|
||||
"subsystems": [
|
||||
{
|
||||
"subsystem": "kernel",
|
||||
"components": [
|
||||
{ "component": "liteos_m", "features": [] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"subsystem": "startup",
|
||||
"components": [
|
||||
{ "component": "bootstrap_lite", "features":[] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"subsystem": "distributedschedule",
|
||||
"components": [
|
||||
{ "component": "samgr_lite", "features":[] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"subsystem": "hiviewdfx",
|
||||
"components": [
|
||||
{ "component": "hilog_lite", "features":[] },
|
||||
{ "component": "hievent_lite", "features":[] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"subsystem": "update",
|
||||
"components": [
|
||||
{ "component": "hota", "features": [
|
||||
"ohos_security_huks_mbedtls_porting_path = \"//device/soc/telink/b91/adapter/hals/mbedtls\""
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"subsystem": "utils",
|
||||
"components": [
|
||||
{ "component": "file", "features":[] },
|
||||
{
|
||||
"component": "kv_store",
|
||||
"features": [
|
||||
"enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = false"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"third_party_dir": "//third_party",
|
||||
"vendor_adapter_dir": "//device/soc/telink/b91/adapter",
|
||||
"product_adapter_dir": "//vendor/telink/led_demo/hals"
|
||||
}
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
# Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
static_library("hal_sysparam") {
|
||||
sources = [ "hal_sys_param.c" ]
|
||||
include_dirs = [ "//base/startup/syspara_lite/hals" ]
|
||||
defines = [
|
||||
"INCREMENTAL_VERSION=\"${ohos_version}\"",
|
||||
"BUILD_TYPE=\"${ohos_build_type}\"",
|
||||
"BUILD_USER=\"${ohos_build_user}\"",
|
||||
"BUILD_TIME=\"${ohos_build_time}\"",
|
||||
"BUILD_HOST=\"${ohos_build_host}\"",
|
||||
"BUILD_ROOTHASH=\"${ohos_build_roothash}\"",
|
||||
]
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "hal_sys_param.h"
|
||||
|
||||
static const char OHOS_DEVICE_TYPE[] = {"Evaluation Board"};
|
||||
static const char OHOS_DISPLAY_VERSION[] = {"OpenHarmony 3.x"};
|
||||
static const char OHOS_MANUFACTURE[] = {"Telink"};
|
||||
static const char OHOS_BRAND[] = {"Telink"};
|
||||
static const char OHOS_MARKET_NAME[] = {"B91 Generic Starter Kit"};
|
||||
static const char OHOS_PRODUCT_SERIES[] = {"TLSR9"};
|
||||
static const char OHOS_PRODUCT_MODEL[] = {"v1.0.0"};
|
||||
static const char OHOS_SOFTWARE_MODEL[] = {"v1.0.0"};
|
||||
static const char OHOS_HARDWARE_MODEL[] = {"v1.3"};
|
||||
static const char OHOS_HARDWARE_PROFILE[] = {"BLE:true"};
|
||||
static const char OHOS_BOOTLOADER_VERSION[] = {"bootloader"};
|
||||
static const char OHOS_ABI_LIST[] = {"default"};
|
||||
static const char OHOS_SERIAL[] = {"1234567890"};
|
||||
static const int OHOS_FIRST_API_VERSION = 1;
|
||||
|
||||
const char *HalGetDeviceType(void)
|
||||
{
|
||||
return OHOS_DEVICE_TYPE;
|
||||
}
|
||||
|
||||
const char *HalGetManufacture(void)
|
||||
{
|
||||
return OHOS_MANUFACTURE;
|
||||
}
|
||||
|
||||
const char *HalGetBrand(void)
|
||||
{
|
||||
return OHOS_BRAND;
|
||||
}
|
||||
|
||||
const char *HalGetMarketName(void)
|
||||
{
|
||||
return OHOS_MARKET_NAME;
|
||||
}
|
||||
|
||||
const char *HalGetProductSeries(void)
|
||||
{
|
||||
return OHOS_PRODUCT_SERIES;
|
||||
}
|
||||
|
||||
const char *HalGetProductModel(void)
|
||||
{
|
||||
return OHOS_PRODUCT_MODEL;
|
||||
}
|
||||
|
||||
const char *HalGetSoftwareModel(void)
|
||||
{
|
||||
return OHOS_SOFTWARE_MODEL;
|
||||
}
|
||||
|
||||
const char *HalGetHardwareModel(void)
|
||||
{
|
||||
return OHOS_HARDWARE_MODEL;
|
||||
}
|
||||
|
||||
const char *HalGetHardwareProfile(void)
|
||||
{
|
||||
return OHOS_HARDWARE_PROFILE;
|
||||
}
|
||||
|
||||
const char *HalGetSerial(void)
|
||||
{
|
||||
return OHOS_SERIAL;
|
||||
}
|
||||
|
||||
const char *HalGetBootloaderVersion(void)
|
||||
{
|
||||
return OHOS_BOOTLOADER_VERSION;
|
||||
}
|
||||
|
||||
const char *HalGetAbiList(void)
|
||||
{
|
||||
return OHOS_ABI_LIST;
|
||||
}
|
||||
|
||||
const char *HalGetDisplayVersion(void)
|
||||
{
|
||||
return OHOS_DISPLAY_VERSION;
|
||||
}
|
||||
|
||||
const char *HalGetIncrementalVersion(void)
|
||||
{
|
||||
return INCREMENTAL_VERSION;
|
||||
}
|
||||
|
||||
const char *HalGetBuildType(void)
|
||||
{
|
||||
return BUILD_TYPE;
|
||||
}
|
||||
|
||||
const char *HalGetBuildUser(void)
|
||||
{
|
||||
return BUILD_USER;
|
||||
}
|
||||
|
||||
const char *HalGetBuildHost(void)
|
||||
{
|
||||
return BUILD_HOST;
|
||||
}
|
||||
|
||||
const char *HalGetBuildTime(void)
|
||||
{
|
||||
return BUILD_TIME;
|
||||
}
|
||||
|
||||
int HalGetFirstApiVersion(void)
|
||||
{
|
||||
return OHOS_FIRST_API_VERSION;
|
||||
}
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
# Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
static_library("hal_token_static") {
|
||||
sources = [ "hal_token.c" ]
|
||||
|
||||
include_dirs = [
|
||||
"//base/startup/syspara_lite/hals",
|
||||
"//utils/native/lite/include",
|
||||
]
|
||||
deps = []
|
||||
}
|
||||
Executable
+107
@@ -0,0 +1,107 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "hal_token.h"
|
||||
#include "ohos_errno.h"
|
||||
#include "ohos_types.h"
|
||||
|
||||
static int OEMReadToken(char *token, unsigned int len)
|
||||
{
|
||||
// OEM need add here, read token from device
|
||||
(void)(token);
|
||||
(void)(len);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int OEMWriteToken(const char *token, unsigned int len)
|
||||
{
|
||||
// OEM need add here, write token to device
|
||||
(void)(token);
|
||||
(void)(len);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int OEMGetAcKey(char *acKey, unsigned int len)
|
||||
{
|
||||
// OEM need add here, get AcKey
|
||||
(void)(acKey);
|
||||
(void)(len);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int OEMGetProdId(char *productId, unsigned int len)
|
||||
{
|
||||
// OEM need add here, get ProdId
|
||||
(void)(productId);
|
||||
(void)(len);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int OEMGetProdKey(char *productKey, unsigned int len)
|
||||
{
|
||||
// OEM need add here, get ProdKey
|
||||
(void)(productKey);
|
||||
(void)(len);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int HalReadToken(char *token, unsigned int len)
|
||||
{
|
||||
if (token == NULL) {
|
||||
return EC_FAILURE;
|
||||
}
|
||||
|
||||
return OEMReadToken(token, len);
|
||||
}
|
||||
|
||||
int HalWriteToken(const char *token, unsigned int len)
|
||||
{
|
||||
if (token == NULL) {
|
||||
return EC_FAILURE;
|
||||
}
|
||||
|
||||
return OEMWriteToken(token, len);
|
||||
}
|
||||
|
||||
int HalGetAcKey(char *acKey, unsigned int len)
|
||||
{
|
||||
if (acKey == NULL) {
|
||||
return EC_FAILURE;
|
||||
}
|
||||
|
||||
return OEMGetAcKey(acKey, len);
|
||||
}
|
||||
|
||||
int HalGetProdId(char *productId, unsigned int len)
|
||||
{
|
||||
if (productId == NULL) {
|
||||
return EC_FAILURE;
|
||||
}
|
||||
|
||||
return OEMGetProdId(productId, len);
|
||||
}
|
||||
|
||||
int HalGetProdKey(char *productKey, unsigned int len)
|
||||
{
|
||||
if (productKey == NULL) {
|
||||
return EC_FAILURE;
|
||||
}
|
||||
|
||||
return OEMGetProdKey(productKey, len);
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
# Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//drivers/adapter/khdf/liteos_m/hdf.gni")
|
||||
|
||||
module_name = "hdf_hcs"
|
||||
hdf_driver(module_name) {
|
||||
hcs_sources = [ "hdf.hcs" ]
|
||||
visibility += [
|
||||
"$device_path",
|
||||
".",
|
||||
]
|
||||
}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
#include "../../../device/soc/telink/b91/hcs/hdf.hcs"
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
LOSCFG_PLATFORM_QEMU_RISCV32_VIRT=y
|
||||
LOSCFG_SOC_SERIES_B91=y
|
||||
LOSCFG_FS_LITTLEFS=y
|
||||
LOSCFG_DRIVERS_HDF=y
|
||||
LOSCFG_DRIVERS_HDF_PLATFORM=y
|
||||
LOSCFG_DRIVERS_HDF_PLATFORM_GPIO=y
|
||||
#LOSCFG_CC_NO_STACKPROTECTOR=y
|
||||
LOSCFG_COMPILE_OPTIMIZE_SIZE=n
|
||||
#LOSCFG_COMPILE_OPTIMIZE=n
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
LOSCFG_PLATFORM_QEMU_RISCV32_VIRT=y
|
||||
LOSCFG_SOC_SERIES_B91=y
|
||||
LOSCFG_FS_LITTLEFS=y
|
||||
LOSCFG_DRIVERS_HDF=y
|
||||
LOSCFG_DRIVERS_HDF_PLATFORM=y
|
||||
LOSCFG_DRIVERS_HDF_PLATFORM_GPIO=y
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"parts": {
|
||||
"product_ota_demo": {
|
||||
"module_list": [
|
||||
"//vendor/telink/ota_demo:ota_demo"
|
||||
]
|
||||
}
|
||||
},
|
||||
"subsystem": "product_ota_demo"
|
||||
}
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
# Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//drivers/adapter/khdf/liteos_m/hdf.gni")
|
||||
|
||||
declare_args() {
|
||||
telink_gpio_irq_sample_enable = false
|
||||
}
|
||||
|
||||
config("myapp_config") {
|
||||
include_dirs = [
|
||||
"//utils/native/lite/include",
|
||||
"//base/update/ota_lite/interfaces/kits",
|
||||
"//base/update/ota_lite/frameworks/source/verify",
|
||||
"$ohos_third_party_dir/mbedtls/include",
|
||||
]
|
||||
|
||||
configs = [
|
||||
"//device/soc/telink/b91:B91_config",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("myapp_inner") {
|
||||
sources = [
|
||||
"app.c",
|
||||
"serial.c",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//base/hiviewdfx/hiview_lite",
|
||||
"//base/update/ota_lite/frameworks:ota_lite",
|
||||
]
|
||||
|
||||
if (!defined(defines)) {
|
||||
defines = []
|
||||
}
|
||||
|
||||
if (telink_gpio_irq_sample_enable) {
|
||||
defines += [ "TELINK_GPIO_IRQ_SAMPLE_ENABLE=1" ]
|
||||
} else {
|
||||
defines += [ "TELINK_GPIO_IRQ_SAMPLE_ENABLE=0" ]
|
||||
}
|
||||
|
||||
configs += [ ":myapp_config" ]
|
||||
}
|
||||
|
||||
static_library("ota_demo") {
|
||||
deps = [
|
||||
":myapp_inner",
|
||||
]
|
||||
|
||||
configs += [ ":myapp_config" ]
|
||||
}
|
||||
Executable
+630
@@ -0,0 +1,630 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <los_arch_interrupt.h>
|
||||
#include <los_task.h>
|
||||
|
||||
#include <hota_updater.h>
|
||||
#include <ohos_init.h>
|
||||
#include <ohos_types.h>
|
||||
|
||||
#include <hiview_log.h>
|
||||
|
||||
#include <app_sha256.h>
|
||||
#include <hota_verify.h>
|
||||
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/pk.h>
|
||||
|
||||
#include <board_config.h>
|
||||
|
||||
#include <B91/flash.h>
|
||||
#include <B91/uart.h>
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
#define OTA_UART_TASK_PRIO 7
|
||||
|
||||
#define SOH 0x01
|
||||
#define STX 0x02
|
||||
#define EOT 0x04
|
||||
#define ACK 0x06
|
||||
#define NAK 0x15
|
||||
#define CAN 0x18
|
||||
#define CTRLZ 0x1A
|
||||
|
||||
#define DLY_1S 1000
|
||||
#define MAXRETRANS 25
|
||||
|
||||
#define XMODEM_BUF_SIZE 1024
|
||||
|
||||
typedef enum {
|
||||
COMMAND_TYPE_ERROR_TIMEOUT = -1,
|
||||
COMMAND_TYPE_ERROR_PREAMBLE = -2,
|
||||
COMMAND_TYPE_ERROR_WRONG_COMMAND = -3,
|
||||
COMMAND_TYPE_ERROR_WRONG_ARGS = -4,
|
||||
|
||||
COMMAND_TYPE_UPLOAD = 0,
|
||||
COMMAND_TYPE_PRINT = 1,
|
||||
COMMAND_TYPE_CANCEL = 2,
|
||||
COMMAND_TYPE_ERASE = 3,
|
||||
COMMAND_TYPE_HASH_SHA256 = 4,
|
||||
COMMAND_TYPE_RESTART = 5,
|
||||
COMMAND_TYPE_ROLLBACK = 6,
|
||||
COMMAND_TYPE_DEBUG = 7,
|
||||
COMMAND_TYPE_SIGN = 8,
|
||||
} CommandType;
|
||||
|
||||
unsigned short crc16_ccitt(const unsigned char *buf, int len)
|
||||
{
|
||||
unsigned short crc = 0;
|
||||
while (len--) {
|
||||
int i;
|
||||
crc ^= *(char *)buf++ << 8;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (crc & 0x8000) {
|
||||
crc = (crc << 1) ^ 0x1021;
|
||||
} else {
|
||||
crc = crc << 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
static int check(bool is_crc, const unsigned char *buf, int sz)
|
||||
{
|
||||
if (is_crc) {
|
||||
unsigned short crc = crc16_ccitt(buf, sz);
|
||||
unsigned short tcrc = (buf[sz] << 8) + buf[sz + 1];
|
||||
if (crc == tcrc) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
unsigned char cks = 0;
|
||||
for (i = 0; i < sz; ++i) {
|
||||
cks += buf[i];
|
||||
}
|
||||
if (cks == buf[sz]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _inbyte(unsigned short timeout_ms)
|
||||
{
|
||||
int c = uart_read(LOS_MS2Tick(timeout_ms));
|
||||
return c;
|
||||
}
|
||||
|
||||
STATIC int read_with_echo(UINT32 timeout_ms)
|
||||
{
|
||||
int c = uart_read(LOS_MS2Tick(timeout_ms));
|
||||
if (c > 0) {
|
||||
if (0x7f == c) {
|
||||
uart_send_byte(UART1, 0x08);
|
||||
uart_send_byte(UART1, ' ');
|
||||
c = 0x08;
|
||||
}
|
||||
uart_send_byte(UART1, (unsigned char)c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void _outbyte(int c)
|
||||
{
|
||||
uart_send_byte(UART1, (unsigned char)c);
|
||||
}
|
||||
|
||||
static void flushinput(void)
|
||||
{
|
||||
while (_inbyte(((DLY_1S)*3) >> 1) >= 0) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*XModemReceiveCB)(uint8_t *buf, size_t addr, size_t len, void *arg);
|
||||
|
||||
int xmodemReceive(unsigned char *xbuff, int destsz, XModemReceiveCB cb, void *arg)
|
||||
{
|
||||
unsigned char *p;
|
||||
int bufsz, crc = 0;
|
||||
unsigned char trychar = 'C';
|
||||
unsigned char packetno = 1;
|
||||
int c, len = 0;
|
||||
int retry, retrans = MAXRETRANS;
|
||||
|
||||
for (;;) {
|
||||
for (retry = 0; retry < 16; ++retry) {
|
||||
if (trychar) {
|
||||
_outbyte(trychar);
|
||||
}
|
||||
if ((c = _inbyte((DLY_1S) << 1)) >= 0) {
|
||||
switch (c) {
|
||||
case SOH: {
|
||||
bufsz = 128;
|
||||
goto start_recv;
|
||||
}
|
||||
case STX: {
|
||||
bufsz = 1024;
|
||||
goto start_recv;
|
||||
}
|
||||
case EOT: {
|
||||
flushinput();
|
||||
_outbyte(ACK);
|
||||
return len; /* normal end */
|
||||
}
|
||||
case CAN: {
|
||||
if ((c = _inbyte(DLY_1S)) == CAN) {
|
||||
flushinput();
|
||||
_outbyte(ACK);
|
||||
return -1; /* canceled by remote */
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trychar == 'C') {
|
||||
trychar = NAK;
|
||||
continue;
|
||||
}
|
||||
flushinput();
|
||||
_outbyte(CAN);
|
||||
_outbyte(CAN);
|
||||
_outbyte(CAN);
|
||||
return -2; /* sync error */
|
||||
|
||||
start_recv:
|
||||
if (trychar == 'C') {
|
||||
crc = 1;
|
||||
}
|
||||
trychar = 0;
|
||||
p = xbuff;
|
||||
*p++ = c;
|
||||
|
||||
INT32 to_read = (bufsz + (crc ? 1 : 0) + 3);
|
||||
INT32 nread = uart_read_buf(LOS_MS2Tick(DLY_1S * 10), p, to_read);
|
||||
if (nread < to_read) {
|
||||
printf(" === %s:%d to_read: %d nread: %d\r\n", __func__, __LINE__, to_read, nread);
|
||||
goto reject;
|
||||
}
|
||||
|
||||
if (xbuff[1] == (unsigned char)(~xbuff[2]) &&
|
||||
(xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno - 1) && check(crc, &xbuff[3], bufsz)) {
|
||||
if (xbuff[1] == packetno) {
|
||||
int count = destsz - len;
|
||||
if (count > bufsz) {
|
||||
count = bufsz;
|
||||
}
|
||||
if (count > 0) {
|
||||
cb(&xbuff[3], len, count, arg);
|
||||
len += count;
|
||||
}
|
||||
++packetno;
|
||||
retrans = MAXRETRANS + 1;
|
||||
}
|
||||
if (--retrans <= 0) {
|
||||
flushinput();
|
||||
_outbyte(CAN);
|
||||
_outbyte(CAN);
|
||||
_outbyte(CAN);
|
||||
return -3; /* too many retry error */
|
||||
}
|
||||
_outbyte(ACK);
|
||||
continue;
|
||||
}
|
||||
reject:
|
||||
flushinput();
|
||||
_outbyte(NAK);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC ptrdiff_t ReadLine(char *buf, size_t bufLen)
|
||||
{
|
||||
ptrdiff_t i;
|
||||
|
||||
for (i = 0; i < bufLen;) {
|
||||
char c;
|
||||
if ((c = read_with_echo(5000)) < 0) {
|
||||
return COMMAND_TYPE_ERROR_TIMEOUT;
|
||||
}
|
||||
|
||||
if ('\r' == c) {
|
||||
continue;
|
||||
}
|
||||
if ('\n' == c) {
|
||||
break;
|
||||
}
|
||||
if ((0x08 == c)) {
|
||||
if (i > 0) {
|
||||
buf[--i] = '\0';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buf[i++] = c;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
STATIC CommandType CommandProcess(UINT32 *arg1, UINT32 *arg2)
|
||||
{
|
||||
int c;
|
||||
if ((c = read_with_echo(LOS_WAIT_FOREVER)) < 0) {
|
||||
return COMMAND_TYPE_ERROR_TIMEOUT;
|
||||
}
|
||||
if ('{' != c) {
|
||||
return COMMAND_TYPE_ERROR_PREAMBLE;
|
||||
}
|
||||
|
||||
if ((c = read_with_echo(5000)) < 0) {
|
||||
return COMMAND_TYPE_ERROR_TIMEOUT;
|
||||
}
|
||||
|
||||
CommandType cmd;
|
||||
|
||||
switch (c) {
|
||||
case 'u': {
|
||||
cmd = COMMAND_TYPE_UPLOAD;
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
cmd = COMMAND_TYPE_PRINT;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
cmd = COMMAND_TYPE_CANCEL;
|
||||
break;
|
||||
}
|
||||
case 'h': {
|
||||
cmd = COMMAND_TYPE_HASH_SHA256;
|
||||
break;
|
||||
}
|
||||
case 'r': {
|
||||
cmd = COMMAND_TYPE_RESTART;
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
cmd = COMMAND_TYPE_ROLLBACK;
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
cmd = COMMAND_TYPE_DEBUG;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
cmd = COMMAND_TYPE_SIGN;
|
||||
return cmd;
|
||||
}
|
||||
default: {
|
||||
return COMMAND_TYPE_ERROR_WRONG_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
char buf[32] = {0};
|
||||
|
||||
ptrdiff_t res = ReadLine(buf, sizeof(buf));
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
*arg1 = UINT32_MAX;
|
||||
*arg2 = UINT32_MAX;
|
||||
|
||||
if ((COMMAND_TYPE_UPLOAD == cmd) || (COMMAND_TYPE_PRINT == cmd) || (COMMAND_TYPE_HASH_SHA256 == cmd)) {
|
||||
char *p;
|
||||
errno = ENOERR;
|
||||
*arg1 = strtoul(buf, &p, 10);
|
||||
if (((0 == *arg1) || (ULONG_MAX == *arg1)) && (ENOERR != errno)) {
|
||||
printf(" === %s:%d errno: %d\r\n", __func__, __LINE__, errno);
|
||||
return COMMAND_TYPE_ERROR_WRONG_ARGS;
|
||||
}
|
||||
*arg2 = strtoul(p, &p, 10);
|
||||
if (((0 == *arg2) || (ULONG_MAX == *arg2)) && (ENOERR != errno)) {
|
||||
printf(" === %s:%d errno: %d\r\n", __func__, __LINE__, errno);
|
||||
*arg2 = UINT32_MAX;
|
||||
}
|
||||
} else if (COMMAND_TYPE_CANCEL == cmd) {
|
||||
if (0 != strcmp("ancel", buf)) {
|
||||
return COMMAND_TYPE_ERROR_WRONG_COMMAND;
|
||||
}
|
||||
} else if (COMMAND_TYPE_RESTART == cmd) {
|
||||
if (0 != strcmp("estart", buf)) {
|
||||
return COMMAND_TYPE_ERROR_WRONG_COMMAND;
|
||||
}
|
||||
} else if (COMMAND_TYPE_ROLLBACK == cmd) {
|
||||
if (0 != strcmp("ack", buf)) {
|
||||
return COMMAND_TYPE_ERROR_WRONG_COMMAND;
|
||||
}
|
||||
} else if (COMMAND_TYPE_DEBUG == cmd) {
|
||||
c = buf[0];
|
||||
if (c != 'm' && c != 'f') {
|
||||
return COMMAND_TYPE_ERROR_WRONG_COMMAND;
|
||||
}
|
||||
char *p;
|
||||
errno = ENOERR;
|
||||
UINT32 addr = strtoul(buf + 1, &p, 10);
|
||||
if (((0 == addr) || (ULONG_MAX == addr)) && (ENOERR != errno)) {
|
||||
printf(" === %s:%d errno: %d\r\n", __func__, __LINE__, errno);
|
||||
return COMMAND_TYPE_ERROR_WRONG_ARGS;
|
||||
}
|
||||
UINT32 sz = strtoul(p, &p, 10);
|
||||
if (((0 == sz) || (ULONG_MAX == sz)) && (ENOERR != errno)) {
|
||||
printf(" === %s:%d errno: %d\r\n", __func__, __LINE__, errno);
|
||||
sz = 1;
|
||||
}
|
||||
if (c == 'm') {
|
||||
p = (const char *)addr;
|
||||
} else if (c == 'f') {
|
||||
p = malloc(sz);
|
||||
flash_read_page(addr, sz, p);
|
||||
}
|
||||
printf("Debug(%c): ", c);
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
printf("%02x", p[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
if (c == 'f') {
|
||||
free(p);
|
||||
}
|
||||
} else if (COMMAND_TYPE_SIGN == cmd) {
|
||||
if (0 != strcmp("ign", buf)) {
|
||||
return COMMAND_TYPE_ERROR_WRONG_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void OtaErrorCallBack(HotaErrorCode errorCode)
|
||||
{
|
||||
printf(" === %s:%d errorCode: %d\r\n", __func__, __LINE__, errorCode);
|
||||
}
|
||||
|
||||
void OtaStatusCallBack(HotaStatus status)
|
||||
{
|
||||
printf(" === %s:%d status: %d\r\n", __func__, __LINE__, status);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int sz, start;
|
||||
|
||||
AppSha256Context sha256;
|
||||
} xmodemReceiveCBArg;
|
||||
|
||||
void xmodemReceiveCB(uint8_t *buf, size_t addr, size_t len, void *_arg)
|
||||
{
|
||||
xmodemReceiveCBArg *arg = _arg;
|
||||
int to_print = len;
|
||||
if (to_print > 0) {
|
||||
printf("Received[%d %d %u %d]: \"", arg->sz, arg->start, addr, to_print);
|
||||
printf("\"\r\n");
|
||||
AppSha256Update(&arg->sha256, buf, len);
|
||||
unsigned int offset = (unsigned)(arg->start > 0 ? arg->start : 0) + addr;
|
||||
HotaWrite(buf, offset, len);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC ptrdiff_t ReadSign(UINT8 *sign, unsigned len)
|
||||
{
|
||||
char buf[32];
|
||||
size_t nbytes = 0;
|
||||
while (nbytes < len) {
|
||||
ptrdiff_t res = ReadLine(buf, sizeof(buf));
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (nbytes + (res / 2) > len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < res; i += 2) {
|
||||
char hex[3] = {buf[i], buf[i + 1], '\0'};
|
||||
errno = ENOERR;
|
||||
UINT32 num = strtoul(hex, NULL, 16);
|
||||
if (((0 == num) || (ULONG_MAX == num)) && (ENOERR != errno)) {
|
||||
printf(" === %s:%d errno: %d \"%s\"\r\n", __func__, __LINE__, errno, hex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sign[nbytes++] = num;
|
||||
}
|
||||
|
||||
if (res < sizeof(buf)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
STATIC VOID OTA_TestThread(VOID)
|
||||
{
|
||||
printf(" === %s:%d\r\n", __func__, __LINE__);
|
||||
|
||||
SerialInit();
|
||||
|
||||
unsigned char *workBuf = malloc(XMODEM_BUF_SIZE + 6); /* 6 bytes XModem overhead */
|
||||
uint8_t hash[32];
|
||||
|
||||
while (1) {
|
||||
int sz, sz2;
|
||||
CommandType cmd = CommandProcess((UINT32 *)&sz, (UINT32 *)&sz2);
|
||||
printf(" === %s:%d cmd: %d sz: %d sz2: %d\r\n", __func__, __LINE__, cmd, sz, sz2);
|
||||
|
||||
int res = 0;
|
||||
if (COMMAND_TYPE_UPLOAD == cmd) {
|
||||
xmodemReceiveCBArg arg = {sz, sz2, {0}};
|
||||
AppSha256Init(&arg.sha256);
|
||||
res = xmodemReceive(workBuf, sz, xmodemReceiveCB, &arg);
|
||||
AppSha256Finish(&arg.sha256, hash);
|
||||
printf("sha256: ");
|
||||
for (size_t i = 0; i < sizeof(hash); ++i) {
|
||||
printf("%02x", hash[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
} else if (COMMAND_TYPE_PRINT == cmd) {
|
||||
unsigned start = sz; // & ~0xFF; //(sz / 256) * 256;
|
||||
unsigned bufLen = (unsigned)(sz2 >= 0 ? sz2 : 256);
|
||||
|
||||
for (unsigned offset = 0, next = XMODEM_BUF_SIZE; next < bufLen; offset = next, next += XMODEM_BUF_SIZE) {
|
||||
if (OHOS_SUCCESS == HotaRead(start + offset, XMODEM_BUF_SIZE, workBuf)) {
|
||||
}
|
||||
printf("Read[%u %u %u %u]: {", start, start + offset, XMODEM_BUF_SIZE, bufLen);
|
||||
for (size_t i = 0; i < XMODEM_BUF_SIZE; ++i) {
|
||||
printf("%02x", workBuf[i]);
|
||||
}
|
||||
printf("}\r\n");
|
||||
}
|
||||
|
||||
unsigned rem = bufLen % XMODEM_BUF_SIZE;
|
||||
|
||||
if (0 != rem) {
|
||||
if (OHOS_SUCCESS == HotaRead(start + bufLen - rem, rem, workBuf)) {
|
||||
}
|
||||
printf("Read[%u %u %u %u]: {", start, start + bufLen - rem, rem, bufLen);
|
||||
for (size_t i = 0; i < rem; ++i) {
|
||||
printf("%02x", workBuf[i]);
|
||||
}
|
||||
printf("}\r\n");
|
||||
}
|
||||
} else if (COMMAND_TYPE_HASH_SHA256 == cmd) {
|
||||
unsigned start = sz;
|
||||
unsigned bufLen = (unsigned)(sz2 >= 0 ? sz2 : 256);
|
||||
uint8_t hashLocal[32];
|
||||
|
||||
AppSha256Context sha256;
|
||||
AppSha256Init(&sha256);
|
||||
|
||||
for (unsigned offset = 0, next = XMODEM_BUF_SIZE; next < bufLen; offset = next, next += XMODEM_BUF_SIZE) {
|
||||
if (OHOS_SUCCESS == HotaRead(start + offset, XMODEM_BUF_SIZE, workBuf)) {
|
||||
}
|
||||
AppSha256Update(&sha256, workBuf, XMODEM_BUF_SIZE);
|
||||
}
|
||||
|
||||
unsigned rem = bufLen % XMODEM_BUF_SIZE;
|
||||
|
||||
if (0 != rem) {
|
||||
if (OHOS_SUCCESS == HotaRead(start + bufLen - rem, rem, workBuf)) {
|
||||
}
|
||||
AppSha256Update(&sha256, workBuf, rem);
|
||||
}
|
||||
|
||||
AppSha256Finish(&sha256, hashLocal);
|
||||
printf("sha256: ");
|
||||
for (size_t i = 0; i < sizeof(hashLocal); ++i) {
|
||||
printf("%02x", hashLocal[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
} else if (COMMAND_TYPE_SIGN == cmd) {
|
||||
UINT8 sign[128];
|
||||
ptrdiff_t len = ReadSign(sign, sizeof(sign));
|
||||
if (len < 0) {
|
||||
printf(" === ERROR %s:%d res: %d\r\n", __func__, __LINE__, len);
|
||||
} else {
|
||||
mbedtls_pk_context context;
|
||||
uint32 length = 0;
|
||||
|
||||
mbedtls_pk_init(&context);
|
||||
uint8 *keyBuf = HotaGetPubKey(&length);
|
||||
if (keyBuf == NULL) {
|
||||
printf("Get key fail\r\n");
|
||||
}
|
||||
|
||||
int32 parseRet = mbedtls_pk_parse_public_key(&context, keyBuf, length);
|
||||
if (parseRet != 0) {
|
||||
printf("Parse public key failed.\r\n");
|
||||
} else {
|
||||
int ret;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_rsa_set_padding(mbedtls_pk_rsa(context), MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);
|
||||
mbedtls_entropy_init(&entropy);
|
||||
if ((ret = mbedtls_rsa_pkcs1_verify(mbedtls_pk_rsa(context), NULL, NULL, MBEDTLS_RSA_PUBLIC,
|
||||
MBEDTLS_MD_SHA256, sizeof(hash), hash, sign)) != 0) {
|
||||
printf("Sign check fail!\r\n");
|
||||
} else {
|
||||
printf("Sign check success!\r\n");
|
||||
}
|
||||
mbedtls_pk_free(&context);
|
||||
}
|
||||
}
|
||||
} else if (COMMAND_TYPE_CANCEL == cmd) {
|
||||
HotaCancel();
|
||||
(VOID) HotaInit(OtaErrorCallBack, OtaStatusCallBack);
|
||||
(VOID) HotaSetPackageType(NOT_USE_DEFAULT_PKG);
|
||||
} else if (COMMAND_TYPE_RESTART == cmd) {
|
||||
int ret = HotaRestart();
|
||||
printf("HotaRestart() = %d\r\n", ret);
|
||||
} else if (COMMAND_TYPE_ROLLBACK == cmd) {
|
||||
int HotaHalRollback(void);
|
||||
int ret = HotaHalRollback();
|
||||
printf("HotaHalRollback() = %d\r\n", ret);
|
||||
}
|
||||
printf(" === %s:%d res: %d\r\n", __func__, __LINE__, res);
|
||||
}
|
||||
|
||||
free(workBuf);
|
||||
}
|
||||
|
||||
VOID OtaUartTestInit(VOID)
|
||||
{
|
||||
(VOID) HotaInit(OtaErrorCallBack, OtaStatusCallBack);
|
||||
(VOID) HotaSetPackageType(NOT_USE_DEFAULT_PKG);
|
||||
|
||||
UINT32 ret = LOS_OK;
|
||||
|
||||
unsigned int task_id;
|
||||
TSK_INIT_PARAM_S task_param = {0};
|
||||
|
||||
task_param.pfnTaskEntry = (TSK_ENTRY_FUNC)OTA_TestThread;
|
||||
task_param.uwStackSize = 1024 * 16;
|
||||
task_param.pcName = "OTA_TestThread";
|
||||
task_param.usTaskPrio = OTA_UART_TASK_PRIO;
|
||||
ret = LOS_TaskCreate(&task_id, &task_param);
|
||||
if (ret != LOS_OK) {
|
||||
printf("Create Task failed! ERROR: 0x%x\r\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
void AppMain(void)
|
||||
{
|
||||
printf("%s %s\r\n", __DATE__, __TIME__);
|
||||
printf("%s: %p\r\n", __func__, AppMain);
|
||||
|
||||
OtaUartTestInit();
|
||||
}
|
||||
|
||||
SYS_RUN(AppMain);
|
||||
@@ -0,0 +1,280 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <los_event.h>
|
||||
#include <los_mux.h>
|
||||
#include <los_interrupt.h>
|
||||
|
||||
#include <B91/clock.h>
|
||||
#include <B91/plic.h>
|
||||
#include <B91/uart.h>
|
||||
|
||||
#include <b91_irq.h>
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
#define SERVICE_UART_PORT UART1
|
||||
#define SERVICE_UART_PIN_TX UART1_TX_PE0
|
||||
#define SERVICE_UART_PIN_RX UART1_RX_PE2
|
||||
#define SERVICE_UART_PARITY UART_PARITY_NONE
|
||||
#define SERVICE_UART_STOP_BITS UART_STOP_BIT_ONE
|
||||
#define SERVICE_UART_BAUDRATE 115200
|
||||
|
||||
#define UARTS_COUNT 2
|
||||
|
||||
#define UART_RX_BUF 256
|
||||
|
||||
#define NON_VALID_MUTEX_ID UINT32_MAX
|
||||
//#define NUM_HAL_INTERRUPT_UART (RISCV_INTERRUPT__PLATFORM_USE + IRQ19_UART0)
|
||||
|
||||
/**
|
||||
* TX:
|
||||
* - Any interface functions are thread-safe after kernel started and @c uart_init is called.
|
||||
* - If buffer is enabled then data are stored in buffer and sent on background using @c UartIdleThreadHandler.
|
||||
* - Considering that Idle thread will capture mutex, all threads that want put data to buffer will wait while Idle
|
||||
* thread will send data to UART. To prevent it, there is mechanism of preemption. Threads that indend to put data
|
||||
* to buffer signalize about it using @c threadWait variable and Idle function will exit after next byte printed.
|
||||
*
|
||||
* RX:
|
||||
* LiteOS Queue has very huge overhead for byte buffer where access is performed byte by byte. LiteOS Ringbuf
|
||||
* doesn't support blocking when no data available. So there is implemented simple ring buffer using Spinlock for
|
||||
* thread-safety and Event for data waiting.
|
||||
*/
|
||||
static struct {
|
||||
struct {
|
||||
struct {
|
||||
UINT32 mux;
|
||||
#if LOSCFG_UART_BUFFERED_TX_BUFFER_ENABLE
|
||||
size_t start;
|
||||
size_t end;
|
||||
#if UART_TX_THREAD_PREEMTION_ENABLE
|
||||
bool threadWait;
|
||||
#endif /* ENABLE_UART_THREAD_PREEMTION */
|
||||
#endif /* LOSCFG_UART_BUFFERED_TX_BUFFER_ENABLE */
|
||||
} tx;
|
||||
struct {
|
||||
size_t start;
|
||||
size_t end;
|
||||
EVENT_CB_S event;
|
||||
struct {
|
||||
UINT8 *ptr;
|
||||
INT32 nbytes;
|
||||
INT32 max;
|
||||
} irq_buf;
|
||||
} rx;
|
||||
} dev[UARTS_COUNT];
|
||||
|
||||
bool init;
|
||||
} g_uartState = {
|
||||
.dev[0 ...(UARTS_COUNT - 1)] =
|
||||
{
|
||||
.tx =
|
||||
{
|
||||
.mux = NON_VALID_MUTEX_ID,
|
||||
#if LOSCFG_UART_BUFFERED_TX_BUFFER_ENABLE
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
#if UART_TX_THREAD_PREEMTION_ENABLE
|
||||
.threadWait = false,
|
||||
#endif /* ENABLE_UART_THREAD_PREEMTION */
|
||||
#endif /* LOSCFG_UART_BUFFERED_TX_BUFFER_ENABLE */
|
||||
},
|
||||
.rx =
|
||||
{
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
},
|
||||
},
|
||||
.init = false,
|
||||
};
|
||||
|
||||
__attribute__((unused)) static struct {
|
||||
#if LOSCFG_UART_BUFFERED_TX_BUFFER_ENABLE
|
||||
CHAR tx[UART_TX_BUF];
|
||||
#endif /* LOSCFG_UART_BUFFERED_TX_BUFFER_ENABLE */
|
||||
CHAR rx[UART_RX_BUF];
|
||||
} g_uartBuf[UARTS_COUNT];
|
||||
|
||||
VOID VendorUartInit(UINT32 uartNum, UINT32 baudrate);
|
||||
|
||||
STATIC_INLINE VOID VendorUartSendByte(UINT32 uartNum, UINT8 txData)
|
||||
{
|
||||
uart_send_byte(uartNum, txData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function serves to send data by byte with not DMA method. Returns immediately.
|
||||
* @param[in] uart_num - UART0 or UART1.
|
||||
* @param[in] tx_data - the data to be send.
|
||||
* @return @c true - if data is sent successfully, @c false - if fifo is full
|
||||
*/
|
||||
static inline bool uart_send_byte_nonblock(uart_num_e uart_num, unsigned char tx_data)
|
||||
{
|
||||
if (uart_get_txfifo_num(uart_num) > 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char index = uart_tx_byte_index[uart_num];
|
||||
reg_uart_data_buf(uart_num, index) = tx_data;
|
||||
index = (index + 1) & 0x03;
|
||||
uart_tx_byte_index[uart_num] = index;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC INLINE bool VendorUartSendByteNonBlock(UINT32 uartNum, UINT8 txData)
|
||||
{
|
||||
return uart_send_byte_nonblock(uartNum, txData);
|
||||
}
|
||||
|
||||
STATIC INLINE char VendorUartGetChar(UINT32 uartNum)
|
||||
{
|
||||
return (char)uart_read_byte(uartNum);
|
||||
}
|
||||
|
||||
STATIC INLINE void VendorUartTxIrqEnable(UINT32 uartNum, bool state)
|
||||
{
|
||||
if (state) {
|
||||
uart_set_irq_mask(uartNum, UART_TX_IRQ_MASK);
|
||||
} else {
|
||||
uart_clr_irq_mask(uartNum, UART_TX_IRQ_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC INLINE void VendorUartRxIrqEnable(UINT32 uartNum, bool state)
|
||||
{
|
||||
if (state) {
|
||||
uart_set_irq_mask(uartNum, UART_RX_IRQ_MASK);
|
||||
} else {
|
||||
uart_clr_irq_mask(uartNum, UART_RX_IRQ_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
INT32 uart_read(UINT32 timeOut)
|
||||
{
|
||||
UINT32 intSave;
|
||||
INT32 rec = 0;
|
||||
|
||||
intSave = LOS_IntLock();
|
||||
|
||||
/* Spinlock disables interrupts. So it should be unlocked while waiting for data.
|
||||
* Data availability check is looped because another thread can consume data before Spinlock will be locked again.
|
||||
*/
|
||||
while (g_uartState.dev[SERVICE_UART_PORT].rx.start == g_uartState.dev[SERVICE_UART_PORT].rx.end) {
|
||||
LOS_IntRestore(intSave);
|
||||
UINT32 ret = LOS_EventRead(&g_uartState.dev[SERVICE_UART_PORT].rx.event, 1, LOS_WAITMODE_OR | LOS_WAITMODE_CLR,
|
||||
timeOut);
|
||||
if (0 != (ret & LOS_ERRTYPE_ERROR)) {
|
||||
return -1;
|
||||
}
|
||||
intSave = LOS_IntLock();
|
||||
}
|
||||
|
||||
rec = (UINT8)g_uartBuf[SERVICE_UART_PORT].rx[g_uartState.dev[SERVICE_UART_PORT].rx.start];
|
||||
g_uartState.dev[SERVICE_UART_PORT].rx.start = (g_uartState.dev[SERVICE_UART_PORT].rx.start + 1) % UART_RX_BUF;
|
||||
|
||||
LOS_IntRestore(intSave);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
INT32 uart_read_buf(UINT32 timeOut, UINT8 *buf, INT32 max)
|
||||
{
|
||||
UINT32 intSave;
|
||||
INT32 nbytes = 0;
|
||||
|
||||
intSave = LOS_IntLock();
|
||||
|
||||
while ((nbytes < max) &&
|
||||
(g_uartState.dev[SERVICE_UART_PORT].rx.start != g_uartState.dev[SERVICE_UART_PORT].rx.end)) {
|
||||
buf[nbytes++] = (UINT8)g_uartBuf[SERVICE_UART_PORT].rx[g_uartState.dev[SERVICE_UART_PORT].rx.start];
|
||||
g_uartState.dev[SERVICE_UART_PORT].rx.start = (g_uartState.dev[SERVICE_UART_PORT].rx.start + 1) % UART_RX_BUF;
|
||||
}
|
||||
|
||||
if ((nbytes < max) && (0 != timeOut)) {
|
||||
g_uartState.dev->rx.irq_buf.ptr = buf;
|
||||
g_uartState.dev->rx.irq_buf.nbytes = nbytes;
|
||||
g_uartState.dev->rx.irq_buf.max = max;
|
||||
LOS_EventClear(&g_uartState.dev[SERVICE_UART_PORT].rx.event, ~1);
|
||||
LOS_IntRestore(intSave);
|
||||
LOS_EventRead(&g_uartState.dev[SERVICE_UART_PORT].rx.event, 1, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, timeOut);
|
||||
intSave = LOS_IntLock();
|
||||
nbytes = g_uartState.dev->rx.irq_buf.nbytes;
|
||||
g_uartState.dev->rx.irq_buf.ptr = NULL;
|
||||
g_uartState.dev->rx.irq_buf.nbytes = 0;
|
||||
g_uartState.dev->rx.irq_buf.max = 0;
|
||||
}
|
||||
|
||||
LOS_IntRestore(intSave);
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
STATIC UINT8 uart_getc_unsafe(uart_num_e uartNum)
|
||||
{
|
||||
UINT8 c = VendorUartGetChar(uartNum);
|
||||
|
||||
size_t nextEnd = (g_uartState.dev[uartNum].rx.end + 1) % UART_RX_BUF;
|
||||
if (nextEnd != g_uartState.dev[uartNum].rx.start) {
|
||||
g_uartBuf[uartNum].rx[g_uartState.dev[uartNum].rx.end] = c;
|
||||
g_uartState.dev[uartNum].rx.end = nextEnd;
|
||||
LOS_EventWrite(&g_uartState.dev[uartNum].rx.event, 1);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
STATIC VOID UartIrqHandler(void *arg)
|
||||
{
|
||||
uart_num_e uartNum = (uart_num_e)arg;
|
||||
while (uart_get_rxfifo_num(uartNum) > 0) {
|
||||
if (NULL != g_uartState.dev->rx.irq_buf.ptr) {
|
||||
UINT8 c = VendorUartGetChar(uartNum);
|
||||
g_uartState.dev->rx.irq_buf.ptr[g_uartState.dev->rx.irq_buf.nbytes++] = c;
|
||||
if (g_uartState.dev->rx.irq_buf.nbytes >= g_uartState.dev->rx.irq_buf.max) {
|
||||
g_uartState.dev->rx.irq_buf.ptr = NULL;
|
||||
LOS_EventWrite(&g_uartState.dev[uartNum].rx.event, 1);
|
||||
}
|
||||
} else {
|
||||
(VOID) uart_getc_unsafe(uartNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SerialInit(void)
|
||||
{
|
||||
LOS_EventInit(&g_uartState.dev[SERVICE_UART_PORT].rx.event);
|
||||
|
||||
unsigned short div;
|
||||
unsigned char bwpc;
|
||||
|
||||
uart_set_pin(SERVICE_UART_PIN_TX, SERVICE_UART_PIN_RX);
|
||||
uart_reset(SERVICE_UART_PORT);
|
||||
uart_cal_div_and_bwpc(SERVICE_UART_BAUDRATE, sys_clk.pclk * 1000 * 1000, &div, &bwpc);
|
||||
telink_b91_uart_init(SERVICE_UART_PORT, div, bwpc, SERVICE_UART_PARITY, SERVICE_UART_STOP_BITS);
|
||||
uart_rx_irq_trig_level(SERVICE_UART_PORT, 1);
|
||||
uart_tx_irq_trig_level(SERVICE_UART_PORT, 0);
|
||||
|
||||
B91IrqRegister(IRQ18_UART1, UartIrqHandler, SERVICE_UART_PORT);
|
||||
plic_interrupt_enable(IRQ18_UART1);
|
||||
VendorUartRxIrqEnable(SERVICE_UART_PORT, true);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
#include <los_compiler.h>
|
||||
|
||||
void SerialInit(void);
|
||||
|
||||
INT32 uart_read(UINT32 timeOut);
|
||||
INT32 uart_read_buf(UINT32 timeOut, UINT8 *buf, INT32 max);
|
||||
|
||||
#endif // SERIAL_H
|
||||
Reference in New Issue
Block a user