0%

无意间发现了一个 python 版的 BLE 利器 - bluepy

简介

bluepy 是 github 上的一个开源项目,它用 python 封装了 linux 上的 BLE 接口。

作者主要基于树莓派开发,也可以运行在 x86 Debian Linux 上。

bluepy 其实是 BlueZ 的 python 封装。

阅读全文 »

Slave 通过 notification 发送 293 字节数据,ATT_MTU 为 247 字节,所以分为两次发送。

抓包看有三次 connection event,其中第二次 connection event 没有数据传输,这是为什么呢?

因为 slave 代码中调用发送 notification API 之后,要等待发送成功事件再发送下一个 notification。

而发送成功事件是在收到的下个 master 数据包的 NESN 后产生,此时 slave 看到 queue 中没有数据,就回复了 Empty PDU。

所以第三次 connection event 才将剩下的数据发送出去。

阅读全文 »

1
2
3
int8_t a = -1;
uint32_t b = a;
b = ?

这要用到整型转换规则, C Programming Language(K & R) (A.6.2)上这样解释:

将任何整数转换为某种指定的无符号数类型数的方法是:以该无符号数类型能够表示的最大值加1为模,找出与此整数同余的最小的非负值。
在对二的补码表示中,如果该无符号类型的位模式较窄,这就相当于左截取;如果该符号类型的位模式较宽,这就相当于对带符号的值进行符号扩展和对无符号的值进行0填充。

将任何整数转换为带符号类型时,如果它可以在新的类型中表示出来,则其值保持不变,否则它的值同具体的实现有关。

其中以该无符号数类型能够表示的最大值加1为模,找出与此整数同余的最小的非负值,我觉得太拗口,下面那段才比较好理解在对二的补码表示中,如果该无符号类型的位模式较窄,这就相当于左截取;如果该符号类型的位模式较宽,这就相当于对带符号的值进行符号扩展和对无符号的值进行0填充。

比如把 0x1234 放到一个 uint8_t 类型变量 x 中,那么高 8 位就被截掉,低 8 位被放到变量中,最终 x 的值为 0x34。
比如把 -1 放到 x 中,因为 -1 的二进制码是 0xFFFFFFFF,那么 x 的值就等于 0xFF。

Linux系统下一般程序的入口是_start,这个函数是Linux系统库(Glibc)的一部分。同样地,newlib等C库也是以_start作为入口函数。

对于C++程序,有两个特殊的段:.init.fini。这两个段.init和.fini的存在有着特别的目的,如果一个函数放到.init段,在main函数执行前系统就会执行它。同理,假如一个函数放到.fint段,在main函数返回后该函数就会被执行。利用这两个特性,C++的全局构造和析构函数就由此实现。

摘自维基百科

整型提升是C程序设计语言中的一项规定:在表达式计算时,各种整形首先要提升为int类型,如果int类型不足以表示则要提升为unsigned int类型;然后执行表达式的运算。[1]

这一规则是由C语言的发明人丹尼斯·里奇与肯·汤普逊创设的:[2]

A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion.

这段话的大意是:表达式中可以使用整数的地方,就可以使用枚举类型,或有符号或无符号的字符、短整数、整数位域。如果一个int可以表示上述类型,则该值被转化为int类型的值;否则,该值被转化为unsigned int类型的值。这一过程被称作integral promotion。

整型提升的意义在于:表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

在项目中遇到一个奇怪的问题,伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
int8_t  a = 0x8F;
uint8_t b = 0x8F;

if( a == b )
{
printf("a = b\n");
}
else
{
printf("a != b, a = %02x, b = %02x\n", a, b);
}

按照我的理解,if(a == b)一定为真。但运行结果却让我大跌眼镜:

a != b, a = ffffff8f, b = 8F

首先,变量a不等于b已经让我吃惊了,然后,打印出来a的值竟然是ffffff8f
查了一通资料,我才知道,原来在 C 语言中有隐式类型转换这么一个规则。
隐式类型转换是指变量在运算中的一种隐式的类型转换,主要分两种:算术赋值转换。

阅读全文 »

最近对 newlib 中的启动代码 crt0 产生了兴趣,于是就分析了下其代码。crt0 的源码位于 libgloss/arm/crt0.S,为了兼容各种 ARM 架构,crt0.S 中有大量的条件判断宏定义,对于只关心 ARMv7e-M 的我来说很是痛苦。刚好手上有个基于 STM32F412 的 mbed 工程用的是 crt0 的启动方式,参考 crt0.o 的反汇编我可以提炼出 crt0.S 中和 ARMv7e-M 相关的部分代码。

阅读全文 »