
熟悉我的朋友会知道,我是一个追求新奇而且做事情比较极致的人,我所追求的不是完美,而是探索过程那一种酣畅淋漓的快感,沉迷于那种思维的锻炼,比如前面这篇:由一个编译参数引发的gn构建依赖图谱查询,这次我又碰到一个感兴趣的东西了,然后一发不可收拾,等研究结束一天就那么过去了。那么这次又是碰到什么让我值得探索的东西,且看后文。
众所周知,在Hi3861芯片里面是支持flash读写的,相应的api长这样:
"file://base/iothardware/peripheral/interfaces/inner_api/iot_flash.h"
unsigned int IoTFlashRead(unsigned int flashOffset, unsigned int size, unsigned char *ramData);
unsigned int IoTFlashWrite(unsigned int flashOffset, unsigned int size,
const unsigned char *ramData, unsigned char doErase);那么使用这样的接口很容易就做出来一个简单的存取flash的demo,比如这样:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_flash.h"
#include "iot_errno.h"
/**************测试flash读写**************/
static void in_flash_test(void)
{
uint8_t w_buf[] = {0x01,0x02,0x03,0x04,0x05};
uint8_t r_buf[100] = {0};
//写入数据
IoTFlashWrite(0x1fb000, 5, (uint8_t *)buf, TRUE);
//读取数据
IoTFlashRead(0x1fb000, 100, (uint8_t *)r_buf);
for(int i=0;i<100;i++)
{
printf("%02x ",r_buf[i]);
}
}
APP_FEATURE_INIT(in_flash_test);这样的程序就能实现写入flash和读取flash内容,那么此时问题就出现了
打开Hiburn软件,仔细观察Hiburn的界面,会发现这样一些内容:

想起来有一个HiBurn软件的使用手册,结果在电脑里面翻箱倒柜的真的被我找出来到了,马上查阅数据手册(手册放在下载附件内):

Burn Size就是管控擦除的flash长度的,所以一个问题的解决办法就是:每次烧录的自己指定一个BurnSize比如可以跟固件的FileSize一致,如下:

但是实际效果发现此种方法却不行,及时手动改了BurnSize,最后在烧录的时候还会被强制恢复成,2097152,这个值其实就是Hi3861的Flash大小(2M),所以此方法失败。
最后经过一番摸索,也没找到有什么办法,所以第一个问题暂时就先放一边吧。
设想如下一个场景:我的设备开机的时候,需要读取一传SN码,然后利用SN码去物联网平台去注册或者登录设备。
那么要实现这样的功能,有一种方法就是提前在产线烧录阶段将SN等信息烧录到芯片内部,这里我们再次使用官方的HiBurn工具,在手册中有这样一句话:

这里的参数文件暂时还不知道是什么意思,根据以往个嵌入式开发经验,这里我暂且理解成一个文本文件吧,所以这里制作一个测试文件:

将这样的文件跟固件文件一起放在Biburn软件里,固件端的代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_flash.h"
#include "iot_errno.h"
/**************测试flash读写**************/
static void in_flash_test(void)
{
uint8_t r_buf[100] = {0};
//读取数据
int ret =IoTFlashRead(0x1fb000, 100, (uint8_t *)r_buf);
printf("==>read ret = %d",ret);
for(int i=0;i<100;i++)
{
printf("%02x ",r_buf[i]);
}
}
APP_FEATURE_INIT(in_flash_test);然后需要设置test.txt文件烧录地址和大小,另外设置烧录文件类型为2,如下(注意此种方法需要两次点击Select File按钮):


这样执行烧录的时候最后可以看到这样的日志:

这样就完成了,串口日志看一下:

因为是按%02x方式打印的,所以是ascii的二进制形式,对比一下源文件就可以知道读出的就是刚刚写入的内容。
到这里第二个问题算是解决成功。
这里如果只想解决第二个问题,问题就已经完事了,然而这里我又产生了新的思考,用这样的方式烧录固件太繁琐,有没有一种自动化的方式呢?
这里我就回想起来,Devco Tools可以使用命令行的方式来下载固件,看一看是怎么实现的,然后下载了新版的Devco Tools,按照以往经验不去执行安装,直接解压出来,却没有发现HiBurn.exe软件,然后没有思考为何没有HiBurn软件了,直接去下载旧版的Devco Tools,找到了那个Birun的脚本文件,大概这样:

这里是用命令行执行Hiburn.exe,然后这里有一些参数,查看文档:

这里,用一个Demo的指令下载一次固件看看,结果不出意外的成功了。
但是有一个问题,这样确实可以自动化下载固件,但是额外的文件呢?
可以看到Hiburn.exe文档里面没有说有烧录额外的文件的说明,此时有一种想法:有没有可能是软件里面实现了但是没在文档里写出来呢?
因为Hiburn软件是直接发布的一个exe文件,所以我们是没有源码的,但是用一些技术手段可以看到源码,那就是用16进制编辑器查看,比如我用的Sublime Txt 4安装Hex Viewer,把HiBurn.exe文件导入进来,是这样的界面:

这东西看起来没有用啊?
那只是你的误解,在我这里,哪怕是一个逗号,一个字母都是有用的.根据手册得知,指令用了com.bin等这样的字段,那么搜索到这个地方就可以查看到是不是有相关提示,一样还真搜到了:

结果比较失望,发现竟然没有额外的指令支持了,所以这种方失败。
回到前面那里,在新版的Devco Tools并没有发现HiBurn.exe这个程序了,但是依然能够实现下载Hi3861的固件烧录,这是怎么回事了,一起来探索这件事.
一番探索,结果发现,新版的Devco Tools使用一个新的方式来下载固件,就是这个hiburn.jar:

点击了这个连接之后,下载得到一个压缩包,经过层层解压,终于得到hiburn.jar文件,然后找到一个文档:

jar文件需要一个java环境才能执行,所幸的是压缩包内自带了一个jre环境,所以制作一个这样的指令就可以烧录固件了:

使用hiburn.jar --help查看一下所支持的指令:

看了一下,还是没有找到如何下载额外flash文件的方式,这时候突然想到,会不会仍然是文档和手册没写,而实际上产品实现了呢,看了这里你可能会想,再用16进制编辑器看内容呗,哈哈,错啦!
因为我们这次是用的jar文件,我们就需要反编译jar文件,这里教大家一个简单的方式,把jar文件用解压软件解压,然后再用vscode来打开文件夹,安装Decompile扩展:

在打开的.class文件上右键,选择decompile,就可以出现反编译的java文件了:

打开这个文件一看,有一个指令写了:

看来是支持按地址下载的方式的,看起来好像跟之前的hiburn.exe里面下载文件的方式比较像,就试试看:

直接就成功了,这肯定有问题,然后一边查看源码,一边又试了很多方法:

可以看到,这种方式都不行。
所以,结论就是这种方式也是失败。
写了这么多,总结起来就是:一次失败的探索经历,但是经过这次失败的经历我想到了几点:
文章相关附件可以点击下面的原文链接前往下载:
https://ost.51cto.com/resource/2671。
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我正在尝试在Rails上安装ruby,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf
我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束
我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里
我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm
-if!request.path_info.include?'A'%{:id=>'A'}"Text"-else"Text"“文本”写了两次。我怎样才能只写一次并同时检查path_info是否包含“A”? 最佳答案 有两种方法可以做到这一点。使用部分,或使用content_forblock:如果“文本”较长,或者是一个重要的子树,您可以将其提取到一个部分。这会使您的代码变干一点。在给出的示例中,这似乎有点矫枉过正。在这种情况下更好的方法是使用content_forblock,如下所示:-if!request.path_info.inc
一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我
我在思考流量控制的最佳实践。我应该走哪条路?1)不要检查任何东西并让程序失败(更清晰的代码,自然的错误消息):defself.fetch(feed_id)feed=Feed.find(feed_id)feed.fetchend2)通过返回nil静默失败(但是,“CleanCode”说,你永远不应该返回null):defself.fetch(feed_id)returnunlessfeed_idfeed=Feed.find(feed_id)returnunlessfeedfeed.fetchend3)抛出异常(因为不按id查找feed是异常的):defself.fetch(feed_id