AliOS Things 笔记

AliOS Things 笔记

[TOC]

1技术架构总览

1.1架构概述

从底部到顶部,AliOS Things包括:

  • 板级支持包(BSP):主要由SoC供应商开发和维护
  • 硬件抽象层(HAL):比如WiFi和UART
  • 内核:包括Rhino实时操作系统内核、Yloop, VFS, KV 存储
  • 协议栈:包括TCP/IP协议栈(LwIP),uMesh网络协议栈
  • 安全:安全传输层协议(TLS),可信服务框架(TFS)、可信运行环境(TEE)
  • AOS API:提供可供应用软件和中间件使用的API
  • 中间件:包括常见的物联网组件和阿里巴巴增值服务中间件
  • 示例应用:阿里自主开发的示例代码,以及通过了完备测试的应用程序(比如Alinkapp)
    所有的模组都已经被组织成组件,且每个组件都有自己的.mk文件,用于描述它和其它组件间的依赖关系,方便应用开发者按需选用。

结构框图

ax.png

文件夹结构

文件夹名称 内容描述
board 评估板(如STM32L496G-Discovery)
build 编译框架
device 连接MCU/SoC的外设,比如支持使用AT命令的WiFi系列模组
example 代码示例,通过了完备测试的应用程序(比如Alink)
framework IoT 通用组件
include 系统头文件
kernel 包括Rhino和协议栈
platform 芯片架构支持的相关文件
security 包括TLS,TFS, TEE在内的安全组件
tools 命令行界面(CLI)和用于建立远程设备中心的testbed工具
utility IoT通用软件库,比如 cJSON
test UT测试用例

2快速开始

2.1配置环境

在一台 Ubuntu 14.04 LTS 64-bit PC 上

sudo apt-get install -y python
sudo apt-get install -y gcc-multilib
sudo apt-get install -y libssl-dev libssl-dev:i386
sudo apt-get install -y libncurses5-dev libncurses5-dev:i386
sudo apt-get install -y libreadline-dev libreadline-dev:i386
sudo apt-get install -y python-pip
sudo apt-get install -y minicom

2.2安装 aos-cube

首先, 用 python 包管理器 pip 来安装 aos-cube 和相关的依赖包在全局环境,以便于后续使用 AliOS Things Studio 进行开发。

$ pip install setuptools
$ pip install wheel
$ pip install aos-cube

请确认pip环境是基于 Python 2.7 的。如果遇到权限问题,可能需要 sudo 来执行。
如果在线安装aos-cube失败,可以下载源码安装,方法如下:

  • 先下载你要安装的包,并解压(aos-cube-0.2.46.tar.gz)
  • $ cd aos-cube-0.2.46
  • $ python setup.py build
  • $ python setup.py install

2.3下载代码并编译运行

git clone https://github.com/alibaba/AliOS-Things.git
cd AliOS-Things
aos make helloworld@linuxhost
./out/helloworld@linuxhost/binary/helloworld@linuxhost.elf

2.4效果

可以看见 app_delayed_action 在1秒时启动,每5秒触发一次。

 [   0.000]<V> AOS [application_start#15] : application started.
 [   1.000]<V> AOS [app_delayed_action#9] : helloworld app_delayed_action:9 app_task
 [   6.000]<V> AOS [app_delayed_action#9] : helloworld app_delayed_action:9 app_task
 [  11.000]<V> AOS [app_delayed_action#9] : helloworld app_delayed_action:9 app_task
 [  16.000]<V> AOS [app_delayed_action#9] : helloworld app_delayed_action:9 app_task
 [  21.000]<V> AOS [app_delayed_action#9] : helloworld app_delayed_action:9 app_task

3 编译过程

3.1 aos

2.2小结安装了aos-cube,aos-cube封装了一系列 AliOS Things使用的 Python包。
官方注解如下:

aos command line tool for repositories version control, publishing and updating code from remotely hosted repositories, and invoking aos own build system and export functions, among other operations

aos 用法如下:

[naiquanhu@naiquanhu-VirtualBox AliOS-Things]$ aos --help
usage: aos [-h] [--version]             ...

Code management tool for aos - https://code.aliyun.com/aos/aos
version 0.2.46

Use 'aos <command> -h|--help' for detailed help.
Online manual and guide available at https://code.aliyun.com/aos/aos-cube

optional arguments:
  -h, --help   show this help message and exit
  --version    print version number and exit

Commands:
             
    new        Create new aos program or component
    ls         List cube info, default components info
    import     Import program from URL
    add        Add component from AOS_SDK_PATH or URL
    rm         Remove component
    deploy     Find and add missing components and source codes
    codes      Import the optional component from the remote repository
    publish    Publish program or component
    update     Update to branch, tag, revision or latest
    sync       Synchronize aos component references
    status     Show version control status
               
    make       Make aos program/component
    scons      Make aos program/component by scons
    makelib    Compile static library
               
    config     Tool configuration
               
    upload     Upload aos image
    monitor    Serial port monitor
               
    devices    List devices on serial ports
               
    upgrade    Upgrade aos-cube to latest
    help       This help screen

看一下aos程序内容:

which aos

/usr/local/bin/aos
vi /usr/local/bin/aos

#!/usr/bin/python                                                                                  
# EASY-INSTALL-ENTRY-SCRIPT: 'aos-cube==0.2.46','console_scripts','aos'
__requires__ = 'aos-cube==0.2.46'
import sys 
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('aos-cube==0.2.46', 'console_scripts', 'aos')()
    )   

/usr/local/bin/aos会调用aos-cube-0.2.46/aos/aos.py

3.2 aos调用make过程

aos make helloworld@linuxhost

该命令会首先进入aos/aos.py中的main()

def _run_make(arg_list):
    #install dependent toolchains
    _install_toolchains(sys.argv[2:])

    # check operating system
    host_os = get_host_os()
    if host_os == None:
        error('Unsupported Operating System!')

    #cd to aos root_dir
    ret, original_dir = cd_aos_root()
    if ret != 'success':
        error("not in AliOS-Things source code directory")

    make_cmds = {
        'Win32': 'cmd/win32/make.exe',
        'Linux64': 'cmd/linux64/make',
        'Linux32': 'cmd/linux32/make',
        'OSX': 'cmd/osx/make'
        }
    tools_dir = os.path.join(os.getcwd(), 'build').replace('\\', '/')
    make_cmd = os.path.join(tools_dir, make_cmds[host_os])

    # Run make command
    make_cmd_str = ' '.join([make_cmd, 'HOST_OS=' + host_os, 'TOOLS_ROOT=' + tools_dir] + list(arg_list))
    popen(make_cmd_str, shell=True, cwd=os.getcwd())
    if os.path.isdir(original_dir): os.chdir(original_dir)

def make_build(make_args):
    # aos new program
    if os.path.isfile(os.path.join(os.getcwd(), Cfg.file)):
        ...
        with cd(os_path):
            ...
            _run_make(['-e', '-f build/Makefile', make_args, app_dir, build_dir])
    else:
        # aos source code
        _run_make(['-e', '-f build/Makefile', make_args])

# Make command
@subcommand('make',
            help='Make aos program/component',
            description="Make aos program/component.")
def make():
    ...
    args = sys.argv[2:]
    ...
    make_args = ' '.join(args)
    for arg in args:
        if '@' in arg: 
            targets = arg.split('@')
            ...
            board = targets[1]
            if board in get_scons_enabled_boards():
                scons_build(args)
            else:
                make_build(make_args)

            return
    #aos make clean go here
    make_build(make_args)

def main():
    ...
    # Parse/run command
    if len(sys.argv) <= 1:
        help_()
        sys.exit(1)
    ...
    pargs, remainder = parser.parse_known_args()
    status = 1

    try:
        ...
        status = pargs.command(pargs)
    except ProcessException as e:
    ...
    sys.exit(status or 0)


if __name__ == "__main__":
    main()

简单来说,调用关系如下:

aos make helloworld@linuxhost
    |-- make()
        |-- make_build()
            |-- _run_make(arg_list)
                |-- popen(make_cmd_str, shell=True, cwd=os.getcwd())

变量的值:
build_dir = 'BUILD_DIR=./out/'
app_dir = 'APPDIR=./'
make_args = helloworld@linuxhost
arg_list = ['-e', '-f build/Makefile', make_args, app_dir, build_dir]
make_cmd = ./build/cmd/linux64/make
make_cmd_str = make_cmd + 'HOST_OS=Linux64' + 'TOOLS_ROOT=./build' + + list(arg_list)

其中,popen是Python的标准库中的subprocess包的类,用来fork一个子进程并运行一个外部程序,进入 ./build/Makefile

3.3 make入口

build/Makefile是make的主入口,传入的参数有:
HOST_OS=Linux64
TOOLS_ROOT=./build
BUILD_DIR=./out/
APPDIR=./
make_args = helloworld@linuxhost

我们先来看看build/Makefile中的一些关键内容:

export SOURCE_ROOT ?= ./  #AliOS-Things 的根目录
export MAKEFILES_PATH := $(SOURCE_ROOT)/build   #MAKEFILES_PATH = ./build
export SCRIPTS_PATH := $(SOURCE_ROOT)/build/scripts  #SCRIPTS_PATH = ./build/scripts
MAKEFILE_TARGETS := clean

#define BUILD_STRING, AOS toolchain commands on different hosts
include $(MAKEFILES_PATH)/aos_host_cmd.mk #./build/aos_host_cmd.mk

接着看一下文件./build/aos_host_cmd.mk:

TOOLS_ROOT ?= $(SOURCE_ROOT)build #TOOLS_ROOT = ./build
COMPILER_ROOT ?=$(TOOLS_ROOT)/compiler #COMPILER_ROOT = ./build/compiler
OPENOCD_PATH      := $(TOOLS_ROOT)/OpenOCD/${HOST_OS}/ #OPENOCD_PATH = ./build/OpenOCD/Linux64/
OPENOCD_CFG_PATH  := $(MAKEFILES_PATH)/OpenOCD/${HOST_OS}/ #OPENOCD_CFG_PATH = ./build/OpenOCD/Linux64/
JTAG         ?= jlink_swd
BUILD_DIR    ?= out
...
COMMON_TOOLS_PATH := $(TOOLS_ROOT)/cmd/linux64/
#COMMON_TOOLS_PATH = ./build/cmd/linux64/
export SHELL       = $(COMMON_TOOLS_PATH)dash #SHELL = ./build/cmd/linux64/dash
OPENOCD_FULL_NAME := "$(OPENOCD_PATH)bin/openocd"
#OPENOCD_FULL_NAME = ./build/OpenOCD/Linux64/bin/openocd
ECHO              := echo
PERL              := $(shell which perl)
PYTHON            := $(shell which python)
CLEAN_COMMAND     := "$(COMMON_TOOLS_PATH)rm" -rf $(BUILD_DIR)
#CLEAN_COMMAND = "./build/cmd/linux64/rm" -rf out
MKDIR              = "$(COMMON_TOOLS_PATH)mkdir" -p $1
#MKDIR = "./build/cmd/linux64/mkdir" -p $1
RMDIR              = "$(COMMON_TOOLS_PATH)rm" -rf $1
#RMDIR = "./build/cmd/linux64/rm" -rf $1
CPDIR              = "$(COMMON_TOOLS_PATH)cp" -rf $1 $2
#CPDIR = "./build/cmd/linux64/cp" -rf $1 $2
TRUE_CMD          := true
FALSE_CMD         := false
RM      := "$(COMMON_TOOLS_PATH)rm$(EXECUTABLE_SUFFIX)" -f
#RM = "./build/cmd/linux64/rm" -f
CP      := "$(COMMON_TOOLS_PATH)cp$(EXECUTABLE_SUFFIX)" -f
#CP = "./build/cmd/linux64/cp" -f
MAKE    := "$(COMMON_TOOLS_PATH)make$(EXECUTABLE_SUFFIX)"
#MAKE = "./build/cmd/linux64/make"
BIN2C   := "$(COMMON_TOOLS_PATH)bin2c$(EXECUTABLE_SUFFIX)"
#BIN2C = "./build/cmd/linux64/bin2c"
CURRENT_TIME = $(shell $(DATE) +%Y%m%d.%H%M)
SHOULD_I_WAIT_FOR_DOWNLOAD := $(filter download, $(MAKECMDGOALS))
#因为MAKECMDGOALS = helloworld@linuxhost,所以 SHOULD_I_WAIT_FOR_DOWNLOAD = null
BUILD_STRING ?= $(strip $(filter-out $(MAKEFILE_TARGETS) download run total, $(MAKECMDGOALS)))
#BUILD_STRING = "helloworld@linuxhost"
BUILD_STRING_TO_DIR = $(subst .,/,$(1))
#BUILD_STRING_TO_DIR = null
DIR_TO_BUILD_STRING = $(subst /,.,$(1))
#DIR_TO_BUILD_STRING = null
CLEANED_BUILD_STRING := $(BUILD_STRING)
#CLEANED_BUILD_STRING = "helloworld@linuxhost"
OUTPUT_DIR   := $(BUILD_DIR)/$(CLEANED_BUILD_STRING)$(MBINS)
#OUTPUT_DIR = "out/helloworld@linuxhost"
AUTO_COMPONENT_DIR := $(OUTPUT_DIR)/auto_component
#AUTO_COMPONENT_DIR = "out/helloworld@linuxhost/auto_component"

主要设置了一些和host os相关的参数。
接着build/Makefile文件继续看,由于IDE = null,则COMPILER = null

include $(MAKEFILES_PATH)/aos_toolchain_gcc.mk
AUTO_COMPONENT = $(AUTO_COMPONENT_DIR)/auto_component.mk
#AUTO_COMPONENT = "out/helloworld@linuxhost/auto_component/auto_component.mk"
TEST_COMPONENT_COLLECTION = $(AUTO_COMPONENT_DIR)/test_collection.default
#TEST_COMPONENT_COLLECTION = "out/helloworld@linuxhost/auto_component/test_collection.default"

$(AUTO_COMPONENT): $(TEST_COMPONENT_COLLECTION)
    $(QUIET)$(PYTHON) $(MAKEFILES_PATH)/scripts/auto_component.py $(AUTO_COMPONENT_DIR)

$(TEST_COMPONENT_COLLECTION):
    $(QUIET)$(PYTHON) $(MAKEFILES_PATH)/scripts/gen_test_collection.py $(AUTO_COMPONENT_DIR) $(TEST_COMPONENT_COLLECTION)

设置完一些变量的值后,执行2条python指令:

python ./build/scripts/gen_test_collection.py ./out/helloworld@linuxhost/auto_component ./out/helloworld@linuxhost/auto_component/test_collection.default

python ./build/scripts/auto_component.py ./out/helloworld@linuxhost/auto_component

命令:

aos make helloworld@linuxhost

该命令最先调用的targe是main_app:

main_app: $(OUTPUT_DIR)/config.mk $(YOS_SDK_PRE_APP_BUILDS) $(MAKEFILES_PATH)/aos_target_build.mk
    $(if $(BINS_ERROR), $(call BINS_EXIT))
    $(if $(MBINS_ERROR), $(call MBINS_EXIT))
    $(QUIET)$(ECHO) Build AOS Now
    $(QUIET)$(ECHO) TOOLCHAIN_PATH=$(TOOLCHAIN_PATH)
    $(QUIET)$(call MKDIR, $(OUTPUT_DIR)/binary)
    $(QUIET)$(call MKDIR, $(OUTPUT_DIR)/modules)
    $(QUIET)$(call MKDIR, $(OUTPUT_DIR)/libraries)
    $(QUIET)$(call MKDIR, $(OUTPUT_DIR)/resources)
    $(QUIET)$(PYTHON) $(MAKEFILES_PATH)/scripts/gen_auto_code.py $(OUTPUT_DIR)/config.mk $(AUTO_COMPONENT_DIR)
    $(QUIET)$(MAKE) -r $(JOBSNO) $(SILENT) -f $(MAKEFILES_PATH)/aos_target_build.mk $(CLEANED_BUILD_STRING) $(PASSDOWN_TARGETS)
    $(QUIET)$(ECHO) Build complete

main_app又依赖$(OUTPUT_DIR)/config.mk,即out/helloworld@linuxhost/config.mk,所以先调用build/aos_target_config.mk生成out/helloworld@linuxhost/config.mk,完成后,主要做了两件事:

  • /usr/bin/python .//build/scripts/gen_auto_code.py out/helloworld@linuxhost/config.mk out/helloworld@linuxhost/auto_component
    根据out/helloworld@linuxhost/config.mk生成out/helloworld@linuxhost/auto_component下的文件。
  • ./build/cmd/linux64/make -r -j4 -f .//build/aos_target_build.mk helloworld@linuxhost
    进入./build/aos_target_build.mk 继续编译。

4 第一个应用Hello World

4.1 创建工程目录及源文件

$ mkdir ./example/helloworld
$ cd ./example/helloworld

创建文件helloworld.c helloworld.mk

#helloworld.mk
NAME := helloworld              ## 指定应用名称
$(NAME)_SOURCES := helloworld.c ## 指定使用的源文件
#$(NAME)_DEFINES += LOCAL_MACRO ## 定义局部符号
GLOBAL_DEFINES += AOS_NO_WIFI   ## 定义全局符号
$(NAME)_COMPONENTS := yloop cli  ## 指定依赖的组件,本例使用yloop cli组件
ifeq ($(BENCHMARKS),1)
$(NAME)_COMPONENTS  += benchmarks
GLOBAL_DEFINES      += CONFIG_CMD_BENCHMARKS 
endif

helloworld.c

static void app_delayed_action(void *arg)
{
    LOG("helloworld %s:%d %s\r\n", __func__, __LINE__, aos_task_name());
    aos_post_delayed_action(5000, app_delayed_action, NULL);
}

int application_start(int argc, char *argv[])
{
    LOG("application started.");
    aos_post_delayed_action(1000, app_delayed_action, NULL);
    aos_loop_run();
    return 0;
}

编译运行参见2.3节。

5 Ubuntu下环境配置

5.1 下载安装Jlink

SEGGER官网下载最新jlink驱动,网址 https://www.segger.com/downloads/jlink
Select J-Link Software and Documentation Pack for Linux.

$ sudo dpkg -i JLink_Linux_V634_x86_64.deb
$ ls /opt/SEGGER/
JLink  JLink_V634

设置环境JLink的环境变量:

vi ~/.bashrc
export JLINK_HOME=/opt/SEGGER/JLink
export PATH=${PATH}:${JLINK_HOME}

5.2 下载安装GNU ARM Embedded Toolchain

download toolchain for Linux, URL: https://launchpad.net/gcc-arm-embedded/+download
解压后放入目录:/opt/gcc-arm-none-eabi-5_4-2016q3
设置环境Toolchain的环境变量:

vi ~/.bashrc
export ARM_TOOLCHAIN_HOME=/opt/gcc-arm-none-eabi-5_4-2016q3
export PATH=${PATH}:${ARM_TOOLCHAIN_HOME}/bin/:${JLINK_HOME}

5.3 连接开发板

$ JLinkExe
J-Link>connect
Device>CORTEX-M4
TIF>S
Speed>20
JLink.png

5.4 下载代码

下载代码到RAM中运行:

J-Link>loadbin firmware.bin 0x1fff0000
J-Link>setpc 0x1fff01fd
J-Link>g

可以整理为脚本:
xxx.jlink

loadbin firmware.bin 0x1fff0000
setpc 0x1fff01fd
g
#q  #退出jlink

在控制台窗口中输入 JLink xxx.jlink 即可。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容