豹哥嵌入式讲堂:ARM Cortex-M开发之文件详解(3)- 工程文件(.ewp)


iOS11对WKWebView的功能进一步完善,新增如下效果:

  我们好,我是豹哥,猎豹的豹,犀利哥的哥。前几天豹哥给我们讲的是嵌入式开发里的project文件

  1. Manager Cookies
  2. Fileter unwanted content
  3. Provide custom resources

  前边两节课里,豹哥分别给我们介绍了嵌入式开发中的两种典型input文件:source文件linker文件。豹哥要再一次提问了,还有没有input文件呢?答案真的是有,但本次真的是有且仅有了,本文要介绍的中流砥柱project文件也属于半个input文件。为何说是半个?因为project文件不仅含有开发者指定的input音信,还隐含众多别样扶助调试的input/output音讯,算是嵌入式开发中承前启后的文件。而本文侧重点在于project文件中与开发者应用相关的input消息,仅当拿到了这几个input音讯,再加上前面介绍的source和linker文件,那么你就早已得到了application所有的音讯,你可以用它们来可以生成无歧义的可举行image
binary。
  随着嵌入式软件工程的发展,为了酬答日益复杂的需求,现代IDE的效率也越发强大了,IDE版本更迭令人无暇,Keil
MDK已然踏入5.0时期,IAR
EWARM更是进入了8.0时代,IDE各有千秋,但本文要讲的内容却是每个IDE必须持有的基本效用,依旧延续以IAR
EWARM为例初阶今天的情节:

下面是对各类特性的简短介绍,详细可参见源码

一、标准IDE功能

  在起来前些天的主题在此以前,豹哥觉得有必不可少先简要给我们常见一下正规IDE应该拥有的功用。现代IDE基本都是由组件构成,嵌入式开发中的每个阶段都对应着相应的零部件,由这一个零部件去落实各等级的需要。

1.Manager Cookies

iOS11新增了一个类来专门管理Cookies:WKHTTPCookieStore。它紧要含有了了对库克ie的操作:删除、添加、获取等。
比如那种情景:
一个页面默认登录,当我从未登录的时候会弹出输入框,输入账号。输入完成往后,会唤醒已登录。再次打开该页面时,页面会先判断有没有cookie,有cookie直接指示已登录,没有cookie则再一次弹框让用户登录。
但是现在有个新需要:第一次安装APP,启动的时候就有个默认的账户登录,而不需要弹框输入。这就用到了cookie的增长。在APP将要加载webView此前,通过HTTPCookie来初叶化一个实例,将其塞到webView的configuration的数码存储中。这样加载WebView时就已经有cookie存在了。这样就打熬了首次默认登录的职能。关键代码如下:

let cookie = HTTPCookie.init(properties: [
            .domain:"172.16.10.26",
            .path:"/src/p/index/index.html",
            .version:0,
            .expires:Date.init(timeIntervalSinceNow: 30*60*60),
            .name:"username",
            .value:"zhanggui33"
            ])

let cookieStore = myWKWebView.configuration.websiteDataStore.httpCookieStore

cookieStore.setCookie(cookie!) {

            self.myWKWebView.load(URLRequest.init(url: URL.init(string: "http://172.16.10.26:3333/src/p/index/index.html")!))
        }

也就是在加载网页前,将cookie注入。更多可参见这里源代码

1.1 IDE组件

  标准嵌入式开发相应至少包括以下6个阶段,而IAR里对于每个阶段都有1个或四个零部件:

  • 输入(IAR Editor):编辑源文件代码。
  • 编译(ICCARM、IASMARM):编译源文件代码生成可实施二进制机器码。
  • 解析(C-STAT、MISRA-C):编译过程中反省代码中神秘的问题。
  • 链接(ILINK):链接可举行二进制机器码到指定ARM存储空间地址。
  • 下载(I-jet、flashloader):将链接好的可举办二进制机器码下载进芯片里面非易失性存储器。
  • 调剂(C-SPY、C-RUN):在线调试代码在芯片中推行情状。

  project文件着重用来记录整合上述6个等级的有着支付需要。

2.Fileter unwanted content

其余一个新特征就是过滤你不想要的情节。比如说你在app中加载的网页中富含http请求,你可以按照以下规则将http资源加载在此之前转换成https加载。那一个是苹果官方演示的一个条条框框:

let jsonString = """
            [{
                "trigger":{
                    "url-filter": ".*"
                },
                "action":{
                    "type": "make-https"
                }

            }]
            """

此处最首要利用了WKContentRuleListStore。下边就来详细对其举行介绍。

1.2 IDE文件类型

  既然IDE有成千上万组件,那么与此同时也会存在不同类其它文本以存储那个零件的所急需的音讯。IAR里匡助的文件扩大项目卓殊多,豹哥在此处仅列举你所创办的工程根目录下的与工程同名的恢宏文件,相信你势必会觉得熟谙。

.eww           // Workspace file
.ewp           // IAR Embedded Workbench project
.ewd           // Project settings for C-SPY
.ewt           // Project settings for C-STAT and C-RUN</td>
.dep           // Dependency information

  本文要讲的情节都饱含在.ewp文件里,ewp文件记录了开发者为运用指定的不足缺失的input音信,没有这个信息,application工程是不完整的。换句话说,假使您拿到了application的富有source文件和linker文件,但未曾ewp文件的话,可能引致最终生成的image
binary文件是见仁见智的。

Note:更多IAR帮忙的扩展文件类型请查阅IAR软件安装目录下\IAR
Systems\Embedded Workbench
xxx\arm\doc\EWARM_IDEGuide.ENU.pdf文档里的File types一节。

创办一个Trigger字典

一个trigger的字典必须要含有url-filter那些key,它指定了匹配url的形式。其他的就是可选的了,例如你可以界定指定的域名,让该域名的始末不加载。例如下边的这些trigger规则,制定了用来图片和体裁资源的平整trigger,不含有某写域名上的:

"trigger": {
        "url-filter": ".*",
        "resource-type": ["image", "style-sheet"],
        "unless-domain": ["your-content-server.com", "trusted-content-server.com"]
}

除去下边提到的trigger
key,还有url-filter-is-case-sensitive、is-domain、unless-domain、resource-type等。具体的详实介绍能够参见法定解释

二、解析project(ewp)文件

  后面豹哥铺垫了诸多IDE/project基础概念,该是直奔核心的时候了,本文主角ewp工程文件到底包含哪些开发者指定的input消息?豹哥从下边3个方面为我们揭开:

创建一个Action字典

当trigger匹配到了符合条件的资源,浏览器便会实施与trigger相关联的操作。当所有的trigger都被评估后,action便会依照顺序执行。
Action只有多少个key:type和selector。type是必须要有些,selector可选,如若type是css-display-none,那么selector也是必须要有些。其他的type中selector是可选的。
type的类型有:block、block-cookies、css-display-none、ignore-previous-rules、make-https。更多可以瞻仰合法表达
比如说我想屏蔽页面中拥有图片的加载:

 //把所有的图片阻塞加载
        let jsonString = """
            [{
                "trigger":{
                    "url-filter": ".*",
                    "resource-type":["image"]
                },
                "action":{
                    "type":"block"
                }
            }]
            """
        WKContentRuleListStore.default().compileContentRuleList(forIdentifier: "demoRuleList", encodedContentRuleList: jsonString) { (list, error) in
            guard let contentRuleList = list else { return }
            let configuration = self.filterWebView.configuration
            configuration.userContentController.add(contentRuleList)
            self.filterWebView.load(URLRequest.init(url: URL.init(string: "http://m.baidu.com")!))
        }

更多词义的解释或者看法定文档,里面介绍的很详细。

2.1 源文件社团

  一个有点复杂一点的嵌入式工程,应用代码行数应该是以百行/千行为单位测算的(此处仅指的是由开发者自己成立的文件与代码),我们在协会代码的时候势必不会只创立一个.c文件,单文件会促成代码功用模块结构不清楚,不便民工程的管理与维护。
  当大家为工程创设多少个文本时,就会涉嫌到一个自然问题:引用路径问题(所以路径信息就是本文要说的率先个input音信)。当源文件数量较多时,日常大家会创制不同文件夹把相同功效的源文件都位于一块儿,当编译器初始编译.c源文件时会搜索include语句所包含的头文件。熟练C语言的意中人一定掌握下边两种不同include语句的用法:

#include <file.h>           // 引用编译器类库下的头文件(IDE安装路径)
#include "file.h"           // 引用当前工程下的头文件(project路径)

  所以在ewp文件里会包含路径音信,所有途径都应当列在Options->C/C++
Compiler->Preprocessor下有Additional include
directories里,这多少个路子既可以是眼下PC的相对路径,也能够是以ewp文件为尺度的绝对路径,为了保证工程得以在随意PC任意地点下健康编译,推荐应用如下相对路径情势列出具有途径:

ewp当前路径:$PROJ_DIR$/
ewp下级路径:$PROJ_DIR$/xxFolder/
ewp上级路径:$PROJ_DIR$/../

  说到路径问题,豹哥在此间顺便给我们介绍一种经典的嵌入式工程文件目录协会措施:

\projectDir
           \doc                            --放置工程文档

           \bsp                            --放置bsp(板级)相关的source file
                  \linker                    --工程linker文件
                  \src                       --板级相关的源文件(比如pinout,clock等)
                  \builds\xxBuild\.ewp       --工程ewp文件
                  .eww                       --工程workspace文件

           \src                            --放置bsp无关的source file
                  \platform                  --芯片头文件及CMSIS文件
                  \drivers                   --芯片片内外设driver
                  \include                   --要被所有source引用的头文件
                  \startup                   --标准的startup code
                  \utilities                 --标准的通用函数
                  \middleware                --独立的中间件
                  \components                --板级外设组件driver
                  \application               --当前应用主逻辑代码

3.Provide custom resources

以此特点允许你提供自定义的资源,这也得以兑现离线缓存。例如你把富有的图形都放置app里面,然后网页加载图片时遵守一定的scheme(比如:wk-feature://cat)来加载,然后在客户端代码中采用一定的SchemeHandler来分析即可。这里最紧要使用了WKURLSchemeHandler和WKURLSchemeTask。
重要代码如下:

        let configuration = WKWebViewConfiguration()
        let schemeHandler = MyCustomSchemeHandler.init(viewController: self)

        configuration.setURLSchemeHandler(schemeHandler, forURLScheme: "wk-feature")

贯彻了温馨的SchemeHandler,然后对特定的Scheme举办拍卖。

2.2 全局宏定义

  通常利用原则编译的爱人一定晓得workspace文件与project文件的涉及,一个门类一般只会有一个eww文件,但却可能会有三个ewp文件,这是因为源代码里不时会有原则编译,大家偶尔会给品种不同的配置从而编译出不同的结果(速度优先/面积优先,特性控制…),这一个安排就是由全局宏定义来实现的,打开Options->C/C++
Compiler->Preprocessor下的Defined
symbols,在框内写入你需要定义的全局宏:

MACRO1            // 等价于源文件里的#define MACRO1 (1)
MACRO2=2          // 等价于源文件里的#define MACRO2 (2)

  全局宏音讯就是本文要说的第二个input音信,假使全局宏音信丢失,有时候工程编译并不会报错,因为编译器在拍卖如下普遍用法里的口径编译语句时会默认未定义的宏为0,而在拍卖推荐用法里的尺度编译语句则会报错,所以推举我们利用第二种口径编译用法来逃避全局宏问题。

// 普遍用法
#if MACRO
    // your code block 1
#else
    // your code block 2
#endif

// 推荐用法
#if !defined(MACRO)
    #error "No valid MACRO defined!"
#elif (MACRO == 1)
    // your code block 1
#else
    // your code block 2
#endif

总结

比方你还在运用UIWebView,那么尽快更换为WKWebView吧。毕竟苹果更倾向于WKWebView。不断地将其成效丰裕。而且通过了多少个本子迭代,使用WKWebView的坑也都日益填平。

2.3 编译选项

  编译选项包含了编译器所急需的装有音讯,代码需通过编译器编译才能生成二进制机器码,不同的编译器选项配置会转变不同的机器码,那么需要指定哪些选项呢?打开project的Options选项卡,分别安装下表item:

Position

Item

Description

General Options->Target->

Processor variant->Core

指定ARM内核版本

Endian mode

点名内核大小端格局

Floating point settings->FPU

点名内核匡助的FPU版本

General Options->Library Configuration->

Library

采取C/C++动态链接库版本

General Options->Library Option 2->

Heap selection

选拔HEAP实现版本

C/C++ Compiler->

Language 1->Language

指定编程语言类型

Language 1->C dialect

点名C语言标准

Language 1->Language conformance

挑选对标准C/C++的遵照程度

Language 2->Plain ‘char’ is

选用对char的符号性默认处理措施

Language 2->Floating-point semantics

分选对浮点数的拍卖遵守C标准的档次

Code->Process mode

指定内核指令集情势

Code->Position-independence

采取要扭转地方无关代码的目的

Optimizations->Level

选择优化等级

管理,Note:更多ewp文件中option解释请查阅IAR软件安装目录下\IAR
Systems\Embedded Workbench
xxx\arm\doc\EWARM_IDEGuide.ENU.pdf文档里的General
Options和Compiler Options俩小节。

  编译设置音信就是本文要说的第六个input信息,当在project中团队好源文件并安装好正确的大局宏定义和编译选项,那么恭喜您,你的application设计工作一度基本做到了。

附源码

1.WKWebViewNewFeature

三、创建demo工程

  为便宜后续课程的拓展,本节课在终极顺便创造一个demo工程,以下是demo工程的信息:

IDE:        IAR EWARM v8.11.2
Device:     NXP MKL25Z128VLH4
project layout:   
    \D\myProject\bsp\builds\demo\demo.ewp
    \D\myProject\bsp\linker\iar\KL25Z128xxx4_flash.icf
    \D\myProject\bsp\src\startup_MKL25Z4.s   (仅保留前16个系统中断)
    \D\myProject\bsp\src\system_MKL25Z4.c   (仅做关闭WDOG操作)
    \D\myProject\bsp\src\system_MKL25Z4.h
    \D\myProject\bsp\helloArm.eww
    \D\myProject\src\platfrom\CMSIS
    \D\myProject\src\platfrom\devices\MKL25Z4
    \D\myProject\src\startup\reset.s
    \D\myProject\src\startup\startup.c
    \D\myProject\src\startup\startup.h
    \D\myProject\src\application\main.c
    \D\myProject\src\application\task.c
    \D\myProject\src\application\task.h

// main.c
//////////////////////////////////////////////////////////
#include "task.h"
const uint32_t s_constant = 0x7f;
int main(void)
{
    uint32_t l_variable = 0x7f;
    if (s_constant == l_variable)
    {
        normal_task();
        ram_task();
        heap_task();
    }
    while (1);
}

// task.c
//////////////////////////////////////////////////////////
#include "task.h"
static    uint32_t s_variable0;
__no_init uint32_t n_variable1;
static    uint32_t s_variable2 = 0x5a;
static uint8_t s_array[16];
void normal_task(void)
{
    s_variable0 *= 2;
}
__ramfunc void ram_task(void)
{
    n_variable1++;
}
void heap_task(void)
{
    uint8_t *heap = (uint8_t *)malloc(16 * sizeof(uint8_t));
    if (heap != NULL)
    {
        memset(heap, 0xa5+s_variable2, 16);
        memcpy(s_array, heap, 16);
        s_variable0 = (uint32_t)heap;
        free(heap);
    }
}

参考

  1. Customized Loading in
    WKWebView
  2. Introduction to Safari Content-Blocking
    Rules

转载请注脚来源:http://www.cnblogs.com/zhanggui/p/8260136.html

番外一、多少个小技巧

  又过来豹哥番外时间了,细心的敌人看出上表有两处标蓝,是的不错,明天的番外内容就是标蓝的序列有关。

技巧1:运行于异构双核

  如今嵌入式产品尤其复杂,对MCU的性能要求也越来越高,各大ARM厂商也在持续推出性能更加强大的ARM
MCU产品,超高主频,双核,四核MCU已经不鲜见了。对于内部的有些异构双核MCU产品,有时在支付中会有诸如此类的要求:你有一份的middleware会被异构双核同时调用,而几个不等基础的授命集有可能是不等同的,怎么化解这多少个题材?有对象会想到分别在各类核上面都编译一份binary停放于存储器不同职务,运行时分别指向对应的binary,这是一个方法,但相比较浪费存储空间,且有可能会搞混淆导致误调用。有没有更好的法门?
  为了能不负众望Cortex-M软件重用,ARM公司在计划Cortex-M处理器时为其给予了处理器向下兼容软件二进制向上兼容特色。通俗的话来说就是在较低版本处理器上编译的代码能够在较高版本处理器上推行。所以解决措施就是采用异构双核里较低版本的内核在编译middleware,这样这份middleware可以而且被多少个核调用。

技巧2:生成PIC代码

  平日和bootloader打交道的意中人一定晓得,代码在经过链接阶段生成binary文件后,这一个binary并不是可以置身任意位置的,必须置于linker文件指定的地方,倘若地方没有放正确,可能会促成执行出错。究其原因,是因为编译器在汇编源代码时因为部分政策并不连续将装有function都汇编成地点无关代码。假若我们赖以IDE编译选项将middleware汇编成PIC代码,那么我们得以在工程中从来投入middleware的binary,然后借助linker的自定义section效用将其放置于自由某个地点,最后只要为这一个middleware
binary建立一个以binary首地址为准绳的函数指针地址列表即可无障碍调用这么些middleware。

技巧3:引用.c文件

  在档次支付中,我们在一个workspace下会制造四个project,通常是因为不同project需要包含不同的.c文件以成就不同的功用。那么能不可能只创制一个project呢能促成不同效能吗?当然可以!经常状态下我们在.c文件中只会用#include
“xx.h”语句来引用.h头文件,其实大家也一样可以引用.c文件,比如那样#include
“xx.c”,只是需要留意尽量不要在.h文件中引用.c文件(除非该.h只会被一个.c文件include)。看到这里的朋友假如脑洞再大一些,你仍可以够形成工程里只需要充裕一个.c文件,而其他.c文件全体由添加进工程的十分.c文件逐级(仅能单级)引用进工程。

  至此,嵌入式开发里的project文件豹哥便介绍完毕了,掌声在何地~~~

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注