转载一个 css3 的自定义滚动条~
1 | ::-webkit-scrollbar { |
转载一个 css3 的自定义滚动条~
1 | ::-webkit-scrollbar { |
ARM 的引脚定义
二、标准 JTAG 20 PIN 信号定义
1 | 1. VCC 3. VCC |
三、标准 SWD 20 PIN 信号定义
1 | 1. VCC 3. VCC |
关于值语义和对象语义
说个在 c 艹中经常遇见的问题.
在 c++ 中和 c# 和 java 不很一样. 它允许程序员定义一个类的复制构造函数和复制赋值运算符, 这就表明对象是可以复制的. (这里的复制的意思是克隆一个完全一致, 但却是一个新的个体的对象)
这就允许程序员把对象当成值一样来使用, 例如:
1 | string a = "hahaha"; |
在这段代码中, string 和 int 使用起来没有差别, 令 j = i 确实是在内存上新申请了一个 int 的空间, 令他和 i 相等. 同理 string b 也是这样.(也就是复制之后和原对象脱离关系, 就像复制 int 一样)
虽然我知道 string 使用 class 来定义的, int 是 c 语言内置类型, 但是用起来却是完全一致.
另外, 你可以吧 string 放入 vector 中放入 map 中, 就和使用一个 int 一样简单.
所以 string 可以说是值语义的.
另外的一种用法就是在面向对象中比较常见的一种了. 就是用 class 定义一个具体的对象, 比如一个 TCP 连接, 一个文件对象.
我在前几天写程序时想要简单封装一个 tcp 连接的时候, 就陷入了一会遐想, 到底怎么定义复制构造函数和复制运算符. 答案是不要定义
因为复制一个对象在语义上本身就是不对的, 复制一个 tcp 连接是什么意思? 新打开一个连接?
所以说对于这种对象应该禁止他们的复制操作. 最好的方法是继承 boost::noncopyable.
那么, 不能复制了, 我想把 tcp 连接放入 vector 或者在函数中传递怎么办? 我是用的方法是统一使用 shared_ptr, 这样资源泄漏的问题也就解决了.
所以, 在实现一个资源相关的类时, 用 RAII 方法封装一下资源, 然后继承 noncopyable 应该能解决大部分问题.
最近猎豹 wifi 共享精灵推出了一个 wifi 控制关机的功能. 我因为没有笔记本一直都用台式机 + linux nat + 无线 ap 来实现 wifi 共享 (见上次用虚拟机建立 NAT 曲线共享上网的经历忘了记录了). 所以看到这个功能之后一直眼红的不行, 在床上看视频到两三点再下去关电脑实在是破坏幸福感的事情. 所以嘛, 就又到了自己造轮子的时间.
首先分析一下需求, 很简单就是在手机上打开一个网页可以远程控制我的台式机关机.
所以必须要有一个 web 服务器, 另外一门 web 脚本语言也是必不可少的, 而且前端网页应该尽量漂亮, 并且适配手机.
首先 web 服务器应当尽量小巧, 一开始我用 shttpd 来做, 用了一天之后发现它对 http 验证支持的不很好. 所以便放弃他选择 thttpd 了. thttpd 也很小巧而且功能更多, 并且自称性能上不弱于 Apache.
然后脚本语言, 脚本语言的话我只会 lua 和 javascript, 如果用 javascript 的话需要用到 nodejs, 可是我有点不习惯 nodejs 的异步模型和一层一层的函数嵌套. 所以还是选 lua 吧. 而且 thttpd 支持 cgi, 可以和 lua 很好的适配
ok, 下面开始搭建环境. 因为对性能的要求不高, 所以决定在 Cygwin 下运行. 下载编译 thttpd, 直接 wget->./configure –prefix/usr->make->make install 就 ok 了.
中间可能在编译 htpasswd.c 文件时提示 getline 重定义. 直接把 htpasswd.c 文件里的所有 getline 改名成_getline 即可.
安装的时候会提示没有 / usr/man/man1 文件夹, 直接 mkdir /usr/man/man1 就 ok
thttpd 支持命令行启动同时也支持配置文件. 具体可以 man thttpd 来查看. 在源码包里的./contrib/redhat-rpm 文件夹有一个例子的配置文件. 我们把它改一下放到用户目录里:
1 | # This section overrides defaults |
然后就是安装 lua 了, Cygwin 源里直接就有, 装上即可.
在用户目录里建立一个 webroot 文件夹, 网站放这里.
建立两个文件, 一个叫 index.cgi, 一个叫 shutdown.cgi 内容如下:
1 | #!/bin/lua |
1 | #!/bin/lua |
ok 了, 效果如图:
为 openwrt 编译 htop
其实就和原来给电视棒交叉编译一样, 不过这次交叉编译器可让我好找…
路由器用的是华为的 hg255d, mips 的芯片, 16M flash, 64M sdram.
一般嵌入式开发都把内核和 app 分开的… 这个 openwrt 却不单独提供 toolchain. 只给一个内核源码包 (也不只是内核, 是内核和软件包的混合体…)
不过最后还是找到一个单独的工具链:
下载地址:
有了工具链一切就好办了. htop 依赖与 ncurses 所以先下载 ncurses.
1 | mkdir openwrt |
下载好之后, 在当前目录建一个文件夹 build, 编译后的文件就安装在这里, 然后分步解压
1 | mkdir build |
然后先编译 ncurses:
1 | cd ncurses-5.9 |
后面几个 without 是去除 c++ 和 ada 支持以及不编译 manpage 和测试程序
然后就能发现在 build/lib 里有编译好的 ncurses 库了
之后编译 htop:
1 | cd htop-1.0.2 |
LDFLAGS=-L/home/zzz/openwrt/build/lib 选项是为了加上链接库的路径
短暂等待过后, 在 build/bin 里应该能看见 htop.
拿到 openwrt 上运行又发生点问题. 提示
Error opening terminal: xterm.
上网 Google 一下发现需要设置 TERMINFO 环境变量:
1 | export TERMINFO=/usr/share/terminfo |
[EOF]
自己造操作系统系列之 0.2 版
新增了信号量功能, 实现进程间同步.
zOS 暂时分成两条线, 一条是上文说的那些功能 (类似于宏内核, 加载执行)
另一条是今天发布的 zOS-mini, 只包含调度, 同步设施. 而且只需要三个文件
还是只能在 stm32 上运行
链接: https://lengzzz.com/zOS/zOS_mini-0.2.zip
下面是一个测试用例
四个线程, 以不同的时间闪烁 led, 线程间通过 sem 信号量同步:
1 |
|
enc28j60 驱动和 udp 协议栈移植到 stm32 成功
软件挂起
类型 | NMI | PendSV | SysTick |
寄存器位 | NMIPENDSET | PENDSVSET | PENDSTSET |
类型 | PendSV | SysTick |
寄存器位 | PENDSVCLR | PENDSVCLR |
中断挂起状态示意
ISRPENDING
寄存器: SCB_ICSR(Interrupt Control and state register)
类型 | Usage fault | Bus fault | mem fault |
寄存器位 | USGFAULTENA | BUSFAULTENA | MEMFAULTENA |
类型 | SVC | Bus fault | mem fault | Usage fault |
寄存器位 | SVCALLPENDED | BUSFAULTPENDED | MEMFAULTPENDED | USGFAULTPENDED |
类型 | SysTick | PendSV | Debug Monitor | SVC | Usage fault | Bus fault | Mem fault |
寄存器位 | SYSTICKACT | PENDSVACT | MONITORACT | SVCALLACT | USGFAULTACT | BUSFAULTACT | MEMFAULTACT |
寄存器: SCB_SHCSR(System handler control and state register)
一个 dump 出 scb(System control block 系统控制块) 的函数, 调试的时候有时很有用
1 | #define PRIORITY_Msk 0xF0 |
自造 UDP 协议栈
这一个星期一直在自造一个 UDP 协议栈.
今天是周五, 屁屁和室友逛街去了, 我就在寝室敲代码搞了一下午, 终于是搞定了.
这个是老师的项目里要用的, 实现 avr 的单片机和 PC 机通讯. 中间通过以太网进行连接, avr 上用的是 enc28j60 芯片. 这个芯片原来我在 C8051F 上写过一个驱动. 移植过来倒是不麻烦, 半天搞定.
麻烦的是协议栈!
原来在 51 上用的是一个我精简了的 uIP 协议栈, 因为 C8051F 系列 FLASH 足够大, 而且 ram 也大 (f340 有 4096 字节). 足够移植 uIP 过去了.
在 avr 上遇了不少麻烦.
首先就是蛋疼的 codevision 编译器乱改 C 语言, 不按标准来. const 修饰的变量没法直接访问. 移植起来很麻烦. 然后就是 uIP 的 ram 占用一直下不去. 我已经把以太网最大帧长度调成 512 了还是费了 1100 多个字节. 然后很不幸, ATMega16 只有 1024 字节的 RAM. 可恶的 uIP 竟然用去了 512 个字节… 知道 RAM 有多宝贵嘛你!
想想算了, 还是换个内存大点的吧. 周一给老师要了 ATMEGA32, 想着鸟枪换炮! 不料, 老师给了我张板子, 说” 自己焊吧”……
贴片的本身就不容易焊, 况且我烙铁吃灰 n 久了脏死了完全不想动呀! (我这个死洁癖!)
切! 想想我也是立志成为驱动工程师的男人, 这种小事应该交给硬件工程师来做嘛, 哼╭(╯^╰)╮(无任何冒犯…)
所以嘛这点困难完全难不倒我! 开源的不行我就自己写一个嘛.
自己动手丰衣足食.
↑一点都不华丽的分割线
自己造轮子的话最大的好处就是可以紧密把握需求, 只写需要的功能, 不需要的一概不写! 另外因为对内存需求比较严格, 所以这个协议栈几乎是不占内存, 除了 6 个 ip 地址 7 个 mac 地址常驻内存以外, 全部使用栈内存.
这个协议栈最大的特点就是简洁, 只有两个文件构成: udp.c, 和 udp.h
而且接口设计的也比较简洁, 只向外部提供三个函数:
1 | void init_udp(unsigned char* mac_addr, ip_t ip_addr, ip_t netmask, ip_t gateway, |
顾名思义
另外在 init_udp 函数中的三个回调函数:
1 | typedef void (*INCOMING_CALLBACK)(struct address* addr, unsigned char* buf, unsigned short len); |
分别是
INCOMING_CALLBACK 函数的 addr 参数传来对端的 ip 端口和本地端口号, buf 中的是 UDP 数据, 不包含任何报头
SENDBUF_CALLBACK 函数传来 buf, SENDBUF_CALLBACK 需要将 buf 中的数据写入一个缓冲区
(可以是硬件缓冲区
中). SENDBUF_CALLBACK 函数会被多次
调用, 应当依次将 buf 中数据写入缓冲
.
当 SENDBUF_CALLBACK 最后一次被调用时, buf 会传入 NULL
. 此时, SENDBUF_CALLBACK 函数应当将缓冲区中数据发送到以太网上
.
DELAY_CALLBACK 函数需要休眠指定的毫秒数, 如果程序运行在一个 RTOS 上的话可以调用 SLEEP 来让出处理器. 如果是裸板程序的话… 那就用循环吧 (这个协议栈在通过 arp 协议查找 mac 地址时会等待, 但最多不超过 1000 毫秒 [这个数值可以改]).
如果不能忍受等待的话, 可以将要紧任务放到中断中处理 (这个常识应该都用吧)
大致就是这样. 下午就是在板子上简单的测试了一下, 基本可用, 能收发 udp 包, 能 ping 通.
源码如下: (不做任何担保, 用了出事不怪我, 逃…
https://lengzzz.com/udp/udp-0.3.zip
最后上图: