分类目录归档:未分类

F2 Status

返回当前目录或者当前应用的相关信息

按照应用规范,这个命令可能用来指出 在UICC的应用的初始化过程已经成功执行,或者终止过程即将执行。

注意:这个之事,也可能用来同步终端和UICC上的应用。

P1 = 0 没有额外的指示,仅仅想知道卡还在不在

P1 = 1 当前应用 已经在终端被初始化(也就是准备好让这张卡入网)

P1= 2 终端准备 关闭uicc上的应用

p2=0 Response parameters and data are identical to the response parameters and data of the SELECT command

p2 =1 The DF name TLV-object of the currently selected application is returned

p2 =c 不要返回额外的数据,我就是看看卡还在不在

6FAD

此EF包含有关操作模式(按照usim类型而不同的模式)的信息。

正常模式(用户登录3GPP网络)

型号批准(在型号批准过程中,允许ME的特定的使用)

基站小区测试(在某个小区在商用之前,进行测试)

制造商特定的用途(允许ME制造商执行专有的自动测试,例如维护阶段)

此文件的内容至少为4个字节,其中前4个字节的含义

1字节 UE operation mode
00 = 正常模式
80 = 类型批准操作
01 = 正常模式+特定设施
81 = 型号批准操作 + 特定
02 = 维护(离线)
04 = 小区测试操作

2-3字节 Additional information
UE操作模式的额外信息
4字节 length of MNC in the IMSI

如果 service n°130 is “available”, 那么这个字节为0
否则,应该为 2 或者 3 表示 MNC的长度为2 或者 3

130号服务是 Support for SUPI of type NSI or GLI or GCI

如130号服务可用,那么 EF_IMSI (6F07)就不应该存在

proactive UICC command通用元素

1命令编号

命令编号是为了满足未来可能出现的多个正在进行的命令(UICC在收到对正在进行的命令的响应之前,发出进一步的命令)。在toolkit规范的这个阶段,还没有对这种多个命令的含义进行详细说明。

在卡会话期间,有主动UICC发出的每个命令都应该有自己的命令编号。编号可以为在01-FE之间的任何十六进制值。命令编号保存在 “命令详细信息”数据对象中.

UICC负责分配命令编号。终端应该记录每条命令的状态和命令编号,直到终端使用TERMINAL RESPONSE向UICC发出命令的结果。

此后,终端可能会擦除有关此命令的所有内部记录。此命令编号可以由UICC分配给新的命令。

UICC Maximum Power Consumption

跟EF_DIR, EF_ICCID, EF_PL, EF_ARR一样, EF_UMPC也是一个应用无关的文件

放在MF(3F00)下

很多卡上实际没有这个文件

虽然规范是要求这个文件 必须存在

电信卡有这个文件

FCP: 62198205422100093283022F088A01058B032F0605800201C28800

62 19

82 05 42(工作EF,线性固定,共享) 21 00 09(记录长度) 32 (记录个数)

83 02 2F08

8A 01 05 (生命周期:激活)

8B 03 2F0605

80 02 01 C2 (文件大小)

88 00 (无SFI)

3F00 2FE2 0000000001

3F00 7F20 6F20 000000

3F00 7F25 6F31 000001

3F00 7FF1 6F31 000001

3F00 7FF1 6F46 000001

看来这个文件被挪做他用了

rust拼接切片(concatenate two slices /join two slices as a new slice)

如果都是vector,可以用vector自带的append方法 或者 Extend trait 或者slice的concat方法

fn main() {
    let mut a = vec![1, 2, 3];
    let mut b = vec![4, 5, 6];

    a.append(&mut b);

    assert_eq!(a, [1, 2, 3, 4, 5, 6]);
    assert_eq!(b, []);
}
或者
fn main() {
    let mut a = vec![1, 2, 3];
    let b = vec![4, 5, 6];

    a.extend(b);
    assert_eq!(a, [1, 2, 3, 4, 5, 6]);
}
或者

fn main() {
    let mut a = vec![1, 2, 3];
    let b = vec![4, 5, 6];

    [a, b].concat()
    assert_eq!(a, [1, 2, 3, 4, 5, 6]);
}

用extend_from_slice

fn cat<T: Clone>(a: &[T], b: &[T]) -> Vec<T> {
let mut v = Vec::with_capacity(a.len() + b.len());
v.extend_from_slice(a);
v.extend_from_slice(b);
v
} 或者
fn join<T: Clone>(a: &[T], b: &[T]) -> Vec<T> { a.iter().cloned().chain(b.iter().cloned()).collect() }
或者 fn join<T: Clone>(a: &[T], b: &[T]) -> Vec<T> { let mut v = a.to_vec(); v.extend_from_slice(b); v }

rust得到变量的类型和占用空间的大小

两种写法
1. 直接打印

fn print_type_of<T>(_: &T) {
    println!( "{}", std::any::type_name::<T>()   );
}

或者
fn print_type_of<T>(_: T) {
    println!("{}", std::any::type_name::<T>());
}
上面那种,传 引用,  
下面这种,直接传值, 会转移所有权

2. 返回字符串

fn type_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
} 或者 fn type_of<T>(_: &T) -> &'static str { std::any::type_name::<T>() } 也是 转移所有权的区别 调用示范: println!("{}", type_of(&x));

3.其他方法 (新功能https://github.com/rust-lang/rust/issues/66359)

use std::any::type_name_of_val;
let x = 1;
println!("{}", type_name_of_val(&x));

4.基本类型:
1)整数:
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128

2)浮点数:
f32, f64

3)逻辑数(布尔类型)
true, false

4)字符 (char)

let alphabet:char = 'A';
let emoji:char = '😁';

5)数组 array

6) 元组 tuple

5. 完整代码

fn type_of(_: &T) -> &'static str {
    std::any::type_name::()
}


fn main() {
    let buff = [0x21 as u8, 0x22, 0x23, 0x24];

    println!("{}", type_of(&buff));
}

运行结果:
[u8; 4]

6. 得到占用空间的大小

fn main() {
    fn size_of_val<T>(_: &T) -> usize {
        std::mem::size_of::<T>()
    }
    
    let arr = [0u8; 4];
    println!("size_of arr: {}", size_of_val(&arr));
}

7. 图示

Rust Container cheat sheet

rust的数组array向量vector切片slice字符串str

1. 数组 array
Rust 中的数组是固定长度的:一旦声明,它们的长度不能增长或缩小。

let a = [1, 2, 3, 4, 5];
let a: [i32; 5] = [1, 2, 3, 4, 5];
let a = [3; 5];
let a = [3, 3, 3, 3, 3];

当你想要在栈(stack)而不是在堆(heap)上为数据分配空间,或者是想要确保总是有固定数量的元素时,数组非常有用。
正是因为array存储在stack上,所以必须固定大小。

2.切片 slice
slice是没有所有权的,它引用集合中一段连续的元素序列,而不用引用整个集合。

let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];

3.基础类型字符串 str

str 本质也是表示一段 u8 序列,只是附带了额外的要求:这些 u8 序列必须是合法的 utf-8 编码

str 类型,也称为字符串切片(string slice),是最基本的字符串类型。它通常以借用的形式出现, 它们是一些储存在别处的 UTF-8 编码字符串数据的引用。它也是字符串字面值(string literals)的类型,  也就是 &'static str

字符串字面值:


let s = "Hello, world!";

这里 s 的类型是 &str:它是一个指向二进制程序(binary executes)特定位置的 slice。这也就是为什么字符串字面值是不可变的;&str 是一个不可变引用。

&str 占用 16 个字节,除了 8 个字节代表其指向的第一个字节的地址之外,还有 8 个字节代表其所涵盖的字节长度(所以 &str 又被称为胖指针

4. 向量 vector

Vec 本质是一个指针,所以 Vec 变量是定长的,可以在Stack上存储;它指向Heap的一段具有相同类型的数据序列

5. String

String本质是Vec<u8>,  同str一样, 要求Heap中的u8序列是合法的utf编码

用代码查看类型

fn type_of<T>(_: T) -> &'static str {
     std::any::type_name::<T>()
}

fn main() {
    let x = 21;
    let y = 2.5;
    let strz = "abcd";
    let str_slice = &strz[1..3];
    
    let array_ref =  b"abcd";
    let array_slice = &array_ref[1..3];
    
    let arr = [0x61 as u8, 0x62, 0x63, 0x64];
    let arr_slice = &arr[1..3]; 

    println!("{}", type_of(&y));
    println!("{}", type_of(x));
    println!("str= {}", type_of(strz));
    println!("str slice= {}", type_of(str_slice));
    println!("array ref ={}", type_of(array_ref));
    println!("array slice= {}", type_of(array_slice)); 
    println!("String={}", type_of(String::from(strz)));
    println!("array={}", type_of(arr)); 
    println!("arr slice={}", type_of(arr_slice)); 
    println!("vec={}", type_of(vec![0x61 as u8, 0x62, 0x63, 0x64]));
    println!("{}", type_of(main));
    println!("{}", type_of(type_of::<u8>));

}


运行结果
&f64
i32
str= &str
str slice= &str
array ref =&[u8; 4]
array slice= &[u8]
String=alloc::string::String
array=[u8; 4]
arr slice=&[u8]
vec=alloc::vec::Vec<u8>
vexample::main
vexample::type_of<u8>

从Rust中调用C代码

unsafe关键字

0. 新建一个InvokeC的工程

cargo new  InvokeC

1.编辑 src/main.c

extern "C" {
    fn doubler(x: i32) -> i32;
}

fn main() {
    println!("[rust] start");
    unsafe { 
        println!("{}", doubler(6));
    }
}

2. 编辑 src/hello.c

#include stdio.h

int doubler(int x) {
    return x * 2;
}

3.编译C代码

$ cc -c src/hello.c
$ cc -shared hello.o -o libnum.so

4.用rustc 编译代码,并动态链接到 libnum

rustc -l num -L . src/main.rs

5. 运行

LD_LIBRARY_PATH=.  ./main

如果不设置 LD_LIBRARY_PATH 变量, 将会找不到 libnu.so 动态库

6. 也考虑生成静态库

$  ar rcs libnum.a   hello.o

7.链接到静态库

rustc -l static=num -L. src/main.rs  

8.直接运行

./main

9. 如何不用rustc编译, 而是用cargo build或者cargo run
在项目的根目录下,建立一个 build.rs 文件

fn main() {
    println!("cargo:rustc-link-search=.");
    println!("cargo:rustc-link-lib=static=num");
}

就可以了
如果是动态库

    println!("cargo:rustc-link-search=all=src");      //  类似"rustc -L src ..." 
    println!("cargo:rustc-link-lib=dylib=num"); // 类似"rustc -l num"

或者在源代码中 指定链接选项
main.c中

#[link(name = "num", kind = "static")]
extern "C" {
    fn doubler(x: i32) -> i32;
}
...

就可以把 build.rs中

println!("cargo:rustc-link-lib=static=num");

这一行去掉

最后,如果连编译C代码都不想手动去做,可以用一个 cc的库, 在Cargo.toml中添加

[build-dependencies]
cc = "1.0"

注意:是 build-dependencies 而不是 dependencies

然后,将 build.rs改为

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("libnum.a");
}

或者

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("anything");
}

adb push照片并用广播更新相册媒体库

上传到 /sdcard/Pictures/up 目录

adb push   front.jpg   /sdcard/Pictures/up

广播通知

adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE   -d file:///storage/emulated/0/Pictures/up/front.jpg
或者
adb shell am broadcast -a android.intent.action.MEDIA_MOUNTED             -d file:///storage/emulated/0/Pictures/up

Linux设备上的永久或半永久ID

用来唯一地识别机器
1. 网卡MAC
MAC地址本来是永久地保存在 网卡的EEPROM里的,通过驱动程序读取出来,该地址放在 Link层用来识别自身。但是驱动程序可以用
自己配置的MAC地址,而不是从网卡芯片读取的
缺点:
1) 有些机器上没有网卡
2) 通ifconfig命令 可以修改地址
命令:

ifconfig eth0
ip link show eth0
cat /sys/class/net/eth0/address 

2. 存储芯片ID
/sys/block/mmcblk2/device/cid

Name Field Linux attribute* Description
Manufacturer ID MID manfid Assigned by SD-3C, LLC.
OEM/Application ID OID oemid Identifies the card OEM and/or the card contents. Assigned by SD-3C, LLC.
Product Name PNM name 5 characters long (ASCII)
Product Revision PRV hwrev, fwrev Two binary coded decimal (BCD) digits. Each is four bits. The PRV is in the form x.y. The PRV can also be found by using the hwrev and fwrev, where x=hwrev and y=fwrev
Serial Number PSN serial This 32 bit field is intended to be read as an unsigned integer
Manufacture Date Code MDT date Manufacture date is stored in the form yym (offset from 2000)
CRC7 checksum CRC 7 bit code used for checking errors in the card register

这个比较难修改,除非修改内核

3. 存储分区ID
文件系统分区时生成的ID, 可以通过分区程序等进行修改

blkid
fdisk -l /dev/mmcblk2

PTUUID
PARTUUID
UUID

4. 安装系统时生成的machine-id
/var/lib/dbus/machine-id
/etc/machine-id
缺点: 非常容易被root权限用户修改

5. 内核随机UUID

/proc/sys/kernel/random/uuid
/proc/sys/kernel/random/boot_id

每次重启会变

6. USB设备的序列号
存在USB设备的EEPROM中
/sys/bus/usb/devices/*/serial

cat  sys/bus/usb/devices/1-4.3/serial

缺点:
1) USB设备是可以热插拔的
2) 有些设备没有序列号,另外有些设备的序列号是伪造的,同一批设备都是一样的