一个人的角落,也许并没人会看到这里~~ 祝福你,工作顺心,学习快乐~

Tag "test":

Tag "标签1":

Bash快捷键 记录备忘

生活在 Bash Shell 中,熟记以下快捷键,将极大的提高你的命令行操作效率。

编辑命令

  • Ctrl + a :移到命令行首
  • Ctrl + e :移到命令行尾
  • Ctrl + f :按字符前移(右向)
  • Ctrl + b :按字符后移(左向)
  • Alt + f :按单词前移(右向)
  • Alt + b :按单词后移(左向)
  • Ctrl + xx:在命令行首和光标之间移动
  • Ctrl + u :从光标处删除至命令行首
  • Ctrl + k :从光标处删除至命令行尾
  • Ctrl + w :从光标处删除至字首
  • Alt + d :从光标处删除至字尾
  • Ctrl + d :删除光标处的字符
  • Ctrl + h :删除光标前的字符
  • Ctrl + y :粘贴至光标后
  • Alt + c :从光标处更改为首字母大写的单词
  • Alt + u :从光标处更改为全部大写的单词
  • Alt + l :从光标处更改为全部小写的单词
  • Ctrl + t :交换光标处和之前的字符
  • Alt + t :交换光标处和之前的单词
  • Alt + Backspace:与 Ctrl + w 相同类似,分隔符有些差别 [感谢 rezilla 指正]

Tag "jekyll":

The Fourth Day, fix some small bugs

第四天

修改了Blog一些细节,还修补一些代码逻辑Bug, Jplayer 循环播放页面音乐, Sidebar滚动固定box 单个box 附着在jquery元素里边的对象在使用 jquery.clone 时,对象并不会clone, 导致jplayer fixed box 里边的元素按钮没有反应,

另外 Gallery.html 下竟然在输出内容时还有使用 {{content}}的, 忘记了 {{content}}{{content}}的使用了

之前由于没有分清 这两变量,导致 内容,死循环 输出,或者无内容输出,花了一个多小时,

Move To My New 'Stitac' Blog and New Domain MyPre

博客优化的还不错了,增加了一些页面,音乐专辑,相册专辑,

这些功能一直想在Wordpress 上实现,但确一直没有实现

许是从来没有这么专注的去学一些东西吧,

也许 Wordpress 提供的各种HOOK及 函数 太多,太复杂了,远没有 Jekyll 来得这么 简单

yaml + liquid 语法,与Jinja2 大同小异,甚至不需要写函数,几个模板,和 简单的输出处理逻辑就搞定了,

若是 有一个强大的 flask 作为 引擎 再配上Jinja 语法,这也决不会比Wordpress差吧~

提取一篇文章里边的 图片链接,以及除去文章里边的 img 标签

从接触 Jekyll 到现在有两整天了

发现 Jekyll 对逻辑处理方面不太善长,许是我没有认真去了解吧,

plugin 也许是很强大的东西 , 虽然不会ruby,但是因为对python的熟悉,还是有很大的帮助的,

之后打算结合国内七牛CDN对资源加速,估计要用到 plugin 希望ruby的语法对新手的亲和度不会让我太失望。

因为 原主题支持不同类型的Post,所以 对Jekyll也想实现这个功能,

做 完了标准的Post 接下来该做 Gallery 了 碰到的问题是,该如何提取Post文章里边的 img 中的src 以及如何 去除 文章里边的img

因为要挪动IMG的位置到文章最前面

因此记下方法 去除 img 标签 如下:


{% for sp in content | split:"<img "%}
    {% for con in sp | split:">" %}
        {% if con contains 'src="' or con contains "src='" %}
        {% else %}
          {% if con contains "href=" %}
            {{con}}>
          {% else %}
            {{con}}
          {% endif %}
        {% endif %}
    {% endfor %}
{% endfor %}

去除 IMG 方法就是 按 切割 除去 含有 src 属性的 项 剩下的 对 因为 > 切割 破坏的a 标签 补上 >

Tag "MyPress":

The Fourth Day, fix some small bugs

第四天

修改了Blog一些细节,还修补一些代码逻辑Bug, Jplayer 循环播放页面音乐, Sidebar滚动固定box 单个box 附着在jquery元素里边的对象在使用 jquery.clone 时,对象并不会clone, 导致jplayer fixed box 里边的元素按钮没有反应,

另外 Gallery.html 下竟然在输出内容时还有使用 {{content}}的, 忘记了 {{content}}{{content}}的使用了

之前由于没有分清 这两变量,导致 内容,死循环 输出,或者无内容输出,花了一个多小时,

Move To My New 'Stitac' Blog and New Domain MyPre

博客优化的还不错了,增加了一些页面,音乐专辑,相册专辑,

这些功能一直想在Wordpress 上实现,但确一直没有实现

许是从来没有这么专注的去学一些东西吧,

也许 Wordpress 提供的各种HOOK及 函数 太多,太复杂了,远没有 Jekyll 来得这么 简单

yaml + liquid 语法,与Jinja2 大同小异,甚至不需要写函数,几个模板,和 简单的输出处理逻辑就搞定了,

若是 有一个强大的 flask 作为 引擎 再配上Jinja 语法,这也决不会比Wordpress差吧~

Tag "Mypre.cn":

Move To My New 'Stitac' Blog and New Domain MyPre

博客优化的还不错了,增加了一些页面,音乐专辑,相册专辑,

这些功能一直想在Wordpress 上实现,但确一直没有实现

许是从来没有这么专注的去学一些东西吧,

也许 Wordpress 提供的各种HOOK及 函数 太多,太复杂了,远没有 Jekyll 来得这么 简单

yaml + liquid 语法,与Jinja2 大同小异,甚至不需要写函数,几个模板,和 简单的输出处理逻辑就搞定了,

若是 有一个强大的 flask 作为 引擎 再配上Jinja 语法,这也决不会比Wordpress差吧~

Tag "iziy":

The Fourth Day, fix some small bugs

第四天

修改了Blog一些细节,还修补一些代码逻辑Bug, Jplayer 循环播放页面音乐, Sidebar滚动固定box 单个box 附着在jquery元素里边的对象在使用 jquery.clone 时,对象并不会clone, 导致jplayer fixed box 里边的元素按钮没有反应,

另外 Gallery.html 下竟然在输出内容时还有使用 {{content}}的, 忘记了 {{content}}{{content}}的使用了

之前由于没有分清 这两变量,导致 内容,死循环 输出,或者无内容输出,花了一个多小时,

Tag "nautilus":

Open Here In Teminal From Nautilus

Linux 下的文件管理器 nautilus 可以很容易在终端中打开通过命令

[lanbing@LanBing-Laptop ~]$ nautilus .

但是要想在 nautilus 中打开 Terminal 却很麻烦 于是google了一下 发现软件包:nautilus-open-terminal 功能如其名,果断:

[lanbing@localhost ~]$ sudo dnf search  nautilus-open-terminal
[sudo] password for lanbing: 
Last metadata expiration check performed 1 day, 5:43:29 ago on Wed Apr 13 14:49:06 2016.
===================== N/S Matched: nautilus-open-terminal ======================
nautilus-open-terminal.x86_64 : Nautilus extension for an open terminal shortcut
[lanbing@localhost ~]$ sudo dnf install nautilus-open-terminal -y

安装后在 文件管理器 中右键 即可 方便打开 Terminal 了

Tag "机械键盘,背光,Scroll开关,":

在Linux下 使用Scroll键开关键盘背光灯

花了4天半的时间鼓捣好了一个机械键盘,

找了一个老外大牛写的stm32-based 键盘矩阵扫描器,改改装在了键盘上边

dfu功能,移植在keil下没有被识别,估计一阵子也没有多少时间来折腾,暂时先用着,

因为io口不够用,多区背光给改成了Scroll键开关,

但是,发现 Scroll 键 在高版本linux下给屏蔽了,

国内百度了半天没找到好的解决方案

转到google 发现 Why is the Scroll Lock key disabled in Cinnamon/Linux/Xorg? 一文给出了详细的方法

Tag "心情日记,生活随笔":

很久不有更新博客了

嗯,刚刚pull了一下博客,发现最后一岾还是5月19号写的。

距离9月7号已经有三个半月了,2018年也俨然过去的3/4,还记得年初的目标吗?

这几个月的经历,仿佛有几年一般,做了些什么?

充实而又放纵?

Jekyll make post categoly without using plugin

在CMS中,tag和categoly的实现方式虽大体相同,但功能和用途却不同。

而当前各种Pages服务仅支持有限的官方插件,自定义插件功能更是可望而不可及,要满足文章自动分类功能实在要用插件完成,之前一直通过本地生成jekyll的方式进行部署。

近日在开发awesom-weblog的时候发现一种不用插件的方法来生成不同的分类的页面。

在不使用自定义插件的情况下,让Jekyll支持文章分类

一、分类页渲染模版(Layout)

由插件版到无插件的迁移会比较简单,已经有存在了分类页文章渲染模版(Layout),无模块的可以参考首页模版进行修改。

示例(categoly.html)如下:

<div id="content">
	  <div class="box archive-meta">
        <h3 class="title-meta"></h3>
      </div>
    

</div>

这里用到的是site全局中的categories属性,该属性以字典的形式存储了所有分类,以及该分类下的post。

比如:我们只需要通过调用site.categories['Linux']便可以拿到该分类下的所有文章。

二、为分类创建分类页而

在layout已经创建好之后, 我们只需要通过该Layout对每个分类进行渲染,而渲染的方法,就是通过创建多个Layout的实现,使其传入不同的page.cat参数,便可生成不同的分类页面了。

一个Layout的实现如下:

添加categories目录,并在目录下创建一个名为Linux.html的文件:

---
layout: category
cat: Linux
---

此实现只需传入分类名无需带任何content,其它分类同样创建不同分类名文件,并传入分类名。

此外,可通过添加permalink:参数自定义目录生成的链接位置。

三、自动创建分类页面

由于分类页面实在简单,但如果分类较多的话,可能通过批量命令的方式,创建页面。

首先获取到博客的分类列表,形成txt文档,每行一个。

在categories目录下创建bash程序autogencat.sh

#!/bin/bash

while read catname
do
	cp Linux.html $catname.html
	sed -i "s/Linux/${catname}/g"  ${catname}.html
done

添加执行权限并且执行:

chmod +x autogencat.sh
./autogencat.sh < catlist.txt

程序会将Linux.html做为生成模板,复制生成其它分类文件,以后新增分类只需要更新catlist.txt目录列表,运行脚本即可。

两个月没写东西了,总结一下这些天都做了些什么吧

上一篇还是 6月的事了,6月20号开完毕业典礼,24号就回家了。那天下着大雨,每走一步,都希望留下些什么,但好像什么也没有留下。

原计划,两个月把Linux内核完全注解看懂,但由于Linux不熟悉和不了解386架构,一直在徘徊中前进。

一星期给机械键盘改键改灯

了解了Linux下X的工作机制。

把Fedora换成了Ubuntu 在Ubuntu下安装了Gnome,没然又将桌面换成了DWM。

CF给上海区,升到了大师6。

其它小事若干。

漂在天空的日子

  • 你有没有听说过,这个世界上有一种鸟……

  • 听过啦,没脚的那种是嘛!这套哄女孩的可以啊,你像鸟吗?哪一寸像鸟啊?你只不是唐人街垃圾堆里捡回来的酒鬼。像鸟,你那要是会飞的话,会窝在这里么?飞呀,有本事飞给我看看啊!

  • 有机会的,不过到时候,你可不要自卑噢。

漂在天空的日子

On The Way, Forever~

一直都挂念着这个地方,想来写一点东西,然而……

也不知道以后会如何回忆这段的日子,

原以为一心考研,却只是想的太简单,

一直想着平静的生活,然而,自从那年高考结束之后,就已经不一样了,

那种一年两个长徦,除了周未每天都要去上课的时光,不需要自己去决定什么的日子早就再了,

2016-12-26 清晨

当被不知道什么时候定好的闹钟惊醒的那一刻,仍然有一种莫名的冲动,结束了吗?结束了,就这样结束了.不知道多少个像这样的日日夜夜夜过去,不知道以后还会有多少个像这样的日日夜夜–我的心,仍在路上.

卧榻将息,辗转之思

路漫漫

入学之期,焉已三年,

情情景景,历历在目,

浮心年华,酒醉酩酊,

学之习之,聚之散之,

絮事繁多,忙忙之为。

今轻年已去,清心求学,

一心一意,无欲它思,

竟不想今时何日。

忆往昔年,

高中之季,意气风发,

夙兴夜寐,进士及第,

时过境迁,期期三年。

今朝之举,黄金榜上,

既无愧于心,何须论得丧。

夜明风清,记之感慨。

——蓝记

Tag "grub,os-prober":

grub-mkconfig 没有Windows项

不知道什么时候开始,我的grub2-mkconfig

找不到Windows的启动项了, 说严重也不严重,但小问题堆起来也会成为大问题的 于是乎,追根溯源, Windows 项原本是在/etc/grub.d/30_os-prober生成

查看其代码,发现使用了os-prober寻找其他系统. 运行发现没有输出,可以确定是这个东西在抽风了

回头一想,之前由于部分主板EFI记动的时候,会检测是否存在/EFI/Microsoft/Boot/bootmfgw.efi,如果存在的话,会直接启动他,所以将其改名了. 将其改回再测试,os-prober可心正常找到Windows项了

于是乎,os-prober要改的话基本没戏,还是写脚本吧,

 vi /etc/grub.d/40_custom

直接将启动项加入就行了.

关于 grub 请详见官方文档!

Tag "windows":

grub-mkconfig 没有Windows项

不知道什么时候开始,我的grub2-mkconfig

找不到Windows的启动项了, 说严重也不严重,但小问题堆起来也会成为大问题的 于是乎,追根溯源, Windows 项原本是在/etc/grub.d/30_os-prober生成

查看其代码,发现使用了os-prober寻找其他系统. 运行发现没有输出,可以确定是这个东西在抽风了

回头一想,之前由于部分主板EFI记动的时候,会检测是否存在/EFI/Microsoft/Boot/bootmfgw.efi,如果存在的话,会直接启动他,所以将其改名了. 将其改回再测试,os-prober可心正常找到Windows项了

于是乎,os-prober要改的话基本没戏,还是写脚本吧,

 vi /etc/grub.d/40_custom

直接将启动项加入就行了.

关于 grub 请详见官方文档!

Tag "Linux系统":

让 Grub2 记住上次选择的启动项

linux 下可以碰到各种各样的问题,今天解决了一部分,明天也许又会冒出一些新的问题, 但是,更重要的是,fix it and remenber it!

linux 使用配置文件进行管理,其中gurb 的配置文件有, /etc/default/grub/etc/grub.d/

前者存储grub变量,后者为生成一个完整,grub.cfg配置的脚本,

此外,还有一个官方给的/boot/grub2/grubenv

Tag "Fedora":

让 Grub2 记住上次选择的启动项

linux 下可以碰到各种各样的问题,今天解决了一部分,明天也许又会冒出一些新的问题, 但是,更重要的是,fix it and remenber it!

linux 使用配置文件进行管理,其中gurb 的配置文件有, /etc/default/grub/etc/grub.d/

前者存储grub变量,后者为生成一个完整,grub.cfg配置的脚本,

此外,还有一个官方给的/boot/grub2/grubenv

Tag "心情日记,考研心得":

考研日记

这段大学最充实的日子,终于结束。回想起来,花人生的一小段时光去奋斗,升学,提升自己,是很有必要的。 那么,也同样恭喜看到篇帖子的人,也许你也选择了与我同样的道路,不论结果如何,这段日子,也将成为你大学时光最难忘的一刻。 至少,你将会在这个时候,学到:

  • 什么叫做坚持,一年如一日的坚持
  • 什么叫做认真,不放过任何一个知识点的认真
  • 什么叫做态度,对待自己人生前途的态度

考研日记

如果已经决定要打一场战了的话,那么就做好充足的准备吧,

随手日记,不忘青春,虽然其中也写了一些废话吧,回头细想,一路过来,也不失为人生中一段乐趣。虽无苦尽甘来之想,人生仍在路上呐。


本着自由贡献的精神, 给某某某以及即将踏上2018年考研孩子们的一些经验吧,希望能有哪怕是一点点的帮助也好。

决定考研是一件比较艰难的事,要面临各种选择与得失、父母和老师们的期盼、为自己的前程的负责,

随着时间的推移,真正要面临这个选择了,

想着三年来一直生活在一个小圈子里边,班上几个同学,学校几个朋友,讨论的话题永远是哪个游戏好玩,新出了哪部电影,哪个人怎么样,肤浅的观点在小圈子里边传播,

过着象牙塔般的生活 好像世界就是这么安逸了。过完四年,连学校有哪些个专业,发生了什么大的事情都不知道。

想想毕业后就是另一番景象,没有学到什么真东西,在小公司里边摸爬滚打一辈子。 最后把自己的青春浪费在一般人走过的路上,我不甘心,于是。

在作出决定之前,也是一往反对考研的。然而,后来会发现, 这是一个正确的选择, 前提是,找到了一个合适的大学,

现在回想以前的对考研看法,甚至有些幼稚,

Tag "数据结构算法,动态规划":

动态规划-最长增长子序列

最长递增子序列(LIS)的问题是要找到一个给定序列的最长子序列的长度,使得子序列中的所有元素被排序的顺序增加。

例如,{2,1,0,5,4,8,9} LIS为{2,4,8,9},{2,4,8,9},{1,5,8,9}….最长长度为4。

这里存在一个局部前后无关性的规律:

设 arr[0..m..m+1] 其中arr[0..m] 的最长子序列是包含于arr[0..m+1]的,且长度包含

所以,求arr[0..m]的最长子序列,只需要找出{ arr[0..m-i],其中m=>i>=1}的LIS,

此时,设{ arr[0..m-i],其中m=>i>=1}的最长子序列:i = k;

如果arr[k] < arr[m]的话,则arr[m]的LIS长度为arr[0..k]的LIS长度+1;

LIS = LIS + arr[m];

int arr[10] = {2,1,0,5,4,8,9};
int n = sizeof(arr) / sizeof(arr[0]);

//返回包含第n个元素作为最后一个元素的子序列的最长长度,
//a用于记录最长长度,
int lis(int n, int &a)
{
    if(n == 1) return 1;
    int cmax = 0;
    for(int i = 1; i < n; i++)
    {
        //第n个元素有可能不是LIS的最后一个元素,所以这里的递归不能放进if里面。
        int r = lis(i,a);
        if(arr[i-1]<arr[n-1])
        {
            if(r > cmax) cmax = r;
        }
    }
    a = max(a,cmax+1);
    return cmax + 1;
}

可以看到,每次lis(n)的执行都会调用n-1次lis,时间复杂度为O(n^2), 下面进行优化: 方法与之前的背包问题和整分拆分问题非常相似。

int arr[10] = {2,1,0,5,4,8,9};
int nSize = sizeof(arr) / sizeof(arr[0]);
int lis2(int nSize)
{
    int *c;
    c = (int *) malloc(sizeof(int)*nSize);
    c[0] = 1;

    int gmax=0;
    for(int n = 1; n < nSize; n++ )
    {
        int cmax = 0;
        for ( int i = 0; i < n; i++ )
        {
            if ( arr[i]<arr[n] && c[i]>cmax ) 
                cmax = c[i];
        }
        c[n] = cmax + 1;

        if ( c[n] > gmax ) gmax = c[n];
    }

    free( c );
    return gmax;
}

01背包问题

恕在下愚钝,01背包问题学了两仨天才搞懂,其中也是断断续续了,

这个问题也是讲烂了的一个知识点,但是由于没有找到一个适合以自己的思维来理解的,所以现在总结一下

大家都说这是一个关于动态规划的问题,但在下才疏学浅,始终无法,理会这其中的关系,

唯一能联想到的就是高中的时候,学过的几何绘画动态规划了,特征是:给出限制条件,求最值。看来应该是这类题目了。

现在只考虑01背包的情况,至于动态规划的思想还要再接触几个相应的题目才能掌握。

Tag "Android第三方ROM二次开发重新打包":

安卓7.x下重新打包第三方ROM

最近对安卓底层比较更兴趣,打算研究一番ROM的制作与移植,汉化之类技术,苦于这方面的比较有技术的文章比较少,多数还借鉴国外帖子,在工具方面也比较少,没有形成一个好的技术圈。

Tag "Linux,DWM":

在Ubuntu 17.04 下DWM的安装

比较简单的安装方法莫过于通过apt来安装了。

sudo apt-get install dwm

这样的安装方式,虽然提供了四种不同的已经配置好的dwm.default dwm.maintainer dwm.web dwm.winky,但相对于dwm的自定义空间基本上是没有的,毕竟dwm的自定义是通过源码重新编译来完成的。

DWM的源码可以从作者的SuckLess网站下载,网站也提供了一些简单的使用方法,对于一般人来说也足够了。

下载解压至相应路径即可以进行,make install

注意,由于新版本的freetype2库的改动,

需要更新config.mk文件,将中下面两行进行注释:

#OpenBSD (uncomment)

FREETYPEINC = ${X11INC}/freetype2

即启用FREETYPEINC = /usr/include/freetype2

如果还缺少其它头文件,可以利用apt-file search youfile.h进行查找,并安装相应软件包。

如果make install成功。此时,dwm已经被安装到/usr/local/bin目录下。

参照:CustomXSession Ubuntu下标准自定义session的配置方法。

在~/.xinitrc 文件中定入以下内容:


#!/bin/bash

# enable ibus
export GTK_IM_MODULE=ibus
export QT_IM_MODULE=ibus
export QT4_IM_MODULE=ibus
export CLUTTER_IM_MODULE=ibus
export XMODIFIERS=@im=ibus



exec /usr/local/bin/dwm

重启Ubuntu即可在登录选项中看到预先设置dwm选项。

此外,也可以在命令行界面下执行startx命令启动dwm。

Tag "Linux,GTK Theme":

Linux下各种修改GTK主题的方法

X为了提供更加灵活桌面的实现,使得Linux下桌面环境比较繁杂,这也衍生出众多Coder对自己Linux桌面进行定制的程序。有功能全面的Desktop Env,比如GNOME,KDE,LightDM,也有轻量功能强大的Window Manage,比如owesome,dwm。

在图形桌面环境下,各个Desktop Env都提供了相应对自身主题的修改,比如gnome-tweak-tool、unity-tweak-tool,通过修改Shell Theme可以切换不同的主题。

命令行下的修改可以通过 gsettings set org.gnome.desktop.interface gtk-theme “Mytheme” 来完成。

Linux发行版安装之后会默认自带部分主题,更多好看的可以在 Gnome LookKDE Look 下载。

主题的安装,一般将主题包下载解压至/usr/share/themes/ 或~/.local/share/themes/下即可被各种Tweak程序检测到。

但是,以上方法仅仅是对相应Desktop Env下主题的修改。一旦更换了桌面环境或者窗口管理器,这些效果将消失。

其实,GTK本身提供修改主题的方法:

一、可以通过修改程序运行时环境参数GTK_THEME来临时修改单个程序的主题,比如运行使用Adwaita:light替代Ubuntu下Firefox的橘红色主题:env GTK_THEME=Adwaita:light firefox

二、可以通过修改/etc/gtk-3.0/settings.ini~/.config/gtk-3.0/settings.ini文件中gtk-theme-name项,进行全局修改。

此外,文件还提供了icon图标以及sound声音的修改。

Tag "客制化机械键盘":

使用STM32可编程芯片的制作的机械键盘主控

曾经是去年四月的想法,自定义一把顺手的机械键盘,终于到了今年暑期才完成,可怕的拖延症。

然而并不是像想象的那么简单,拿到手的是一把 JAGOR TITON 100 ,由于键盘主控制器与轴板是可分离的连接方式,才有了这个想法。

这其中所要经历的工作有:主控芯片的选择,设计键盘主控制器PCB,为其焊接可编程芯片,开发主控代码,完全拆卸键盘结构,重新焊接键盘轴体和布局背光灯。

芯片选择至关重要,最终找到了一块引脚数量足够多,而且又不缺Demo的Stm32f103c8t6。

将芯片所有多功能引脚全改为IO引脚,其中8个IO作为外部中断使用的列矩阵引脚,其余做为行矩阵引脚,留出多余的用作LED指示灯。

PCB板的设计大小长宽不能超过50*13mm,使用芯片的最小核心Demo,研究了一番,将多余芯片功能去掉,最后根据轴板IC座引脚功能,调整芯片和电容电阻位置以达到最大化的引脚对应和最少的线路穿插(AD提供鸡肋的组件布局自动化浪费了半天的时间,最后还是手动布局比较靠谱)。最后将设计文档交给华强北的PCB打印厂,50包邮搞定~

接着是将从taobao买到的STM芯片焊到PCB上,没有专业的工具,多用一些松香增加锡的张力,一支尖角电烙铁也可以搞定。

轴板拆缷要借助吸锡器来完成,像PCB这类除了第一次生产之后,永不变动的东西,要再进行二次焊接的话,焊盘很容易脱落,所以改轴和灯光部分需要一次完成。

Tag "机械键盘主控器":

使用STM32可编程芯片的制作的机械键盘主控

曾经是去年四月的想法,自定义一把顺手的机械键盘,终于到了今年暑期才完成,可怕的拖延症。

然而并不是像想象的那么简单,拿到手的是一把 JAGOR TITON 100 ,由于键盘主控制器与轴板是可分离的连接方式,才有了这个想法。

这其中所要经历的工作有:主控芯片的选择,设计键盘主控制器PCB,为其焊接可编程芯片,开发主控代码,完全拆卸键盘结构,重新焊接键盘轴体和布局背光灯。

芯片选择至关重要,最终找到了一块引脚数量足够多,而且又不缺Demo的Stm32f103c8t6。

将芯片所有多功能引脚全改为IO引脚,其中8个IO作为外部中断使用的列矩阵引脚,其余做为行矩阵引脚,留出多余的用作LED指示灯。

PCB板的设计大小长宽不能超过50*13mm,使用芯片的最小核心Demo,研究了一番,将多余芯片功能去掉,最后根据轴板IC座引脚功能,调整芯片和电容电阻位置以达到最大化的引脚对应和最少的线路穿插(AD提供鸡肋的组件布局自动化浪费了半天的时间,最后还是手动布局比较靠谱)。最后将设计文档交给华强北的PCB打印厂,50包邮搞定~

接着是将从taobao买到的STM芯片焊到PCB上,没有专业的工具,多用一些松香增加锡的张力,一支尖角电烙铁也可以搞定。

轴板拆缷要借助吸锡器来完成,像PCB这类除了第一次生产之后,永不变动的东西,要再进行二次焊接的话,焊盘很容易脱落,所以改轴和灯光部分需要一次完成。

Tag "更新ibus输入法词库":

linux下更新ibus-wubi输入法词库

参考 ubuntu Wiki:https://wiki.ubuntu.com.cn/IBus

IBus 全称 Intelligent Input Bus是下一代输入法框架(或者说“平台”)。 项目现托管于 Google Code - https://code.google.com/p/ibus/ 此项目包含了世界多数语言的文字输入需求——由世界多个国家开发者维护。

虽然世界上有那么多人在维护IBus,然而相对于国内的输入法市场,也算是相形见绌了。

输入法默认提供的词库,并没有经过人性化的处理,大部分异体字,以及不常用的词语,还有各类流行短语,比如“跑路”、“静静”、“微博”,部分字词还停还停留在上个世纪的感觉,

所以不得不变回我的Win7从QQ Wubi设置里边导出了一份txt格式的默认词库。(不得不说,腾讯的产品就剩下这点儿清白了)

Tag "MCU,MSP432,GPIO":

MSP432中GPIO中断相关操作

GPIO的P1,P2,PA支持中断

MSP432 中的中断相关寄存器 PxIFG 中断标志寄存器 PxIV 中断向量寄存器

Driverlib 所涉及到GPIO中断的函数

GPIO_registerInterrupt GPIO_unregisterInterrupt //Registers/UnRegister s an interrupt handler for the port interrupt. GPIO_disableInterrupt GPIO_enableInterrupt GPIO_getEnabledInterruptStatus GPIO_interruptEdgeselect GPIO_getInterruptStatus GPIO_clearInterruptFlag

![GPIO_IES寄存器][/post_res/GPIO_IES.png]

![GPIO_PxIFG寄存器][/post_res/GPIO_PxIFG.png]

![GPIO_PxIV寄存器][/post_res/GPIO_PxIV.png]

对中断的配置

/* Confinguring P1.1 & P1.4 as an input and enabling interrupts */
MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
MAP_GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
MAP_GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);

Tag "MCU":

一款小型哺乳动物仓笼体温监测与活动检测的装置以及部署方案

本方案使用物联网技术,通过高精度嵌入式红外摄像头,持续采集仓笼内热源信号,以及动物运动状态,使用嵌入式MCU对感知数据进行前端采集与简单分析,通过Wifi网络上传到数据中心,可形成数据汇总,采集时间跨度短可几周,长则跨年。装置。可按照需求,定制化按时按天按月或按年,生成可视化温度变化曲线,成本低廉,可供学术研究参考,或生物实验佐证使用。

单套设备仅需人民币300~500左右,约合美元60~80,成本低廉。对于单个仓笼,可同时部署多套设备,多套设备数据融合处理,以达到最佳采样角度,确保检测无死角。

方案包含完整装置采购清单,设备运行程序以及设备程序烧录指导,设备联网方法,现场部署指导等一系列指导文档,以及售后指导服务。

方案主体框架如下:

system_flow

一些国内用户的使用范例:

example_all

view_2

example_view

类似竞品论文参考:

https://journals.plos.org/plosbiology/article?id=10.1371/journal.pbio.3000406 http://journals.plos.org/plosbiology/article/asset?unique&id=info:doi/10.1371/journal.pbio.3000406.s014

合作洽谈可联系:iziy#mypre.cn / c834606877#163.com

一例MusicBox的固件简单分析,基于STM32芯片固件分析总结(待续)

从硬件到软件,制作一个高还原性,高保真的音乐盒子一直是我的兴趣之一。因此,我尝试在淘宝买一些音乐盒子做为设计参考,从双轨正负电压供电电路,电池充放电电路,stm32核心电路,到dac的解码电路,前极放大电路。到USB声卡,sdcard播放等功能。

最近发现某款音乐播放器的固件很有趣,因此,我在这简单记录一下分析过程,顺便总结一下从中学到的一些分析经验。

固件是通过SDcard更新的,商家发布新固件后,将固件放入SDcard后,芯片上的bootloader会检测并触发更新。

固件的部分内容如下:

bin-img

经过分析,固件使用了简单的压缩,一来减少固件体积,二是有校验机制。

通常,固件前一部分内容是,固件定义的栈顶指针以及芯片的中断向量表,均为4字节对齐。

MSP432 Graphics Library

MSP432提供了对LCD屏操作的库函数,而从整个对LCD的操控来说,自下面上的分成了三层:HAL硬件抽象层,LCD屏的驱动层以及grlib上层图形库。

按照官方文档的介绍grlib库提供了一些上下文控制函数以及一系列简单的图表绘制函数:圆,位图,直线,矩形,字符串,按钮,图像按钮,单选框,多选框,以及位图数据转C格式数据工具。

HAL实现对MCU与LCD之间接口的配置,以及底层LCD控制器的串行通信,实现控制字符与数据字符的传输。 LCD驱动层利用HAL实现LCD的基本元素的绘制(点、直线等的绘制),为 grlib 提供调用接口。

以下为三层架构所对应的头文件,包含各自了所在层的函数原型,以及函数调用的方法

#include <ti/grlib/grlib.h>
#include "LcdDriver/Crystalfontz128x128_ST7735.h"
#include "LcdDriver/HAL_MSP_EXP432P401R_Crystalfontz128x128_ST7735.h"

LCD的初始化代码一般如下:

    /* Graphic library context */
    Graphics_Context g_sContext;  //全局上下文

    /* Initializes display */
    Crystalfontz128x128_Init();   //驱动层的LCD初始化代码

    /* Set default screen orientation */
    Crystalfontz128x128_SetOrientation(0);  //设置屏幕方向

    /* Initializes graphics context */
    Graphics_initContext(&g_sContext, &g_sCrystalfontz128x128, &g_sCrystalfontz128x128_funcs); 
    Graphics_setForegroundColor(&g_sContext, GRAPHICS_COLOR_BLUE);
    Graphics_setBackgroundColor(&g_sContext, GRAPHICS_COLOR_WHITE);
    GrContextFontSet(&g_sContext, &g_sFontFixed6x8);

可以看出初始化函数调用关系是逐层的,驱动层初始化通过调用HAL层进行硬件初始化,其中包括PortInit、SpiInit与LCD芯片初始化。 PortInit:为TI通用的端口复用配置,针对不同TI芯片电路进行端口的开启与复用,此部分代码同样为通用。

需要定制的只有HAL通信功能引脚的配置:

// Ports from MSP432 connected to LCD
#define LCD_SCK_PORT          GPIO_PORT_P1
#define LCD_SCK_PIN_FUNCTION  GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_MOSI_PORT         GPIO_PORT_P1
#define LCD_MOSI_PIN_FUNCTION GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_RST_PORT          GPIO_PORT_P5
#define LCD_CS_PORT           GPIO_PORT_P5
#define LCD_DC_PORT           GPIO_PORT_P3

// Pins from MSP432 connected to LCD
#define LCD_SCK_PIN           GPIO_PIN5
#define LCD_MOSI_PIN          GPIO_PIN6
#define LCD_RST_PIN           GPIO_PIN7
#define LCD_CS_PIN            GPIO_PIN0
#define LCD_DC_PIN            GPIO_PIN7

// Definition of USCI base address to be used for SPI communication
#define LCD_EUSCI_BASE        EUSCI_B0_BASE

grlib的初始化内容则是主要围绕一个g_sContext结构体进行, Graphics_Context 结构体定义如下:

typedef struct Graphics_Context
{
    int32_t size;                         //!< The size of this structure.
    const Graphics_Display *display;    //!< The screen onto which drawing operations are performed.
    Graphics_Rectangle clipRegion;        //!< The clipping region to be used when drawing onto the screen.
    uint32_t foreground;                 //!< The color used to draw primitives onto the screen.
    uint32_t background;                 //!< The background color used to draw primitives onto the screen.
    const Graphics_Font *font;            //!< The font used to render text onto the screen.
} Graphics_Context;

Graphics_Display *display结构体包括了特定LCD的宽高信息以及驱动函数指针。由此可以看出,LCD屏与上grlib也是分离的,当硬件更换为不同的LCD时,只需修改对应LCD驱动层函数指针,甚至可以实现LCD热更换。

但三层架构的设计架构移植性较高,牺牲了一部分屏幕控制器的硬件性能。

MSP432 launchpad User Application Port UART

串口通信的配置

串口的配置 主要包括两个方面:

  • 初始化结构体的配置
  • 串口模块中断的开启

以下是基于DriverLib的初始化代码

    const eUSCI_UART_Config uartConfig =
    {
            EUSCI_A_UART_CLOCKSOURCE_SMCLK,        // SMCLK Clock Source 48Mhz
            312,                                   // BRDIV = 312
            8,                                     // UCxBRF = 8
            0xAA,                                  // UCxBRS = 0xAA
            EUSCI_A_UART_NO_PARITY,                // No Parity
            EUSCI_A_UART_LSB_FIRST,                // MSB First
            EUSCI_A_UART_ONE_STOP_BIT,             // One stop bit
            EUSCI_A_UART_MODE,                     // UART mode
            EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // overSampling Mode
    };

    /* Configuring UART Module */
     UART_initModule(EUSCI_A0_BASE, &uartConfig);

    /* Enable UART module */
     UART_enableModule(EUSCI_A0_BASE);

     UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
     Interrupt_enableInterrupt(INT_EUSCIA0);

     MAP_Interrupt_enableSleepOnIsrExit(); //低功耗模式

比较困难的地方在于波特率的设置主要涉及到BRDIV,UCxBRF,UCxBRS, overSampling Mode这几个寄存器参数。

DriverLib手册中提到了一个参数计算器 http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html

如果上位机可以接收到FF FE之类的乱码一般是波特率设置不正确导致,不同的时钟源频率需要将其分离成所需要的频率,具体的计算公式在Reference Manual 的22.3.10小节有详细说明,将计算出来的波特率只要与上位机设置的相差不远也是可以进行通信的。

此外,网上有一部分相关帖子提到中断名的问题在CCS里边,系统会为所有中断定义一个默认中断,如果程序没有定义相关中断,在程序中又开启了此中断,中断触发后将会陷入到默认中断中。这里的默认中断内容是一个死循环,中断向量表在startup_msp432p401r_ccs.c中有定义。

  //Configure UART pins

  P1SEL0 |=BIT2 | BIT3;                  // set2-UART pin as second function



 __enable_interrupt();

 NVIC->ISER[0] = 1 << ((EUSCIA0_IRQn) & 31); // EnableeUSCIA0 interrupt in NVIC module

  //Configure UART

  UCA0CTLW0|= UCSWRST;
  UCA0CTLW0|= UCSSEL__SMCLK;             // PuteUSCI in reset

  // BaudRate calculation
  //12000000/(16*9600) = 78.125
  //Fractional portion = 0.125
  // User'sGuide Table 21-4: UCBRSx = 0x10
  // UCBRFx =int ( (78.125-78)*16) = 2

  UCA0BR0 =78;                           //12000000/16/9600
  UCA0BR1 =0x00;
  UCA0MCTLW= 0x1000 | UCOS16 | 0x0020;    //注意这一行的设定

  UCA0CTLW0&= ~UCSWRST;                  //Initialize eUSCI

  UCA0IE |=UCRXIE;                       // EnableUSCI_A0 RX interrupt

近几年来使用DriverLib开发的越来越多了,个人认为DriverLib可以在一定程度上简化开发流程,对新手友好,上手快,但是由于432官方对DriverLib手册并不是非常的友好,很多函数仅仅是一带而过,函数说明甚至没有源码注释写得好,这一使得学习432的内容需要齐头并进,能够简单易懂的用DriverLib难一些的还是要参考寄存器配置。

以下是串口中断处理函数,利用寄存器操作,将收到的串口数据进行回传。

/*
 * EUSCI A0 UART interrupt handler.
 */
void EUSCIA0_IRQHandler(void)
{
    if(UCA0IFG & UCRXIFG)
    {
     while(!(UCA0IFG&UCTXIFG));
           UCA0TXBUF = UCA0RXBUF;
     __no_operation();

    }
}

而DriverLib版:

    int receiveByte;
    receiveByte = UART_receiveData(EUSCI_A0_BASE);
    UART_transmitData(EUSCI_A0_BASE,receiveByte);

DriverLib的底层实现也是通过寄存器来完成的,这样可以通过学习源代码的方式了解某些寄存器的功能,省略某些技术细节,随着处理器执行效率的提高,代码越来越复杂,这样的库函数操作将会非常常见。

MSP432 使用Timer_A输出PWM

Timer_A 输出 PWM的问题

在官方例程中给出的是一种直接操作寄存器的方式启动的,这让我们这些刚刚接触MSP432这种嵌入式芯片的来说是很难看懂的,然而PWM的输出是可以重新映射到其它端口输出的,例程中又掺杂了PMAP GPIO端口的映射,这更使得学习无从下手。

通过寄存器操作的方式输出PWM波形

    TIMER_A0->CCR[0] = PWM_PERIOD;
    TIMER_A0->CCTL[1] = TIMER_A_CCTLN_OUTMOD_7;      // CCR1 Reset/set
    TIMER_A0->CCR[1] = PWM_PERIOD * (55 / 100.0);    // CCR1 PWM duty cycle
    TIMER_A0->CTL = TIMER_A_CTL_SSEL__SMCLK // 使用SMCLK时钟源
                  | TIMER_A_CTL_MC__UP   
                  | TIMER_A_CTL_CLR;  // SMCLK, up mode, clear TAR

引用msp432p401r.h头文件定义:

#define TIMER_A_CTL_MC__UP    ((uint16_t)0x0010)    /*!< Up mode: Timer counts up to TAxCCR0 */

通过 动态修改 TIMER_A0->CCR[1] 内容可以改变PWM间隔时间

通过DriverLib操作的方式输出PWM波形

/* Timer_A PWM Configuration Parameter */
Timer_A_PWMConfig pwmConfig =
{
    TIMER_A_CLOCKSOURCE_SMCLK,
    TIMER_A_CLOCKSOURCE_DIVIDER_1,
    32000,
    TIMER_A_CAPTURECOMPARE_REGISTER_1,
    TIMER_A_OUTPUTMODE_RESET_SET,
    3200
};
Timer_A_generatePWM(TIMER_A1_BASE, &pwmConfig);

Timer_A_setCompareValue(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, PWM_PERIOD * (50/100.0f)); //动态设置PWM 间隔时间

而timer_a.C文件中对Timer_A_generatePWM函数定义如下

void Timer_A_generatePWM(uint32_t timer, const Timer_A_PWMConfig *config)
{
    //此处省略一部分,参数合法判断...

    privateTimer_AProcessClockSourceDivider(timer, config->clockSourceDivider);

    TIMER_A_CMSIS(timer)->CTL &=
            ~(TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLK + TIMER_A_UPDOWN_MODE
                    + TIMER_A_DO_CLEAR + TIMER_A_TAIE_INTERRUPT_ENABLE);

    TIMER_A_CMSIS(timer)->CTL |= (config->clockSource + TIMER_A_UP_MODE
            + TIMER_A_DO_CLEAR);

    TIMER_A_CMSIS(timer)->CCR[0] = config->timerPeriod;

    TIMER_A_CMSIS(timer)->CCTL[0] &= ~(TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE
            + TIMER_A_OUTPUTMODE_RESET_SET);

    uint8_t idx = (config->compareRegister>>1) - 1;
    TIMER_A_CMSIS(timer)->CCTL[idx] |= config->compareOutputMode;
    TIMER_A_CMSIS(timer)->CCR[idx] = config->dutyCycle;
}

可以看到相关操作与寄存器类似,但一次只能修改一路PWM输出。难怪官方例程中直接使用寄存器操作,多路输出更加容易控制。

Tag "MSP432":

MSP432 Graphics Library

MSP432提供了对LCD屏操作的库函数,而从整个对LCD的操控来说,自下面上的分成了三层:HAL硬件抽象层,LCD屏的驱动层以及grlib上层图形库。

按照官方文档的介绍grlib库提供了一些上下文控制函数以及一系列简单的图表绘制函数:圆,位图,直线,矩形,字符串,按钮,图像按钮,单选框,多选框,以及位图数据转C格式数据工具。

HAL实现对MCU与LCD之间接口的配置,以及底层LCD控制器的串行通信,实现控制字符与数据字符的传输。 LCD驱动层利用HAL实现LCD的基本元素的绘制(点、直线等的绘制),为 grlib 提供调用接口。

以下为三层架构所对应的头文件,包含各自了所在层的函数原型,以及函数调用的方法

#include <ti/grlib/grlib.h>
#include "LcdDriver/Crystalfontz128x128_ST7735.h"
#include "LcdDriver/HAL_MSP_EXP432P401R_Crystalfontz128x128_ST7735.h"

LCD的初始化代码一般如下:

    /* Graphic library context */
    Graphics_Context g_sContext;  //全局上下文

    /* Initializes display */
    Crystalfontz128x128_Init();   //驱动层的LCD初始化代码

    /* Set default screen orientation */
    Crystalfontz128x128_SetOrientation(0);  //设置屏幕方向

    /* Initializes graphics context */
    Graphics_initContext(&g_sContext, &g_sCrystalfontz128x128, &g_sCrystalfontz128x128_funcs); 
    Graphics_setForegroundColor(&g_sContext, GRAPHICS_COLOR_BLUE);
    Graphics_setBackgroundColor(&g_sContext, GRAPHICS_COLOR_WHITE);
    GrContextFontSet(&g_sContext, &g_sFontFixed6x8);

可以看出初始化函数调用关系是逐层的,驱动层初始化通过调用HAL层进行硬件初始化,其中包括PortInit、SpiInit与LCD芯片初始化。 PortInit:为TI通用的端口复用配置,针对不同TI芯片电路进行端口的开启与复用,此部分代码同样为通用。

需要定制的只有HAL通信功能引脚的配置:

// Ports from MSP432 connected to LCD
#define LCD_SCK_PORT          GPIO_PORT_P1
#define LCD_SCK_PIN_FUNCTION  GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_MOSI_PORT         GPIO_PORT_P1
#define LCD_MOSI_PIN_FUNCTION GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_RST_PORT          GPIO_PORT_P5
#define LCD_CS_PORT           GPIO_PORT_P5
#define LCD_DC_PORT           GPIO_PORT_P3

// Pins from MSP432 connected to LCD
#define LCD_SCK_PIN           GPIO_PIN5
#define LCD_MOSI_PIN          GPIO_PIN6
#define LCD_RST_PIN           GPIO_PIN7
#define LCD_CS_PIN            GPIO_PIN0
#define LCD_DC_PIN            GPIO_PIN7

// Definition of USCI base address to be used for SPI communication
#define LCD_EUSCI_BASE        EUSCI_B0_BASE

grlib的初始化内容则是主要围绕一个g_sContext结构体进行, Graphics_Context 结构体定义如下:

typedef struct Graphics_Context
{
    int32_t size;                         //!< The size of this structure.
    const Graphics_Display *display;    //!< The screen onto which drawing operations are performed.
    Graphics_Rectangle clipRegion;        //!< The clipping region to be used when drawing onto the screen.
    uint32_t foreground;                 //!< The color used to draw primitives onto the screen.
    uint32_t background;                 //!< The background color used to draw primitives onto the screen.
    const Graphics_Font *font;            //!< The font used to render text onto the screen.
} Graphics_Context;

Graphics_Display *display结构体包括了特定LCD的宽高信息以及驱动函数指针。由此可以看出,LCD屏与上grlib也是分离的,当硬件更换为不同的LCD时,只需修改对应LCD驱动层函数指针,甚至可以实现LCD热更换。

但三层架构的设计架构移植性较高,牺牲了一部分屏幕控制器的硬件性能。

MSP432 launchpad User Application Port UART

串口通信的配置

串口的配置 主要包括两个方面:

  • 初始化结构体的配置
  • 串口模块中断的开启

以下是基于DriverLib的初始化代码

    const eUSCI_UART_Config uartConfig =
    {
            EUSCI_A_UART_CLOCKSOURCE_SMCLK,        // SMCLK Clock Source 48Mhz
            312,                                   // BRDIV = 312
            8,                                     // UCxBRF = 8
            0xAA,                                  // UCxBRS = 0xAA
            EUSCI_A_UART_NO_PARITY,                // No Parity
            EUSCI_A_UART_LSB_FIRST,                // MSB First
            EUSCI_A_UART_ONE_STOP_BIT,             // One stop bit
            EUSCI_A_UART_MODE,                     // UART mode
            EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // overSampling Mode
    };

    /* Configuring UART Module */
     UART_initModule(EUSCI_A0_BASE, &uartConfig);

    /* Enable UART module */
     UART_enableModule(EUSCI_A0_BASE);

     UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
     Interrupt_enableInterrupt(INT_EUSCIA0);

     MAP_Interrupt_enableSleepOnIsrExit(); //低功耗模式

比较困难的地方在于波特率的设置主要涉及到BRDIV,UCxBRF,UCxBRS, overSampling Mode这几个寄存器参数。

DriverLib手册中提到了一个参数计算器 http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html

如果上位机可以接收到FF FE之类的乱码一般是波特率设置不正确导致,不同的时钟源频率需要将其分离成所需要的频率,具体的计算公式在Reference Manual 的22.3.10小节有详细说明,将计算出来的波特率只要与上位机设置的相差不远也是可以进行通信的。

此外,网上有一部分相关帖子提到中断名的问题在CCS里边,系统会为所有中断定义一个默认中断,如果程序没有定义相关中断,在程序中又开启了此中断,中断触发后将会陷入到默认中断中。这里的默认中断内容是一个死循环,中断向量表在startup_msp432p401r_ccs.c中有定义。

  //Configure UART pins

  P1SEL0 |=BIT2 | BIT3;                  // set2-UART pin as second function



 __enable_interrupt();

 NVIC->ISER[0] = 1 << ((EUSCIA0_IRQn) & 31); // EnableeUSCIA0 interrupt in NVIC module

  //Configure UART

  UCA0CTLW0|= UCSWRST;
  UCA0CTLW0|= UCSSEL__SMCLK;             // PuteUSCI in reset

  // BaudRate calculation
  //12000000/(16*9600) = 78.125
  //Fractional portion = 0.125
  // User'sGuide Table 21-4: UCBRSx = 0x10
  // UCBRFx =int ( (78.125-78)*16) = 2

  UCA0BR0 =78;                           //12000000/16/9600
  UCA0BR1 =0x00;
  UCA0MCTLW= 0x1000 | UCOS16 | 0x0020;    //注意这一行的设定

  UCA0CTLW0&= ~UCSWRST;                  //Initialize eUSCI

  UCA0IE |=UCRXIE;                       // EnableUSCI_A0 RX interrupt

近几年来使用DriverLib开发的越来越多了,个人认为DriverLib可以在一定程度上简化开发流程,对新手友好,上手快,但是由于432官方对DriverLib手册并不是非常的友好,很多函数仅仅是一带而过,函数说明甚至没有源码注释写得好,这一使得学习432的内容需要齐头并进,能够简单易懂的用DriverLib难一些的还是要参考寄存器配置。

以下是串口中断处理函数,利用寄存器操作,将收到的串口数据进行回传。

/*
 * EUSCI A0 UART interrupt handler.
 */
void EUSCIA0_IRQHandler(void)
{
    if(UCA0IFG & UCRXIFG)
    {
     while(!(UCA0IFG&UCTXIFG));
           UCA0TXBUF = UCA0RXBUF;
     __no_operation();

    }
}

而DriverLib版:

    int receiveByte;
    receiveByte = UART_receiveData(EUSCI_A0_BASE);
    UART_transmitData(EUSCI_A0_BASE,receiveByte);

DriverLib的底层实现也是通过寄存器来完成的,这样可以通过学习源代码的方式了解某些寄存器的功能,省略某些技术细节,随着处理器执行效率的提高,代码越来越复杂,这样的库函数操作将会非常常见。

MSP432 使用Timer_A输出PWM

Timer_A 输出 PWM的问题

在官方例程中给出的是一种直接操作寄存器的方式启动的,这让我们这些刚刚接触MSP432这种嵌入式芯片的来说是很难看懂的,然而PWM的输出是可以重新映射到其它端口输出的,例程中又掺杂了PMAP GPIO端口的映射,这更使得学习无从下手。

通过寄存器操作的方式输出PWM波形

    TIMER_A0->CCR[0] = PWM_PERIOD;
    TIMER_A0->CCTL[1] = TIMER_A_CCTLN_OUTMOD_7;      // CCR1 Reset/set
    TIMER_A0->CCR[1] = PWM_PERIOD * (55 / 100.0);    // CCR1 PWM duty cycle
    TIMER_A0->CTL = TIMER_A_CTL_SSEL__SMCLK // 使用SMCLK时钟源
                  | TIMER_A_CTL_MC__UP   
                  | TIMER_A_CTL_CLR;  // SMCLK, up mode, clear TAR

引用msp432p401r.h头文件定义:

#define TIMER_A_CTL_MC__UP    ((uint16_t)0x0010)    /*!< Up mode: Timer counts up to TAxCCR0 */

通过 动态修改 TIMER_A0->CCR[1] 内容可以改变PWM间隔时间

通过DriverLib操作的方式输出PWM波形

/* Timer_A PWM Configuration Parameter */
Timer_A_PWMConfig pwmConfig =
{
    TIMER_A_CLOCKSOURCE_SMCLK,
    TIMER_A_CLOCKSOURCE_DIVIDER_1,
    32000,
    TIMER_A_CAPTURECOMPARE_REGISTER_1,
    TIMER_A_OUTPUTMODE_RESET_SET,
    3200
};
Timer_A_generatePWM(TIMER_A1_BASE, &pwmConfig);

Timer_A_setCompareValue(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, PWM_PERIOD * (50/100.0f)); //动态设置PWM 间隔时间

而timer_a.C文件中对Timer_A_generatePWM函数定义如下

void Timer_A_generatePWM(uint32_t timer, const Timer_A_PWMConfig *config)
{
    //此处省略一部分,参数合法判断...

    privateTimer_AProcessClockSourceDivider(timer, config->clockSourceDivider);

    TIMER_A_CMSIS(timer)->CTL &=
            ~(TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLK + TIMER_A_UPDOWN_MODE
                    + TIMER_A_DO_CLEAR + TIMER_A_TAIE_INTERRUPT_ENABLE);

    TIMER_A_CMSIS(timer)->CTL |= (config->clockSource + TIMER_A_UP_MODE
            + TIMER_A_DO_CLEAR);

    TIMER_A_CMSIS(timer)->CCR[0] = config->timerPeriod;

    TIMER_A_CMSIS(timer)->CCTL[0] &= ~(TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE
            + TIMER_A_OUTPUTMODE_RESET_SET);

    uint8_t idx = (config->compareRegister>>1) - 1;
    TIMER_A_CMSIS(timer)->CCTL[idx] |= config->compareOutputMode;
    TIMER_A_CMSIS(timer)->CCR[idx] = config->dutyCycle;
}

可以看到相关操作与寄存器类似,但一次只能修改一路PWM输出。难怪官方例程中直接使用寄存器操作,多路输出更加容易控制。

Tag "Timer_A":

MSP432 使用Timer_A输出PWM

Timer_A 输出 PWM的问题

在官方例程中给出的是一种直接操作寄存器的方式启动的,这让我们这些刚刚接触MSP432这种嵌入式芯片的来说是很难看懂的,然而PWM的输出是可以重新映射到其它端口输出的,例程中又掺杂了PMAP GPIO端口的映射,这更使得学习无从下手。

通过寄存器操作的方式输出PWM波形

    TIMER_A0->CCR[0] = PWM_PERIOD;
    TIMER_A0->CCTL[1] = TIMER_A_CCTLN_OUTMOD_7;      // CCR1 Reset/set
    TIMER_A0->CCR[1] = PWM_PERIOD * (55 / 100.0);    // CCR1 PWM duty cycle
    TIMER_A0->CTL = TIMER_A_CTL_SSEL__SMCLK // 使用SMCLK时钟源
                  | TIMER_A_CTL_MC__UP   
                  | TIMER_A_CTL_CLR;  // SMCLK, up mode, clear TAR

引用msp432p401r.h头文件定义:

#define TIMER_A_CTL_MC__UP    ((uint16_t)0x0010)    /*!< Up mode: Timer counts up to TAxCCR0 */

通过 动态修改 TIMER_A0->CCR[1] 内容可以改变PWM间隔时间

通过DriverLib操作的方式输出PWM波形

/* Timer_A PWM Configuration Parameter */
Timer_A_PWMConfig pwmConfig =
{
    TIMER_A_CLOCKSOURCE_SMCLK,
    TIMER_A_CLOCKSOURCE_DIVIDER_1,
    32000,
    TIMER_A_CAPTURECOMPARE_REGISTER_1,
    TIMER_A_OUTPUTMODE_RESET_SET,
    3200
};
Timer_A_generatePWM(TIMER_A1_BASE, &pwmConfig);

Timer_A_setCompareValue(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, PWM_PERIOD * (50/100.0f)); //动态设置PWM 间隔时间

而timer_a.C文件中对Timer_A_generatePWM函数定义如下

void Timer_A_generatePWM(uint32_t timer, const Timer_A_PWMConfig *config)
{
    //此处省略一部分,参数合法判断...

    privateTimer_AProcessClockSourceDivider(timer, config->clockSourceDivider);

    TIMER_A_CMSIS(timer)->CTL &=
            ~(TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLK + TIMER_A_UPDOWN_MODE
                    + TIMER_A_DO_CLEAR + TIMER_A_TAIE_INTERRUPT_ENABLE);

    TIMER_A_CMSIS(timer)->CTL |= (config->clockSource + TIMER_A_UP_MODE
            + TIMER_A_DO_CLEAR);

    TIMER_A_CMSIS(timer)->CCR[0] = config->timerPeriod;

    TIMER_A_CMSIS(timer)->CCTL[0] &= ~(TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE
            + TIMER_A_OUTPUTMODE_RESET_SET);

    uint8_t idx = (config->compareRegister>>1) - 1;
    TIMER_A_CMSIS(timer)->CCTL[idx] |= config->compareOutputMode;
    TIMER_A_CMSIS(timer)->CCR[idx] = config->dutyCycle;
}

可以看到相关操作与寄存器类似,但一次只能修改一路PWM输出。难怪官方例程中直接使用寄存器操作,多路输出更加容易控制。

Tag "PWM":

MSP432 使用Timer_A输出PWM

Timer_A 输出 PWM的问题

在官方例程中给出的是一种直接操作寄存器的方式启动的,这让我们这些刚刚接触MSP432这种嵌入式芯片的来说是很难看懂的,然而PWM的输出是可以重新映射到其它端口输出的,例程中又掺杂了PMAP GPIO端口的映射,这更使得学习无从下手。

通过寄存器操作的方式输出PWM波形

    TIMER_A0->CCR[0] = PWM_PERIOD;
    TIMER_A0->CCTL[1] = TIMER_A_CCTLN_OUTMOD_7;      // CCR1 Reset/set
    TIMER_A0->CCR[1] = PWM_PERIOD * (55 / 100.0);    // CCR1 PWM duty cycle
    TIMER_A0->CTL = TIMER_A_CTL_SSEL__SMCLK // 使用SMCLK时钟源
                  | TIMER_A_CTL_MC__UP   
                  | TIMER_A_CTL_CLR;  // SMCLK, up mode, clear TAR

引用msp432p401r.h头文件定义:

#define TIMER_A_CTL_MC__UP    ((uint16_t)0x0010)    /*!< Up mode: Timer counts up to TAxCCR0 */

通过 动态修改 TIMER_A0->CCR[1] 内容可以改变PWM间隔时间

通过DriverLib操作的方式输出PWM波形

/* Timer_A PWM Configuration Parameter */
Timer_A_PWMConfig pwmConfig =
{
    TIMER_A_CLOCKSOURCE_SMCLK,
    TIMER_A_CLOCKSOURCE_DIVIDER_1,
    32000,
    TIMER_A_CAPTURECOMPARE_REGISTER_1,
    TIMER_A_OUTPUTMODE_RESET_SET,
    3200
};
Timer_A_generatePWM(TIMER_A1_BASE, &pwmConfig);

Timer_A_setCompareValue(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, PWM_PERIOD * (50/100.0f)); //动态设置PWM 间隔时间

而timer_a.C文件中对Timer_A_generatePWM函数定义如下

void Timer_A_generatePWM(uint32_t timer, const Timer_A_PWMConfig *config)
{
    //此处省略一部分,参数合法判断...

    privateTimer_AProcessClockSourceDivider(timer, config->clockSourceDivider);

    TIMER_A_CMSIS(timer)->CTL &=
            ~(TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLK + TIMER_A_UPDOWN_MODE
                    + TIMER_A_DO_CLEAR + TIMER_A_TAIE_INTERRUPT_ENABLE);

    TIMER_A_CMSIS(timer)->CTL |= (config->clockSource + TIMER_A_UP_MODE
            + TIMER_A_DO_CLEAR);

    TIMER_A_CMSIS(timer)->CCR[0] = config->timerPeriod;

    TIMER_A_CMSIS(timer)->CCTL[0] &= ~(TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE
            + TIMER_A_OUTPUTMODE_RESET_SET);

    uint8_t idx = (config->compareRegister>>1) - 1;
    TIMER_A_CMSIS(timer)->CCTL[idx] |= config->compareOutputMode;
    TIMER_A_CMSIS(timer)->CCR[idx] = config->dutyCycle;
}

可以看到相关操作与寄存器类似,但一次只能修改一路PWM输出。难怪官方例程中直接使用寄存器操作,多路输出更加容易控制。

Tag "UART":

MSP432 launchpad User Application Port UART

串口通信的配置

串口的配置 主要包括两个方面:

  • 初始化结构体的配置
  • 串口模块中断的开启

以下是基于DriverLib的初始化代码

    const eUSCI_UART_Config uartConfig =
    {
            EUSCI_A_UART_CLOCKSOURCE_SMCLK,        // SMCLK Clock Source 48Mhz
            312,                                   // BRDIV = 312
            8,                                     // UCxBRF = 8
            0xAA,                                  // UCxBRS = 0xAA
            EUSCI_A_UART_NO_PARITY,                // No Parity
            EUSCI_A_UART_LSB_FIRST,                // MSB First
            EUSCI_A_UART_ONE_STOP_BIT,             // One stop bit
            EUSCI_A_UART_MODE,                     // UART mode
            EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // overSampling Mode
    };

    /* Configuring UART Module */
     UART_initModule(EUSCI_A0_BASE, &uartConfig);

    /* Enable UART module */
     UART_enableModule(EUSCI_A0_BASE);

     UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
     Interrupt_enableInterrupt(INT_EUSCIA0);

     MAP_Interrupt_enableSleepOnIsrExit(); //低功耗模式

比较困难的地方在于波特率的设置主要涉及到BRDIV,UCxBRF,UCxBRS, overSampling Mode这几个寄存器参数。

DriverLib手册中提到了一个参数计算器 http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html

如果上位机可以接收到FF FE之类的乱码一般是波特率设置不正确导致,不同的时钟源频率需要将其分离成所需要的频率,具体的计算公式在Reference Manual 的22.3.10小节有详细说明,将计算出来的波特率只要与上位机设置的相差不远也是可以进行通信的。

此外,网上有一部分相关帖子提到中断名的问题在CCS里边,系统会为所有中断定义一个默认中断,如果程序没有定义相关中断,在程序中又开启了此中断,中断触发后将会陷入到默认中断中。这里的默认中断内容是一个死循环,中断向量表在startup_msp432p401r_ccs.c中有定义。

  //Configure UART pins

  P1SEL0 |=BIT2 | BIT3;                  // set2-UART pin as second function



 __enable_interrupt();

 NVIC->ISER[0] = 1 << ((EUSCIA0_IRQn) & 31); // EnableeUSCIA0 interrupt in NVIC module

  //Configure UART

  UCA0CTLW0|= UCSWRST;
  UCA0CTLW0|= UCSSEL__SMCLK;             // PuteUSCI in reset

  // BaudRate calculation
  //12000000/(16*9600) = 78.125
  //Fractional portion = 0.125
  // User'sGuide Table 21-4: UCBRSx = 0x10
  // UCBRFx =int ( (78.125-78)*16) = 2

  UCA0BR0 =78;                           //12000000/16/9600
  UCA0BR1 =0x00;
  UCA0MCTLW= 0x1000 | UCOS16 | 0x0020;    //注意这一行的设定

  UCA0CTLW0&= ~UCSWRST;                  //Initialize eUSCI

  UCA0IE |=UCRXIE;                       // EnableUSCI_A0 RX interrupt

近几年来使用DriverLib开发的越来越多了,个人认为DriverLib可以在一定程度上简化开发流程,对新手友好,上手快,但是由于432官方对DriverLib手册并不是非常的友好,很多函数仅仅是一带而过,函数说明甚至没有源码注释写得好,这一使得学习432的内容需要齐头并进,能够简单易懂的用DriverLib难一些的还是要参考寄存器配置。

以下是串口中断处理函数,利用寄存器操作,将收到的串口数据进行回传。

/*
 * EUSCI A0 UART interrupt handler.
 */
void EUSCIA0_IRQHandler(void)
{
    if(UCA0IFG & UCRXIFG)
    {
     while(!(UCA0IFG&UCTXIFG));
           UCA0TXBUF = UCA0RXBUF;
     __no_operation();

    }
}

而DriverLib版:

    int receiveByte;
    receiveByte = UART_receiveData(EUSCI_A0_BASE);
    UART_transmitData(EUSCI_A0_BASE,receiveByte);

DriverLib的底层实现也是通过寄存器来完成的,这样可以通过学习源代码的方式了解某些寄存器的功能,省略某些技术细节,随着处理器执行效率的提高,代码越来越复杂,这样的库函数操作将会非常常见。

Tag "串口通信":

MSP432 launchpad User Application Port UART

串口通信的配置

串口的配置 主要包括两个方面:

  • 初始化结构体的配置
  • 串口模块中断的开启

以下是基于DriverLib的初始化代码

    const eUSCI_UART_Config uartConfig =
    {
            EUSCI_A_UART_CLOCKSOURCE_SMCLK,        // SMCLK Clock Source 48Mhz
            312,                                   // BRDIV = 312
            8,                                     // UCxBRF = 8
            0xAA,                                  // UCxBRS = 0xAA
            EUSCI_A_UART_NO_PARITY,                // No Parity
            EUSCI_A_UART_LSB_FIRST,                // MSB First
            EUSCI_A_UART_ONE_STOP_BIT,             // One stop bit
            EUSCI_A_UART_MODE,                     // UART mode
            EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // overSampling Mode
    };

    /* Configuring UART Module */
     UART_initModule(EUSCI_A0_BASE, &uartConfig);

    /* Enable UART module */
     UART_enableModule(EUSCI_A0_BASE);

     UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
     Interrupt_enableInterrupt(INT_EUSCIA0);

     MAP_Interrupt_enableSleepOnIsrExit(); //低功耗模式

比较困难的地方在于波特率的设置主要涉及到BRDIV,UCxBRF,UCxBRS, overSampling Mode这几个寄存器参数。

DriverLib手册中提到了一个参数计算器 http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html

如果上位机可以接收到FF FE之类的乱码一般是波特率设置不正确导致,不同的时钟源频率需要将其分离成所需要的频率,具体的计算公式在Reference Manual 的22.3.10小节有详细说明,将计算出来的波特率只要与上位机设置的相差不远也是可以进行通信的。

此外,网上有一部分相关帖子提到中断名的问题在CCS里边,系统会为所有中断定义一个默认中断,如果程序没有定义相关中断,在程序中又开启了此中断,中断触发后将会陷入到默认中断中。这里的默认中断内容是一个死循环,中断向量表在startup_msp432p401r_ccs.c中有定义。

  //Configure UART pins

  P1SEL0 |=BIT2 | BIT3;                  // set2-UART pin as second function



 __enable_interrupt();

 NVIC->ISER[0] = 1 << ((EUSCIA0_IRQn) & 31); // EnableeUSCIA0 interrupt in NVIC module

  //Configure UART

  UCA0CTLW0|= UCSWRST;
  UCA0CTLW0|= UCSSEL__SMCLK;             // PuteUSCI in reset

  // BaudRate calculation
  //12000000/(16*9600) = 78.125
  //Fractional portion = 0.125
  // User'sGuide Table 21-4: UCBRSx = 0x10
  // UCBRFx =int ( (78.125-78)*16) = 2

  UCA0BR0 =78;                           //12000000/16/9600
  UCA0BR1 =0x00;
  UCA0MCTLW= 0x1000 | UCOS16 | 0x0020;    //注意这一行的设定

  UCA0CTLW0&= ~UCSWRST;                  //Initialize eUSCI

  UCA0IE |=UCRXIE;                       // EnableUSCI_A0 RX interrupt

近几年来使用DriverLib开发的越来越多了,个人认为DriverLib可以在一定程度上简化开发流程,对新手友好,上手快,但是由于432官方对DriverLib手册并不是非常的友好,很多函数仅仅是一带而过,函数说明甚至没有源码注释写得好,这一使得学习432的内容需要齐头并进,能够简单易懂的用DriverLib难一些的还是要参考寄存器配置。

以下是串口中断处理函数,利用寄存器操作,将收到的串口数据进行回传。

/*
 * EUSCI A0 UART interrupt handler.
 */
void EUSCIA0_IRQHandler(void)
{
    if(UCA0IFG & UCRXIFG)
    {
     while(!(UCA0IFG&UCTXIFG));
           UCA0TXBUF = UCA0RXBUF;
     __no_operation();

    }
}

而DriverLib版:

    int receiveByte;
    receiveByte = UART_receiveData(EUSCI_A0_BASE);
    UART_transmitData(EUSCI_A0_BASE,receiveByte);

DriverLib的底层实现也是通过寄存器来完成的,这样可以通过学习源代码的方式了解某些寄存器的功能,省略某些技术细节,随着处理器执行效率的提高,代码越来越复杂,这样的库函数操作将会非常常见。

Tag "Graphic":

MSP432 Graphics Library

MSP432提供了对LCD屏操作的库函数,而从整个对LCD的操控来说,自下面上的分成了三层:HAL硬件抽象层,LCD屏的驱动层以及grlib上层图形库。

按照官方文档的介绍grlib库提供了一些上下文控制函数以及一系列简单的图表绘制函数:圆,位图,直线,矩形,字符串,按钮,图像按钮,单选框,多选框,以及位图数据转C格式数据工具。

HAL实现对MCU与LCD之间接口的配置,以及底层LCD控制器的串行通信,实现控制字符与数据字符的传输。 LCD驱动层利用HAL实现LCD的基本元素的绘制(点、直线等的绘制),为 grlib 提供调用接口。

以下为三层架构所对应的头文件,包含各自了所在层的函数原型,以及函数调用的方法

#include <ti/grlib/grlib.h>
#include "LcdDriver/Crystalfontz128x128_ST7735.h"
#include "LcdDriver/HAL_MSP_EXP432P401R_Crystalfontz128x128_ST7735.h"

LCD的初始化代码一般如下:

    /* Graphic library context */
    Graphics_Context g_sContext;  //全局上下文

    /* Initializes display */
    Crystalfontz128x128_Init();   //驱动层的LCD初始化代码

    /* Set default screen orientation */
    Crystalfontz128x128_SetOrientation(0);  //设置屏幕方向

    /* Initializes graphics context */
    Graphics_initContext(&g_sContext, &g_sCrystalfontz128x128, &g_sCrystalfontz128x128_funcs); 
    Graphics_setForegroundColor(&g_sContext, GRAPHICS_COLOR_BLUE);
    Graphics_setBackgroundColor(&g_sContext, GRAPHICS_COLOR_WHITE);
    GrContextFontSet(&g_sContext, &g_sFontFixed6x8);

可以看出初始化函数调用关系是逐层的,驱动层初始化通过调用HAL层进行硬件初始化,其中包括PortInit、SpiInit与LCD芯片初始化。 PortInit:为TI通用的端口复用配置,针对不同TI芯片电路进行端口的开启与复用,此部分代码同样为通用。

需要定制的只有HAL通信功能引脚的配置:

// Ports from MSP432 connected to LCD
#define LCD_SCK_PORT          GPIO_PORT_P1
#define LCD_SCK_PIN_FUNCTION  GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_MOSI_PORT         GPIO_PORT_P1
#define LCD_MOSI_PIN_FUNCTION GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_RST_PORT          GPIO_PORT_P5
#define LCD_CS_PORT           GPIO_PORT_P5
#define LCD_DC_PORT           GPIO_PORT_P3

// Pins from MSP432 connected to LCD
#define LCD_SCK_PIN           GPIO_PIN5
#define LCD_MOSI_PIN          GPIO_PIN6
#define LCD_RST_PIN           GPIO_PIN7
#define LCD_CS_PIN            GPIO_PIN0
#define LCD_DC_PIN            GPIO_PIN7

// Definition of USCI base address to be used for SPI communication
#define LCD_EUSCI_BASE        EUSCI_B0_BASE

grlib的初始化内容则是主要围绕一个g_sContext结构体进行, Graphics_Context 结构体定义如下:

typedef struct Graphics_Context
{
    int32_t size;                         //!< The size of this structure.
    const Graphics_Display *display;    //!< The screen onto which drawing operations are performed.
    Graphics_Rectangle clipRegion;        //!< The clipping region to be used when drawing onto the screen.
    uint32_t foreground;                 //!< The color used to draw primitives onto the screen.
    uint32_t background;                 //!< The background color used to draw primitives onto the screen.
    const Graphics_Font *font;            //!< The font used to render text onto the screen.
} Graphics_Context;

Graphics_Display *display结构体包括了特定LCD的宽高信息以及驱动函数指针。由此可以看出,LCD屏与上grlib也是分离的,当硬件更换为不同的LCD时,只需修改对应LCD驱动层函数指针,甚至可以实现LCD热更换。

但三层架构的设计架构移植性较高,牺牲了一部分屏幕控制器的硬件性能。

Tag "library":

MSP432 Graphics Library

MSP432提供了对LCD屏操作的库函数,而从整个对LCD的操控来说,自下面上的分成了三层:HAL硬件抽象层,LCD屏的驱动层以及grlib上层图形库。

按照官方文档的介绍grlib库提供了一些上下文控制函数以及一系列简单的图表绘制函数:圆,位图,直线,矩形,字符串,按钮,图像按钮,单选框,多选框,以及位图数据转C格式数据工具。

HAL实现对MCU与LCD之间接口的配置,以及底层LCD控制器的串行通信,实现控制字符与数据字符的传输。 LCD驱动层利用HAL实现LCD的基本元素的绘制(点、直线等的绘制),为 grlib 提供调用接口。

以下为三层架构所对应的头文件,包含各自了所在层的函数原型,以及函数调用的方法

#include <ti/grlib/grlib.h>
#include "LcdDriver/Crystalfontz128x128_ST7735.h"
#include "LcdDriver/HAL_MSP_EXP432P401R_Crystalfontz128x128_ST7735.h"

LCD的初始化代码一般如下:

    /* Graphic library context */
    Graphics_Context g_sContext;  //全局上下文

    /* Initializes display */
    Crystalfontz128x128_Init();   //驱动层的LCD初始化代码

    /* Set default screen orientation */
    Crystalfontz128x128_SetOrientation(0);  //设置屏幕方向

    /* Initializes graphics context */
    Graphics_initContext(&g_sContext, &g_sCrystalfontz128x128, &g_sCrystalfontz128x128_funcs); 
    Graphics_setForegroundColor(&g_sContext, GRAPHICS_COLOR_BLUE);
    Graphics_setBackgroundColor(&g_sContext, GRAPHICS_COLOR_WHITE);
    GrContextFontSet(&g_sContext, &g_sFontFixed6x8);

可以看出初始化函数调用关系是逐层的,驱动层初始化通过调用HAL层进行硬件初始化,其中包括PortInit、SpiInit与LCD芯片初始化。 PortInit:为TI通用的端口复用配置,针对不同TI芯片电路进行端口的开启与复用,此部分代码同样为通用。

需要定制的只有HAL通信功能引脚的配置:

// Ports from MSP432 connected to LCD
#define LCD_SCK_PORT          GPIO_PORT_P1
#define LCD_SCK_PIN_FUNCTION  GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_MOSI_PORT         GPIO_PORT_P1
#define LCD_MOSI_PIN_FUNCTION GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_RST_PORT          GPIO_PORT_P5
#define LCD_CS_PORT           GPIO_PORT_P5
#define LCD_DC_PORT           GPIO_PORT_P3

// Pins from MSP432 connected to LCD
#define LCD_SCK_PIN           GPIO_PIN5
#define LCD_MOSI_PIN          GPIO_PIN6
#define LCD_RST_PIN           GPIO_PIN7
#define LCD_CS_PIN            GPIO_PIN0
#define LCD_DC_PIN            GPIO_PIN7

// Definition of USCI base address to be used for SPI communication
#define LCD_EUSCI_BASE        EUSCI_B0_BASE

grlib的初始化内容则是主要围绕一个g_sContext结构体进行, Graphics_Context 结构体定义如下:

typedef struct Graphics_Context
{
    int32_t size;                         //!< The size of this structure.
    const Graphics_Display *display;    //!< The screen onto which drawing operations are performed.
    Graphics_Rectangle clipRegion;        //!< The clipping region to be used when drawing onto the screen.
    uint32_t foreground;                 //!< The color used to draw primitives onto the screen.
    uint32_t background;                 //!< The background color used to draw primitives onto the screen.
    const Graphics_Font *font;            //!< The font used to render text onto the screen.
} Graphics_Context;

Graphics_Display *display结构体包括了特定LCD的宽高信息以及驱动函数指针。由此可以看出,LCD屏与上grlib也是分离的,当硬件更换为不同的LCD时,只需修改对应LCD驱动层函数指针,甚至可以实现LCD热更换。

但三层架构的设计架构移植性较高,牺牲了一部分屏幕控制器的硬件性能。

Tag "grlib":

MSP432 Graphics Library

MSP432提供了对LCD屏操作的库函数,而从整个对LCD的操控来说,自下面上的分成了三层:HAL硬件抽象层,LCD屏的驱动层以及grlib上层图形库。

按照官方文档的介绍grlib库提供了一些上下文控制函数以及一系列简单的图表绘制函数:圆,位图,直线,矩形,字符串,按钮,图像按钮,单选框,多选框,以及位图数据转C格式数据工具。

HAL实现对MCU与LCD之间接口的配置,以及底层LCD控制器的串行通信,实现控制字符与数据字符的传输。 LCD驱动层利用HAL实现LCD的基本元素的绘制(点、直线等的绘制),为 grlib 提供调用接口。

以下为三层架构所对应的头文件,包含各自了所在层的函数原型,以及函数调用的方法

#include <ti/grlib/grlib.h>
#include "LcdDriver/Crystalfontz128x128_ST7735.h"
#include "LcdDriver/HAL_MSP_EXP432P401R_Crystalfontz128x128_ST7735.h"

LCD的初始化代码一般如下:

    /* Graphic library context */
    Graphics_Context g_sContext;  //全局上下文

    /* Initializes display */
    Crystalfontz128x128_Init();   //驱动层的LCD初始化代码

    /* Set default screen orientation */
    Crystalfontz128x128_SetOrientation(0);  //设置屏幕方向

    /* Initializes graphics context */
    Graphics_initContext(&g_sContext, &g_sCrystalfontz128x128, &g_sCrystalfontz128x128_funcs); 
    Graphics_setForegroundColor(&g_sContext, GRAPHICS_COLOR_BLUE);
    Graphics_setBackgroundColor(&g_sContext, GRAPHICS_COLOR_WHITE);
    GrContextFontSet(&g_sContext, &g_sFontFixed6x8);

可以看出初始化函数调用关系是逐层的,驱动层初始化通过调用HAL层进行硬件初始化,其中包括PortInit、SpiInit与LCD芯片初始化。 PortInit:为TI通用的端口复用配置,针对不同TI芯片电路进行端口的开启与复用,此部分代码同样为通用。

需要定制的只有HAL通信功能引脚的配置:

// Ports from MSP432 connected to LCD
#define LCD_SCK_PORT          GPIO_PORT_P1
#define LCD_SCK_PIN_FUNCTION  GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_MOSI_PORT         GPIO_PORT_P1
#define LCD_MOSI_PIN_FUNCTION GPIO_PRIMARY_MODULE_FUNCTION
#define LCD_RST_PORT          GPIO_PORT_P5
#define LCD_CS_PORT           GPIO_PORT_P5
#define LCD_DC_PORT           GPIO_PORT_P3

// Pins from MSP432 connected to LCD
#define LCD_SCK_PIN           GPIO_PIN5
#define LCD_MOSI_PIN          GPIO_PIN6
#define LCD_RST_PIN           GPIO_PIN7
#define LCD_CS_PIN            GPIO_PIN0
#define LCD_DC_PIN            GPIO_PIN7

// Definition of USCI base address to be used for SPI communication
#define LCD_EUSCI_BASE        EUSCI_B0_BASE

grlib的初始化内容则是主要围绕一个g_sContext结构体进行, Graphics_Context 结构体定义如下:

typedef struct Graphics_Context
{
    int32_t size;                         //!< The size of this structure.
    const Graphics_Display *display;    //!< The screen onto which drawing operations are performed.
    Graphics_Rectangle clipRegion;        //!< The clipping region to be used when drawing onto the screen.
    uint32_t foreground;                 //!< The color used to draw primitives onto the screen.
    uint32_t background;                 //!< The background color used to draw primitives onto the screen.
    const Graphics_Font *font;            //!< The font used to render text onto the screen.
} Graphics_Context;

Graphics_Display *display结构体包括了特定LCD的宽高信息以及驱动函数指针。由此可以看出,LCD屏与上grlib也是分离的,当硬件更换为不同的LCD时,只需修改对应LCD驱动层函数指针,甚至可以实现LCD热更换。

但三层架构的设计架构移植性较高,牺牲了一部分屏幕控制器的硬件性能。

Tag "ECNU":

北理研究生CTF Reverse 之 mips

这次北理面向在读研究生举办CTF大赛,直接线下赛,时长12小时,其中选择填空1小时,关卡题2小时(之后加时2小时),9小时攻防,攻防赛题在先知安全有提到。

由于第一届,邀请的学校队伍属于中等偏下水平。最后,24支队伍只有9个分数为正,另有近一半左右队伍线下攻防没有拿分。

主办方声称原则上不提供外网环境。

逆向题只有一道,而且为mips架构第一次遇到。手上没有运行环境,只能静态调,花了一个多小时才搞清楚流程,之后时间不够只能做罢,后来发现当场也没有人做出。

赛后再分析一遍其实还是挺简单的。

先附上解密代码,回舍,日后有时间再补。

程序: mips

gdb-reverse-key

#include <stdint.h>
#include <stdio.h>


void dec(uint32_t *val, uint32_t *k)
{
	uint32_t delta = 0x9e3779B9;
	uint32_t sum = 0xb8ab04e8;
	uint32_t v1 = val[1], v0=val[0];
	for(int i = 0; i < 40; i++)
	{
		v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[(sum >> 11) & 3]);
		sum -= delta;
		v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
	}
	printf("0x%x~~~\n", sum);
	val[0] = v0;
	val[1] = v1;

	return ;

}
int main()
{
	uint32_t key[4]={
		0x2bc12411, 0x0deadbee, 0x0276630b, 0x014f53f5
		};
	uint32_t value[]={
		0x9a5e3731, 0x2ed28785,
		0xeb26da7d, 0x82b06241,
		0x21d9dcd4, 0x44bdda49,
		0x15f62308, 0x7b0546ee,
		0xf6b4a519, 0x71c0d531
		};
	for(int i =0; i< 10; i+=2)
	{
		dec(&value[i],key);
	}
	printf("%s\n", value);
	//printf("0x%8x, 0x%8x\n", value[0], value[1]);
	return 0;
	
}

华师大CTF逆向题分析之Draw It(Monster)

Draw It(Monster)

程序打开运行界面:

draw_it_1

查壳发现为UPX压缩壳,UPX壳代码是开源的,加壳脱壳是同一个程序。

draw_it_2

手脱ESP定律,或者往下找popad接着一个大跳可以直接到程序OEP。 手脱比较节省时间,但是有一些区段或者其它信息没法还原。

draw_it_3

脱壳之后用IDA分析来到程序消息处理函数找到关键位置:

draw_it_4

通过分析,程序取所画图片的连续相同的点的个数与cmp数据做对比, 猜测cmp数据为Flag相关数据,存储了Flag图片的一些信息,即bitmap方式连续相同的点的个数。 因为位图是24位,每个像素点用3位来存储,所以比较的时候需要乘3。

导出数据:

draw_it_5

进一步验证,将数据全部相加得到30000(50*600),确定了之前的分析。

编写Win32程序,解析数据:

int sum=0,cmp_i=0,
for(int i=0;i<50;i++)
{
	for(int j=0;j<600;j++)
	{
		sum++;
		if(sum < cmp[cmp_i])
		{
			if(  odd )
				SetPixel(hdc,j, 50-i,RGB(255,0,0));//BMP从上到下,从左到右存贮
		}
		else
		{
			sum = 0;
			odd = !odd;
			all+=cmp[cmp_i] ;
			cmp_i++;
			
		}

	}
}

可以得到结果:

draw_it_6

华师大CTF逆向题分析之巴黎解密

预赛逆向题有三道 第一道为巴黎解密ctf文件 第二道为画出FLAG 第三道为Stephen

决赛逆向题有四道,只做出了前两题。 第一题为MFC程序跑不起来 第二道为Elf64、STL对素数表加密 第三道使用 VirtualProtect 反调试。 第四道使用了一个linux程序对数据进行封装,没时间做。 前两道相对简单

巴黎解密ctf文件

有个文件加密工具,能将一个文件加密到一个.ctf文件中去。

有一个犯罪分子将存有犯罪记录的一个名为“CTFtest.ctf” 的加密文件被删除了。现经过数据恢复,我们已经恢复了该文件。

但是很不幸,该文件头部的部分数据已经被覆盖掉了。这个.ctf文件已经不能正常打开了。 而且加密该文件的口令,犯罪分子也不愿意交代,我们只知道他惯用的口令是一个8位纯数字口令。

请选手下载http://ctf.ecnu.edu.cn/question/attachment1.zip

通过其中的.ctf文件以及解密程序最大限度地恢复出文件中的内容,flag就在里面。 Flag形式为大写32位md5。

题目给出了一个解密程序以及一个加密后丢失了一部分文件头的文件

如图:

final_re_1

目测丢失了前35bytes的数据

解密程序无壳无花,直接IDA,MFC静态库编译。

结合导入表以及程序运行来看,调用了CreateFile、ReadFile、MessageBox等参数,

顺利跟踪到了程序关键地址 0x402570 分析函数,局部变量比较多,

final_re_2

应该八九不十了。 接着分析:

final_re_3

程序打开文件,判断前4 bytes 内容为 0x33465443 转换为字符CTF3

final_re_4

接着读4bytes转为DWORD型,为接下来要读取的长度并存储。 接着读文件16字节,取密码框内容, 将密码进行两次MD5加密,将结果与取到的16字节进行对比。

final_re_5

接着读4bytes转为DWORD型,做为接下来要读取的长度,再次读取,然后关闭文件。

至此,加密文件全部读取完毕,小结一下文件结构:

4 bytes 为固定字符‘CTF3’
4 bytes 为len of head
{...}   为head
16 bytes 将密码经两次MD5加密的密文
4 bytes 为len of body
{...}   为body

此时回过头来分析.ctf加密文件内容。

final_re_6

发现偏移为0x29位置4bytes的内容为0x0000619C,这一部分正好对应为文件此后的长度, 可以推定为len_of_body存储位置。向前16bytes为MD5密文区域,并且只有6bytes保留。

根据提示,密码为8位数字,通过这一部分MD5,应该可以还原。 编写程序:

#include <stdio.h>
#include <windows.h>
#include "md5.h"

unsigned char data[6]={0x48,  0xB1,  0xED,  0x05,  0x8D,  0xF7 };

int main()
{
	unsigned char  a[100] = {0},b[17] = {0},c[17] = {0};
	int num = 0, i=0;

	for( num = 10000000; num < 99999999; num++){
		_itoa(num,(char *)a, 10);
		MD5_CTX md5;

		MD5Init(&md5);                
		MD5Update(&md5,a,strlen((char *)a));  
		MD5Final(&md5,b);
		
		MD5Init(&md5);                
		MD5Update(&md5,b,16);  
		MD5Final(&md5,c);

		i=0;
		while(data[i] == c[i+10])
		{
			i++;
			if(i>=6)
				goto l;
		}
	}
l:
	printf("%d", num);
	getchar();
	getchar();
	system("pause");
	return 1;

}

程序跑出密码为20160610。 此时还剩11bytes的head内容不知道。

final_re_7

接着查找程序对head部分的引用,发现程序对head沁使用多字节字符转宽字符库函数。 进行字符串拼接之后,传入CreateFile。 由此可以断定,head部分内容为加密文件的文件名。

至此我们可以对加密文件的分析,基本结束,将文件头丢失部分恢复,Head部分随便指定一个文件名。 解密程序将文件恢复:

final_re_8

得到一个压缩包文件,查看内容为Word文件,打开得到Flag。

final_re_9

Tag "CTF":

华师大CTF逆向题分析之Draw It(Monster)

Draw It(Monster)

程序打开运行界面:

draw_it_1

查壳发现为UPX压缩壳,UPX壳代码是开源的,加壳脱壳是同一个程序。

draw_it_2

手脱ESP定律,或者往下找popad接着一个大跳可以直接到程序OEP。 手脱比较节省时间,但是有一些区段或者其它信息没法还原。

draw_it_3

脱壳之后用IDA分析来到程序消息处理函数找到关键位置:

draw_it_4

通过分析,程序取所画图片的连续相同的点的个数与cmp数据做对比, 猜测cmp数据为Flag相关数据,存储了Flag图片的一些信息,即bitmap方式连续相同的点的个数。 因为位图是24位,每个像素点用3位来存储,所以比较的时候需要乘3。

导出数据:

draw_it_5

进一步验证,将数据全部相加得到30000(50*600),确定了之前的分析。

编写Win32程序,解析数据:

int sum=0,cmp_i=0,
for(int i=0;i<50;i++)
{
	for(int j=0;j<600;j++)
	{
		sum++;
		if(sum < cmp[cmp_i])
		{
			if(  odd )
				SetPixel(hdc,j, 50-i,RGB(255,0,0));//BMP从上到下,从左到右存贮
		}
		else
		{
			sum = 0;
			odd = !odd;
			all+=cmp[cmp_i] ;
			cmp_i++;
			
		}

	}
}

可以得到结果:

draw_it_6

华师大CTF逆向题分析之巴黎解密

预赛逆向题有三道 第一道为巴黎解密ctf文件 第二道为画出FLAG 第三道为Stephen

决赛逆向题有四道,只做出了前两题。 第一题为MFC程序跑不起来 第二道为Elf64、STL对素数表加密 第三道使用 VirtualProtect 反调试。 第四道使用了一个linux程序对数据进行封装,没时间做。 前两道相对简单

巴黎解密ctf文件

有个文件加密工具,能将一个文件加密到一个.ctf文件中去。

有一个犯罪分子将存有犯罪记录的一个名为“CTFtest.ctf” 的加密文件被删除了。现经过数据恢复,我们已经恢复了该文件。

但是很不幸,该文件头部的部分数据已经被覆盖掉了。这个.ctf文件已经不能正常打开了。 而且加密该文件的口令,犯罪分子也不愿意交代,我们只知道他惯用的口令是一个8位纯数字口令。

请选手下载http://ctf.ecnu.edu.cn/question/attachment1.zip

通过其中的.ctf文件以及解密程序最大限度地恢复出文件中的内容,flag就在里面。 Flag形式为大写32位md5。

题目给出了一个解密程序以及一个加密后丢失了一部分文件头的文件

如图:

final_re_1

目测丢失了前35bytes的数据

解密程序无壳无花,直接IDA,MFC静态库编译。

结合导入表以及程序运行来看,调用了CreateFile、ReadFile、MessageBox等参数,

顺利跟踪到了程序关键地址 0x402570 分析函数,局部变量比较多,

final_re_2

应该八九不十了。 接着分析:

final_re_3

程序打开文件,判断前4 bytes 内容为 0x33465443 转换为字符CTF3

final_re_4

接着读4bytes转为DWORD型,为接下来要读取的长度并存储。 接着读文件16字节,取密码框内容, 将密码进行两次MD5加密,将结果与取到的16字节进行对比。

final_re_5

接着读4bytes转为DWORD型,做为接下来要读取的长度,再次读取,然后关闭文件。

至此,加密文件全部读取完毕,小结一下文件结构:

4 bytes 为固定字符‘CTF3’
4 bytes 为len of head
{...}   为head
16 bytes 将密码经两次MD5加密的密文
4 bytes 为len of body
{...}   为body

此时回过头来分析.ctf加密文件内容。

final_re_6

发现偏移为0x29位置4bytes的内容为0x0000619C,这一部分正好对应为文件此后的长度, 可以推定为len_of_body存储位置。向前16bytes为MD5密文区域,并且只有6bytes保留。

根据提示,密码为8位数字,通过这一部分MD5,应该可以还原。 编写程序:

#include <stdio.h>
#include <windows.h>
#include "md5.h"

unsigned char data[6]={0x48,  0xB1,  0xED,  0x05,  0x8D,  0xF7 };

int main()
{
	unsigned char  a[100] = {0},b[17] = {0},c[17] = {0};
	int num = 0, i=0;

	for( num = 10000000; num < 99999999; num++){
		_itoa(num,(char *)a, 10);
		MD5_CTX md5;

		MD5Init(&md5);                
		MD5Update(&md5,a,strlen((char *)a));  
		MD5Final(&md5,b);
		
		MD5Init(&md5);                
		MD5Update(&md5,b,16);  
		MD5Final(&md5,c);

		i=0;
		while(data[i] == c[i+10])
		{
			i++;
			if(i>=6)
				goto l;
		}
	}
l:
	printf("%d", num);
	getchar();
	getchar();
	system("pause");
	return 1;

}

程序跑出密码为20160610。 此时还剩11bytes的head内容不知道。

final_re_7

接着查找程序对head部分的引用,发现程序对head沁使用多字节字符转宽字符库函数。 进行字符串拼接之后,传入CreateFile。 由此可以断定,head部分内容为加密文件的文件名。

至此我们可以对加密文件的分析,基本结束,将文件头丢失部分恢复,Head部分随便指定一个文件名。 解密程序将文件恢复:

final_re_8

得到一个压缩包文件,查看内容为Word文件,打开得到Flag。

final_re_9

Tag "逆向":

一例MusicBox的固件简单分析,基于STM32芯片固件分析总结(待续)

从硬件到软件,制作一个高还原性,高保真的音乐盒子一直是我的兴趣之一。因此,我尝试在淘宝买一些音乐盒子做为设计参考,从双轨正负电压供电电路,电池充放电电路,stm32核心电路,到dac的解码电路,前极放大电路。到USB声卡,sdcard播放等功能。

最近发现某款音乐播放器的固件很有趣,因此,我在这简单记录一下分析过程,顺便总结一下从中学到的一些分析经验。

固件是通过SDcard更新的,商家发布新固件后,将固件放入SDcard后,芯片上的bootloader会检测并触发更新。

固件的部分内容如下:

bin-img

经过分析,固件使用了简单的压缩,一来减少固件体积,二是有校验机制。

通常,固件前一部分内容是,固件定义的栈顶指针以及芯片的中断向量表,均为4字节对齐。

华师大CTF逆向题分析之Draw It(Monster)

Draw It(Monster)

程序打开运行界面:

draw_it_1

查壳发现为UPX压缩壳,UPX壳代码是开源的,加壳脱壳是同一个程序。

draw_it_2

手脱ESP定律,或者往下找popad接着一个大跳可以直接到程序OEP。 手脱比较节省时间,但是有一些区段或者其它信息没法还原。

draw_it_3

脱壳之后用IDA分析来到程序消息处理函数找到关键位置:

draw_it_4

通过分析,程序取所画图片的连续相同的点的个数与cmp数据做对比, 猜测cmp数据为Flag相关数据,存储了Flag图片的一些信息,即bitmap方式连续相同的点的个数。 因为位图是24位,每个像素点用3位来存储,所以比较的时候需要乘3。

导出数据:

draw_it_5

进一步验证,将数据全部相加得到30000(50*600),确定了之前的分析。

编写Win32程序,解析数据:

int sum=0,cmp_i=0,
for(int i=0;i<50;i++)
{
	for(int j=0;j<600;j++)
	{
		sum++;
		if(sum < cmp[cmp_i])
		{
			if(  odd )
				SetPixel(hdc,j, 50-i,RGB(255,0,0));//BMP从上到下,从左到右存贮
		}
		else
		{
			sum = 0;
			odd = !odd;
			all+=cmp[cmp_i] ;
			cmp_i++;
			
		}

	}
}

可以得到结果:

draw_it_6

华师大CTF逆向题分析之巴黎解密

预赛逆向题有三道 第一道为巴黎解密ctf文件 第二道为画出FLAG 第三道为Stephen

决赛逆向题有四道,只做出了前两题。 第一题为MFC程序跑不起来 第二道为Elf64、STL对素数表加密 第三道使用 VirtualProtect 反调试。 第四道使用了一个linux程序对数据进行封装,没时间做。 前两道相对简单

巴黎解密ctf文件

有个文件加密工具,能将一个文件加密到一个.ctf文件中去。

有一个犯罪分子将存有犯罪记录的一个名为“CTFtest.ctf” 的加密文件被删除了。现经过数据恢复,我们已经恢复了该文件。

但是很不幸,该文件头部的部分数据已经被覆盖掉了。这个.ctf文件已经不能正常打开了。 而且加密该文件的口令,犯罪分子也不愿意交代,我们只知道他惯用的口令是一个8位纯数字口令。

请选手下载http://ctf.ecnu.edu.cn/question/attachment1.zip

通过其中的.ctf文件以及解密程序最大限度地恢复出文件中的内容,flag就在里面。 Flag形式为大写32位md5。

题目给出了一个解密程序以及一个加密后丢失了一部分文件头的文件

如图:

final_re_1

目测丢失了前35bytes的数据

解密程序无壳无花,直接IDA,MFC静态库编译。

结合导入表以及程序运行来看,调用了CreateFile、ReadFile、MessageBox等参数,

顺利跟踪到了程序关键地址 0x402570 分析函数,局部变量比较多,

final_re_2

应该八九不十了。 接着分析:

final_re_3

程序打开文件,判断前4 bytes 内容为 0x33465443 转换为字符CTF3

final_re_4

接着读4bytes转为DWORD型,为接下来要读取的长度并存储。 接着读文件16字节,取密码框内容, 将密码进行两次MD5加密,将结果与取到的16字节进行对比。

final_re_5

接着读4bytes转为DWORD型,做为接下来要读取的长度,再次读取,然后关闭文件。

至此,加密文件全部读取完毕,小结一下文件结构:

4 bytes 为固定字符‘CTF3’
4 bytes 为len of head
{...}   为head
16 bytes 将密码经两次MD5加密的密文
4 bytes 为len of body
{...}   为body

此时回过头来分析.ctf加密文件内容。

final_re_6

发现偏移为0x29位置4bytes的内容为0x0000619C,这一部分正好对应为文件此后的长度, 可以推定为len_of_body存储位置。向前16bytes为MD5密文区域,并且只有6bytes保留。

根据提示,密码为8位数字,通过这一部分MD5,应该可以还原。 编写程序:

#include <stdio.h>
#include <windows.h>
#include "md5.h"

unsigned char data[6]={0x48,  0xB1,  0xED,  0x05,  0x8D,  0xF7 };

int main()
{
	unsigned char  a[100] = {0},b[17] = {0},c[17] = {0};
	int num = 0, i=0;

	for( num = 10000000; num < 99999999; num++){
		_itoa(num,(char *)a, 10);
		MD5_CTX md5;

		MD5Init(&md5);                
		MD5Update(&md5,a,strlen((char *)a));  
		MD5Final(&md5,b);
		
		MD5Init(&md5);                
		MD5Update(&md5,b,16);  
		MD5Final(&md5,c);

		i=0;
		while(data[i] == c[i+10])
		{
			i++;
			if(i>=6)
				goto l;
		}
	}
l:
	printf("%d", num);
	getchar();
	getchar();
	system("pause");
	return 1;

}

程序跑出密码为20160610。 此时还剩11bytes的head内容不知道。

final_re_7

接着查找程序对head部分的引用,发现程序对head沁使用多字节字符转宽字符库函数。 进行字符串拼接之后,传入CreateFile。 由此可以断定,head部分内容为加密文件的文件名。

至此我们可以对加密文件的分析,基本结束,将文件头丢失部分恢复,Head部分随便指定一个文件名。 解密程序将文件恢复:

final_re_8

得到一个压缩包文件,查看内容为Word文件,打开得到Flag。

final_re_9

Tag "ArchLinux":

Linux Sound Server

ArchLinux下使用DWM有两个月了,但是声音模块一直是很大的问题。

一开始以为DELL Vsion3668的声卡驱动不同寻常,毕竟之前在Windows下的驱动就装了老费劲了。

之前CTF校赛加上嵌入式论文讨论班一阵忙活,空出时间继续搞ArchLinux,没有声音一直很难受。

查文档发现原来是pulseaudio没有启动,这是Linux下的声音Server。

Linux下的声音系统比较杂,现今多数使用ALSA;

ALSA是一个集成了声卡驱动和底层接口的东西,而pulseaudio是声音服务器,应用程序要想输出声音需要往pulseaudio里边送。

于是:

vim ~/.xinitrc
pulseaudio --start

启动声间服务器。

参考:

https://wiki.archlinux.org/index.php/Sound_system https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture

Tag "BIT":

北理研究生CTF Reverse 之 mips

这次北理面向在读研究生举办CTF大赛,直接线下赛,时长12小时,其中选择填空1小时,关卡题2小时(之后加时2小时),9小时攻防,攻防赛题在先知安全有提到。

由于第一届,邀请的学校队伍属于中等偏下水平。最后,24支队伍只有9个分数为正,另有近一半左右队伍线下攻防没有拿分。

主办方声称原则上不提供外网环境。

逆向题只有一道,而且为mips架构第一次遇到。手上没有运行环境,只能静态调,花了一个多小时才搞清楚流程,之后时间不够只能做罢,后来发现当场也没有人做出。

赛后再分析一遍其实还是挺简单的。

先附上解密代码,回舍,日后有时间再补。

程序: mips

gdb-reverse-key

#include <stdint.h>
#include <stdio.h>


void dec(uint32_t *val, uint32_t *k)
{
	uint32_t delta = 0x9e3779B9;
	uint32_t sum = 0xb8ab04e8;
	uint32_t v1 = val[1], v0=val[0];
	for(int i = 0; i < 40; i++)
	{
		v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[(sum >> 11) & 3]);
		sum -= delta;
		v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
	}
	printf("0x%x~~~\n", sum);
	val[0] = v0;
	val[1] = v1;

	return ;

}
int main()
{
	uint32_t key[4]={
		0x2bc12411, 0x0deadbee, 0x0276630b, 0x014f53f5
		};
	uint32_t value[]={
		0x9a5e3731, 0x2ed28785,
		0xeb26da7d, 0x82b06241,
		0x21d9dcd4, 0x44bdda49,
		0x15f62308, 0x7b0546ee,
		0xf6b4a519, 0x71c0d531
		};
	for(int i =0; i< 10; i+=2)
	{
		dec(&value[i],key);
	}
	printf("%s\n", value);
	//printf("0x%8x, 0x%8x\n", value[0], value[1]);
	return 0;
	
}

Tag "Reverse":

北理研究生CTF Reverse 之 mips

这次北理面向在读研究生举办CTF大赛,直接线下赛,时长12小时,其中选择填空1小时,关卡题2小时(之后加时2小时),9小时攻防,攻防赛题在先知安全有提到。

由于第一届,邀请的学校队伍属于中等偏下水平。最后,24支队伍只有9个分数为正,另有近一半左右队伍线下攻防没有拿分。

主办方声称原则上不提供外网环境。

逆向题只有一道,而且为mips架构第一次遇到。手上没有运行环境,只能静态调,花了一个多小时才搞清楚流程,之后时间不够只能做罢,后来发现当场也没有人做出。

赛后再分析一遍其实还是挺简单的。

先附上解密代码,回舍,日后有时间再补。

程序: mips

gdb-reverse-key

#include <stdint.h>
#include <stdio.h>


void dec(uint32_t *val, uint32_t *k)
{
	uint32_t delta = 0x9e3779B9;
	uint32_t sum = 0xb8ab04e8;
	uint32_t v1 = val[1], v0=val[0];
	for(int i = 0; i < 40; i++)
	{
		v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[(sum >> 11) & 3]);
		sum -= delta;
		v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
	}
	printf("0x%x~~~\n", sum);
	val[0] = v0;
	val[1] = v1;

	return ;

}
int main()
{
	uint32_t key[4]={
		0x2bc12411, 0x0deadbee, 0x0276630b, 0x014f53f5
		};
	uint32_t value[]={
		0x9a5e3731, 0x2ed28785,
		0xeb26da7d, 0x82b06241,
		0x21d9dcd4, 0x44bdda49,
		0x15f62308, 0x7b0546ee,
		0xf6b4a519, 0x71c0d531
		};
	for(int i =0; i< 10; i+=2)
	{
		dec(&value[i],key);
	}
	printf("%s\n", value);
	//printf("0x%8x, 0x%8x\n", value[0], value[1]);
	return 0;
	
}

Tag "Linux":

群晖利用公网服务器ip中转流量与内网无缝切换

最近想起nas的公网访问一直是个问题。中转网络一直不通畅,如果走公网转nas又会过度暴露而被自动扫描攻击,导致硬盘频繁唤醒。

这里实现一套方案,利用公网服务器的ip进行流量转发,并且添加一道简单的防火墙来过滤网络扫描。可以在回家以后自行将流量切换到内网。

在使用公网ip转发的时候,流量和带宽受公网服务器上限所限制。在家中互联场景,本地路由器可以通过拦截公网ip流量,自动转发到nas。免去内外网ip来回切换的问题。

graph TD User1(["User1/Phone/PC"]) -->|Access from local NetWork| B{Router} NAS["NAS lisening:5000(http)/5001(https)"] <-->|In local NetWork| B{Router} Internet{Internet} <--> PubServer[PubServer onPort:80/443/5001] Internet <--> B{Router} User2(["User2/DS File/Photo"]) --> |Access to PubServer:5001| PubServer

主要有以下几个部分实现:

在nas上,将本地端口5000映射到公网ip上,通过 ssh -R 转发。

在计划任务中添加一个bash脚本,建立公网服务器的ssh连接用于端口转发,并设置为开机启动。内容如下:

#!/bin/bash

while true; do
sleep 1
echo "Start Port Forward 5000 @ " `date`
ssh -R 5000:127.0.0.1:5000 yourAccount@YourServer.com -C -q -N -o ServerAliveInterval=60 -o ServerAliveCountMax=10
echo "End of Port Forward 5000 @ " `date`
done;

该脚本启动后会将公网服务器所有来自5000端口的流量转发到nas本身。

5000端口为nas的http服务的连接端口,5001端口为nas的https服务的连接端口。

接下来在公网服务器上配置nginx来实现http流量转发并且配置https端口为5001,通过白名单机制将流量转发到nas。

server {
    server_name yourServerName;
    location / {

#       set $pass_url http://127.0.0.1:8000; # for enter password.
#       if ( $http_user_agent ~ 'Synology-' ) { 
#          // we can also use UA to imp more filters.
           set $pass_url http://127.0.0.1:5000;
#       }
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        include <your_list_path>/nas_allow_list.conf;
        deny all;
    }

    location /log {  // 
        set $pass_url http://127.0.0.1:8000; # for enter password
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    listen 443 ssl; # managed by Certbot
    listen 5001 ssl; # managed by Certbot
    <the ssh certs config >
}

在上述conf中/log访问点的流量反代到白名单配置程序,可以用于动态更新 nas_allow_list.conf白名单。

一个简单的基于白名单配置程序:

from werkzeug.wrappers import Request, Response
import subprocess

@Request.application
def application(request):
    auth_html = '''<body style="margin: 0;"><div style="margin: auto ; width: 100%; height:100%; border: 2px solid green; padding: 50px 0; text-align: center; "><form  method="POST">
            <input type="password" name="psw" style="line-height: 25px;" value="" required placehold="Enter Text..." />
            <input type="submit" style="width: 90px;height: 30px;" value="Submit" />
        </form></div>'''
    if request.method != "POST":
        return Response(auth_html, content_type="text/html")

    data = request.get_data(cache=False,parse_form_data=True)

    input = request.form.get("psw", None)
    if input != "<Your Pass Word>":
        return Response(auth_html[:-6] + "<red>N/a</red></div>", content_type="text/html")

    iplist = ",".join(request.access_route)
    if request.remote_addr == "127.0.0.1": // the traffic is came from nginx.
        record_addr = request.access_route
    else:
        record_addr = [request.remote_addr]
    for ipaddr in record_addr:
        ipaddr = ''.join(i for i in ipaddr if i in '0123456789.')
        # also we can use firewall to filter te trific
        #cmd = ["firewall-cmd","--zone=sszone","--add-source="+ipaddr+"/32"]
        cmd = ["bash","-c", "echo 'allow "+ipaddr+";'>> <your_list_path>/nas_allow_list.conf"]
        subprocess.check_call(cmd)
        cmd = ["nginx", "-s", "reload"]
        subprocess.check_call(cmd)

    return Response("<h1>You are grand to access, IP<" + iplist + "> has record.<h1>")

if __name__ == "__main__":
    from werkzeug.serving import run_simple
    run_simple("0.0.0.0", 8000, application, threaded=True)

在路由器配置iptables , 将内网client到公网服务器的流量直接转发到local nas:

iptables -t nat -A PREROUTING -d <yourPubServerIP> -p tcp --dport 5001 -j DNAT --to-destination <yourLocalNasIP>:5001

记一次黑群晖系统升级失败之后的数据恢复

最近折腾了一下群晖系统的硬盘休眠, 由于不小心动到了硬盘的RAID设置, 导致系统认定系统盘和数据盘中的系统出现了diverge. 重启之后, 提示需要重装安装系统, 重装失败后系统丢失.

群晖系统要求的重装安装时,操作界面给出了两个选项: 迁移和重新安装.

群晖崩溃出现的安装界面

虽然都提示数据不会改动, 因此没有太在意细节 . 而不小心点到了重新安装, 并且选到了自动更新,(没有手动从官网下载安装包), 没想到安装包没自动下载成功, 直接就安装失败了. 当时也没管,直接强制断电关机睡觉了(这也许是最好的保护软件损毁数据的方法), (原本只需抹去并从启动盘中重新sync一份系统到数据盘, 现在事情弄复杂了.)

第二天起来,发现惊奇的是, 群晖已经将所有系统整个/dev/dm0格式化了.. 格式化这种敏感的操作, 居然不是放在最后等必要条件准备就绪才做. 这波操作让人着迷, 恐怕只有印度小伙能干出来.

Linux数据救援不同于win平台使用PE, 搜寻了一蕃LiveCD的解决方案, systemrescue(https://www.system-rescue.org/) 看起来可以不错,后续使用过程中也都满足了需求,.

基本的disk io操作工具都有,包括testdisk, photorec, parted, mdadm, cifs.

注意: Ubuntu的server版liveCD似乎由于内核没有编译RAID模块, 无法操作raid分区, 已踩坑,不建议用作数据救援.

Linux下的日志自动打包分割工具

在VPS上经常需要跑一些程序或脚本,自然会产生出很多日志。 但要是单单为一个几十行代码的程序去加一个日志管理的功能也显得臃肿。

造轮子是不可能造轮子的。

于是,又查了一遍system log相关的内容,有rsyslogd等等, 但不方便使用,而且是系统级别的。 后来发现像nginx,httpd,等等都是有通过一个名为logrotate的工具,自动对日志文件进行整理。

man logrotate

写得有些不知所云,英语是个二把刀。 花了几些时间整理一下用法。 程序功能比较简单,配置文件(/etc/logrotate.d/*)的参数有两大方面:

  • 一是控制日志整理周期,保存方式等等。
  • 二是对原程序的输出做接管,处理(通过kill发送信号量)。

日志输出程序只需输出日志到指定位置既可,其它所有对日志的整理操作由logrotate来完成。


未完,待续。

Use DWM in Gnome Desktop Environment without Gnome-shell

自从换上轻量级的桌面管理器DWM之后,屏幕利用率得到了提升。但是,由于在dwm仅仅是一个桌面管理器,并不具备其它一些实用功能,比如Ubuntu的NightMode,控制中心等,只有在Gnome环境下才能使用。

之前使用 CustomXSession,调用/etc/X11/Xsession,接着调用~/.xsesseion脚本启动dwm,比如ibus,gtk,相关的配置均在用户目录下的.xsession脚本中完成。

而现在通过gnome-session --session=dwm-gnome方式调用dwm-gnome脚本,由dwm-gnome调用dwm启动,此外,在 /usr/share/gnome-session/sessions/下建立同名session文件,模仿gnome.session,填写RequiredComponents,并且去除org.gnome.Shell,这些组件的启动将会由Gnome-Session进行统一启动管理。

自动安装方案在ArchLinux下有相应关的包可供下载:

pacman -S dwm-gnome

Ubuntu 可以通过Makefile进行安装:

dwm-gnome: https://github.com/palopezv/dwm-gnome

Ubuntu 17.04 apt 无法更新,repository '...' does not have a Release file

这阵子打算换Arch的时候,想在Ubuntu最后折腾一番,没想到apt update的时候出现了其怪的事情。

lanbing@LanBing-Ubuntu:~$ sudo apt update
Hit:1 http://ppa.launchpad.net/webupd8team/sublime-text-3/ubuntu zesty InRelease
Ign:2 http://cn.archive.ubuntu.com/ubuntu zesty InRelease
Ign:3 http://cn.archive.ubuntu.com/ubuntu zesty-security InRelease
Ign:4 http://cn.archive.ubuntu.com/ubuntu zesty-updates InRelease
Err:5 http://cn.archive.ubuntu.com/ubuntu zesty Release
  404  Not Found [IP: 91.189.91.23 80]
Err:6 http://cn.archive.ubuntu.com/ubuntu zesty-security Release
  404  Not Found [IP: 91.189.91.23 80]
Err:7 http://cn.archive.ubuntu.com/ubuntu zesty-updates Release
  404  Not Found [IP: 91.189.91.23 80]
Reading package lists... Done
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-security Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-updates Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

尝试了国内的几个主流源:

https://mirrors.tuna.tsinghua.edu.cn/ubuntu/
http://mirrors.aliyun.com/ubuntu/
http://ftp.sjtu.edu.cn/ubuntu/

均出现了类似的错误,后改为官方的源,同样出现此错误,还莫名其妙多出几百个Ign。 仔细到源目录下分析 发现确实不存在http://cn.archive.ubuntu.com/ubuntu/dists/zesty/Release

原来官方把17.04 zesty这个版本的源移到了old-release。 然而国内大部分源也是同步了官方的源,导致了找不到相关源的信息。

遂将source.list源修改成官方的

http://old-releases.ubuntu.com/ubuntu

于是apt update可以顺利更新了。

但问题又来了,由于官方的源在国外,更新速度太慢,眼看着50M的带宽不满足于此。

最后,发现中科大的镜像源提供了old-release,于是:

sudo vi /etc/apt/source.list

将源地址换为:
http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu



lanbing@LanBing-Ubuntu:~$ cat /etc/apt/sources.list
###### Ubuntu Main Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty main universe 

###### Ubuntu Update Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty-updates main universe 


参考:

![http://www.cnblogs.com/jiangz/p/4076811.html]http://www.cnblogs.com/jiangz/p/4076811.html

Tag "Ubuntu":

Ubuntu下如何切换Intel和Nvidia显卡

原文:How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

翻译水平有限,还望批评指正,都㚏2020s了,有关解决方案大家还是自行Google吧。

在笔记本上如何查看核显和N卡是折腾显卡的第一步。这篇文章展示在Ubuntu理如何和谐的切换Intel核显和N卡。

你应该使用哪块显卡?

对于游戏和3D绘图等要求大量图形计算来说,应该切换至N卡。

如果你对游戏和3D绘图不感觉兴趣,那么,Intlel核显将满足你的日常使用,并且比起N卡更省电。

#1 查看电脑上哪些显卡

在Ubuntu下可以非常简单的做这个事:

lspci -k | grep -E -A2 -i 'VGA|3D'

https://www.linuxbabe.com/wp-content/uploads/2016/04/Selection_010-1.png

#2 查看正在使用哪块显卡

Ubuntu 默认会使用Intel核显。

如果你以前对显卡驱动做过改动,又不记得了,那么可以在图形界面下,系统设置 > 细节system settings > details)中查看。

#3 安装Nvidia显卡驱动

Ubuntu本身集成了N卡开源驱动nouveau在Linux内核里,但此驱动缺少3D加速的支持. 要发挥显卡性能,我们可以用software-properties-gtk程序去安装合适的驱动。

Software & Updates_ additional drivers

你可以选择最新的版本,应用更改。

也可以通过下列命令,查看推荐的驱动版本:

 sudo ubuntu-drivers devices

How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

下列命令将会自动安装Nvidia驱动。

sudo ubuntu-drivers autoinstall

在合适的驱动安装成功后,重新打开系统设置 > 细节system settings > details),你将会看到新安装的驱动已经选择上了,如果没有的话,请自行选择,并应用修改。

https://www.linuxbabe.com/wp-content/uploads/2016/04/Software-Updates_013.png

现在我们已经安装好了合适的N卡驱动了,但是,我们仍然在使用Intel核显。

#4 切换到N卡

在你选择好了N卡驱动后,可能需要重启你的电脑,以启用PRIME支持。如果PRIME没有启动,可能会出现下面的信息:

Message: PRIME: is it supported? no

重启之后,可以从应用列表中打开Nvidia X Server Settings,或者从命令行打开:

#: nvidia-settings

NVIDIA X Server Settings_ prime profiles

在PRIME Profiles` 选项卡中,选择你想切换的显卡, 重启电脑。

你就可以在系统设置 > 细节system settings > details)中看到N卡了。

想要切换回Intel核显,只需要在上图中点击Intel即可。

也可以通过命令行的方式,切换到核显:

sudo prime-select intel

或N卡:

sudo prime-select nvidia

查看哪块显卡正在使用:

prime-select query

如何和卸载N卡驱动

有时个你Nvidia安装失败,或者没有成功,黑屏了,没有办法进入图形界面,或者出现以下错误:

driver ebridge is already registered aborting

这种情况你需要完全的卸载N卡驱动,通过运行下列命令,完全移除nvidia相关包:

sudo apt purge nvidia-*

Use DWM in Gnome Desktop Environment without Gnome-shell

自从换上轻量级的桌面管理器DWM之后,屏幕利用率得到了提升。但是,由于在dwm仅仅是一个桌面管理器,并不具备其它一些实用功能,比如Ubuntu的NightMode,控制中心等,只有在Gnome环境下才能使用。

之前使用 CustomXSession,调用/etc/X11/Xsession,接着调用~/.xsesseion脚本启动dwm,比如ibus,gtk,相关的配置均在用户目录下的.xsession脚本中完成。

而现在通过gnome-session --session=dwm-gnome方式调用dwm-gnome脚本,由dwm-gnome调用dwm启动,此外,在 /usr/share/gnome-session/sessions/下建立同名session文件,模仿gnome.session,填写RequiredComponents,并且去除org.gnome.Shell,这些组件的启动将会由Gnome-Session进行统一启动管理。

自动安装方案在ArchLinux下有相应关的包可供下载:

pacman -S dwm-gnome

Ubuntu 可以通过Makefile进行安装:

dwm-gnome: https://github.com/palopezv/dwm-gnome

Ubuntu 17.04 apt 无法更新,repository '...' does not have a Release file

这阵子打算换Arch的时候,想在Ubuntu最后折腾一番,没想到apt update的时候出现了其怪的事情。

lanbing@LanBing-Ubuntu:~$ sudo apt update
Hit:1 http://ppa.launchpad.net/webupd8team/sublime-text-3/ubuntu zesty InRelease
Ign:2 http://cn.archive.ubuntu.com/ubuntu zesty InRelease
Ign:3 http://cn.archive.ubuntu.com/ubuntu zesty-security InRelease
Ign:4 http://cn.archive.ubuntu.com/ubuntu zesty-updates InRelease
Err:5 http://cn.archive.ubuntu.com/ubuntu zesty Release
  404  Not Found [IP: 91.189.91.23 80]
Err:6 http://cn.archive.ubuntu.com/ubuntu zesty-security Release
  404  Not Found [IP: 91.189.91.23 80]
Err:7 http://cn.archive.ubuntu.com/ubuntu zesty-updates Release
  404  Not Found [IP: 91.189.91.23 80]
Reading package lists... Done
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-security Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-updates Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

尝试了国内的几个主流源:

https://mirrors.tuna.tsinghua.edu.cn/ubuntu/
http://mirrors.aliyun.com/ubuntu/
http://ftp.sjtu.edu.cn/ubuntu/

均出现了类似的错误,后改为官方的源,同样出现此错误,还莫名其妙多出几百个Ign。 仔细到源目录下分析 发现确实不存在http://cn.archive.ubuntu.com/ubuntu/dists/zesty/Release

原来官方把17.04 zesty这个版本的源移到了old-release。 然而国内大部分源也是同步了官方的源,导致了找不到相关源的信息。

遂将source.list源修改成官方的

http://old-releases.ubuntu.com/ubuntu

于是apt update可以顺利更新了。

但问题又来了,由于官方的源在国外,更新速度太慢,眼看着50M的带宽不满足于此。

最后,发现中科大的镜像源提供了old-release,于是:

sudo vi /etc/apt/source.list

将源地址换为:
http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu



lanbing@LanBing-Ubuntu:~$ cat /etc/apt/sources.list
###### Ubuntu Main Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty main universe 

###### Ubuntu Update Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty-updates main universe 


参考:

![http://www.cnblogs.com/jiangz/p/4076811.html]http://www.cnblogs.com/jiangz/p/4076811.html

Tag "zesty":

Ubuntu 17.04 apt 无法更新,repository '...' does not have a Release file

这阵子打算换Arch的时候,想在Ubuntu最后折腾一番,没想到apt update的时候出现了其怪的事情。

lanbing@LanBing-Ubuntu:~$ sudo apt update
Hit:1 http://ppa.launchpad.net/webupd8team/sublime-text-3/ubuntu zesty InRelease
Ign:2 http://cn.archive.ubuntu.com/ubuntu zesty InRelease
Ign:3 http://cn.archive.ubuntu.com/ubuntu zesty-security InRelease
Ign:4 http://cn.archive.ubuntu.com/ubuntu zesty-updates InRelease
Err:5 http://cn.archive.ubuntu.com/ubuntu zesty Release
  404  Not Found [IP: 91.189.91.23 80]
Err:6 http://cn.archive.ubuntu.com/ubuntu zesty-security Release
  404  Not Found [IP: 91.189.91.23 80]
Err:7 http://cn.archive.ubuntu.com/ubuntu zesty-updates Release
  404  Not Found [IP: 91.189.91.23 80]
Reading package lists... Done
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-security Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-updates Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

尝试了国内的几个主流源:

https://mirrors.tuna.tsinghua.edu.cn/ubuntu/
http://mirrors.aliyun.com/ubuntu/
http://ftp.sjtu.edu.cn/ubuntu/

均出现了类似的错误,后改为官方的源,同样出现此错误,还莫名其妙多出几百个Ign。 仔细到源目录下分析 发现确实不存在http://cn.archive.ubuntu.com/ubuntu/dists/zesty/Release

原来官方把17.04 zesty这个版本的源移到了old-release。 然而国内大部分源也是同步了官方的源,导致了找不到相关源的信息。

遂将source.list源修改成官方的

http://old-releases.ubuntu.com/ubuntu

于是apt update可以顺利更新了。

但问题又来了,由于官方的源在国外,更新速度太慢,眼看着50M的带宽不满足于此。

最后,发现中科大的镜像源提供了old-release,于是:

sudo vi /etc/apt/source.list

将源地址换为:
http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu



lanbing@LanBing-Ubuntu:~$ cat /etc/apt/sources.list
###### Ubuntu Main Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty main universe 

###### Ubuntu Update Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty-updates main universe 


参考:

![http://www.cnblogs.com/jiangz/p/4076811.html]http://www.cnblogs.com/jiangz/p/4076811.html

Tag "apt":

Ubuntu 17.04 apt 无法更新,repository '...' does not have a Release file

这阵子打算换Arch的时候,想在Ubuntu最后折腾一番,没想到apt update的时候出现了其怪的事情。

lanbing@LanBing-Ubuntu:~$ sudo apt update
Hit:1 http://ppa.launchpad.net/webupd8team/sublime-text-3/ubuntu zesty InRelease
Ign:2 http://cn.archive.ubuntu.com/ubuntu zesty InRelease
Ign:3 http://cn.archive.ubuntu.com/ubuntu zesty-security InRelease
Ign:4 http://cn.archive.ubuntu.com/ubuntu zesty-updates InRelease
Err:5 http://cn.archive.ubuntu.com/ubuntu zesty Release
  404  Not Found [IP: 91.189.91.23 80]
Err:6 http://cn.archive.ubuntu.com/ubuntu zesty-security Release
  404  Not Found [IP: 91.189.91.23 80]
Err:7 http://cn.archive.ubuntu.com/ubuntu zesty-updates Release
  404  Not Found [IP: 91.189.91.23 80]
Reading package lists... Done
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-security Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-updates Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

尝试了国内的几个主流源:

https://mirrors.tuna.tsinghua.edu.cn/ubuntu/
http://mirrors.aliyun.com/ubuntu/
http://ftp.sjtu.edu.cn/ubuntu/

均出现了类似的错误,后改为官方的源,同样出现此错误,还莫名其妙多出几百个Ign。 仔细到源目录下分析 发现确实不存在http://cn.archive.ubuntu.com/ubuntu/dists/zesty/Release

原来官方把17.04 zesty这个版本的源移到了old-release。 然而国内大部分源也是同步了官方的源,导致了找不到相关源的信息。

遂将source.list源修改成官方的

http://old-releases.ubuntu.com/ubuntu

于是apt update可以顺利更新了。

但问题又来了,由于官方的源在国外,更新速度太慢,眼看着50M的带宽不满足于此。

最后,发现中科大的镜像源提供了old-release,于是:

sudo vi /etc/apt/source.list

将源地址换为:
http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu



lanbing@LanBing-Ubuntu:~$ cat /etc/apt/sources.list
###### Ubuntu Main Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty main universe 

###### Ubuntu Update Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty-updates main universe 


参考:

![http://www.cnblogs.com/jiangz/p/4076811.html]http://www.cnblogs.com/jiangz/p/4076811.html

Tag "release":

Ubuntu 17.04 apt 无法更新,repository '...' does not have a Release file

这阵子打算换Arch的时候,想在Ubuntu最后折腾一番,没想到apt update的时候出现了其怪的事情。

lanbing@LanBing-Ubuntu:~$ sudo apt update
Hit:1 http://ppa.launchpad.net/webupd8team/sublime-text-3/ubuntu zesty InRelease
Ign:2 http://cn.archive.ubuntu.com/ubuntu zesty InRelease
Ign:3 http://cn.archive.ubuntu.com/ubuntu zesty-security InRelease
Ign:4 http://cn.archive.ubuntu.com/ubuntu zesty-updates InRelease
Err:5 http://cn.archive.ubuntu.com/ubuntu zesty Release
  404  Not Found [IP: 91.189.91.23 80]
Err:6 http://cn.archive.ubuntu.com/ubuntu zesty-security Release
  404  Not Found [IP: 91.189.91.23 80]
Err:7 http://cn.archive.ubuntu.com/ubuntu zesty-updates Release
  404  Not Found [IP: 91.189.91.23 80]
Reading package lists... Done
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-security Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://cn.archive.ubuntu.com/ubuntu zesty-updates Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

尝试了国内的几个主流源:

https://mirrors.tuna.tsinghua.edu.cn/ubuntu/
http://mirrors.aliyun.com/ubuntu/
http://ftp.sjtu.edu.cn/ubuntu/

均出现了类似的错误,后改为官方的源,同样出现此错误,还莫名其妙多出几百个Ign。 仔细到源目录下分析 发现确实不存在http://cn.archive.ubuntu.com/ubuntu/dists/zesty/Release

原来官方把17.04 zesty这个版本的源移到了old-release。 然而国内大部分源也是同步了官方的源,导致了找不到相关源的信息。

遂将source.list源修改成官方的

http://old-releases.ubuntu.com/ubuntu

于是apt update可以顺利更新了。

但问题又来了,由于官方的源在国外,更新速度太慢,眼看着50M的带宽不满足于此。

最后,发现中科大的镜像源提供了old-release,于是:

sudo vi /etc/apt/source.list

将源地址换为:
http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu



lanbing@LanBing-Ubuntu:~$ cat /etc/apt/sources.list
###### Ubuntu Main Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty main universe 

###### Ubuntu Update Repos
deb http://mirrors.ustc.edu.cn/ubuntu-old-releases/ubuntu/ zesty-updates main universe 


参考:

![http://www.cnblogs.com/jiangz/p/4076811.html]http://www.cnblogs.com/jiangz/p/4076811.html

Tag "Ubuntu,Gnome":

Change Gnome Shell theme after ubuntu upgraded to 1710

由于Ubuntu非LTS版,官方维护周期为9个月,遂更新了Ubuntu从17.04到17.10。

然而更新之后Gnome的桌面管理器(GDM),主题被修改成了类Ubuntu风格橘红色。

这种奇葩的风格,也许只有Ubuntu的创始者们才喜欢吧。

最初想法是寻找到gnome-look上找到原版gdm主题,果然发现了很多好看的主题,类XP,类WIN789,类osx。但花虽美,却不是我想要的。

随着google一通之后,发现解决方案也简单,

sudo update-alternatives --config gdm3.css
There are 2 choices for the alternative gdm3.css (providing /usr/share/gnome-shell/theme/gdm3.css).

  Selection    Path                                          Priority   Status
------------------------------------------------------------
* 0            /usr/share/gnome-shell/theme/ubuntu.css        10        auto mode
  1            /usr/share/gnome-shell/theme/gnome-shell.css   5         manual mode
  2            /usr/share/gnome-shell/theme/ubuntu.css        10        manual mode

Press <enter> to keep the current choice[*], or type selection number:

GDM在/etc/alternatives/目录下有设置了一些可选项,其中就包括了控制gnome-shell主题的配置选项,而更新的Ubuntu只是新增了该选项,并增加了优先级。

如此,可以比较方便的通过update-alternatives命令来修改gdm主题了。

参考

Ubuntu GNOME Shell in Artful: Day 11

Tag "GDM":

Change Gnome Shell theme after ubuntu upgraded to 1710

由于Ubuntu非LTS版,官方维护周期为9个月,遂更新了Ubuntu从17.04到17.10。

然而更新之后Gnome的桌面管理器(GDM),主题被修改成了类Ubuntu风格橘红色。

这种奇葩的风格,也许只有Ubuntu的创始者们才喜欢吧。

最初想法是寻找到gnome-look上找到原版gdm主题,果然发现了很多好看的主题,类XP,类WIN789,类osx。但花虽美,却不是我想要的。

随着google一通之后,发现解决方案也简单,

sudo update-alternatives --config gdm3.css
There are 2 choices for the alternative gdm3.css (providing /usr/share/gnome-shell/theme/gdm3.css).

  Selection    Path                                          Priority   Status
------------------------------------------------------------
* 0            /usr/share/gnome-shell/theme/ubuntu.css        10        auto mode
  1            /usr/share/gnome-shell/theme/gnome-shell.css   5         manual mode
  2            /usr/share/gnome-shell/theme/ubuntu.css        10        manual mode

Press <enter> to keep the current choice[*], or type selection number:

GDM在/etc/alternatives/目录下有设置了一些可选项,其中就包括了控制gnome-shell主题的配置选项,而更新的Ubuntu只是新增了该选项,并增加了优先级。

如此,可以比较方便的通过update-alternatives命令来修改gdm主题了。

参考

Ubuntu GNOME Shell in Artful: Day 11

Tag "Theme":

Change Gnome Shell theme after ubuntu upgraded to 1710

由于Ubuntu非LTS版,官方维护周期为9个月,遂更新了Ubuntu从17.04到17.10。

然而更新之后Gnome的桌面管理器(GDM),主题被修改成了类Ubuntu风格橘红色。

这种奇葩的风格,也许只有Ubuntu的创始者们才喜欢吧。

最初想法是寻找到gnome-look上找到原版gdm主题,果然发现了很多好看的主题,类XP,类WIN789,类osx。但花虽美,却不是我想要的。

随着google一通之后,发现解决方案也简单,

sudo update-alternatives --config gdm3.css
There are 2 choices for the alternative gdm3.css (providing /usr/share/gnome-shell/theme/gdm3.css).

  Selection    Path                                          Priority   Status
------------------------------------------------------------
* 0            /usr/share/gnome-shell/theme/ubuntu.css        10        auto mode
  1            /usr/share/gnome-shell/theme/gnome-shell.css   5         manual mode
  2            /usr/share/gnome-shell/theme/ubuntu.css        10        manual mode

Press <enter> to keep the current choice[*], or type selection number:

GDM在/etc/alternatives/目录下有设置了一些可选项,其中就包括了控制gnome-shell主题的配置选项,而更新的Ubuntu只是新增了该选项,并增加了优先级。

如此,可以比较方便的通过update-alternatives命令来修改gdm主题了。

参考

Ubuntu GNOME Shell in Artful: Day 11

Tag "Gnome,DWM":

Use DWM in Gnome Desktop Environment without Gnome-shell

自从换上轻量级的桌面管理器DWM之后,屏幕利用率得到了提升。但是,由于在dwm仅仅是一个桌面管理器,并不具备其它一些实用功能,比如Ubuntu的NightMode,控制中心等,只有在Gnome环境下才能使用。

之前使用 CustomXSession,调用/etc/X11/Xsession,接着调用~/.xsesseion脚本启动dwm,比如ibus,gtk,相关的配置均在用户目录下的.xsession脚本中完成。

而现在通过gnome-session --session=dwm-gnome方式调用dwm-gnome脚本,由dwm-gnome调用dwm启动,此外,在 /usr/share/gnome-session/sessions/下建立同名session文件,模仿gnome.session,填写RequiredComponents,并且去除org.gnome.Shell,这些组件的启动将会由Gnome-Session进行统一启动管理。

自动安装方案在ArchLinux下有相应关的包可供下载:

pacman -S dwm-gnome

Ubuntu 可以通过Makefile进行安装:

dwm-gnome: https://github.com/palopezv/dwm-gnome

Tag "jekyll,git pages":

利用git WebHooks自动部署Pages(Coding Pages)

github pages服务由于安全性的考虑,对其原生jekyll的支持插件进行了过滤。使得只能使用其有限的插件,而且无法使用自定义的插件。这导致了很多问题,比如不能按自己的规则生成归档文件或者分类目录,甚至部署爬虫之类等等。

具体详见: https://pages.github.com/versions/

而国内几大git服务商(Coding,码市之类),也对支持的插件进行了限制,所以在多数情况下,还是选择在本地搭建Jekyll环境,生成静态页面直接上传。

但这极大限制了Jekyll的Markdown in Anywhere便利性,需要在不同的系统上都装上Jekyll的开发环境。

## 现在讨论一种利用中间生产服务器代替本地发布过程的方法。

依赖:一台部署gh-hooks-server的VPS

既然选择不使用git的原生jekyll,也那么需要两个branch, 一个用于jekyll源码的存放, 一个用于托管静态代码

通过一台中间服务器,当源branch进行了更新,则通过webhook自动通知gh-hooks-server,使其执行pull、push操作。

VPS的jekyll环境的搭建不再赘述【首先安装rvm,ruby, 再装jekyll以及插件比如jekyll-paginate】

下面演示安装gh-hooks-server并启动

git clone https://github.com/c834606877/gh-hooks-server.git
cd gh-hooks-server
python setup.py install

ghhooks -a updatemypre:/home/lanbing/updatemypre.sh --secret s3cret

 

程序启动后会侦听8011端口,处理http://0.0.0.0:8011/ghhooks/updatemypre的请求信息,当请求密码通过后,执行对应的bash脚本。

故,我们只需要对源Branch的push消息发送webhook,当gh-hooks-server接收收post消息后,pull 源 Branch,jekyll编译,然后push到Pages Branch。

为了兼容手动发布,编写了一个makefile,用于本地自动发布的脚本:

temp-folder = /tmp/jekyll-temp-site/
repo = git@git.coding.net:iziy/iziy.git

JEKYLL = jekyll

s:
        ${JEKYLL} server
build:
        ${JEKYLL} build -d ${temp-folder}

deploy: build
        cd ${temp-folder} ;\
        git init ${temp-folder} ;\
        git checkout -b coding-pages ;\
        git remote add origin ${repo} ;\
        git add -A ${temp-folder} ;\
        git commit -m "deployed by make" ;\
        git push origin coding-pages --force

push:
        git add -A
        git commit -m "pushed by make"
        git push


clean:
        rm -rf ${temp-folder}

而对于webhook响应的脚本为updatemypre.sh:

#!/usr/bin/bash

echo "webhook enter!"

source /usr/local/rvm/scripts/rvm

cd iziy
git pull
make deploy

Tag "Coding Pages":

利用git WebHooks自动部署Pages(Coding Pages)

github pages服务由于安全性的考虑,对其原生jekyll的支持插件进行了过滤。使得只能使用其有限的插件,而且无法使用自定义的插件。这导致了很多问题,比如不能按自己的规则生成归档文件或者分类目录,甚至部署爬虫之类等等。

具体详见: https://pages.github.com/versions/

而国内几大git服务商(Coding,码市之类),也对支持的插件进行了限制,所以在多数情况下,还是选择在本地搭建Jekyll环境,生成静态页面直接上传。

但这极大限制了Jekyll的Markdown in Anywhere便利性,需要在不同的系统上都装上Jekyll的开发环境。

## 现在讨论一种利用中间生产服务器代替本地发布过程的方法。

依赖:一台部署gh-hooks-server的VPS

既然选择不使用git的原生jekyll,也那么需要两个branch, 一个用于jekyll源码的存放, 一个用于托管静态代码

通过一台中间服务器,当源branch进行了更新,则通过webhook自动通知gh-hooks-server,使其执行pull、push操作。

VPS的jekyll环境的搭建不再赘述【首先安装rvm,ruby, 再装jekyll以及插件比如jekyll-paginate】

下面演示安装gh-hooks-server并启动

git clone https://github.com/c834606877/gh-hooks-server.git
cd gh-hooks-server
python setup.py install

ghhooks -a updatemypre:/home/lanbing/updatemypre.sh --secret s3cret

 

程序启动后会侦听8011端口,处理http://0.0.0.0:8011/ghhooks/updatemypre的请求信息,当请求密码通过后,执行对应的bash脚本。

故,我们只需要对源Branch的push消息发送webhook,当gh-hooks-server接收收post消息后,pull 源 Branch,jekyll编译,然后push到Pages Branch。

为了兼容手动发布,编写了一个makefile,用于本地自动发布的脚本:

temp-folder = /tmp/jekyll-temp-site/
repo = git@git.coding.net:iziy/iziy.git

JEKYLL = jekyll

s:
        ${JEKYLL} server
build:
        ${JEKYLL} build -d ${temp-folder}

deploy: build
        cd ${temp-folder} ;\
        git init ${temp-folder} ;\
        git checkout -b coding-pages ;\
        git remote add origin ${repo} ;\
        git add -A ${temp-folder} ;\
        git commit -m "deployed by make" ;\
        git push origin coding-pages --force

push:
        git add -A
        git commit -m "pushed by make"
        git push


clean:
        rm -rf ${temp-folder}

而对于webhook响应的脚本为updatemypre.sh:

#!/usr/bin/bash

echo "webhook enter!"

source /usr/local/rvm/scripts/rvm

cd iziy
git pull
make deploy

Tag "linux":

利用git WebHooks自动部署Pages(Coding Pages)

github pages服务由于安全性的考虑,对其原生jekyll的支持插件进行了过滤。使得只能使用其有限的插件,而且无法使用自定义的插件。这导致了很多问题,比如不能按自己的规则生成归档文件或者分类目录,甚至部署爬虫之类等等。

具体详见: https://pages.github.com/versions/

而国内几大git服务商(Coding,码市之类),也对支持的插件进行了限制,所以在多数情况下,还是选择在本地搭建Jekyll环境,生成静态页面直接上传。

但这极大限制了Jekyll的Markdown in Anywhere便利性,需要在不同的系统上都装上Jekyll的开发环境。

## 现在讨论一种利用中间生产服务器代替本地发布过程的方法。

依赖:一台部署gh-hooks-server的VPS

既然选择不使用git的原生jekyll,也那么需要两个branch, 一个用于jekyll源码的存放, 一个用于托管静态代码

通过一台中间服务器,当源branch进行了更新,则通过webhook自动通知gh-hooks-server,使其执行pull、push操作。

VPS的jekyll环境的搭建不再赘述【首先安装rvm,ruby, 再装jekyll以及插件比如jekyll-paginate】

下面演示安装gh-hooks-server并启动

git clone https://github.com/c834606877/gh-hooks-server.git
cd gh-hooks-server
python setup.py install

ghhooks -a updatemypre:/home/lanbing/updatemypre.sh --secret s3cret

 

程序启动后会侦听8011端口,处理http://0.0.0.0:8011/ghhooks/updatemypre的请求信息,当请求密码通过后,执行对应的bash脚本。

故,我们只需要对源Branch的push消息发送webhook,当gh-hooks-server接收收post消息后,pull 源 Branch,jekyll编译,然后push到Pages Branch。

为了兼容手动发布,编写了一个makefile,用于本地自动发布的脚本:

temp-folder = /tmp/jekyll-temp-site/
repo = git@git.coding.net:iziy/iziy.git

JEKYLL = jekyll

s:
        ${JEKYLL} server
build:
        ${JEKYLL} build -d ${temp-folder}

deploy: build
        cd ${temp-folder} ;\
        git init ${temp-folder} ;\
        git checkout -b coding-pages ;\
        git remote add origin ${repo} ;\
        git add -A ${temp-folder} ;\
        git commit -m "deployed by make" ;\
        git push origin coding-pages --force

push:
        git add -A
        git commit -m "pushed by make"
        git push


clean:
        rm -rf ${temp-folder}

而对于webhook响应的脚本为updatemypre.sh:

#!/usr/bin/bash

echo "webhook enter!"

source /usr/local/rvm/scripts/rvm

cd iziy
git pull
make deploy

Tag "CC3220":

在学习CC3220碰到的一些常见问题,贴出来以免新手再绕弯路。

每次程序启动之后,可以正常运行,但reset之后,会运行out of box 程序

通过uniflash工具,删除 /sys/下的bin文件 参考 https://e2e.ti.com/support/wireless_connectivity/simplelink_wifi_cc31xx_cc32xx/f/968/t/625681


provisioning的时候,可以连上simplelink的wifi,但是在checking if device is simplelink的时候显示失败,原因不明。

通过在安卓手机上使用logcat显示smartconfig日志,发现程序访问了,mysimplelink.net这个域名,并且无法解析这个域名。

所以恍然大悟发现自己使用了影梭vpn,将会使用我的代理进行DNS解析,由于这是个本地域名,需要使用板载dns服务器。

此外,还发现,板载的HTTP服务器还提供,RESTful API接口,可以对通过POST对芯片配网等参数进行修改。


让cc3220自动连接Wifi。

成功配网后,串口调试信息显示: [Provisioning] Profile Added: SSID: LanBing’s_Wiki-Free [Provisioning] Profile confirmation: WLAN Connected! [Provisioning] Profile confirmation: IP Acquired!

但reset之后,设备不会自动使用保存的密码进行连接。

原因是cc3220的连接策略有四种选项组合:

  1. Auto
  2. Fast
  3. AnyP2P
  4. Auto Provisioning

其中Auto Provisioning就是在设备启动之后自己进行连接。

详见文档SWRU455E3.3.3.1节。

这里有三种方式可以对策略进行修改:

  1. 调用库函数: sl_WlanPolicySet(SL_WLAN_POLICY_CONNECTION,SL_WLAN_CONNECTION_POLICY(1,1,0,1),NULL,0);
  2. POST RESTful API: POST /api/1/wlan/policy_set HTTP/1.1 Host: mysimplelink.net Content-Type: application/x-www-form-urlencoded __SL_P_P.E=&__SL_P_P.F= 详见文档 SWRU455E 节8.4.7
  3. 通过SimpleLink Uniflash工具设置。

Tag "CC3220SF":

在学习CC3220碰到的一些常见问题,贴出来以免新手再绕弯路。

每次程序启动之后,可以正常运行,但reset之后,会运行out of box 程序

通过uniflash工具,删除 /sys/下的bin文件 参考 https://e2e.ti.com/support/wireless_connectivity/simplelink_wifi_cc31xx_cc32xx/f/968/t/625681


provisioning的时候,可以连上simplelink的wifi,但是在checking if device is simplelink的时候显示失败,原因不明。

通过在安卓手机上使用logcat显示smartconfig日志,发现程序访问了,mysimplelink.net这个域名,并且无法解析这个域名。

所以恍然大悟发现自己使用了影梭vpn,将会使用我的代理进行DNS解析,由于这是个本地域名,需要使用板载dns服务器。

此外,还发现,板载的HTTP服务器还提供,RESTful API接口,可以对通过POST对芯片配网等参数进行修改。


让cc3220自动连接Wifi。

成功配网后,串口调试信息显示: [Provisioning] Profile Added: SSID: LanBing’s_Wiki-Free [Provisioning] Profile confirmation: WLAN Connected! [Provisioning] Profile confirmation: IP Acquired!

但reset之后,设备不会自动使用保存的密码进行连接。

原因是cc3220的连接策略有四种选项组合:

  1. Auto
  2. Fast
  3. AnyP2P
  4. Auto Provisioning

其中Auto Provisioning就是在设备启动之后自己进行连接。

详见文档SWRU455E3.3.3.1节。

这里有三种方式可以对策略进行修改:

  1. 调用库函数: sl_WlanPolicySet(SL_WLAN_POLICY_CONNECTION,SL_WLAN_CONNECTION_POLICY(1,1,0,1),NULL,0);
  2. POST RESTful API: POST /api/1/wlan/policy_set HTTP/1.1 Host: mysimplelink.net Content-Type: application/x-www-form-urlencoded __SL_P_P.E=&__SL_P_P.F= 详见文档 SWRU455E 节8.4.7
  3. 通过SimpleLink Uniflash工具设置。

Tag "Provisioning":

在学习CC3220碰到的一些常见问题,贴出来以免新手再绕弯路。

每次程序启动之后,可以正常运行,但reset之后,会运行out of box 程序

通过uniflash工具,删除 /sys/下的bin文件 参考 https://e2e.ti.com/support/wireless_connectivity/simplelink_wifi_cc31xx_cc32xx/f/968/t/625681


provisioning的时候,可以连上simplelink的wifi,但是在checking if device is simplelink的时候显示失败,原因不明。

通过在安卓手机上使用logcat显示smartconfig日志,发现程序访问了,mysimplelink.net这个域名,并且无法解析这个域名。

所以恍然大悟发现自己使用了影梭vpn,将会使用我的代理进行DNS解析,由于这是个本地域名,需要使用板载dns服务器。

此外,还发现,板载的HTTP服务器还提供,RESTful API接口,可以对通过POST对芯片配网等参数进行修改。


让cc3220自动连接Wifi。

成功配网后,串口调试信息显示: [Provisioning] Profile Added: SSID: LanBing’s_Wiki-Free [Provisioning] Profile confirmation: WLAN Connected! [Provisioning] Profile confirmation: IP Acquired!

但reset之后,设备不会自动使用保存的密码进行连接。

原因是cc3220的连接策略有四种选项组合:

  1. Auto
  2. Fast
  3. AnyP2P
  4. Auto Provisioning

其中Auto Provisioning就是在设备启动之后自己进行连接。

详见文档SWRU455E3.3.3.1节。

这里有三种方式可以对策略进行修改:

  1. 调用库函数: sl_WlanPolicySet(SL_WLAN_POLICY_CONNECTION,SL_WLAN_CONNECTION_POLICY(1,1,0,1),NULL,0);
  2. POST RESTful API: POST /api/1/wlan/policy_set HTTP/1.1 Host: mysimplelink.net Content-Type: application/x-www-form-urlencoded __SL_P_P.E=&__SL_P_P.F= 详见文档 SWRU455E 节8.4.7
  3. 通过SimpleLink Uniflash工具设置。

Tag "CTF, 逆向":

CISCN(2018)逆向之task-reverse_06

午睡的时候,朋友发来个题,反正闲也闲着,来练练手。

#1 查壳

拿到程序先确认使用的是什么编译器,什么环境下运行,以决定用何种工具。

1525058201289

程序无花无壳,直接上IDA静态了,CTF的题在实机调比较方便。

Tag "AZ3166":

在学习AZ3166碰到的一些常见问题,贴出来以免新手再绕弯路。

一、Mico开发环境的搭建

Mico开发环境由三部分组成,

  1. Mico Cube : 用于在命令行下对mico-os 编译链接下载,以及对mico-os进行版本管理的工具, 这是个python工具,所以需要使用pip install mico-cube 进行安装,并且需要在环境中安装git,以用于版本管理和os的import。

  2. Micoder:用于编译链接的组件,提供的gcc、gdb等交叉编译调试工具链: 这个需要和mico Cube配合使用,下载解压后, 需要使用 mico config --global micoder D:\MXCHIP\MiCO_SDK\MiCO\MiCoder 进行配置,使得mico可以调用micoder,进行编译,链接,下载。 否则会报错[mico]: can not found micoder

  3. Micoder IDE:用于在图形环境下进行版本管理,开发,还可以进行调试。 需要java运行环境,并且设置好path系统环境参数。 在安装Micoder IDE时会自动附带安装一个mico-os的sdk,

二、AZ3166对应mico-os的配置

在你的项目文件夹下通过命令 mico import mico-demos 从aliyun的git上下载一最新的demos和os

从eclipse中导入mico-demos, 右键根项目(mico-demos) Team->Switch To->Other : Remote Tracking->origin/experiment 右键mico-osTeam->Switch To->Other : Remote Tracking->origin/mico-os-4.0

三、Build Targets

添加编译命令可编译运行下载:

application.wifi_uart@AZ3166 total download run JTAG=stlink-v2-1

这里对解释一下编译命令:

@前面的部分代表要编译的程序所在文件夹,用.代替\表示文件目录的结构层次。

@后面的部分代表要编译使用的板子库型号。

最后,Eclipse IDE,会组合成命令:

mico make application.wifi_uart@AZ3166 total download run JTAG=stlink-v2-1

并在因为只有在根目录中,才能同时相对的找到mico-os和其相关的库文件和程序,否则会报找不到mico-os等等编译错误。

四、添加AZ3166驱动组件

在一个现有的MiCO项目中添加AZ3166组件,并运行附带的示例程序。在进行以下操作之前,先确保MiCO Cude已经正确安装。 导入AZ3166组件

进入一个MiCO项目的根目录,例如:cd helloworld。(如果本地没有现成的MiCO项目,可以使用mico new xxx创建一个项目,或者使用mico import xxx从版本库导入一个项目),
执行指令:mico add https://code.aliyun.com/mico/drv_AZ3166.git,从远程版本库中下载组件并且添加到当前项目。

运行AZ3166示例

1.组件中内置示例程序:drv_AZ3166/demo,执行编译命令。

例如在MXCHIP Microsoft Azure IoT Developer Kit平台AZ3166上:

mico make drv_AZ3166.demo@AZ3166@RTX total download JTAG=stlink-v2-1 run

详细的编译选项参考MiCO Cude

2.程序运行后,在设备OLED显示屏上显示传感器信息,并且在设备串口终端上显示传感器信息,例如:

50885 humidity = 52.90%, temp = 31.30C
50892 magnet =     84,    193,   -207
50899 lps22hb tmep = 32.00C, press = 1010.00hPa
50907 LSM6DSL [acc/mg]:       26,    -104,    1011
50915 LSM6DSL [gyro/mdps]:        0,   -1680,    1260

Tag "AZURE":

在学习AZ3166碰到的一些常见问题,贴出来以免新手再绕弯路。

一、Mico开发环境的搭建

Mico开发环境由三部分组成,

  1. Mico Cube : 用于在命令行下对mico-os 编译链接下载,以及对mico-os进行版本管理的工具, 这是个python工具,所以需要使用pip install mico-cube 进行安装,并且需要在环境中安装git,以用于版本管理和os的import。

  2. Micoder:用于编译链接的组件,提供的gcc、gdb等交叉编译调试工具链: 这个需要和mico Cube配合使用,下载解压后, 需要使用 mico config --global micoder D:\MXCHIP\MiCO_SDK\MiCO\MiCoder 进行配置,使得mico可以调用micoder,进行编译,链接,下载。 否则会报错[mico]: can not found micoder

  3. Micoder IDE:用于在图形环境下进行版本管理,开发,还可以进行调试。 需要java运行环境,并且设置好path系统环境参数。 在安装Micoder IDE时会自动附带安装一个mico-os的sdk,

二、AZ3166对应mico-os的配置

在你的项目文件夹下通过命令 mico import mico-demos 从aliyun的git上下载一最新的demos和os

从eclipse中导入mico-demos, 右键根项目(mico-demos) Team->Switch To->Other : Remote Tracking->origin/experiment 右键mico-osTeam->Switch To->Other : Remote Tracking->origin/mico-os-4.0

三、Build Targets

添加编译命令可编译运行下载:

application.wifi_uart@AZ3166 total download run JTAG=stlink-v2-1

这里对解释一下编译命令:

@前面的部分代表要编译的程序所在文件夹,用.代替\表示文件目录的结构层次。

@后面的部分代表要编译使用的板子库型号。

最后,Eclipse IDE,会组合成命令:

mico make application.wifi_uart@AZ3166 total download run JTAG=stlink-v2-1

并在因为只有在根目录中,才能同时相对的找到mico-os和其相关的库文件和程序,否则会报找不到mico-os等等编译错误。

四、添加AZ3166驱动组件

在一个现有的MiCO项目中添加AZ3166组件,并运行附带的示例程序。在进行以下操作之前,先确保MiCO Cude已经正确安装。 导入AZ3166组件

进入一个MiCO项目的根目录,例如:cd helloworld。(如果本地没有现成的MiCO项目,可以使用mico new xxx创建一个项目,或者使用mico import xxx从版本库导入一个项目),
执行指令:mico add https://code.aliyun.com/mico/drv_AZ3166.git,从远程版本库中下载组件并且添加到当前项目。

运行AZ3166示例

1.组件中内置示例程序:drv_AZ3166/demo,执行编译命令。

例如在MXCHIP Microsoft Azure IoT Developer Kit平台AZ3166上:

mico make drv_AZ3166.demo@AZ3166@RTX total download JTAG=stlink-v2-1 run

详细的编译选项参考MiCO Cude

2.程序运行后,在设备OLED显示屏上显示传感器信息,并且在设备串口终端上显示传感器信息,例如:

50885 humidity = 52.90%, temp = 31.30C
50892 magnet =     84,    193,   -207
50899 lps22hb tmep = 32.00C, press = 1010.00hPa
50907 LSM6DSL [acc/mg]:       26,    -104,    1011
50915 LSM6DSL [gyro/mdps]:        0,   -1680,    1260

Tag "MXCHIP":

在学习AZ3166碰到的一些常见问题,贴出来以免新手再绕弯路。

一、Mico开发环境的搭建

Mico开发环境由三部分组成,

  1. Mico Cube : 用于在命令行下对mico-os 编译链接下载,以及对mico-os进行版本管理的工具, 这是个python工具,所以需要使用pip install mico-cube 进行安装,并且需要在环境中安装git,以用于版本管理和os的import。

  2. Micoder:用于编译链接的组件,提供的gcc、gdb等交叉编译调试工具链: 这个需要和mico Cube配合使用,下载解压后, 需要使用 mico config --global micoder D:\MXCHIP\MiCO_SDK\MiCO\MiCoder 进行配置,使得mico可以调用micoder,进行编译,链接,下载。 否则会报错[mico]: can not found micoder

  3. Micoder IDE:用于在图形环境下进行版本管理,开发,还可以进行调试。 需要java运行环境,并且设置好path系统环境参数。 在安装Micoder IDE时会自动附带安装一个mico-os的sdk,

二、AZ3166对应mico-os的配置

在你的项目文件夹下通过命令 mico import mico-demos 从aliyun的git上下载一最新的demos和os

从eclipse中导入mico-demos, 右键根项目(mico-demos) Team->Switch To->Other : Remote Tracking->origin/experiment 右键mico-osTeam->Switch To->Other : Remote Tracking->origin/mico-os-4.0

三、Build Targets

添加编译命令可编译运行下载:

application.wifi_uart@AZ3166 total download run JTAG=stlink-v2-1

这里对解释一下编译命令:

@前面的部分代表要编译的程序所在文件夹,用.代替\表示文件目录的结构层次。

@后面的部分代表要编译使用的板子库型号。

最后,Eclipse IDE,会组合成命令:

mico make application.wifi_uart@AZ3166 total download run JTAG=stlink-v2-1

并在因为只有在根目录中,才能同时相对的找到mico-os和其相关的库文件和程序,否则会报找不到mico-os等等编译错误。

四、添加AZ3166驱动组件

在一个现有的MiCO项目中添加AZ3166组件,并运行附带的示例程序。在进行以下操作之前,先确保MiCO Cude已经正确安装。 导入AZ3166组件

进入一个MiCO项目的根目录,例如:cd helloworld。(如果本地没有现成的MiCO项目,可以使用mico new xxx创建一个项目,或者使用mico import xxx从版本库导入一个项目),
执行指令:mico add https://code.aliyun.com/mico/drv_AZ3166.git,从远程版本库中下载组件并且添加到当前项目。

运行AZ3166示例

1.组件中内置示例程序:drv_AZ3166/demo,执行编译命令。

例如在MXCHIP Microsoft Azure IoT Developer Kit平台AZ3166上:

mico make drv_AZ3166.demo@AZ3166@RTX total download JTAG=stlink-v2-1 run

详细的编译选项参考MiCO Cude

2.程序运行后,在设备OLED显示屏上显示传感器信息,并且在设备串口终端上显示传感器信息,例如:

50885 humidity = 52.90%, temp = 31.30C
50892 magnet =     84,    193,   -207
50899 lps22hb tmep = 32.00C, press = 1010.00hPa
50907 LSM6DSL [acc/mg]:       26,    -104,    1011
50915 LSM6DSL [gyro/mdps]:        0,   -1680,    1260

Tag "N卡":

Ubuntu下如何切换Intel和Nvidia显卡

原文:How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

翻译水平有限,还望批评指正,都㚏2020s了,有关解决方案大家还是自行Google吧。

在笔记本上如何查看核显和N卡是折腾显卡的第一步。这篇文章展示在Ubuntu理如何和谐的切换Intel核显和N卡。

你应该使用哪块显卡?

对于游戏和3D绘图等要求大量图形计算来说,应该切换至N卡。

如果你对游戏和3D绘图不感觉兴趣,那么,Intlel核显将满足你的日常使用,并且比起N卡更省电。

#1 查看电脑上哪些显卡

在Ubuntu下可以非常简单的做这个事:

lspci -k | grep -E -A2 -i 'VGA|3D'

https://www.linuxbabe.com/wp-content/uploads/2016/04/Selection_010-1.png

#2 查看正在使用哪块显卡

Ubuntu 默认会使用Intel核显。

如果你以前对显卡驱动做过改动,又不记得了,那么可以在图形界面下,系统设置 > 细节system settings > details)中查看。

#3 安装Nvidia显卡驱动

Ubuntu本身集成了N卡开源驱动nouveau在Linux内核里,但此驱动缺少3D加速的支持. 要发挥显卡性能,我们可以用software-properties-gtk程序去安装合适的驱动。

Software & Updates_ additional drivers

你可以选择最新的版本,应用更改。

也可以通过下列命令,查看推荐的驱动版本:

 sudo ubuntu-drivers devices

How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

下列命令将会自动安装Nvidia驱动。

sudo ubuntu-drivers autoinstall

在合适的驱动安装成功后,重新打开系统设置 > 细节system settings > details),你将会看到新安装的驱动已经选择上了,如果没有的话,请自行选择,并应用修改。

https://www.linuxbabe.com/wp-content/uploads/2016/04/Software-Updates_013.png

现在我们已经安装好了合适的N卡驱动了,但是,我们仍然在使用Intel核显。

#4 切换到N卡

在你选择好了N卡驱动后,可能需要重启你的电脑,以启用PRIME支持。如果PRIME没有启动,可能会出现下面的信息:

Message: PRIME: is it supported? no

重启之后,可以从应用列表中打开Nvidia X Server Settings,或者从命令行打开:

#: nvidia-settings

NVIDIA X Server Settings_ prime profiles

在PRIME Profiles` 选项卡中,选择你想切换的显卡, 重启电脑。

你就可以在系统设置 > 细节system settings > details)中看到N卡了。

想要切换回Intel核显,只需要在上图中点击Intel即可。

也可以通过命令行的方式,切换到核显:

sudo prime-select intel

或N卡:

sudo prime-select nvidia

查看哪块显卡正在使用:

prime-select query

如何和卸载N卡驱动

有时个你Nvidia安装失败,或者没有成功,黑屏了,没有办法进入图形界面,或者出现以下错误:

driver ebridge is already registered aborting

这种情况你需要完全的卸载N卡驱动,通过运行下列命令,完全移除nvidia相关包:

sudo apt purge nvidia-*

Tag "核显":

Ubuntu下如何切换Intel和Nvidia显卡

原文:How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

翻译水平有限,还望批评指正,都㚏2020s了,有关解决方案大家还是自行Google吧。

在笔记本上如何查看核显和N卡是折腾显卡的第一步。这篇文章展示在Ubuntu理如何和谐的切换Intel核显和N卡。

你应该使用哪块显卡?

对于游戏和3D绘图等要求大量图形计算来说,应该切换至N卡。

如果你对游戏和3D绘图不感觉兴趣,那么,Intlel核显将满足你的日常使用,并且比起N卡更省电。

#1 查看电脑上哪些显卡

在Ubuntu下可以非常简单的做这个事:

lspci -k | grep -E -A2 -i 'VGA|3D'

https://www.linuxbabe.com/wp-content/uploads/2016/04/Selection_010-1.png

#2 查看正在使用哪块显卡

Ubuntu 默认会使用Intel核显。

如果你以前对显卡驱动做过改动,又不记得了,那么可以在图形界面下,系统设置 > 细节system settings > details)中查看。

#3 安装Nvidia显卡驱动

Ubuntu本身集成了N卡开源驱动nouveau在Linux内核里,但此驱动缺少3D加速的支持. 要发挥显卡性能,我们可以用software-properties-gtk程序去安装合适的驱动。

Software & Updates_ additional drivers

你可以选择最新的版本,应用更改。

也可以通过下列命令,查看推荐的驱动版本:

 sudo ubuntu-drivers devices

How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

下列命令将会自动安装Nvidia驱动。

sudo ubuntu-drivers autoinstall

在合适的驱动安装成功后,重新打开系统设置 > 细节system settings > details),你将会看到新安装的驱动已经选择上了,如果没有的话,请自行选择,并应用修改。

https://www.linuxbabe.com/wp-content/uploads/2016/04/Software-Updates_013.png

现在我们已经安装好了合适的N卡驱动了,但是,我们仍然在使用Intel核显。

#4 切换到N卡

在你选择好了N卡驱动后,可能需要重启你的电脑,以启用PRIME支持。如果PRIME没有启动,可能会出现下面的信息:

Message: PRIME: is it supported? no

重启之后,可以从应用列表中打开Nvidia X Server Settings,或者从命令行打开:

#: nvidia-settings

NVIDIA X Server Settings_ prime profiles

在PRIME Profiles` 选项卡中,选择你想切换的显卡, 重启电脑。

你就可以在系统设置 > 细节system settings > details)中看到N卡了。

想要切换回Intel核显,只需要在上图中点击Intel即可。

也可以通过命令行的方式,切换到核显:

sudo prime-select intel

或N卡:

sudo prime-select nvidia

查看哪块显卡正在使用:

prime-select query

如何和卸载N卡驱动

有时个你Nvidia安装失败,或者没有成功,黑屏了,没有办法进入图形界面,或者出现以下错误:

driver ebridge is already registered aborting

这种情况你需要完全的卸载N卡驱动,通过运行下列命令,完全移除nvidia相关包:

sudo apt purge nvidia-*

Tag "切换":

Ubuntu下如何切换Intel和Nvidia显卡

原文:How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

翻译水平有限,还望批评指正,都㚏2020s了,有关解决方案大家还是自行Google吧。

在笔记本上如何查看核显和N卡是折腾显卡的第一步。这篇文章展示在Ubuntu理如何和谐的切换Intel核显和N卡。

你应该使用哪块显卡?

对于游戏和3D绘图等要求大量图形计算来说,应该切换至N卡。

如果你对游戏和3D绘图不感觉兴趣,那么,Intlel核显将满足你的日常使用,并且比起N卡更省电。

#1 查看电脑上哪些显卡

在Ubuntu下可以非常简单的做这个事:

lspci -k | grep -E -A2 -i 'VGA|3D'

https://www.linuxbabe.com/wp-content/uploads/2016/04/Selection_010-1.png

#2 查看正在使用哪块显卡

Ubuntu 默认会使用Intel核显。

如果你以前对显卡驱动做过改动,又不记得了,那么可以在图形界面下,系统设置 > 细节system settings > details)中查看。

#3 安装Nvidia显卡驱动

Ubuntu本身集成了N卡开源驱动nouveau在Linux内核里,但此驱动缺少3D加速的支持. 要发挥显卡性能,我们可以用software-properties-gtk程序去安装合适的驱动。

Software & Updates_ additional drivers

你可以选择最新的版本,应用更改。

也可以通过下列命令,查看推荐的驱动版本:

 sudo ubuntu-drivers devices

How To Switch Between Intel and Nvidia Graphics Card on Ubuntu

下列命令将会自动安装Nvidia驱动。

sudo ubuntu-drivers autoinstall

在合适的驱动安装成功后,重新打开系统设置 > 细节system settings > details),你将会看到新安装的驱动已经选择上了,如果没有的话,请自行选择,并应用修改。

https://www.linuxbabe.com/wp-content/uploads/2016/04/Software-Updates_013.png

现在我们已经安装好了合适的N卡驱动了,但是,我们仍然在使用Intel核显。

#4 切换到N卡

在你选择好了N卡驱动后,可能需要重启你的电脑,以启用PRIME支持。如果PRIME没有启动,可能会出现下面的信息:

Message: PRIME: is it supported? no

重启之后,可以从应用列表中打开Nvidia X Server Settings,或者从命令行打开:

#: nvidia-settings

NVIDIA X Server Settings_ prime profiles

在PRIME Profiles` 选项卡中,选择你想切换的显卡, 重启电脑。

你就可以在系统设置 > 细节system settings > details)中看到N卡了。

想要切换回Intel核显,只需要在上图中点击Intel即可。

也可以通过命令行的方式,切换到核显:

sudo prime-select intel

或N卡:

sudo prime-select nvidia

查看哪块显卡正在使用:

prime-select query

如何和卸载N卡驱动

有时个你Nvidia安装失败,或者没有成功,黑屏了,没有办法进入图形界面,或者出现以下错误:

driver ebridge is already registered aborting

这种情况你需要完全的卸载N卡驱动,通过运行下列命令,完全移除nvidia相关包:

sudo apt purge nvidia-*

Tag "Android":

bfs-iscc 2018 Mobile 分析

题目是上上周末,同学发来的,当时分析了一阵,没有出最终结果。

直到上周末,才将关键加密部分,分析出来。

今天将分析过程记录于此。

一、前言

安卓的题目,多少会结合jni来个so,或者动态载入dex,再加一些加密手段,隐藏入口等等,本题目基本都调试方法都涉及到了。

但是,就单单解题来说,掌握一些常用的调试方法,逆向基础不弱,通过勤加苦练,也是可以在赛场上取得好成绩的。如今安全意识的普及,现实情况下,app多数会进行代码混淆,甚至不惜性能加个比较复杂的vm壳。

本题前后总共花有差不多15个小时的时间,但难度不高,层层剥壳,均有迹可寻。

二、程序信息

程序名:signed.apk
md5:56de5d88051a6f44d0e83e843172a6f9
sha1:084f1b51f8ac3b167b748ac24c474a00688c5652
大小:2.79 MB

下载地址:点击下载

信息如下:

1540645435208

Tag "本博动态":

工作一年总结

工作一年总结

虽然名为工作总结,但实际我应该总结的是这一年来个人的成长。

工作中成长虽然也算是一种。如果将当下的努力方向划分为短期、中期和长期目标的话。然而我过去一年的努力方向基本都在完成超短期内容的。事情是被推着走的。

正常的时间分配,对我而言,应该是泊松分布,主要时间分布在短期目标中,短期目标服从于长期目标,因此不会有太大的分歧。

半年来工作内容归纳

总结一下近半年来所做的工作吧,可怜的还需要去实验室网站,拉自己发的周报,才有可能回想起来做了些什么事。游戏伤身还伤心。

从去年国庆节回家后,就没有回庆科实习了,老师也同意在实验室完成一部分公司的实习工作,继续给我发一部分实习工资,以补贴学习期间的囊中羞涩。

实习期间主要做唤醒词的研发,目前来看效果还好,虽然达不到业界水平,有些产品也用上了。

FPGA相关

FPGA是十月份开始正式接触的一直到现在。

起先开始跑了一些官方的简单例程,比如亮个灯,从clk手动计数分频转接到LED,控制频闪。

学习简单的verlog语法和VHDL语法。同样也找了一些所谓的学习视频,但都比较老旧,圈子也比较小。很多涉及到的基础知识多也点到为止,不能透彻的了解其中细节原理。

断断续续折腾了一个月左右,发现入门有很大的困难,国内知识体系太过封闭,接触不到最新的处理器设计相关知识,仍然停留在一些简单的电路设计的层面。

Tag "RiscV":

设计一个简单的RiscV协处理器RoCC(数组求和)一

 从系统效率和功能可复性方面来讲,当要使得协处理器能够处理更多的应用情景时,应当将目标事物,拆分成一系列更小的重复通用的事物处理过程,在上层软件中再进行事物处理的组装。而当要使得协处理器以系统效率为主,比如低功耗,则需将系统功能整体设计为一个功能单一的模块,做为专用处理器。

本文叙述一个简单的协处理器设计过程,用以加深对RoCC接口的理解。

RoCC加速器模块是由LazyRoCC类继承而来,该模块包含一个由LazyRoCCModuleImp继承而来的实例。

依葫芦画瓢,我们先设计一个加速器模块的外壳,用以可以被Rocket核调用。


class ArraySumCoP(opcodes: OpcodeSet)(implicit p: Parameters) extends LazyRoCC(opcodes) {
  override lazy val module = new ArraySumCoPImp(this)
}

class ArraySumCoPImp(outer: ArraySumCoP)(implicit p: Parameters) extends LazyRoCCModuleImp(outer)
    with HasCoreParameters {
    val cmd = Queue(io.cmd)
        ...
        ...
        ...
        
}

由于LazyRoCCModuleImp中已经包含了一个RoCCIO的接口,我们可以在实现中直接使用此接口。

RoCCIO接口由多组不同的Wire和bundle组成,具体信息参考上一篇文章:RoCC接口介绍

其中,cmd包含了Custom指令调用时,加速器接收到的内容,参数如下:

  • cmd.inst,为32位指令内容,由以下组成:cmd.inst.[opcode, rd, rs1, rs2, funct, xd, xs1, xs2
  • cmd.rs1,为源寄存器1内容
  • cmd.rs2, 为源寄存器2内容

此外,LazyRoCC类包含了两个TLOutputNode实例: atlNodetlNode,分别通过Tilelink总线的方式连接到L1缓存,和L2缓存

mem实例用于直接访问L1 Cache缓存,ptw直接访问页表,busy信号指明加速器是否正在处理指令以及一个中断信号。

本次,我们使用mem接口来实现对内存数据的访问和存储。

RiscV-RoCC(RiscV协处理器, Rocket Custom Coprocessor) 介绍

RiscV作为一个新的开源指令集架构,由Aspire Lab开放,具有简单开放的特点,主要用于教育研究.

一个最主要的特点是其ISA通过支持自定义指令的方式,支持自定义硬件加速器,用于专用领域的计算加速设计。

本文简单介绍RiscV的RoCC,以及其与RiscV处理器核通信的接口RoCC Interface。

RiscV自定义指令

RiscV ISA定义了四种自定义指令用于与协处理器进行交互。

customX rd, rs1, rs2, funct

标准自定义指令格式如下:

Screenshot from 2019-04-08 21-07-00

其中rs1,rs2 为源寄存器,rd为目的寄存器,xd,xs1,xs2为寄存器有效位,分别指明rd,rs1,rs2是否已使用。

opcode为四种不同的custom指令(custom-0/1/2/3/)

在arty a7-35t FPGA开发板上运行Sifive开源RiscV处理器简单指导

要在FPGA开发板上调通RiscV主要需要两方面知识,一方面是简单的电子电路知识,二是软件层工具链和嵌入式开发知识。

在ARTY 35T FPGA开发板上运行RiscV还需要一个支持RiscV处理器核的JTag调试器,用于调试和下载程序。 官方使用的是Olimex ARM-USB-TINY-H。

主要流程分为三个部分:

  1. 生成用于烧录到FPGA开发板上包含整个RiscV Soc的mcs文件
  2. 安装RiscV gcc工具链,生成并上传软件代码程序。
  3. 调试和测试软件程序

运行环境 整个过程使用Ubuntu 16.04完成,并且建议使用实体机器运行,100g以上硬盘空间,原因主要有几点:

  1. 生成Sifive fe310处理器需要用到linux环境。
  2. vivado 目前只支持Ubuntu1604而且是较老的Ubuntu1604.3
  3. 减小USB插拔转换不必要的麻烦。
  4. 运行效率和GUI体验。

一、安装和下载必要的软件

在开始之前需要准备好以下软件。

  1. vivado HLx –> 用于生成arty的mcs文件和fpga烧写 大小17G左右 https://www.xilinx.com/support/download.html

  2. sifive/freedom –> Github RiscV SoC 源代码

  3. sifive/freedom-e-sdk –> Github Sifive提供的软件开发SDK 代码

  4. 预编译gcc工具链和riscv OpenOCD –> 由Sifive官方网站Tools提供。

    https://www.sifive.com/boards/

  5. Digilent/vivado-boards –> Github vivado arty开发板文件

  6. Adept 2 –> Arty FPGA开发板驱动

    https://reference.digilentinc.com/reference/software/adept/start

下载和安装可以同时进行以节约时间

Tag "Sifive":

在arty a7-35t FPGA开发板上运行Sifive开源RiscV处理器简单指导

要在FPGA开发板上调通RiscV主要需要两方面知识,一方面是简单的电子电路知识,二是软件层工具链和嵌入式开发知识。

在ARTY 35T FPGA开发板上运行RiscV还需要一个支持RiscV处理器核的JTag调试器,用于调试和下载程序。 官方使用的是Olimex ARM-USB-TINY-H。

主要流程分为三个部分:

  1. 生成用于烧录到FPGA开发板上包含整个RiscV Soc的mcs文件
  2. 安装RiscV gcc工具链,生成并上传软件代码程序。
  3. 调试和测试软件程序

运行环境 整个过程使用Ubuntu 16.04完成,并且建议使用实体机器运行,100g以上硬盘空间,原因主要有几点:

  1. 生成Sifive fe310处理器需要用到linux环境。
  2. vivado 目前只支持Ubuntu1604而且是较老的Ubuntu1604.3
  3. 减小USB插拔转换不必要的麻烦。
  4. 运行效率和GUI体验。

一、安装和下载必要的软件

在开始之前需要准备好以下软件。

  1. vivado HLx –> 用于生成arty的mcs文件和fpga烧写 大小17G左右 https://www.xilinx.com/support/download.html

  2. sifive/freedom –> Github RiscV SoC 源代码

  3. sifive/freedom-e-sdk –> Github Sifive提供的软件开发SDK 代码

  4. 预编译gcc工具链和riscv OpenOCD –> 由Sifive官方网站Tools提供。

    https://www.sifive.com/boards/

  5. Digilent/vivado-boards –> Github vivado arty开发板文件

  6. Adept 2 –> Arty FPGA开发板驱动

    https://reference.digilentinc.com/reference/software/adept/start

下载和安装可以同时进行以节约时间

Tag "RoCC":

设计一个简单的RiscV协处理器RoCC(数组求和)一

 从系统效率和功能可复性方面来讲,当要使得协处理器能够处理更多的应用情景时,应当将目标事物,拆分成一系列更小的重复通用的事物处理过程,在上层软件中再进行事物处理的组装。而当要使得协处理器以系统效率为主,比如低功耗,则需将系统功能整体设计为一个功能单一的模块,做为专用处理器。

本文叙述一个简单的协处理器设计过程,用以加深对RoCC接口的理解。

RoCC加速器模块是由LazyRoCC类继承而来,该模块包含一个由LazyRoCCModuleImp继承而来的实例。

依葫芦画瓢,我们先设计一个加速器模块的外壳,用以可以被Rocket核调用。


class ArraySumCoP(opcodes: OpcodeSet)(implicit p: Parameters) extends LazyRoCC(opcodes) {
  override lazy val module = new ArraySumCoPImp(this)
}

class ArraySumCoPImp(outer: ArraySumCoP)(implicit p: Parameters) extends LazyRoCCModuleImp(outer)
    with HasCoreParameters {
    val cmd = Queue(io.cmd)
        ...
        ...
        ...
        
}

由于LazyRoCCModuleImp中已经包含了一个RoCCIO的接口,我们可以在实现中直接使用此接口。

RoCCIO接口由多组不同的Wire和bundle组成,具体信息参考上一篇文章:RoCC接口介绍

其中,cmd包含了Custom指令调用时,加速器接收到的内容,参数如下:

  • cmd.inst,为32位指令内容,由以下组成:cmd.inst.[opcode, rd, rs1, rs2, funct, xd, xs1, xs2
  • cmd.rs1,为源寄存器1内容
  • cmd.rs2, 为源寄存器2内容

此外,LazyRoCC类包含了两个TLOutputNode实例: atlNodetlNode,分别通过Tilelink总线的方式连接到L1缓存,和L2缓存

mem实例用于直接访问L1 Cache缓存,ptw直接访问页表,busy信号指明加速器是否正在处理指令以及一个中断信号。

本次,我们使用mem接口来实现对内存数据的访问和存储。

RiscV-RoCC(RiscV协处理器, Rocket Custom Coprocessor) 介绍

RiscV作为一个新的开源指令集架构,由Aspire Lab开放,具有简单开放的特点,主要用于教育研究.

一个最主要的特点是其ISA通过支持自定义指令的方式,支持自定义硬件加速器,用于专用领域的计算加速设计。

本文简单介绍RiscV的RoCC,以及其与RiscV处理器核通信的接口RoCC Interface。

RiscV自定义指令

RiscV ISA定义了四种自定义指令用于与协处理器进行交互。

customX rd, rs1, rs2, funct

标准自定义指令格式如下:

Screenshot from 2019-04-08 21-07-00

其中rs1,rs2 为源寄存器,rd为目的寄存器,xd,xs1,xs2为寄存器有效位,分别指明rd,rs1,rs2是否已使用。

opcode为四种不同的custom指令(custom-0/1/2/3/)

Tag "树":

求最小连通图或树的最短遍历路程

题目描述

给定一张包含N个点、N-1条边的无向连通图,节点从1到N编号,每条边的长度均为1。从1号节点出发并打算遍历所有节点,那么总路程至少是多少?

输入

第一行包含一个整数N,1<=N<=10^5

接下来N-1行,每行包含两个整数X和Y,表于X号节点和Y号节点之间有一条边,1<=X,Y<=N。

输出

输出总路程的最小值。

样例输入

4
1 2
1 3
3 4

样例输出

4

解题思路:

从题目描述来看姑且可以将题目输入看做是树,以根节点开始遍历,计算总路程。

关键在于如何判断最短路径。分析可知,除最后一个遍历的叶子节点到根节点的弧只需走一遍外,其它所有弧都要走两遍。

因此,只需要计算出树的深度为D。

结果为 :

[N-1)*2 - (D-1)


编码待续。

Tag "图":

求最小连通图或树的最短遍历路程

题目描述

给定一张包含N个点、N-1条边的无向连通图,节点从1到N编号,每条边的长度均为1。从1号节点出发并打算遍历所有节点,那么总路程至少是多少?

输入

第一行包含一个整数N,1<=N<=10^5

接下来N-1行,每行包含两个整数X和Y,表于X号节点和Y号节点之间有一条边,1<=X,Y<=N。

输出

输出总路程的最小值。

样例输入

4
1 2
1 3
3 4

样例输出

4

解题思路:

从题目描述来看姑且可以将题目输入看做是树,以根节点开始遍历,计算总路程。

关键在于如何判断最短路径。分析可知,除最后一个遍历的叶子节点到根节点的弧只需走一遍外,其它所有弧都要走两遍。

因此,只需要计算出树的深度为D。

结果为 :

[N-1)*2 - (D-1)


编码待续。

Tag "路由器":

歌华链路由器刷机历程

一入恩山深似海,从此节操是路人。。。

本文纯属闲扯,用到的方法恩山都有,但没有一个路径完全整合的方法,这里记录一下。

实验室的路由器一直用的还是大一买的,当时为便宜走奶茶家一次性买了俩,想着学校小水管D-Link内置天线就够用了,79包邮到一食堂门口。签收完,发现系统着实垃圾,但能用稳定还凑合,接有线一用就是四五年,直到现在9102年了都。

一直用的都是2.4Ghz频段的无线,因为宿舍区墙多隔离效果也好,实际对上网络要求不高,延迟要求不高的应用来讲,2.4Ghz频段的干扰也不大,不像商场比较开旷的地区,对普通应用体验来讲也是感觉不到干扰的。实际上干扰是存在的,主要表现为,当附近有2.4Ghz的大数据量传输时,其它设备会有严重丢包和Ping值变高的影响。

Tag "刷机":

歌华链路由器刷机历程

一入恩山深似海,从此节操是路人。。。

本文纯属闲扯,用到的方法恩山都有,但没有一个路径完全整合的方法,这里记录一下。

实验室的路由器一直用的还是大一买的,当时为便宜走奶茶家一次性买了俩,想着学校小水管D-Link内置天线就够用了,79包邮到一食堂门口。签收完,发现系统着实垃圾,但能用稳定还凑合,接有线一用就是四五年,直到现在9102年了都。

一直用的都是2.4Ghz频段的无线,因为宿舍区墙多隔离效果也好,实际对上网络要求不高,延迟要求不高的应用来讲,2.4Ghz频段的干扰也不大,不像商场比较开旷的地区,对普通应用体验来讲也是感觉不到干扰的。实际上干扰是存在的,主要表现为,当附近有2.4Ghz的大数据量传输时,其它设备会有严重丢包和Ping值变高的影响。

Tag "系统应用":

群晖利用公网服务器ip中转流量与内网无缝切换

最近想起nas的公网访问一直是个问题。中转网络一直不通畅,如果走公网转nas又会过度暴露而被自动扫描攻击,导致硬盘频繁唤醒。

这里实现一套方案,利用公网服务器的ip进行流量转发,并且添加一道简单的防火墙来过滤网络扫描。可以在回家以后自行将流量切换到内网。

在使用公网ip转发的时候,流量和带宽受公网服务器上限所限制。在家中互联场景,本地路由器可以通过拦截公网ip流量,自动转发到nas。免去内外网ip来回切换的问题。

graph TD User1(["User1/Phone/PC"]) -->|Access from local NetWork| B{Router} NAS["NAS lisening:5000(http)/5001(https)"] <-->|In local NetWork| B{Router} Internet{Internet} <--> PubServer[PubServer onPort:80/443/5001] Internet <--> B{Router} User2(["User2/DS File/Photo"]) --> |Access to PubServer:5001| PubServer

主要有以下几个部分实现:

在nas上,将本地端口5000映射到公网ip上,通过 ssh -R 转发。

在计划任务中添加一个bash脚本,建立公网服务器的ssh连接用于端口转发,并设置为开机启动。内容如下:

#!/bin/bash

while true; do
sleep 1
echo "Start Port Forward 5000 @ " `date`
ssh -R 5000:127.0.0.1:5000 yourAccount@YourServer.com -C -q -N -o ServerAliveInterval=60 -o ServerAliveCountMax=10
echo "End of Port Forward 5000 @ " `date`
done;

该脚本启动后会将公网服务器所有来自5000端口的流量转发到nas本身。

5000端口为nas的http服务的连接端口,5001端口为nas的https服务的连接端口。

接下来在公网服务器上配置nginx来实现http流量转发并且配置https端口为5001,通过白名单机制将流量转发到nas。

server {
    server_name yourServerName;
    location / {

#       set $pass_url http://127.0.0.1:8000; # for enter password.
#       if ( $http_user_agent ~ 'Synology-' ) { 
#          // we can also use UA to imp more filters.
           set $pass_url http://127.0.0.1:5000;
#       }
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        include <your_list_path>/nas_allow_list.conf;
        deny all;
    }

    location /log {  // 
        set $pass_url http://127.0.0.1:8000; # for enter password
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    listen 443 ssl; # managed by Certbot
    listen 5001 ssl; # managed by Certbot
    <the ssh certs config >
}

在上述conf中/log访问点的流量反代到白名单配置程序,可以用于动态更新 nas_allow_list.conf白名单。

一个简单的基于白名单配置程序:

from werkzeug.wrappers import Request, Response
import subprocess

@Request.application
def application(request):
    auth_html = '''<body style="margin: 0;"><div style="margin: auto ; width: 100%; height:100%; border: 2px solid green; padding: 50px 0; text-align: center; "><form  method="POST">
            <input type="password" name="psw" style="line-height: 25px;" value="" required placehold="Enter Text..." />
            <input type="submit" style="width: 90px;height: 30px;" value="Submit" />
        </form></div>'''
    if request.method != "POST":
        return Response(auth_html, content_type="text/html")

    data = request.get_data(cache=False,parse_form_data=True)

    input = request.form.get("psw", None)
    if input != "<Your Pass Word>":
        return Response(auth_html[:-6] + "<red>N/a</red></div>", content_type="text/html")

    iplist = ",".join(request.access_route)
    if request.remote_addr == "127.0.0.1": // the traffic is came from nginx.
        record_addr = request.access_route
    else:
        record_addr = [request.remote_addr]
    for ipaddr in record_addr:
        ipaddr = ''.join(i for i in ipaddr if i in '0123456789.')
        # also we can use firewall to filter te trific
        #cmd = ["firewall-cmd","--zone=sszone","--add-source="+ipaddr+"/32"]
        cmd = ["bash","-c", "echo 'allow "+ipaddr+";'>> <your_list_path>/nas_allow_list.conf"]
        subprocess.check_call(cmd)
        cmd = ["nginx", "-s", "reload"]
        subprocess.check_call(cmd)

    return Response("<h1>You are grand to access, IP<" + iplist + "> has record.<h1>")

if __name__ == "__main__":
    from werkzeug.serving import run_simple
    run_simple("0.0.0.0", 8000, application, threaded=True)

在路由器配置iptables , 将内网client到公网服务器的流量直接转发到local nas:

iptables -t nat -A PREROUTING -d <yourPubServerIP> -p tcp --dport 5001 -j DNAT --to-destination <yourLocalNasIP>:5001

记一次黑群晖系统升级失败之后的数据恢复

最近折腾了一下群晖系统的硬盘休眠, 由于不小心动到了硬盘的RAID设置, 导致系统认定系统盘和数据盘中的系统出现了diverge. 重启之后, 提示需要重装安装系统, 重装失败后系统丢失.

群晖系统要求的重装安装时,操作界面给出了两个选项: 迁移和重新安装.

群晖崩溃出现的安装界面

虽然都提示数据不会改动, 因此没有太在意细节 . 而不小心点到了重新安装, 并且选到了自动更新,(没有手动从官网下载安装包), 没想到安装包没自动下载成功, 直接就安装失败了. 当时也没管,直接强制断电关机睡觉了(这也许是最好的保护软件损毁数据的方法), (原本只需抹去并从启动盘中重新sync一份系统到数据盘, 现在事情弄复杂了.)

第二天起来,发现惊奇的是, 群晖已经将所有系统整个/dev/dm0格式化了.. 格式化这种敏感的操作, 居然不是放在最后等必要条件准备就绪才做. 这波操作让人着迷, 恐怕只有印度小伙能干出来.

Linux数据救援不同于win平台使用PE, 搜寻了一蕃LiveCD的解决方案, systemrescue(https://www.system-rescue.org/) 看起来可以不错,后续使用过程中也都满足了需求,.

基本的disk io操作工具都有,包括testdisk, photorec, parted, mdadm, cifs.

注意: Ubuntu的server版liveCD似乎由于内核没有编译RAID模块, 无法操作raid分区, 已踩坑,不建议用作数据救援.

黑苹果实现iPhone/iPad快充功能

通常,iphon或iPad连接苹果电脑的USB口时,会使用快充功能,充电功率可以达到2.1A,在[关于本机->系统报告->USB-iPad]中可以看到可用电流为500mA,加上额外的操作电流1600mA,总共2.1A。

然而在MacOS 10.13中USB的电源管理部分,由之前的AppleBusPowerControllerUSB变成了AppleBusPowerController,对应的电源描述属性也有所变化,在tonymacx86.com上RehabMan大佬已经详细阐述了这个问题:

[Guide] USB power property injection for Sierra (and later)

也就是EC的问题。

然而,在我的k610d笔记本上,显示EC被正常识别,AppleBusPowerController也正常加载,USB接上iPad后,额外的所需电流只有900mA,起初没太在意,直到后来把网卡换成BCM943后,额外的所需电流变成了850mA,再到后来接上鼠标后, 额外的操作电流 (mA)变成了650mA,于是不能再忍了。

今天,查看主板USB供电部分,三个接口,左侧USB有一块1.5A限流芯片,右边一个USB3.0和一个USB2.0供电部分直接接到了S5态的19v转5v的DC-DC上,芯片型号为nb671,查看数据手册发现,该芯片持续电流可达6A,峰值电流可达9A,分出2A来充电也是绰绰有余了,不会造成沁硬件损伤。

由于重新修改SSDT-UIACaml中电源电流供应参数,将USB总电流供应由3200ma提升为4100ma,这样在有耗电设备增加时,也不会由于总供电量不足而减少iPad的快充供电。

参考https://www.tonymacx86.com/threads/cant-charge-ipad-using-usb-ports-el-capitan.230465/

阿里YunOS电视盒子中多遥控器兼容实现

Allwinner h3处理器,作为入门级4k解决方案,经过了四五年时间的打磨,使用定制化的系统,目前还是可以运行一些简单的直播类点播类应用,这两天闲着把家里两款H3的积灰了的盒子刷下固件,一个是迪优美特X16,一个是忆典S1,两者均使用的512MB内存,8GB存储的公版设计,使用了阿里的YunOS系统的机器,刷机时只能刷YunOS系统,否则刷机工具会提示 “烧写BOOT1分区失败” ,具体实现机制应该是有芯片设计配合实现。网上有大虾破解这限制,并制作了可以刷入的安卓固件。

h3的机器固件大多可以通刷,只是小部分gpio,包括遥控器等无法正常使用,这里分析其支持多遥控器的实现机制。

涉及到一个内核模块和一个交互程序以及一个按键映射表文件夹。分别是sunxi-ir-rx.ko和/system/bin/multi_ir以及/system/usr/keylayout/custom_ir_xxxx.kl,其源代码分别可在github上找到。

sunxi-ir-rx.ko负责接收红外数据并进行解析。具体外红数据格式为NEC协议,参考:https://www.cnblogs.com/zhugeanran/p/9334289.html

根据遥控器发出的设备地址码和命令码,结合/dev/下注册设备用于与multi_ir交互提供的按键映射,向系统input发送按键消息。通常,设备地址码与遥控器厂商相关,而命令码对应具体物理按键。

而multi_ir用于解析/system/usr/keylayout/中的custom_ir_xxxx.kl。并向sunxi-ir-rx.ko提供不同设备地址的命令码对应的系统按键。其中xxxx为设备地址码。

通过cat /proc/kmsg 可以实时查看sunxi-ir-rx.ko接收到的数据。

sunxi-ir-rx.ko中默认编译可以最大存储16个不同设备地址的映射,因此,文件夹中最多可能存在16个不同的设备地址映射文件。

一例多系统共存下的无陨迁移

四年前买的固态如今不知道什么原因,开机会有一定概率主板检测不到固态,需要多次重启才检测到。

然而最近这种情况概率越来越大了,于是决定换一块三星的,毕竟数据重要。现在的固态价格比起四年前大约降低了一倍多,可能是TLC技术的普及吧。

系统环境

原系统使用了128G固态msata接口+500G机械,都使用的是GPT分区。原来加固态的时候就把机械上的Windows迁移到到固态,顺便把MBR分区转成了GPT,以兼容UEFI启动。

其中固态上为了三个分区,分别为(EFI分区,windows系统区,Ubuntu分区),机械硬盘5个分区,分别为(EFI分区,MacOS分区(原windows所在)以及D,E,F分区)

迁移环境

现在新换的固态为120G,原机械硬盘内容不动。需要将旧固态内容迁移到新固态。

Tag "DisCourse":

多站共存的Nginx配置下使用腾讯云CDN加速Discourse出现乱码的问题

上文讲述了在国内环境下加速Discourse的部署过程。

Discourse官方并不建议在同一主机上部署多个站点,但也提供了方案:Running other websites on the same machine as Discourse

按照官方的提供方案部署,通常可以正常将Discourse运行在standlone模式下,再通过Nginx反代访问。https的实现通过certbot也可以简单完成。

以下是nginx配置exsample:

在国内环境下安装Discourse

Discourse的版本升级与维护都是基于github来完成的,而Discourse本身又是基于ruby编写。

使用包括腾讯云的CVM、轻量服务器以及阿里云的ECS都存在国外网站访问慢的问题,主要是为了扶持国内git仓库做的限流操作。

在clone托管在github上的discourse时,可以通过将clone链接替换github.com为github.com.cnpmjs.org来加速对github的访问,比如:

git clone https://github.com/discourse/discourse_docker.git 替换为 git clone https://github.com.cnpmjs.org/discourse/discourse_docker.git

除此之外,在运行./discourse-setup时,安装程序同样会在docker中安装一些额外的的项目,

比如:gem update,同样需要添加ruby的镜像。

可以通过修改配置文件来添加ruby镜像地址,主要涉及到的文件有

Tag "LLVM-Obfuscation":

XCode11下兼容arm64e的代码混淆编译器llvm11

对于ios程序,即使对binnary进行了加密,但启动之后加载到了memory中,还是存在一个解密的过程。 所以从源码以及编译器级别,对binary代码进行混淆是对抗安全攻击的最有效方法。

最新的apple处理器 a12 a13增加了arm64e架构,同时兼容arm64指令。

然而目前的最新的llvm-obfuscation 最高支持到llvm9,支持arm64e的llvm版本最低到llvm11。

去github上从apple的仓库中拉了llvm11的代码下来,给编译了一下,参考了现有的代码。重新实现了一个以支持arm64e。

Tag "网络应用":

群晖利用公网服务器ip中转流量与内网无缝切换

最近想起nas的公网访问一直是个问题。中转网络一直不通畅,如果走公网转nas又会过度暴露而被自动扫描攻击,导致硬盘频繁唤醒。

这里实现一套方案,利用公网服务器的ip进行流量转发,并且添加一道简单的防火墙来过滤网络扫描。可以在回家以后自行将流量切换到内网。

在使用公网ip转发的时候,流量和带宽受公网服务器上限所限制。在家中互联场景,本地路由器可以通过拦截公网ip流量,自动转发到nas。免去内外网ip来回切换的问题。

graph TD User1(["User1/Phone/PC"]) -->|Access from local NetWork| B{Router} NAS["NAS lisening:5000(http)/5001(https)"] <-->|In local NetWork| B{Router} Internet{Internet} <--> PubServer[PubServer onPort:80/443/5001] Internet <--> B{Router} User2(["User2/DS File/Photo"]) --> |Access to PubServer:5001| PubServer

主要有以下几个部分实现:

在nas上,将本地端口5000映射到公网ip上,通过 ssh -R 转发。

在计划任务中添加一个bash脚本,建立公网服务器的ssh连接用于端口转发,并设置为开机启动。内容如下:

#!/bin/bash

while true; do
sleep 1
echo "Start Port Forward 5000 @ " `date`
ssh -R 5000:127.0.0.1:5000 yourAccount@YourServer.com -C -q -N -o ServerAliveInterval=60 -o ServerAliveCountMax=10
echo "End of Port Forward 5000 @ " `date`
done;

该脚本启动后会将公网服务器所有来自5000端口的流量转发到nas本身。

5000端口为nas的http服务的连接端口,5001端口为nas的https服务的连接端口。

接下来在公网服务器上配置nginx来实现http流量转发并且配置https端口为5001,通过白名单机制将流量转发到nas。

server {
    server_name yourServerName;
    location / {

#       set $pass_url http://127.0.0.1:8000; # for enter password.
#       if ( $http_user_agent ~ 'Synology-' ) { 
#          // we can also use UA to imp more filters.
           set $pass_url http://127.0.0.1:5000;
#       }
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        include <your_list_path>/nas_allow_list.conf;
        deny all;
    }

    location /log {  // 
        set $pass_url http://127.0.0.1:8000; # for enter password
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    listen 443 ssl; # managed by Certbot
    listen 5001 ssl; # managed by Certbot
    <the ssh certs config >
}

在上述conf中/log访问点的流量反代到白名单配置程序,可以用于动态更新 nas_allow_list.conf白名单。

一个简单的基于白名单配置程序:

from werkzeug.wrappers import Request, Response
import subprocess

@Request.application
def application(request):
    auth_html = '''<body style="margin: 0;"><div style="margin: auto ; width: 100%; height:100%; border: 2px solid green; padding: 50px 0; text-align: center; "><form  method="POST">
            <input type="password" name="psw" style="line-height: 25px;" value="" required placehold="Enter Text..." />
            <input type="submit" style="width: 90px;height: 30px;" value="Submit" />
        </form></div>'''
    if request.method != "POST":
        return Response(auth_html, content_type="text/html")

    data = request.get_data(cache=False,parse_form_data=True)

    input = request.form.get("psw", None)
    if input != "<Your Pass Word>":
        return Response(auth_html[:-6] + "<red>N/a</red></div>", content_type="text/html")

    iplist = ",".join(request.access_route)
    if request.remote_addr == "127.0.0.1": // the traffic is came from nginx.
        record_addr = request.access_route
    else:
        record_addr = [request.remote_addr]
    for ipaddr in record_addr:
        ipaddr = ''.join(i for i in ipaddr if i in '0123456789.')
        # also we can use firewall to filter te trific
        #cmd = ["firewall-cmd","--zone=sszone","--add-source="+ipaddr+"/32"]
        cmd = ["bash","-c", "echo 'allow "+ipaddr+";'>> <your_list_path>/nas_allow_list.conf"]
        subprocess.check_call(cmd)
        cmd = ["nginx", "-s", "reload"]
        subprocess.check_call(cmd)

    return Response("<h1>You are grand to access, IP<" + iplist + "> has record.<h1>")

if __name__ == "__main__":
    from werkzeug.serving import run_simple
    run_simple("0.0.0.0", 8000, application, threaded=True)

在路由器配置iptables , 将内网client到公网服务器的流量直接转发到local nas:

iptables -t nat -A PREROUTING -d <yourPubServerIP> -p tcp --dport 5001 -j DNAT --to-destination <yourLocalNasIP>:5001

图片伪造技术 - 使用exiftool对图片描述信息进行增删查改

通常,一张图片本身包含其所应该包括的图像像素内容以外,还包含了很多其它描述该图片元信息,比如图片大小,图片拍摄设备,拍摄时间,焦距,地理位置等,若经过中间处理,还可能包含剪辑软件名称,版本号,版权等信息。

图片在互联网上转发的过程中,也可能经过服务器的有陨/无损压缩,格式转换,大小裁剪,水印添加。根据服务器所使用的不同处理程序也有可能对元数据进行增删改等操作。

因此简单通过分析图片的元数据可以获得除本身所能代表的信息以外,还可能可以初步确定图片是否直接来自于手机或相机拍摄,是否经过修改之类。

exIftool是一个功能强大的命令行执行工具,exiftool.org,支持对大量常见的图片格式进行操作。具体信息见其官方网站说明。

一张经过ps处理的图片文件头如下:

1_raw_meta_info_ps_processed

记一例简单web业务性能瓶颈的改造过程

web项目通常由于需求紧,任务重,在上线初期,通常不会考虑太多架构性以及可靠性的问题。因此在业务稳定增长的过程中,大多都存在一个持续优化的过程。

这里记录一下前段时间,因某业务需要,对其持续优化的过程。

业务包括两个数据部分,一个负责实时数据上报的client,一个是负责数据接收以及实时数据展示的web系统。

优化目标有两个,一个是保证实时数据从收集到展示的延迟尽可能短,另一个是提高业务的可扩展性,保证业务的吞吐量不被一台服务器瓶颈所限制。

主要的操作包括静态资源加速,数据上报通道优化,服务器分布差异导致的延迟问题等。

web服务原始架构:

Client为安装在客户终端设备中的一个程序,浏览器为客户的其它带屏终端。Web Server为部署的服务器。

登录:

Client ==(认证信息)==> Web Server ==(返回服务URL)==> Client显示

授权通过后,Client开始收集数据并上传,客户通过Client显示的URL,在浏览器中加载完素材后,便有如下数据流。

Tag "嵌入式应用":

Tag "Padavan":

在Padavan上实现支持RTSP网络摄像头的录像机功能

基于mt7621处理器的路由器通常都具有一个可扩展的USB接口,可以转接U盘,硬盘或者USB网卡之类。

既是路由器也是一个小型网络存储器,可省去额外配置一个nas,相比nas功能比较少,但也具有一定的可配置性。

这里简单介绍如何在运行类openwrt系统的路由器上实现网络录像机(NVR)的功能。

如今网络上的云摄像头已经卖到100元上下了,有萤石云摄像头,360摄像头,小米摄像头,TP-Link等,但这类型的摄像头都需要额外购买云存储服务才存储回放录像,显然这部分附加服务不具有性价比。

按照专物专用的原则,一台群晖也可以解决,但毕竟要多出一个东西。因此在路由器上实现类似NVR功能是最经济的做法。

很多云摄像头的商品描述页面,并不会直接写明支持RTSP传输,但会写支持NVR功能。

据我了解,TPLink全系均支持NVR功能,莹石云摄像机官方未显式支持但C2C/C3C/C6C等几个型号存在RTSP协议。

下面开始正文。

Tag "MT7621":

在Padavan上实现支持RTSP网络摄像头的录像机功能

基于mt7621处理器的路由器通常都具有一个可扩展的USB接口,可以转接U盘,硬盘或者USB网卡之类。

既是路由器也是一个小型网络存储器,可省去额外配置一个nas,相比nas功能比较少,但也具有一定的可配置性。

这里简单介绍如何在运行类openwrt系统的路由器上实现网络录像机(NVR)的功能。

如今网络上的云摄像头已经卖到100元上下了,有萤石云摄像头,360摄像头,小米摄像头,TP-Link等,但这类型的摄像头都需要额外购买云存储服务才存储回放录像,显然这部分附加服务不具有性价比。

按照专物专用的原则,一台群晖也可以解决,但毕竟要多出一个东西。因此在路由器上实现类似NVR功能是最经济的做法。

很多云摄像头的商品描述页面,并不会直接写明支持RTSP传输,但会写支持NVR功能。

据我了解,TPLink全系均支持NVR功能,莹石云摄像机官方未显式支持但C2C/C3C/C6C等几个型号存在RTSP协议。

下面开始正文。

Tag "IPCamera":

在Padavan上实现支持RTSP网络摄像头的录像机功能

基于mt7621处理器的路由器通常都具有一个可扩展的USB接口,可以转接U盘,硬盘或者USB网卡之类。

既是路由器也是一个小型网络存储器,可省去额外配置一个nas,相比nas功能比较少,但也具有一定的可配置性。

这里简单介绍如何在运行类openwrt系统的路由器上实现网络录像机(NVR)的功能。

如今网络上的云摄像头已经卖到100元上下了,有萤石云摄像头,360摄像头,小米摄像头,TP-Link等,但这类型的摄像头都需要额外购买云存储服务才存储回放录像,显然这部分附加服务不具有性价比。

按照专物专用的原则,一台群晖也可以解决,但毕竟要多出一个东西。因此在路由器上实现类似NVR功能是最经济的做法。

很多云摄像头的商品描述页面,并不会直接写明支持RTSP传输,但会写支持NVR功能。

据我了解,TPLink全系均支持NVR功能,莹石云摄像机官方未显式支持但C2C/C3C/C6C等几个型号存在RTSP协议。

下面开始正文。

Tag "OpenWrt":

在Padavan上实现支持RTSP网络摄像头的录像机功能

基于mt7621处理器的路由器通常都具有一个可扩展的USB接口,可以转接U盘,硬盘或者USB网卡之类。

既是路由器也是一个小型网络存储器,可省去额外配置一个nas,相比nas功能比较少,但也具有一定的可配置性。

这里简单介绍如何在运行类openwrt系统的路由器上实现网络录像机(NVR)的功能。

如今网络上的云摄像头已经卖到100元上下了,有萤石云摄像头,360摄像头,小米摄像头,TP-Link等,但这类型的摄像头都需要额外购买云存储服务才存储回放录像,显然这部分附加服务不具有性价比。

按照专物专用的原则,一台群晖也可以解决,但毕竟要多出一个东西。因此在路由器上实现类似NVR功能是最经济的做法。

很多云摄像头的商品描述页面,并不会直接写明支持RTSP传输,但会写支持NVR功能。

据我了解,TPLink全系均支持NVR功能,莹石云摄像机官方未显式支持但C2C/C3C/C6C等几个型号存在RTSP协议。

下面开始正文。

Tag "NVR":

在Padavan上实现支持RTSP网络摄像头的录像机功能

基于mt7621处理器的路由器通常都具有一个可扩展的USB接口,可以转接U盘,硬盘或者USB网卡之类。

既是路由器也是一个小型网络存储器,可省去额外配置一个nas,相比nas功能比较少,但也具有一定的可配置性。

这里简单介绍如何在运行类openwrt系统的路由器上实现网络录像机(NVR)的功能。

如今网络上的云摄像头已经卖到100元上下了,有萤石云摄像头,360摄像头,小米摄像头,TP-Link等,但这类型的摄像头都需要额外购买云存储服务才存储回放录像,显然这部分附加服务不具有性价比。

按照专物专用的原则,一台群晖也可以解决,但毕竟要多出一个东西。因此在路由器上实现类似NVR功能是最经济的做法。

很多云摄像头的商品描述页面,并不会直接写明支持RTSP传输,但会写支持NVR功能。

据我了解,TPLink全系均支持NVR功能,莹石云摄像机官方未显式支持但C2C/C3C/C6C等几个型号存在RTSP协议。

下面开始正文。

Tag "ffmpeg":

在Padavan上实现支持RTSP网络摄像头的录像机功能

基于mt7621处理器的路由器通常都具有一个可扩展的USB接口,可以转接U盘,硬盘或者USB网卡之类。

既是路由器也是一个小型网络存储器,可省去额外配置一个nas,相比nas功能比较少,但也具有一定的可配置性。

这里简单介绍如何在运行类openwrt系统的路由器上实现网络录像机(NVR)的功能。

如今网络上的云摄像头已经卖到100元上下了,有萤石云摄像头,360摄像头,小米摄像头,TP-Link等,但这类型的摄像头都需要额外购买云存储服务才存储回放录像,显然这部分附加服务不具有性价比。

按照专物专用的原则,一台群晖也可以解决,但毕竟要多出一个东西。因此在路由器上实现类似NVR功能是最经济的做法。

很多云摄像头的商品描述页面,并不会直接写明支持RTSP传输,但会写支持NVR功能。

据我了解,TPLink全系均支持NVR功能,莹石云摄像机官方未显式支持但C2C/C3C/C6C等几个型号存在RTSP协议。

下面开始正文。

Tag "生物实验":

一款小型哺乳动物仓笼体温监测与活动检测的装置以及部署方案

本方案使用物联网技术,通过高精度嵌入式红外摄像头,持续采集仓笼内热源信号,以及动物运动状态,使用嵌入式MCU对感知数据进行前端采集与简单分析,通过Wifi网络上传到数据中心,可形成数据汇总,采集时间跨度短可几周,长则跨年。装置。可按照需求,定制化按时按天按月或按年,生成可视化温度变化曲线,成本低廉,可供学术研究参考,或生物实验佐证使用。

单套设备仅需人民币300~500左右,约合美元60~80,成本低廉。对于单个仓笼,可同时部署多套设备,多套设备数据融合处理,以达到最佳采样角度,确保检测无死角。

方案包含完整装置采购清单,设备运行程序以及设备程序烧录指导,设备联网方法,现场部署指导等一系列指导文档,以及售后指导服务。

方案主体框架如下:

system_flow

一些国内用户的使用范例:

example_all

view_2

example_view

类似竞品论文参考:

https://journals.plos.org/plosbiology/article?id=10.1371/journal.pbio.3000406 http://journals.plos.org/plosbiology/article/asset?unique&id=info:doi/10.1371/journal.pbio.3000406.s014

合作洽谈可联系:iziy#mypre.cn / c834606877#163.com

Tag "心情日记":

传统文化之偏见

我对传统文化的偏见始于一部名为《天道》的电视剧,剧中主角对养儿防老问题的看法,掀开了我对传统文化的重新认识。

我所认为的传统文化,不仅限于语文教科书中儒道法默等众家,被封建帝王所用于奴隶人民的思想,还包括一部分近代,近现代以及改开之后,老一辈所灌输的某些受封建文化影响的思想。更具体的是指那部分盛行于现代生活之中的。

正如马克思所树立的形面上学的思想一样,传统文化中大部分内容是片面的,是孤立的,是静止。甚至有时候,它伪装成所谓正确的言论,印入脑中,使得无法分辨。“有朋自远方来,不亦说乎”,看起来没有错误,但它并没有强调什么是朋友,而机械式的强调对待朋友的应该友善。在如今的现实生活中,事情并不是非黑既白,人性的多样化,区分不同的人,对待不同的人使用不同的态度,显然更加重要。

因此,传统文化是片面的而非普遍的,是感性的而非理性的,是奴役的而非真理的。人在什么样的文化渲染下成长,便会在其文化下形成某种固有的思维方式,并形成群体性思想。在群体性思想的渲染下,又会反过来影响个人。

我认为文化的作用,应该是对人的方方面面有所启发,引发人的思考,塑造人的价值观,真理观。

我们国家的社会发展,从过去到今天,社会决策,政府运作,也大多在这种文化渲染下进行。一些人口中的政治正确,在一定程序上也就成了传统文化正确。为此,我们是否应该反思,在工业自动化,农业自动化经历了高速发展的今天,人的基本物质得到极大保障的今天,传统文化是否还能肩负得起,解决现代社会问题的重任?

下面总结一些,我认为的传统文化的某些观点,具有误导性,或者不满足现代社会下的应用。

Tag "生活随笔":

传统文化之偏见

我对传统文化的偏见始于一部名为《天道》的电视剧,剧中主角对养儿防老问题的看法,掀开了我对传统文化的重新认识。

我所认为的传统文化,不仅限于语文教科书中儒道法默等众家,被封建帝王所用于奴隶人民的思想,还包括一部分近代,近现代以及改开之后,老一辈所灌输的某些受封建文化影响的思想。更具体的是指那部分盛行于现代生活之中的。

正如马克思所树立的形面上学的思想一样,传统文化中大部分内容是片面的,是孤立的,是静止。甚至有时候,它伪装成所谓正确的言论,印入脑中,使得无法分辨。“有朋自远方来,不亦说乎”,看起来没有错误,但它并没有强调什么是朋友,而机械式的强调对待朋友的应该友善。在如今的现实生活中,事情并不是非黑既白,人性的多样化,区分不同的人,对待不同的人使用不同的态度,显然更加重要。

因此,传统文化是片面的而非普遍的,是感性的而非理性的,是奴役的而非真理的。人在什么样的文化渲染下成长,便会在其文化下形成某种固有的思维方式,并形成群体性思想。在群体性思想的渲染下,又会反过来影响个人。

我认为文化的作用,应该是对人的方方面面有所启发,引发人的思考,塑造人的价值观,真理观。

我们国家的社会发展,从过去到今天,社会决策,政府运作,也大多在这种文化渲染下进行。一些人口中的政治正确,在一定程序上也就成了传统文化正确。为此,我们是否应该反思,在工业自动化,农业自动化经历了高速发展的今天,人的基本物质得到极大保障的今天,传统文化是否还能肩负得起,解决现代社会问题的重任?

下面总结一些,我认为的传统文化的某些观点,具有误导性,或者不满足现代社会下的应用。

Tag "应用技巧":

图片伪造技术 - 使用exiftool对图片描述信息进行增删查改

通常,一张图片本身包含其所应该包括的图像像素内容以外,还包含了很多其它描述该图片元信息,比如图片大小,图片拍摄设备,拍摄时间,焦距,地理位置等,若经过中间处理,还可能包含剪辑软件名称,版本号,版权等信息。

图片在互联网上转发的过程中,也可能经过服务器的有陨/无损压缩,格式转换,大小裁剪,水印添加。根据服务器所使用的不同处理程序也有可能对元数据进行增删改等操作。

因此简单通过分析图片的元数据可以获得除本身所能代表的信息以外,还可能可以初步确定图片是否直接来自于手机或相机拍摄,是否经过修改之类。

exIftool是一个功能强大的命令行执行工具,exiftool.org,支持对大量常见的图片格式进行操作。具体信息见其官方网站说明。

一张经过ps处理的图片文件头如下:

1_raw_meta_info_ps_processed

Tag "Synology":

群晖利用公网服务器ip中转流量与内网无缝切换

最近想起nas的公网访问一直是个问题。中转网络一直不通畅,如果走公网转nas又会过度暴露而被自动扫描攻击,导致硬盘频繁唤醒。

这里实现一套方案,利用公网服务器的ip进行流量转发,并且添加一道简单的防火墙来过滤网络扫描。可以在回家以后自行将流量切换到内网。

在使用公网ip转发的时候,流量和带宽受公网服务器上限所限制。在家中互联场景,本地路由器可以通过拦截公网ip流量,自动转发到nas。免去内外网ip来回切换的问题。

graph TD User1(["User1/Phone/PC"]) -->|Access from local NetWork| B{Router} NAS["NAS lisening:5000(http)/5001(https)"] <-->|In local NetWork| B{Router} Internet{Internet} <--> PubServer[PubServer onPort:80/443/5001] Internet <--> B{Router} User2(["User2/DS File/Photo"]) --> |Access to PubServer:5001| PubServer

主要有以下几个部分实现:

在nas上,将本地端口5000映射到公网ip上,通过 ssh -R 转发。

在计划任务中添加一个bash脚本,建立公网服务器的ssh连接用于端口转发,并设置为开机启动。内容如下:

#!/bin/bash

while true; do
sleep 1
echo "Start Port Forward 5000 @ " `date`
ssh -R 5000:127.0.0.1:5000 yourAccount@YourServer.com -C -q -N -o ServerAliveInterval=60 -o ServerAliveCountMax=10
echo "End of Port Forward 5000 @ " `date`
done;

该脚本启动后会将公网服务器所有来自5000端口的流量转发到nas本身。

5000端口为nas的http服务的连接端口,5001端口为nas的https服务的连接端口。

接下来在公网服务器上配置nginx来实现http流量转发并且配置https端口为5001,通过白名单机制将流量转发到nas。

server {
    server_name yourServerName;
    location / {

#       set $pass_url http://127.0.0.1:8000; # for enter password.
#       if ( $http_user_agent ~ 'Synology-' ) { 
#          // we can also use UA to imp more filters.
           set $pass_url http://127.0.0.1:5000;
#       }
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        include <your_list_path>/nas_allow_list.conf;
        deny all;
    }

    location /log {  // 
        set $pass_url http://127.0.0.1:8000; # for enter password
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    listen 443 ssl; # managed by Certbot
    listen 5001 ssl; # managed by Certbot
    <the ssh certs config >
}

在上述conf中/log访问点的流量反代到白名单配置程序,可以用于动态更新 nas_allow_list.conf白名单。

一个简单的基于白名单配置程序:

from werkzeug.wrappers import Request, Response
import subprocess

@Request.application
def application(request):
    auth_html = '''<body style="margin: 0;"><div style="margin: auto ; width: 100%; height:100%; border: 2px solid green; padding: 50px 0; text-align: center; "><form  method="POST">
            <input type="password" name="psw" style="line-height: 25px;" value="" required placehold="Enter Text..." />
            <input type="submit" style="width: 90px;height: 30px;" value="Submit" />
        </form></div>'''
    if request.method != "POST":
        return Response(auth_html, content_type="text/html")

    data = request.get_data(cache=False,parse_form_data=True)

    input = request.form.get("psw", None)
    if input != "<Your Pass Word>":
        return Response(auth_html[:-6] + "<red>N/a</red></div>", content_type="text/html")

    iplist = ",".join(request.access_route)
    if request.remote_addr == "127.0.0.1": // the traffic is came from nginx.
        record_addr = request.access_route
    else:
        record_addr = [request.remote_addr]
    for ipaddr in record_addr:
        ipaddr = ''.join(i for i in ipaddr if i in '0123456789.')
        # also we can use firewall to filter te trific
        #cmd = ["firewall-cmd","--zone=sszone","--add-source="+ipaddr+"/32"]
        cmd = ["bash","-c", "echo 'allow "+ipaddr+";'>> <your_list_path>/nas_allow_list.conf"]
        subprocess.check_call(cmd)
        cmd = ["nginx", "-s", "reload"]
        subprocess.check_call(cmd)

    return Response("<h1>You are grand to access, IP<" + iplist + "> has record.<h1>")

if __name__ == "__main__":
    from werkzeug.serving import run_simple
    run_simple("0.0.0.0", 8000, application, threaded=True)

在路由器配置iptables , 将内网client到公网服务器的流量直接转发到local nas:

iptables -t nat -A PREROUTING -d <yourPubServerIP> -p tcp --dport 5001 -j DNAT --to-destination <yourLocalNasIP>:5001

记一次黑群晖系统升级失败之后的数据恢复

最近折腾了一下群晖系统的硬盘休眠, 由于不小心动到了硬盘的RAID设置, 导致系统认定系统盘和数据盘中的系统出现了diverge. 重启之后, 提示需要重装安装系统, 重装失败后系统丢失.

群晖系统要求的重装安装时,操作界面给出了两个选项: 迁移和重新安装.

群晖崩溃出现的安装界面

虽然都提示数据不会改动, 因此没有太在意细节 . 而不小心点到了重新安装, 并且选到了自动更新,(没有手动从官网下载安装包), 没想到安装包没自动下载成功, 直接就安装失败了. 当时也没管,直接强制断电关机睡觉了(这也许是最好的保护软件损毁数据的方法), (原本只需抹去并从启动盘中重新sync一份系统到数据盘, 现在事情弄复杂了.)

第二天起来,发现惊奇的是, 群晖已经将所有系统整个/dev/dm0格式化了.. 格式化这种敏感的操作, 居然不是放在最后等必要条件准备就绪才做. 这波操作让人着迷, 恐怕只有印度小伙能干出来.

Linux数据救援不同于win平台使用PE, 搜寻了一蕃LiveCD的解决方案, systemrescue(https://www.system-rescue.org/) 看起来可以不错,后续使用过程中也都满足了需求,.

基本的disk io操作工具都有,包括testdisk, photorec, parted, mdadm, cifs.

注意: Ubuntu的server版liveCD似乎由于内核没有编译RAID模块, 无法操作raid分区, 已踩坑,不建议用作数据救援.

Tag "群晖系统":

群晖利用公网服务器ip中转流量与内网无缝切换

最近想起nas的公网访问一直是个问题。中转网络一直不通畅,如果走公网转nas又会过度暴露而被自动扫描攻击,导致硬盘频繁唤醒。

这里实现一套方案,利用公网服务器的ip进行流量转发,并且添加一道简单的防火墙来过滤网络扫描。可以在回家以后自行将流量切换到内网。

在使用公网ip转发的时候,流量和带宽受公网服务器上限所限制。在家中互联场景,本地路由器可以通过拦截公网ip流量,自动转发到nas。免去内外网ip来回切换的问题。

graph TD User1(["User1/Phone/PC"]) -->|Access from local NetWork| B{Router} NAS["NAS lisening:5000(http)/5001(https)"] <-->|In local NetWork| B{Router} Internet{Internet} <--> PubServer[PubServer onPort:80/443/5001] Internet <--> B{Router} User2(["User2/DS File/Photo"]) --> |Access to PubServer:5001| PubServer

主要有以下几个部分实现:

在nas上,将本地端口5000映射到公网ip上,通过 ssh -R 转发。

在计划任务中添加一个bash脚本,建立公网服务器的ssh连接用于端口转发,并设置为开机启动。内容如下:

#!/bin/bash

while true; do
sleep 1
echo "Start Port Forward 5000 @ " `date`
ssh -R 5000:127.0.0.1:5000 yourAccount@YourServer.com -C -q -N -o ServerAliveInterval=60 -o ServerAliveCountMax=10
echo "End of Port Forward 5000 @ " `date`
done;

该脚本启动后会将公网服务器所有来自5000端口的流量转发到nas本身。

5000端口为nas的http服务的连接端口,5001端口为nas的https服务的连接端口。

接下来在公网服务器上配置nginx来实现http流量转发并且配置https端口为5001,通过白名单机制将流量转发到nas。

server {
    server_name yourServerName;
    location / {

#       set $pass_url http://127.0.0.1:8000; # for enter password.
#       if ( $http_user_agent ~ 'Synology-' ) { 
#          // we can also use UA to imp more filters.
           set $pass_url http://127.0.0.1:5000;
#       }
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        include <your_list_path>/nas_allow_list.conf;
        deny all;
    }

    location /log {  // 
        set $pass_url http://127.0.0.1:8000; # for enter password
        proxy_pass $pass_url;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    listen 443 ssl; # managed by Certbot
    listen 5001 ssl; # managed by Certbot
    <the ssh certs config >
}

在上述conf中/log访问点的流量反代到白名单配置程序,可以用于动态更新 nas_allow_list.conf白名单。

一个简单的基于白名单配置程序:

from werkzeug.wrappers import Request, Response
import subprocess

@Request.application
def application(request):
    auth_html = '''<body style="margin: 0;"><div style="margin: auto ; width: 100%; height:100%; border: 2px solid green; padding: 50px 0; text-align: center; "><form  method="POST">
            <input type="password" name="psw" style="line-height: 25px;" value="" required placehold="Enter Text..." />
            <input type="submit" style="width: 90px;height: 30px;" value="Submit" />
        </form></div>'''
    if request.method != "POST":
        return Response(auth_html, content_type="text/html")

    data = request.get_data(cache=False,parse_form_data=True)

    input = request.form.get("psw", None)
    if input != "<Your Pass Word>":
        return Response(auth_html[:-6] + "<red>N/a</red></div>", content_type="text/html")

    iplist = ",".join(request.access_route)
    if request.remote_addr == "127.0.0.1": // the traffic is came from nginx.
        record_addr = request.access_route
    else:
        record_addr = [request.remote_addr]
    for ipaddr in record_addr:
        ipaddr = ''.join(i for i in ipaddr if i in '0123456789.')
        # also we can use firewall to filter te trific
        #cmd = ["firewall-cmd","--zone=sszone","--add-source="+ipaddr+"/32"]
        cmd = ["bash","-c", "echo 'allow "+ipaddr+";'>> <your_list_path>/nas_allow_list.conf"]
        subprocess.check_call(cmd)
        cmd = ["nginx", "-s", "reload"]
        subprocess.check_call(cmd)

    return Response("<h1>You are grand to access, IP<" + iplist + "> has record.<h1>")

if __name__ == "__main__":
    from werkzeug.serving import run_simple
    run_simple("0.0.0.0", 8000, application, threaded=True)

在路由器配置iptables , 将内网client到公网服务器的流量直接转发到local nas:

iptables -t nat -A PREROUTING -d <yourPubServerIP> -p tcp --dport 5001 -j DNAT --to-destination <yourLocalNasIP>:5001

记一次黑群晖系统升级失败之后的数据恢复

最近折腾了一下群晖系统的硬盘休眠, 由于不小心动到了硬盘的RAID设置, 导致系统认定系统盘和数据盘中的系统出现了diverge. 重启之后, 提示需要重装安装系统, 重装失败后系统丢失.

群晖系统要求的重装安装时,操作界面给出了两个选项: 迁移和重新安装.

群晖崩溃出现的安装界面

虽然都提示数据不会改动, 因此没有太在意细节 . 而不小心点到了重新安装, 并且选到了自动更新,(没有手动从官网下载安装包), 没想到安装包没自动下载成功, 直接就安装失败了. 当时也没管,直接强制断电关机睡觉了(这也许是最好的保护软件损毁数据的方法), (原本只需抹去并从启动盘中重新sync一份系统到数据盘, 现在事情弄复杂了.)

第二天起来,发现惊奇的是, 群晖已经将所有系统整个/dev/dm0格式化了.. 格式化这种敏感的操作, 居然不是放在最后等必要条件准备就绪才做. 这波操作让人着迷, 恐怕只有印度小伙能干出来.

Linux数据救援不同于win平台使用PE, 搜寻了一蕃LiveCD的解决方案, systemrescue(https://www.system-rescue.org/) 看起来可以不错,后续使用过程中也都满足了需求,.

基本的disk io操作工具都有,包括testdisk, photorec, parted, mdadm, cifs.

注意: Ubuntu的server版liveCD似乎由于内核没有编译RAID模块, 无法操作raid分区, 已踩坑,不建议用作数据救援.