ios15.0.1真机调试支持包

Failed to prepare device for development

这个是xcode和ios设备的版本不匹配导致。需要更新xcode的设备支持包,

以下为例子,因为系统是不断升级的,具体自己对照下:

区块链杂记

DAO: Decentralized Autonomous Organization(去中心化自治组织)

瑞波币(XRP): 是瑞波(Ripple)系统内的流动性工具,是一个桥梁货币,是各类货币之间兑换的中间品

TRX: 波场币发行 波场币是由波场基金会发行的基于波场协议的主网货币,简称TRX。 TRX是TRON区块链上账户的基本单位,所有其他代币的价值均从TRON价值衍生出来,TRX也是所有基于TRC标准代币的天然桥梁货币。

TRC20:类似ERC20,是一种基于波场的转帐协议或者通道.

DXO: DeepSpace Token

L1,L2: https://www.jianshu.com/p/2c957b67fa19

其中第 0 层对应 OSI 模型的底层协议,大致包括物理层、数据链路层、网络层和传输层。第一层(Layer 1)大致包括数据层、共识层和激励层。
而第 2 层(Layer 2)则主要包括合约层和应用层。
按照这个维度来划分,像我们所熟悉的比特币网络、以太坊主网等主流公链都属于 Layer 1 的范畴。只不过,由于在当前众多的公链项目中,以太坊是运行智能合约、DAPP 最多的公链,也是锁仓资产价值和日均交易量最大的公链,所以在有关以太坊网络 Layer1 和 Layer2 不同扩容方案的讨论也是最多的,所以在本文中,如没有特殊说明,所提到的 Layer1 和 Layer2 一般以以太坊为主。
通俗来说,在以太坊网络中,Layer 1 的主要作用就是确保网络安全、去中心化及最终状态确认,做到状态共识,并作为一条公链网络中可信的“加密法院”,通过智能合约设计的规则进行仲裁,以经济激励的形式将信任传递到 Layer2 上;而 Layer2 则以追求更高效的性能为终极目标,从上面区块链技术逻辑架构示意图中,我们可以看到,作为第二层网络,可以替 Layer1 承担大部分计算工作,近年来,不少项目都是基于 Layer2 搭建的,从而将交易行为从主链上分离出来,降低一层网络的负担,提高业务处理效率,从而实现扩容。在这个过程中,Layer2 虽然只做到了局部共识,但是基本可以满足各类场景的需求。
目前行业内比较贴切的是将 Layer1 和 Layer2 的关系和中央银行与商业银行的关系来类比:把 Layer1 承担着中央银行的角色,而 layer2 则是各大商业银行。
在现行主流的金融系统中,所有的资产都必须在中央银行结算,而具体的流通过程可以同时发生在中央银行和商业银行。因为如果所有人都去央行结算的话,势必会发生业务拥堵的情况,更好的解决办法当然是由商业银行来先处理大量交易业务,然后由各个商业银行和中央银行结算一次整体业务,这样才能使得整个金融系统更加高效有序的运转起来。
所以从中我们能够得到的启示就是,对于在以太坊网络中存在的交易拥堵、手续费居高不下的问题,一个可行的解决方案就出炉了——将以太坊的资产存入 Layer2,之后的资产流动交易环节都在 Layer2 上进行,只把最终结算过程放到 Layer1 上就可以了.

区块链杂记

celr: celer network 代币,属于l2技术,主打链下链上结合,发挥链下方案的性能优势
ren: republic protocol 代币,主打私密撮合交易
rune: THOR chain的代币,主打快速结算
dydx:基于ERC20的dydx exchange平台的token,主打deFi和低手续费

docsify maxLevel subMaxLevel参数说明

maxLevel,subMaxLevel是docsify中的两个重要的参数,用来控制整个文档站左侧导航菜单的层级。

作用

maxLevel:控制着左侧的菜单的总层级.
subMaxLevel:表示由文档内容中的标题自动生成菜单的级别,从第一级起算。例如subMaxLevel取2,表示一共两级,所以实际只显示第二级(##),因为第一级默认跟外层的入口同级,显示外层的名字。

数值关系

maxLevel>=1
subMaxLevel>=1 && subMaxLevel<maxLevel

source code illustration of TLS support in esp32

嵌入式下实现TLS支持原理

我们知道要实现https,MQTT等协议时,要求通讯安全,客户端就必须实现tls证书的支持。

但是日常我们打来电脑和手机浏览器访问https网站,好像并不需要关注tls的问题?

答案是因为浏览器厂商已经帮助我们兼容好了,但当你要通过嵌入式IOT设备或者单片机实现https访问的时候,你就需要处理TLS证书的问题了。

因为ESP32的开源代码比较清晰简洁,所以我们今天的讲解,以ESP32为硬件平台。其他硬件也是类似的原理,你只要实现自己的过程,替换底层的socket接口就可以实现类似的效果。

此文通过对关键代码的详细讲解,说明在ESP32下支持TLS证书的实现原理和过程。以此原理和过程作为参考,用户也可以实现其他嵌入式硬件和单片机的TLS证书支持,因为ESP的证书的内容和代码都是源码可见的,在弄懂了后就可以很好的移植和仿制。

ESP32 HTTPS demo

官方的例子见 \examples\protocols\https_request,举例了三种支持TLS的方式:

    https_get_request_using_crt_bundle();
    https_get_request_using_cacert_buf();
    https_get_request_using_global_ca_store();

第一种是cert bundle方式,这个是今天我们重点的讲解。后两种就是使用用户指定的证书的方式,代码非常简单,就不展开了,今天主要介绍 cert bundle的方式。把cert bundle方式弄清楚了,后面两种也就清楚了,因为就是等于是cert bundle 方式的简化,简化了证书的创建,匹配和校验过程。

cert bundle的优劣

  • 优点:cert bundle的优势是不需要用户关注证书和手动下载证书,自动实现全球几乎所有TLS根证书的支持。
  • 缺点:因为内置一百多种证书,所以占用空间要大写,经过实际代码测试验证,大概大了60K左右。

ESP32 x509 Certificate Bundle

esp32 针对TLS的场景提供了x509 Certificate Bundle的实现支持,其可以简单理解为 x509证书集合。

关于x509 Certificate Bundle的详细介绍,可以参看:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/protocols/esp_crt_bundle.html

原文已经讲的非常清楚了,我们就不赘述了,今天只重点关注源码细节。

ESP32 TLS实现过程简述

  1. cert bundle 反序列化
  2. 创建空的证书
  3. 在https的访问回调中,根据cert name,查找对应的证书。
  4. 校验证书合法性
  5. 校验通过后,建立链接,进行基于tls的读写过程。
  6. 关闭链接,释放tls对象

源码分析

上面简述了整个过程,接下来我们将针对上面的步骤,对关键源码进行解析说明。

cert bundle 反序列化

外层调用:

if (s_crt_bundle.crts == NULL) {
        ret = esp_crt_bundle_init(x509_crt_imported_bundle_bin_start);
    }

参数 x509_crt_imported_bundle_bin_start 对应的值为 asm("_binary_x509_crt_bundle_start")

这个asm对象表示一段汇编代码,作用是返回x509对象数据地址,这个对象是通过python工具将cacrt_all.pem打包成二进制文件的,具体汇编的内容,可以自己参见 build目录下的 x509_crt_bundle.S汇编文件。

里层函数实现,解析注释:

static esp_err_t esp_crt_bundle_init(const uint8_t* x509_bundle)
{
    // 根据包头的两个字节获取证书个数
    s_crt_bundle.num_certs = (x509_bundle[0] << 8) | x509_bundle[1];
    s_crt_bundle.crts      = calloc(s_crt_bundle.num_certs, sizeof(x509_bundle));

    if (s_crt_bundle.crts == NULL) {
        ESP_LOGE(TAG, "Unable to allocate memory for bundle");
        return ESP_ERR_NO_MEM;
    }

    const uint8_t* cur_crt;
    cur_crt = x509_bundle + BUNDLE_HEADER_OFFSET;

    ESP_LOGW(TAG, "cert num:%d", s_crt_bundle.num_certs);

    // 根据个数一个一个的来偏移获取每个证书的内容
    for (int i = 0; i < s_crt_bundle.num_certs; i++) {
        s_crt_bundle.crts[i] = cur_crt;
        // 每个证书前面4个字节是长度信息
        size_t name_len = cur_crt[0] << 8 | cur_crt[1];
        size_t key_len  = cur_crt[2] << 8 | cur_crt[3];
        ESP_LOGW(TAG, "cert name len:%d,key len:%d", name_len, key_len);
        // 根据长度进行每个证书的偏移
        cur_crt = cur_crt + CRT_HEADER_OFFSET + name_len + key_len;
    }

    return ESP_OK;
}

这段代码的作用就是 将入参的cert bundle 地址内存,根据数据结构定义{BUNDLE_HEADER_OFFSET,{name_len,key_len, name,key}}反序列化成cert结构数组对象 s_crt_bundle。

截止本文撰写日期,esp32 实现的这个x509 cert bundle 支持135个根证书,几乎支持了全球所有的证书。

创建空的证书

mbedtls_x509_crt_init(&s_dummy_crt);
mbedtls_ssl_conf_ca_chain(ssl_conf, &s_dummy_crt, NULL);

这个空证书的作用主要是承载访问服务器时获取的服务器证书特征,这个特征会通过回调的方式传给 mbedtls_ssl_conf_verify 函数参数。

查找和校验证书

代码如下,解析见注释:

int esp_crt_verify_callback(void* buf, mbedtls_x509_crt* crt, int depth, uint32_t* flags)
{
    mbedtls_x509_crt* child = crt;

    /* It's OK for a trusted cert to have a weak signature hash alg.
       as we already trust this certificate */
    uint32_t flags_filtered = *flags & ~(MBEDTLS_X509_BADCERT_BAD_MD);

    if (flags_filtered != MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
        return 0;
    }

    if (s_crt_bundle.crts == NULL) {
        ESP_LOGE(TAG, "No certificates in bundle");
        return MBEDTLS_ERR_X509_FATAL_ERROR;
    }

    ESP_LOGD(TAG, "%d certificates in bundle", s_crt_bundle.num_certs);

    size_t name_len = 0;
    const uint8_t* crt_name;

    // start 和 end 是证书数组的index。这里实现的是二分查找算法,说明cert bundle     
    // 数组的名字是增加了排序特征的,具体细节,需要查看python的打包工具的实现代码。
    bool crt_found = false;
    int start      = 0;
    int end        = s_crt_bundle.num_certs - 1;
    int middle     = (end - start) / 2;

    /* Look for the certificate using binary search on subject name */
    while (start <= end) {
        name_len = s_crt_bundle.crts[middle][0] << 8 | s_crt_bundle.crts[middle][1];
        crt_name = s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET;

        int cmp_res = memcmp(child->issuer_raw.p, crt_name, name_len);
        if (cmp_res == 0) {
            crt_found = true;
            break;
        } else if (cmp_res < 0) {
            end = middle - 1;
        } else {
            start = middle + 1;
        }
        middle = (start + end) / 2;
    }
    // 二分查找结束

    // 校验证书合法性
    int ret = MBEDTLS_ERR_X509_FATAL_ERROR;
    if (crt_found) {
        size_t key_len = s_crt_bundle.crts[middle][2] << 8 | s_crt_bundle.crts[middle][3];
        ret = esp_crt_check_signature(child, s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET + name_len, key_len);
    }

    if (ret == 0) {
        ESP_LOGI(TAG, "Certificate validated");
        *flags = 0;
        return 0;
    }

    ESP_LOGE(TAG, "Failed to verify certificate");
    return MBEDTLS_ERR_X509_FATAL_ERROR;
}

代码很简单,注释中已经说了,就是一个二分查找过程。

校验证书合法性

相关代码在上面的部分已经注释过了,就是esp_crt_check_signature函数。校验的细节,感兴趣的朋友可以自己查看此函数源码。

TLS读写过程

写请求过程:

do {
        ret = esp_tls_conn_write(tls, REQUEST + written_bytes, sizeof(REQUEST) - written_bytes);
        if (ret >= 0) {
            ESP_LOGI(TAG, "%d bytes written", ret);
            written_bytes += ret;
        } else if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
            ESP_LOGE(TAG, "esp_tls_conn_write  returned: [0x%02X](%s)", ret, esp_err_to_name(ret));
            goto exit;
        }
    } while (written_bytes < sizeof(REQUEST));

esp_tls_conn_write根据长度来循环写。

读响应过程:

    do {
        len = sizeof(buf) - 1;
        bzero(buf, sizeof(buf));
        ret = esp_tls_conn_read(tls, (char*) buf, len);

        if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ) {
            continue;
        }

        if (ret < 0) {
            ESP_LOGE(TAG, "esp_tls_conn_read  returned [-0x%02X](%s)", -ret, esp_err_to_name(ret));
            break;
        }

        if (ret == 0) {
            ESP_LOGI(TAG, "connection closed");
            break;
        }

        len = ret;
        ESP_LOGD(TAG, "%d bytes read", len);
        /* Print response directly to stdout as it is read */
        for (int i = 0; i < len; i++) {
            putchar(buf[i]);
        }
        putchar('\n'); // JSON output doesn't have a newline at end
    } while (1);

esp_tls_conn_read 循环读,直到链接关闭为止,跳出循环

释放 tls对象:

esp_tls_conn_delete(tls);

结束

好了,整个代码过程还是封装的非常干净和清晰的,如果你需要在自己的嵌入式系统中实现TLS证书过程,那么也可以仿照以上的过程,实现自己的bundle和匹配校验过程,并且可以根据实际需要定制和优化。

希望以上的分析,能帮你快速实现自己的TLS访问功能。

letsencrypt root certification expire illustration

letsencrypt 跟证书过期更换说明

见官方的声明 https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/

今年2021.9.30后,原有的DST RootCA X3就要过期了,改成ISRG Root X1。

对于浏览器用户基本不用担心,因为浏览器厂商自动做了支持。但是对于老旧的设备和一些嵌入式IOT设备等,就需要支持最新的证书,否则可能出现访问的问题。

use openssl client to download ssl certification

显示目标链中的所有证书:

openssl s_client -showcerts -connect www.xxx.com:443 </dev/null

当有多个子域名的时候,第一个不一定是想要的,所以自己根据CN来判断到底是哪组证书。然后自己截取 "-BEGIN CERTIFICATE-" "-END CERTIFICATE-" 之间的部分。

如果直接取第一个:

openssl s_client -showcerts -connect www.xxx.com:443 </dev/null |sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > test.cert

UNRAID下基于dnspod实现免费DDNS服务

UNRAID下基于dnspod实现免费DDNS服务

目标环境:unraid

玩nas的都知道,ddns是必不可少的服务,让你能在互联网访问家里服务器的所有服务。

之前用的是一个免费的ddns,但是一个月要手动激活确认一次,觉得很麻烦。其次测试发现ip的同步时效有问题,时间久了就导致服务地址不可用(中间做了proxy,目前还没有最终确认是nginx的问题,还是这个ip失效的问题,待换了此新方案后确认)。

补充:这问题应该是nginx的proxy_pass的dns缓存问题。

简单的搜了下,目前有宝塔,群晖等方案,但考虑到方案的通用性,还是决定直接用原生cron的方案,而实际操作下来,也非常方便。

dnspod 域名设置

  1. 创建或者导入已有的域名,添加子域名,设置默认的地址,比如127.0.0.1
  2. 注意ipv4 和ipv6的设置差别。 一个是A类型,一个是AAAA类型。

dnspod 获取token

  1. 登陆dnspod, 我的账号 - api秘钥 - DSPod Token。
  2. 根据要求填写,然后生成id和token,自己保存起来。

软件包使用

dnspod目前支持的工具包地址: https://github.com/rehiy/dnspod-shell

1. 编辑ddnspod.sh,分别修改/your_real_path/ardnspod、arToken和arDdnsCheck为真实信息
2. 运行ddnspod.sh,开启循环更新任务;建议将此脚本支持添加到计划任务;

unraid定时运行

crontab -e

在末尾添加:

# Run minute cron jobs at every minutes after the hour:
* * * * * /xxx/dnspod-shell/ddnspod.sh 1> /dev/null

路径改成自己实际的。

刷新域名

如果发现127.0.0.1变成实际的ip了,说明脚本和定时任务生效了。

android studio环境gradle配置

build.gradle的内容都是由系统配置自动生成的,如果有相关报错,先确认系统配置。

要点

  1. grandle配置。file -> project structure -> project。
    file
    dependecies的配置,目前看是grandle的插件来自动更新这部分内容的,需要确认grandle插件的正确安装:

    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.2'
        classpath 'com.google.gms:google-services:4.3.3'
    }
  2. app 签名管理:file -> project structure -> Modules -> Signing configs

问题

  1. Execution failed for task ':processReleaseResources'
    解决:在build.gradle尾部添加:

    allprojects {
    repositories {
        google()
        jcenter()
    }
    }
  2. goole地图的支持:通过在dependencies添加实现:

    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    
    implementation 'com.google.android.gms:play-services-maps:12.0.1'
    implementation 'com.google.maps.android:android-maps-utils:0.5+'
    }

    具体版本,需要自己实际调整。

apns pem 推送证书生成

  1. Certificates, Identifiers & Profiles,下载 Apple Push Services文件,生成的是 apns.cer,将cer双击导入到苹果系统。

  2. 从钥匙串中导出p12文件,证书和证书的key,注意设置安全密码:
    file

  3. 通过命令行开始生成

    cert:
    openssl pkcs12 -clcerts -nokeys -out apns_cert.pem -in apns_cert.p12
    key:
    openssl pkcs12 -nocerts -out apns_cert_key.pem -in apns_cert_key.p12

    这个过程会提示你输入之前的文件的密码,以及新生成的文件的密码,一定要区分清楚,因为后面的程序调试是需要生成文件的密码的。

  4. 将两个pem合成一个

    cat apns_cert.pem apns_cert_key.pem > ck.pem
  5. 验证
    开发证书:
    openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert apns_cert.pem -key apns_cert_key.pem
    量产证书:
    openssl s_client -connect gateway.push.apple.com:2195 -cert apns_cert.pem -key apns_cert_key.pem
    如果验证成功,内容结尾显示如下:

    SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : DES-CBC3-SHA
    Session-ID: 
    Session-ID-ctx: 
    Master-Key: xxx
    Start Time: 1627218051
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)

    Verify return code: 0 (ok),说明成功。

如何解除google ads和google账户的绑定关系

如果你恰好在研究admob,当你开通admob时,提示你有ads绑定无法开通。

那么如何将ads从google账号下解除呢:

  • 登录ads
  • 依次点击顶部的“工具与设置”-“帐号访问权限和安全”,在这里可以看到有权访问该Google Ads帐号的用户,其中就有“您本人”。
  • 点击“您本人”后面的“移除访问权限”,即可彻底删除Google Ads帐号

esp32 header fields are too long issue

error log

httpd_txrx: httpd_resp_send_err: 431 Request Header Fields Too Large - Header fields are too long for server to interpret

解决

在menuconfig中,调整HTTPD_MAX_REQ_HDR_LEN 的值:

menuconfig=>component config=>HTTP server=>max http request header leagth

官方其实已经对此问题做了说明,\examples\protocols\http_server\simple\README.md

If the server log shows "httpd_parse: parse_block: request URI/header too long", especially when handling POST requests, then you probably need to increase HTTPD_MAX_REQ_HDR_LEN, which you can find in the project configuration menu (`idf.py menuconfig`): Component config -> HTTP Server -> Max HTTP Request Header Length

esp32 console 源码关键部分解析

相关源码路径: \examples\system\console\components\cmd_system

这个框架实际就是一个现成构架好的命令字,参数以及回调函数的框架,只要我们按照规范填写对应的参数,就能实现一个完整的console命令。

流程框架

    // 第1步:
    /*参数段设置*/
    // 第2步:
    /*命令结构体配置*/
    // 第3步:将命令结构体插入命令序列
    ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));

第1步,参数段说明

我们找一个例子说明,其他的都是类似的步骤。

    int num_args                = 1;
    deep_sleep_args.wakeup_time = arg_int0("t", "time", "<t>", "Wake up time, ms");
#if SOC_PM_SUPPORT_EXT_WAKEUP
    deep_sleep_args.wakeup_gpio_num = arg_int0(NULL, "io", "<n>", "If specified, wakeup using GPIO with given number");
    deep_sleep_args.wakeup_gpio_level = arg_int0(NULL, "io_level", "<0|1>", "GPIO level to trigger wakeup");
    num_args += 2;
#endif
    deep_sleep_args.end = arg_end(num_args);

字段

deep_sleep_args 是用户创建的结构体,这个根据实际需要创建,例子中用的是int做参数,所以结构体主要是 arg_int, 以此类推,你可以选择arg_rem、arg_lit、arg_db1、arg_str等等。

这个结构体定义的最后一个成员是固定的 end,用来限制参数的个数。

参数构造函数

arg_int0:表示当前字段最多一个参数,可以为空,类型为int。
arg_int1:标识当前为一个必填字段,类型为int。
arg_intn:以此类推。

如果是其他类型,就有其他类似arg_xxx的参数构造函数。

我们具体以上面的内容为例子

arg_int0("t", "time", "<t>", "Wake up time, ms");

其中有4个成员,分别是:

  • "t":参数字段简写
  • "time":参数字段全拼
  • "< t >":参数类型,t表示时间值
  • "Wake up time, ms":参数功能描述

第2步,命令结构体

源码例子:

 const esp_console_cmd_t cmd = {
        .command = "deep_sleep",
        .help =
            "Enter deep sleep mode. "
#if SOC_PM_SUPPORT_EXT_WAKEUP
            "Two wakeup modes are supported: timer and GPIO. "
#else
            "Timer wakeup mode is supported. "
#endif
            "If no wakeup option is specified, will sleep indefinitely.",
        .hint     = NULL,
        .func     = &deep_sleep,
        .argtable = &deep_sleep_args
    };

其中 command、help、hint、func、argtable 是系统的固定定义,分别表示:

  1. command:命令字
  2. help:帮助说明
  3. hint:参数详细说明,为NULL时,由系统生成
  4. func:回调函数
  5. argtable:参数列表

第3步,开发自己的命令行

从上面的内容可以知道,我们要设计自己的命令行需要做一下工作:

  1. 设计完整的命令。
  2. 拆分出命令字,参数,搞清楚参数的类型和个数。
  3. 填写deep_sleep_args参数结构(填写实际的对象,这里只是举例)。
  4. 填写 esp_console_cmd_t cmd对象。
  5. 实现回调函数,这个也是最主要的内容。
  6. 将cmd将入系统命令队列。

到这里,我们就实现了自己的命令行,是不是很简单,主要的工作量都在准确实现参数列表和回调上。

ble-gatt-communication-flow-between-eps32-and-nordic

ble gatt 通讯过程详解(基于esp32和nordic)

最近完成了esp32 自动扫描nordic设备的广播名称,并跟nordic uart server通讯的功能。

esp32 :ble uart client, gatt_client
nordic:ble uart server (NUS), gatt_server

要点

  • 要注意UUID表示成数组时的高低序,刚开始一直在排查代码,导致在这里浪费了好多时间。
  • 获取正确的UUID,以及char的数量和properties,可以通过第三方LightBlue来获取这些信息。

说明:因为通讯的交互过程跟char的数量以及属性有关系的,有几个char,是只读还是读写等,这些都对应不同的交互流程。 所以以下的内容过程就是针对nordic NUS的特征的而撰写的,如果你自己的设备有所不同,要灵活调整,不可生搬硬套,重要的是理解gatt本质。

nordic NUS服务配置




说明:ca9e 是nordic的蓝牙串口服务 NUS,下面有两个 char。 RX uuid 是0002,属性是write 和write without response, TX uuid 是0003,属性是notify。

通讯交互流程图

说明

  • 本来想文字再详细的说明下流程,发现上面的图已经表达的很清晰了,就没必要了,看图反而更直观。
  • 以上的流程是标准参考流程,开发时,根据实际的产品流程需求,可以重新打断和组合,实现新的流程。
  • 业务层实际的交互数据是在 esp_ble_gattc_write_char_descr过程中完成的。
  • 因为整个流程是一环扣一环的,所以如果开发中发现结果不对,就是哪一步错误了或者遗漏触发了,可以参考以上的流程和代码来核对。
  • 以上的内容对应gattc_demo的例子,可以从esp官网下载和确认。

How to Secure ESP32 Firmware and Flash Memory on ESP-IDF Framework

ref:https://circuitdigest.com/article/how-to-secure-esp32-firmware-and-flash-memory-using-esp-idf-framework

How to Secure ESP32 Firmware and Flash Memory on ESP-IDF Framework

In the era of Internet of Things(IoT), wireless communication is getting increasingly popular in everyday life. In the world of IoT devices, ESP32 is a popular low-cost System on Chip (SoC) microcontroller with built-in hybrid WiFi and Bluetooth chips by Espressif Systems. Because of its robust design and ultra-low power consumption, it has become so popular in IoT applications. But when we talk about IoT applications, security in IoT will come to our mind for data safety and secure connection. ESP32 supports X.509 certificate-based mutual authentication for HTTPs, IoT cloud (AWS-IoT, Azure, Google Firebase, etc.) authentication, and data communications. Over the Internet, ESP32 also gives us the data security for stored data into FLASH memory and Boot Sectors to prevent the data from being stolen. Today we talk about the ESP32 security features, mainly related to of Boot sectors. The two main security features on ESP32 are called Secure-Boot and flash security, also known as Flash-Encryption.

What eFUSE Blocks in ESP32?

The ESP32 has a 1024-bits One-Time-Programmable (OTP) memory block. This OTP memory block is divided into 4-block of 256-bits each.

file

These blocks of memory store the keys of the Flash encryption and Secure Boot. Because of the OTP memory block, there is no software present to read out those memory blocks. One and only ESP32 hardware can read and validate the Security features.

What is Flash Encryption? How to Enable it on ESP32?

ESP32 Flash Encryption is a security feature for the ESP32 provided by the ESP-IDF by Espressif System to protect the flash memory. Flash encryption is encrypting the contents of ESP32’s SPI flash memory and when this feature is enabled, the following types of data are encrypted by default:

  • Firmware Bootloader
  • Partition Table
  • “app” type partitions or Application partitions
  • Any partition marked with an “encrypted” flag in the partition table is also encrypted.
    In ESP-IDF projects, users can easily enable the Flash Encryption from the project configuration by the
idf.py menuconfig

After open the ESP32 project config menu, now navigate to

“Security Features” -->  
“Enable flash encryption on boot” --> 
“Enable usage mode (Development(NOT SECURE))” / “Enable usage mode (Release)”

In flash encryption there are two modes:

  • Development Mode: In this mode, the ESP32 flash memory partitions are all encrypted and open for modification and are also accessible to readout flash by the UART.
  • Release Mode: This mode is especially recommended for the manufacturing and production stages. In this mode, the readout of the flash by the UART/JTAG is totally blocked and new firmware can only be updated by over-the-air(OTA).

When the flash encryption is enabled, the binaries of the current code flash into the ESP32’s memory as a plain text file. But after completion of the flash process, on the first boot of the ESP32, the device itself encrypted each and every upper mention partition, one by one by using the AES flash encryption key which is stored into the eFUSE-BLK1 at the time of flash. After encrypting the partition the ESP32 device restarted itself and processed with the programmed logic.

The ESP32’s flash execution process decrypts the flash memory data when the ESP32’s execution unit tries to read and for the writing process, the flash execution process encrypts the data before writing into the flash memory.

file

What is Secure-Boot? How to Enable it on ESP32?

The ESP32 Secure-boot is a security feature, which provides security to run correct applications on ESP32 hardware. When secure boot is enabled, each and every flash memory’s binaries [Software bootloader & Application firmware] are verified before loading with the RSA-3072 based Secure-boot’s signature keys. We can call the Secure-boot a “Guardian of The ESP32”.

For enabling the Flash Encryption, in the same steps we can enable the Secure-boot from the project menuconfig.

“Security Features” -->  
“Enable hardware Secure Boot in bootloader”

How Secure-boot works?

When the ESP32 device is booted up, then ESP32 hardware’s trusted rom or we said the 1st stage bootloader runs verification with RSA-3072 based secure-boot key on the software bootloader and then the software bootloader verifies the application firmware with the same signature key and start the application.
file

Conclusion

The ESP32 comes with a secure environment [Secure-boot & Flash-Encryption], which we need to enable while flashing the code. For more security, we need to enable both of them.

centos change timezone

copy /usr/share/zoneinfo/xxx/xxx to /etc/localtime

原因:

为什么设置了时区以后,已经运行的程序在使用localtime函数调用时没有使用新时区呢?这个可以通过glibc的源码来回 答。localtime等涉及到本地所在时区的函数在调用的时候会先调用tzset这个函数,这一点可以通过tzset函数的manpage看出来。 tzset完成的工作是把当前时区信息(通过TZ环境变量或者/etc/localtime)读入并缓冲。事实上tzset在实现的时候是通过内部的 tzset_internal函数来完成的,显式的调用tzset会以显式的方式告知tzset_internal,而单独调用localtime的时候 是以隐式的方式告知tzset_internal,前者将强制tzset不管何种情况一律重新加载TZ信息或者/etc/localtime,而后者则是 只有在TZ发生变化,或者加载文件名发生变化的时候才会再次加载时区信息。因此,如果只是/etc/localtime的内容发生了变化,而文件名" /etc/localtime"没有变化,则不会再次加载时区信息,导致localtime函数调用仍然以老时区转换UTC时间到本地时间。

解决方法:在调用localtime之前调用tzset,则可强制刷新时区信息

mysql导入ibd文件错误提示

现象

执行

ALTER TABLE tbl_name IMPORT TABLESPACE;

提示

Table 'xxx.xxx' doesn't exist in engine

先检查是不是真的不存在,其实是刚手动创建的,所以不是这个问题。

再排查,发现其中的一种错误:
覆盖或者导入的ibd文件,没有给予正确的用户归属权限,用chown设置下,就正常了

当iphone升级成14.6以后,xcode12.4出现Unsupported OS version的问题

配置

system:mac air 11.4beta
xcode:12.4 12D4e
iphone:XR 14.6

现象

在xcode,手机出现“Unsupported OS version”,导致无法下载调试。

原因

原因是当前系统和硬件下,xcode就本限制在了当前版本,无法升级到最新的,导致无法支持最新的手机版本。

解决

参考:

https://stackoverflow.com/questions/67863355/xcode-12-4-unsupported-os-version-after-iphone-ios-update-14-6

因为原贴已经说的很清楚了,建议直接看原贴,如果想偷懒可以直接看以下总结步骤:

  1. 本机切换到路径:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
  2. 下载最新的release版本 https://raw.githubusercontent.com/iGhibli/iOS-DeviceSupport/master/DeviceSupport/14.5(FromXcode_12.5_Release_Candidate_xip).zip
  3. 解压后,出现的是14.5
  4. 将14.5复制一份,改成14.6,然后xcode退出,重进,然后iphone就正常了,可以连接下载了

esp32分区表分析总结

esp32分区表分析总结

要点

  • 分区表的首地址是0x8000。
  • 分区若偏移地址为空,则会紧跟着前一个分区之后开始;若为首个分区,则将紧跟着分区表开始。目前根据实际的代码和信息分析,第一个分区默认是从0x9000开始。
  • factory (0x00) 是默认的 app 分区。启动加载器将默认加载该应用程序。但如果存在类型为 data/ota 分区,则启动加载器将加载 data/ota 分区中的数据,进而判断启动哪个 OTA 镜像文件。
  • OTA 升级永远都不会更新 factory 分区中的内容。
  • 如果您希望在 OTA 项目中预留更多 flash,可以删除 factory 分区,转而使用 ota_0 分区
  • app 分区始终会被加密,不管 Flags 字段是否设置。
  • 如果您在项目配置菜单(idf.py menuconfig)中设置了分区表 CSV 文件的名称,然后构建项目或执行 idf.py partition_table。这时,转换将在编译过程中自动完成。
  • idf.py partition_table-flash :使用 esptool.py 工具烧写分区表。
  • idf.py flash :会烧写所有内容,包括分区表。

官方参考: https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-guides/partition-tables.html

分区表

如下是Factory app, two OTA definitions 的内容

# ESP-IDF Partition Table
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x4000,
otadata,  data, ota,     0xd000,  0x2000,
phy_init, data, phy,     0xf000,  0x1000,
factory,  app,  factory, 0x10000,  1M,
ota_0,    app,  ota_0,   0x110000, 1M,
ota_1,    app,  ota_1,   0x210000, 1M,
  • nvs:系统的非易失区,wifi配置,校准数据,以及其他通过api写入的非易失数据在这里。
  • otadata:这个用户存储ota的过程数据,比如当前区标识,完整性,校验等等。
  • phy_init:针对不同PHY的初始配置信息
  • factory:出厂分区,内容是我们的用户代码,我们的程序主体。当ota区有效时,此区会被跳过,默认没有ota时,运行的就是此区,一旦有ota版本,系统会尝试去启动ota的内容。
  • ota_0:第1个ota分区。
  • ota_1:第2个ota分区,无论如何总有一个是当期使用的激活区,另一个作为ota缓存空间用。
  • nvs_key:nvs区的秘钥分区。

    解释

    分区表的长度是0xc00,后面还md5校验,签名等,所以整个内容在 0x1000以内。
    0x9000=0x8000+0x1000
    0xd000=0x9000+0x4000
    0xf000=0xd000+0x2000
    0x10000=0xf000+0x1000
    0x110000=0x10000+0x100000(1M)
    0x210000=0x110000+0x100000(1M)

从上面的计算中,我们就可以看到,偏移地址和容量都是连续的,这也就是为什么实际的分区表,只天容量,不填其实偏移地址,因为地址可以根据容量进行计算得出。

实际例子分析

分区表

# Name,   Type, SubType, Offset,   Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs,      data, nvs,     ,        0x4000,
otadata,  data, ota,     ,        0x2000,
phy_init, data, phy,     ,        0x1000,
ota_0,    app,  ota_0,   ,        0x180000,
ota_1,    app,  ota_1,   ,        0x180000,
fctry,    data, nvs,     ,        0x4000

系统运行日志

I (58) boot: ## Label            Usage          Type ST Offset   Length
I (65) boot:  0 nvs              WiFi data        01 02 00009000 00004000
I (72) boot:  1 otadata          OTA data         01 00 0000d000 00002000
I (80) boot:  2 phy_init         RF data          01 01 0000f000 00001000
I (87) boot:  3 ota_0            OTA app          00 10 00010000 00180000
I (95) boot:  4 ota_1            OTA app          00 11 00190000 00180000
I (102) boot:  5 fctry            WiFi data        01 02 00310000 00004000

从运行日志看,跟我们上面介绍的计算结果一致。

flash工具配置

烧录时的地址配置如下:
file

  • bootloader.bin: 默认从0地址开始。
  • partition-table.bin: 默认起始地址0x8000
  • ota_data_initial.bin: 对应的otadata和phy_init两个分区内容
  • app.bin:对应的是ota_0

从这个例子看,为了节省空间,factory分区被省掉了,直接是ota_0分区。

how to build an esp32 centos environment

esp32 centos开发环境搭建

系统:CentOS Linux release 7.8.2003 (Core)

chip:esp32c3

前言

重点:之前是在windows下工作的,因为编译烧录都比较方便。最近因为各种git的不稳定原因,导致无法正确编译和运行,所以才打算在海外搞个linux环境,这样就可以解决git相关的困扰。

环境安装

官方指导参考:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32c3/get-started/index.html#id4

  1. 进入目标目录, 下载工具:

    git clone --recursive https://github.com/espressif/esp-idf.git
  2. 设置工具

    ./install.sh

    遇到的问题:

1)python版本问题

ESP-IDF supports Python 3.6 or newer but you are using Python 2.7.5. Please upgrade your installation as described in the documentation.

需要升级python,请参考网上文章,通过最新源码更新python。

2)ModuleNotFoundError: No module named '_ctypes' 问题

解决:

yum install libffi-devel -y

然后需要重新安装python3

make clean 
./configure
make&&make install
  1. 设置环境变量

    ./export.sh

遇到的问题:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'click'
env: idf.py: No such file or directory

解决:

python -m pip install click

由于是vps,所以 export.sh 实际上不会成功,一直卡死在 libusb-1.0 的错误中。所以只能手动设置环境变量,需要设置IDF_PYTHON_ENV_PATH 和PATH:

export PATH=/data/develop/esp/esp-idf/tools:$PATH
export PATH=/root/.espressif/python_env/idf4.4_py3.9_env/bin:$PATH
export IDF_PYTHON_ENV_PATH=/root/.espressif/python_env/idf4.4_py3.9_env

注意IDF_PYTHON_ENV_PATH一定要设置成 espressif的python路径,否则会一直提醒你执行 install.sh

验证idf.py环境ok:

idf.py --version
Setting IDF_PATH environment variable: /data/develop/esp/esp-idf
ESP-IDF v4.4-dev-1849-g8e3e65a-dirty

编译

找一个例子测试下

idf.py set-target esp32c3
idf.py build

出现错误:

  1. CMake 3.5 or higher is required. You are running version 2.8.12.2

升级cmake:

wget https://github.com/Kitware/CMake/releases/download/v3.21.0-rc2/cmake-3.21.0-rc2.tar.gz
tar zxvf cmake-3.21.0-rc2.tar.gz
make&&make install

添加cmake的环境变量
/usr/local/share/cmake-3.21

cmake --version
cmake version 3.21.0-rc2

CMake suite maintained and supported by Kitware (kitware.com/cmake).
  1. 工具链错误 :
    
    riscv32-esp-elf-gcc

is not a full path and was not found in the PATH.


解决:把
> /root/.espressif/tools/riscv32-esp-elf/esp-2021r1-8.4.0/riscv32-esp-elf/bin 

添加到PATH环境变量里

排除完问题后,以前在windows下无法正常编译的demo,编译通过,

centos python2.7 升级 python3

安装一个软件要求python3.6 以上版本,当前的版本是2.7.5

系统配置

CentOS Linux release 7.8.2003 (Core)

python源码下载

https://www.python.org/downloads/source/
我们下载最新的版本。

wget https://www.python.org/ftp/python/3.9.6/Python-3.9.6.tgz
tar zxvf Python-3.9.6.tgz

编译

./configure
make
make install

设置系统默认的python版本

检查版本

python -V
Python 2.7.5
python3 -V
Python 3.9.6

我们需要设置环境变量,默认使用python3

cd /usr/bin
ls -al /usr/bin | grep python
lrwxrwxrwx    1 root root          7 Jul 10  2020 python -> python2
lrwxrwxrwx    1 root root          9 Jul 10  2020 python2 -> python2.7
-rwxr-xr-x    1 root root       7144 Apr  2  2020 python2.7
-rwxr-xr-x    1 root root       1835 Apr  2  2020 python2.7-config
lrwxrwxrwx    1 root root         16 Jul 10  2020 python2-config -> python2.7-config
lrwxrwxrwx    1 root root         14 Jul 10  2020 python-config -> python2-config

照猫画虎,将建立python3的软连接

ln -s /usr/local/bin/python3 /usr/bin/python
python -V
Python 3.9.6
[root@li1974-11

可见python3已生效。

还原yum

因为yum是用的默认版本,python3会导致yum失效。需要对yum的python做指定。修改以下2个文件:

vi /usr/bin/yum
vi /usr/libexec/urlgrabber-ext-down

修改首行的 #!/usr/bin/python 为 #!/usr/bin/python2.7

验证yum修改后的效果:

yum --version
3.4.3
  Installed: rpm-4.11.3-43.el7.x86_64 at 2020-07-10 12:34
  Built    : CentOS BuildSystem <http://bugs.centos.org> at 2020-04-01 04:21
  Committed: Panu Matilainen <pmatilai@redhat.com> at 2019-10-04

  Installed: subscription-manager-1.24.45-1.el7.centos.x86_64 at 2021-04-29 18:18
  Built    : CentOS BuildSystem <http://bugs.centos.org> at 2020-12-15 16:38
  Committed: William Poteat <wpoteat@redhat.com> at 2020-11-24

  Installed: yum-3.4.3-167.el7.centos.noarch at 2020-07-10 12:36
  Built    : CentOS BuildSystem <http://bugs.centos.org> at 2020-04-02 15:56
  Committed: CentOS Sources <bugs@centos.org> at 2020-03-31

  Installed: yum-plugin-fastestmirror-1.1.31-54.el7_8.noarch at 2020-07-10 12:36
  Built    : CentOS BuildSystem <http://bugs.centos.org> at 2020-05-12 16:27
  Committed: Michal Domonkos <mdomonko@redhat.com> at 2020-03-12

yum 正常。

ESP32 下载工具说明

ESP32系列 flash下载

环境

硬件: esp32c3

环境: windows7

目前最新的IDF环境编译和下载都是python脚本完成的,但是对于非开发人员,测试或者工厂等下载最简单的方式还是通过下载工具,而不是配置负载的开发环境。

工具获取

去乐鑫官网下载最新的下载工具,工具页面:
https://www.espressif.com/zh-hans/support/download/other-tools

V3.8.8下载链接:
https://www.espressif.com/sites/default/files/tools/flash_download_tool_v3.8.8.zip

下载

解压后,运行工具,chip选择esp32c3,workmode选择develop

确定后,进入主页面,需要选择3个对应的bin档,他们分别是:

build\bootloader\bootloader.bin
build\partition_table\partition_table.bin
build\xxx.bin

其中xxx.bin是你的工程名称,也就是你的用户代码bin。
3个bin对应的地址分别是 0x0,0x8000,0x1000。以上bin的名称和地址都是根据命令行模式下载的日志中找到的,根据对应的size和地址,基本就能找到以上的信息。具体如图所示:

注意设置正确的串口,点击开始后,工具会自动读取正确的spiflash信息。

完成

完成后,绿色的按钮会显示完成字样,中间不要断电或者中断。
工具下载完成后不像命令行,不会自动重启,需要手动重启。

esp apsta lwip config

when you are developing an apsta app of esp, you should config int the menuconfig procedure, such as below:

  • Component config -> LWIP > [x] Enable copy between Layer2 and Layer3 packets.
  • Component config -> LWIP > [x] Enable IP forwarding.
  • Component config -> LWIP > [x] Enable NAT (new/experimental).

esp8266-window7-environment-installation

esp8266 window7开发环境搭建

最新代码

https://github.com/espressif/ESP8266_RTOS_SDK

安装toolchain

下载msys32

在windows环境下我们需要msys32,在linux不需要

https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20181001.zip

下载8266对应的toolchain

在默认的msys下是没有8266的toolchain的,我们需要下载:

https://dl.espressif.com/dl/xtensa-lx106-elf-gcc8_4_0-esp-2020r3-win32.zip

将解压后的xtensa-lx106-elf放到/msys32/opt/下

安装python环境

# python -m pip install --user -r $IDF_PATH/requirements.txt
Requirement already satisfied: setuptools in g:/msys32/mingw32/lib/python2.7/site-packages (from -r requirements.txt (line 4)) (40.4.3)
Collecting click>=5.0 (from -r requirements.txt (line 8))
  Downloading https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl (82kB)
    49% |▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒                | 40kB 450kB/s eta 0:00    61% |▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒            | 51kB 248kB/s eta     74% |▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒        | 61kB 296kB/s     86% |▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒    | 71kB 344k    98% |▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒| 81kB     100% |▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒| 92kB 385kB/s
Requirement already satisfied: pyserial>=3.0 in g:/msys32/mingw32/lib/python2.7/site-packages (from -r requirements.txt (line 9)) (3.4)
Requirement already satisfied: future>=0.15.2 in g:/msys32/mingw32/lib/python2.7/site-packages (from -r requirements.txt (line 10)) (0.16.0)
Requirement already satisfied: cryptography>=2.1.4 in g:/msys32/mingw32/lib/python2.7/site-packages (from -r requirements.txt (line 11)) (2.3.1)
Requirement already satisfied: pyparsing<2.4.0,>=2.0.3 in g:/msys32/mingw32/lib/python2.7/site-packages (from -r requirements.txt (line 12)) (2.2.0)
Collecting pyelftools>=0.22 (from -r requirements.txt (line 13))
  Using cached https://files.pythonhosted.org/packages/6f/50/3d7729d64bb23393aa4c166af250a6e6f9def40c90bf0e9af3c5ad25b6f7/pyelftools-0.27-py2.py3-none-any.whl
Requirement already satisfied: idna>=2.1 in g:/msys32/mingw32/lib/python2.7/site-packages (from cryptography>=2.1.4->-r requirements.txt (line 11)) (2.7)
Requirement already satisfied: asn1crypto>=0.21.0 in g:/msys32/mingw32/lib/python2.7/site-packages (from cryptography>=2.1.4->-r requirements.txt (line 11)) (0.24.0)
Requirement already satisfied: six>=1.4.1 in g:/msys32/mingw32/lib/python2.7/site-packages (from cryptography>=2.1.4->-r requirements.txt (line 11)) (1.11.0)
Requirement already satisfied: cffi!=1.11.3,>=1.7 in g:/msys32/mingw32/lib/python2.7/site-packages (from cryptography>=2.1.4->-r requirements.txt (line 11)) (1.10.0)
Requirement already satisfied: enum34 in g:/msys32/mingw32/lib/python2.7/site-packages (from cryptography>=2.1.4->-r requirements.txt (line 11)) (1.1.6)
Requirement already satisfied: ipaddress in g:/msys32/mingw32/lib/python2.7/site-packages (from cryptography>=2.1.4->-r requirements.txt (line 11)) (1.0.22)
Requirement already satisfied: pycparser in g:/msys32/mingw32/lib/python2.7/site-packages (from cffi!=1.11.3,>=1.7->cryptography>=2.1.4->-r requirements.txt (line 11)) (2.19)
Installing collected packages: click, pyelftools
Successfully installed click-7.1.2 pyelftools-0.27

编译工程

设置环境变量

因为我们使用的是msys32的虚拟环境,所以我们只要设置msys32的虚拟环境变量即可,不需要设置windows的环境变量。这样正好可以让我们在window系统下同时兼容esp32和esp8266的开发环境。
修改/home/xxx[用户]/.bashrc

新增:

export IDF_PATH=~/esp/ESP8266_RTOS_SDK
export PATH=/opt/xtensa-lx106-elf/bin:$PATH

检验环境变量:
重新打开mingw32.exe,执行

xtensa-lx106-elf-gcc -v
# xtensa-lx106-elf-gcc -v
Using built-in specs.
COLLECT_GCC=G:\msys32\opt\xtensa-lx106-elf\bin\xtensa-lx106-elf-gcc.exe
COLLECT_LTO_WRAPPER=g:/msys32/opt/xtensa-lx106-elf/bin/../libexec/gcc/xtensa-lx106-elf/8.4.0/lto-wrapper.exe
Target: xtensa-lx106-elf
Configured with: /builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-lx106-elf/src/gcc/configure --build=x86_64-build_pc-linux-gnu --host=i686-host_w64-mingw32 --target=xtensa-lx106-elf --prefix=/builds/idf/crosstool-NG/builds/xtensa-lx106-elf --with-local-prefix=/builds/idf/crosstool-NG/builds/xtensa-lx106-elf/xtensa-lx106-elf --with-headers=/builds/idf/crosstool-NG/builds/xtensa-lx106-elf/xtensa-lx106-elf/include --with-newlib --enable-threads=no --disable-shared --with-pkgversion='crosstool-NG esp-2020r3-49-gd5524c1' --disable-__cxa_atexit --enable-cxx-flags=-ffunction-sections --disable-libgomp --disable-libmudflap --disable-libmpx --disable-libssp --disable-libquadmath --disable-libquadmath-support --with-gmp=/builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-lx106-elf/buildtools/complibs-host --with-mpfr=/builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-lx106-elf/buildtools/complibs-host --with-mpc=/builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-lx106-elf/buildtools/complibs-host --with-isl=/builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-lx106-elf/buildtools/complibs-host --enable-lto --enable-target-optspace --without-long-double-128 --disable-nls --enable-multiarch --enable-languages=c,c++ --disable-libstdcxx-verbose --enable-threads=posix --enable-libstdcxx-time=yes
Thread model: posix
gcc version 8.4.0 (crosstool-NG esp-2020r3-49-gd5524c1)

下载最新代码

务必git pull,不要zip解压,windows下很多隐藏文件容易出问题

git pull https://github.com/espressif/ESP8266_RTOS_SDK.git

menuconfig

进入需要编译的工程例子目录

make menuconfig

进行必要的配置。为了接下来的下载,我们需要配置串口:Serial flasher config > Default serial port,根据实际的串口来配置。

On Windows, serial ports have names like COM1. On MacOS, they start with /dev/cu.. On Linux, they start with /dev/tty

编译

make

# make
Toolchain path: /opt/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: esp-2020r3-49-gd5524c1
Compiler version: 8.4.0
Python requirements from G:/msys32/home/zcj/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
App "wifi_softAP" version: v3.4-28-g08e225dd
To flash all build output, run 'make flash' or:
python /home/zcj/esp/ESP8266_RTOS_SDK/components/esptool_py/esptool/esptool.py --chip esp8266 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 2MB 0x0 /home/zcj/esp/ESP8266_RTOS_SDK/examples/wifi/getting_started/softAP/build/bootloader/bootloader.bin 0x10000 /home/zcj/esp/ESP8266_RTOS_SDK/examples/wifi/getting_started/softAP/build/wifi_softAP.bin 0x8000 /home/zcj/esp/ESP8266_RTOS_SDK/examples/wifi/getting_started/softAP/build/partitions_singleapp.bin

编译 & 下载

make flash

esp32 menuconfig 中Example Configuration及sdkconfig.h中宏的生成

在esp32的框架中,我们发现例子引用的sdkconfig.h在 build\config\ 目录下,因为build目录是生成的,所以我们很容易判断这个头文件也是动态生成的。

那么这个头文件的内容我们怎么控制呢?
经过验证,文件中大概分两类宏,用户自定义宏和硬件默认规格宏。用户自定义宏都是CONFIG_ESP_ 开头,其他的都是默认规格宏。

那么这些用户自定义宏又是在什么地方定义的呢,答案是 \main\Kconfig.projbuild 文件,这个文件是类似yaml的脚本,当你执行 idf.py menuconfig 时,会加载这个文件,进行对应的修改。

esp32 win7开发环境搭建

环境

系统:win7
hw target:esp32c3

注意:很多问题都跟git的网络有关,要仔细看错误提示。很多错误需要尝试多遍,才有可能成功。

安装包

离线包安装 https://dl.espressif.com/dl/esp-idf/?idf=4.4

更新最新代码

将安装的IDF_PATH更新成最新的git版本 https://github.com/espressif/esp-idf

更新submodule

git submodule update --init --recursive

安装python virtual environment

install.bat

设置环境变量

export.bat

编译工程

设置hw 平台类型

idf.py set-target esp32c3

错误1:

Unable to checkout '4f5e89fa84ce1d178a6765b8b46f2b6f91216677' in submodule path 'components/libsodium/libsodium'

解决1:
看日志是git无法成功,我们改为手动git pull,如果提示 openssl 10054错误。则

git config --global http.sslVerify "false"

其后还有很多的失败,基本需要逐个确认,多次执行

git submodule update --init --recursive

配置成功

-- Configuring done
-- Generating done
-- Build files have been written to: G:/esp/esp-idf/examples/wifi/getting_started/softAP/build

菜单配置

idf.py menuconfig

component config->esp32c3-specific,选择rev 2:
file

编译成功

idf.py build
[84/85] Generating binary image from built executable
esptool.py v3.1-dev
Merged 1 ELF section Generated G:/esp/espidf/examples/wifi/getting_started/softAP/build/bootloader/bootloader.bin
[85/85] cmd.exe /C "cd /D G:\esp\espidf\examples\wifi\getting_started\softAP\build\bootloader\esp-idf\esptool_py &&g:\esp\espressif\python_env\idf4.4_py3.8_env\Scripts\python.exe G:/esp/espidf/components/partition_table/check_sizes.py --
offset 0x8000 bootloader 0x0 G:/esp/espidf/examples/wifi/getting_started/softAP
/build/bootloader/bootloader.bin"
Bootloader binary size 0x48a0 bytes. 0x3760 bytes (76%) free.
[954/955] Generating binary image from built executable
esptool.py v3.1-dev
Merged 1 ELF section
Generated G:/esp/esp-idf/examples/wifi/getting_started/softAP/build/wifi_softAP.bin
[955/955] cmd.exe /C "cd /D G:\esp\esp..._started/softAP/build/wifi_softAP.bin"
wifi_softAP.bin binary size 0xa3490 bytes. Smallest app partition is 0x100000 by
tes. 0x5cb70 bytes (36%) free.

Project build complete. To flash, run this command:
g:\esp\espressif\python_env\idf4.4_py3.8_env\Scripts\python.exe ..\..\..\..\comp
onents\esptool_py\esptool\esptool.py -p (PORT) -b 460800 --before default_reset
--after hard_reset --chip esp32c3  write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 build\bootloader\bootloader.bin 0x8000 build\partition_
table\partition-table.bin 0x10000 build\wifi_softAP.bin
or run 'idf.py -p (PORT) flash'

烧录

idf.py -p COM105 flash
esptool.py v3.1-dev
Serial port COM105
Connecting....
Chip is ESP32-C3 (revision 2)
Features: Wi-Fi
Crystal is 40MHz
MAC: 7c:df:a1:86:4a:94
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00004fff...
Flash will be erased from 0x00010000 to 0x000b3fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Compressed 18592 bytes to 11216...
Writing at 0x00000000... (100 %)
Wrote 18592 bytes (11216 compressed) at 0x00000000 in 0.6 seconds (effective 253
.8 kbit/s)...
Hash of data verified.
Compressed 668816 bytes to 372018...
Writing at 0x00010000... (4 %)
Writing at 0x0001bf69... (8 %)
Writing at 0x00025854... (13 %)
Writing at 0x0002c95b... (17 %)
Writing at 0x0003382e... (21 %)
Writing at 0x0003ae72... (26 %)
Writing at 0x00041d6a... (30 %)
Writing at 0x0004886c... (34 %)
Writing at 0x0004fb4e... (39 %)
Writing at 0x00056b56... (43 %)
Writing at 0x0005d1f1... (47 %)
Writing at 0x0006332e... (52 %)
Writing at 0x00068eeb... (56 %)
Writing at 0x0006f110... (60 %)
Writing at 0x0007537e... (65 %)
Writing at 0x0007b840... (69 %)
Writing at 0x00081ae0... (73 %)
Writing at 0x00087df9... (78 %)
Writing at 0x0008df30... (82 %)
Writing at 0x000945f7... (86 %)
Writing at 0x0009b5fe... (91 %)
Writing at 0x000a66e9... (95 %)
Writing at 0x000ae4bc... (100 %)
Wrote 668816 bytes (372018 compressed) at 0x00010000 in 11.2 seconds (effective
476.2 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 103...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 258.7
kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
Done

擦除flash

idf.py erase_flash

查看日志

idf.py -p COMXXX monitor

esp32 windows environment issue of python requirements

pc系统:win7 x64

按照指导文档,无论是命令行安装还是msi安装,都一直卡在:

G:\esp\esp-idf-src\examples\wifi\getting_started\softAP>idf.py build
The following Python requirements are not satisfied:
pyserial>=3.0
future>=0.15.2
cryptography>=2.1.4
pyparsing>=2.0.3,<2.4.0
pyelftools>=0.22
gdbgui==0.13.2.0
pygdbmi<=0.9.0.2
reedsolo>=1.5.3,<=1.5.4
bitstring>=3.1.6
ecdsa>=0.16.0
esp-windows-curses; sys_platform == 'win32'
To install the missing packages, please run "G:\esp\esp-idf\install.bat"
Diagnostic information:
    IDF_PYTHON_ENV_PATH: D:\Programs\Python\Python38
    Python interpreter used: D:\Programs\Python\Python38\python.exe

ESP-IDF v4.2.1

解决:
python -m pip install --user -r \xxx\xxx\requirements.txt

docker Permissiissuon denied issue

realpath(): Permission denied
System.UnauthorizedAccessException: Access to the path '/app' is denied

同样的操作,在另一台同样系统版本的机器上正常。

确认了需要link的volume 目录权限,没有问题。

因为是权限问题,所以怀疑是否是selinux的问题,对比了下,确实不一样,是开启的。

尝试去disable

然后就正常了

centos6 repo update for the yum issue

yum 安装时报错:

YumRepo Error: All mirror URLs are not using ftp, http[s] or file.YumRepo Error: All mirror URLs are not using ftp, http[s] or file.

centos6 repo源一键修复:

sed -i "s|enabled=1|enabled=0|g" /etc/yum/pluginconf.d/fastestmirror.conf
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://www.xmpan.com/Centos-6-Vault-Aliyun.repo 
yum clean all
yum makecache

千牛操作纪要

开通花呗付款:交易管理=》分期管理=》花呗
关闭聊天机器人:
1)店铺管理=》子账号管理=》分流设置=》设置=》店铺服务助手。一个bug式的存在是因为阿里总是把在线客服状态判断为离线,所以如果你开启了旺旺分流里面的“离线分流”,你将仍然收到自动回复。
2)禁用店小蜜中的自动接待和智能辅助

淘宝多客服自定义代码

其中xxx是子账号的URL编码,根据实际需要自己填写:

<div class="tb-module tshop-um tshop-um-kfzx">
    <div>
         
    </div>
    <div class="kefu190">
        <div class="hd"></div>
        <div class="bd">
            <div class="one">
                <h3 style="border-bottom:1px solid #D8D8D8;" > 售前客服</h3>
                <ul>
                    <li style="width:145px;line-height:35px;overflow:hidden;" class="item item0">
                         <a target="_blank" href="http://amos.alicdn.com/getcid.aw?v=2&uid=xxx&site=cntaobao&s=1&groupid=0&charset=utf-8">
<img border="0" src="http://amos.alicdn.com/online.aw?v=2&uid=%E6%9E%81%E9%80%9F%E7%89%A9%E8%81%94%3A%E5%BC%A0%E5%85%88%E7%94%9F&site=cntaobao&s=1&charset=utf-8" alt="给我发消息" /></a> <b style="margin-top:5px;width:30px;height:15px;right:3px;top:1px;"> AAA </b>
                    </li>
                </ul>
            </div>
            <div class="one">
                <h3 style="border-bottom:1px solid #D8D8D8;"> 售后客服</h3>
                <ul>
                    <li style="width:145px;line-height:35px;overflow:hidden;" class="item item0">
                         <a target="_blank" href="http://amos.alicdn.com/getcid.aw?v=2&uid=xxx&site=cntaobao&s=1&groupid=0&charset=utf-8">
<img border="0" src="http://amos.alicdn.com/online.aw?v=2&uid=%E6%9E%81%E9%80%9F%E7%89%A9%E8%81%94%3A%E8%82%96%E5%85%88%E7%94%9F&site=cntaobao&s=1&charset=utf-8" alt="给我发消息" /></a> <b style="margin-top:5px;width:30px;height:15px;right:3px;top:1px;"> BBB </b>
                    </li>
                </ul>
            </div>
            <div class="onez" style="padding-bottom:5px;padding-left:0px;margin-left:0px;width:100%;">
                <ul>
                    <h3 style="border-top:1px solid #D8D8D8;border-bottom:none;margin-bottom:0px;padding-top:8px;width:100%;"> 工作时间:9:00-18:00</h3>
                    <li style="height:46px;margin:0;padding-top:5px;width:100%;color:#888;background:none;line-height:23px;text-align:center;">
                         周日和法定节假日休息
                        <p style="color:#888;">只接单不发货</p>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</div>

certbot renew errors

certbot renew时,突然出错:

ImportError: cannot import name UnrewindableBodyError

尝试安装更新:

pip install requests urllib3 pyOpenSSL --force --upgrade

安装后,依然有错:

pkg_resources.DistributionNotFound: The 'urllib3<1.23,>=1.21.1' distribution was not found and is required by requests

从提示看是urllib3版本不满足要求导致的问题,尝试安装最新版:

pip install urllib3
Looking in indexes: http://mirrors.aliyun.com/pypi/simple/
Requirement already satisfied: urllib3 in /usr/local/lib/python3.9/site-packages (1.21.1)

安装完最新的1.21.1 错误提示依然,说明还需要处理路径的问题。

首先需要找到的是目前到底是哪个版本,哪个路径?

find / -name "urllib3-*"
/usr/lib/python2.7/site-packages/urllib3-1.10.2-py2.7.egg-info
/usr/local/lib/python3.6/site-packages/urllib3-1.23-py3.6.egg
/usr/local/lib/python3.6/site-packages/urllib3-1.21.1-py3.6.egg
/usr/local/lib/python3.6/site-packages/urllib3-1.25.11.dist-info
/usr/local/lib/python3.9/site-packages/urllib3-1.21.1.dist-info

从上面的后缀看基本都是大于1.21的,那么当前系统索引的应该就是 urllib3-1.10.2 这个版本了。

解决

问题分析清楚了,解决就很简单了。
将前面安装时提示的最新的1.21.1对应的相关文件 手动拷贝到 1.10.2 对应的路径就好了。
分别拷贝 urllib3 和 urllib3-1.21.1.dist-info 两个目录

再去测试 certbot renew, 一切恢复正常

unraid中使用docker安装Lychee荔枝相册

管理自己的私人照片,目前的选择是群晖的moments,偶然看到荔枝相册Lychee的效果,觉得做公开图片管理很合适,所以准备学习下。

github

https://github.com/LycheeOrg/Lychee
https://github.com/LycheeOrg/Lychee-Docker

准备工作

在宝塔中创建需要的数据库lychee。

docker安装

docker run -d --name lychee --link=baota -p 50003:80 --restart always -e DB_CONNECTION=mysql -e DB_HOST=baota -e DB_DATABASE=lychee -e DB_USERNAME=lychee -e DB_PASSWORD=xxx --network=myNetwork --ip 172.18.0.203 -v /mnt/user/appdata/lychee/conf:/conf -v /mnt/user/appdata/lychee/uploads:/uploads  -v /mnt/user/appdata/lychee/sym:/sym linuxserver/lychee

安装完,系统初始化要等一会儿,然后按照设置的端口登录。
第一次要设置帐户密码,然后就可以使用了。

版本更新

4.2.2发现有升级的问题,解决办法就是删了image重新装,因为数据都在本地和数据库,所以更新后数据没问题。

群晖moments的正确玩法

很多人装黑群晖就是因为看了网上推荐的photo station+moments的文章。

之所以这里说正确玩法,因为网上大部分推荐的photo station+moment的玩法是不合适的,或者说不是最佳的方案。

从群晖官方对moments的定位看,drive是和moments强绑定的,但photo station不是,看目录结构就能看出来:
file

我们推荐的正确基本玩法是drive+moments,也就是官方默认配置,高级玩法是drive+resilio sync+moments+sync(resilio/cloud)。

为什么说photo station方案不是最佳?

  • 我们先说下网上推荐的moments+photo station的方案。这个方案需要在moments开启“共享照片库”,然后在首页的左上角就会出现下拉框,多出来一个“共享照片库”的选项,对于有强迫症的人就会觉得不爽,因为你需要选一下,才能看到共享照片库里面的内容。当然如果你用相册模式,从不care照片模式,也许这个也不算什么大问题。

  • 其次,用photo station主要是为了规避moments按照日期归档的毛病,在photo station中可以手动归档,不会显得凌乱,这个作用完全被Drive替代了,在drive下的moments目录里面手动整理照片,就可以在moments直接看了。

  • drive是系统默认的组件,而photo station是一个独立的应用,需要额外安装,就显得多余了。

高级用法

上面提到的只是一套照片管理的方法,但是你还是需要把内容拷贝到drive下才可以,因为群晖大部分人可能是虚拟机安装的,把文件直接放到虚拟机里面我们是不放心的,所以我们的照片的实际源头在unraid下面,这样容量问题我们就不甚care了,unraid下全部磁盘空间可见,随时可以扩容。所以最后我们还要个能把unraid下内容同步到群晖中drive中的方案。

我们首先想到的是群晖原生支持的webdav方案,但是unraid不是原生支持的,需要自己安装app,自己搜索安装app后,结合cloud sync可以实现自动同步的效果,但是发现因为webdav的部署,unraid的照片路径的权限被破坏了,samba不能正确访问这些目录了,所以最终这个方案被毙。

然后就出现了我们上面提到的resilio sync方案,按照说明部署后,发现功能正常,也没有权限的问题。

至此,drive+moments+resilio sync已经可以解决本地或者局域网的问题了,但是对于google相册,百度云和其他在线云盘相册的照片,我们怎么同步呢,这里我们就要用cloud sync了。所以最终的方案就是drive+moments+resilio sync+cloud sync,兼顾本地存储和各种云盘,我们所有所有的照片都可以在moments中出现了,也不会破坏原始内容,不用担心群晖虚拟机出故障后,珍贵的照片丢失的风险。

resilio-sync 设置

同步源地址


file
file
拷贝以上地址,后面设置同步的目的地址时需要。

同步目的地址


file
这里需要填的就是上面拷贝的地址。

设置成功后,就能看到同步状态和日志:
file

chrome 实时翻译插件

如果你想练英语,啃英语生肉,这个是个轻量级的很好的选择。体验了下,目前针对英语,准确性还好。

安装:
chrome://flags/#enable-accessibility-live-captions

Live Caption =》enable

安装后重启浏览器。

然后在高级=》无障碍=》字幕中进行设置

卡西欧GA-140GB-1A1表盘功能及相关符号说明

如果有强迫症,相信第一次拿到这个表应该有点挠头,因为很多显示符号和表盘元素看不懂。

手表表盘

GA-140GB-1A1

手表功能的在线视频
https://www.casio.com.cn/support/guidevideo/wat/GA-140.html

表盘符号

  • STW:秒表
  • SNZ:间歇闹铃标识
  • SIG:整点提示标识
  • AL :闹铃标识
  • LAP:间断计时
  • SPL:中途计时
  • DST:夏令时
  • LT :自动照明标识

FAQ

  • 如何激活表盘上面的LT标识?
    这个视频没有讲,但是附送的手册里面有讲,那就是长按reverse按键(B)三秒激活。

  • 如何设置亮屏时间?
    默认按下B键,亮屏1.5s。系统提供LT1 LT3两种模式,LT1表示亮屏1.5秒,LT3表示亮屏3秒。
    如何设置:计时模式下-》长按A->按C-》循环按C-》出现LT1时-》按D进行设置-》按A-》回到计时模式

  • 表盘上面的速度区段和速度指针怎么计算速度?
    这个手册里面没官方视频里面也没有讲,所以稍微多花了点时间才弄清楚。
    区段和速度指针是组合的关系,单位是KM/h,区段表示整百部分的数值,指针表示100以内的部分。这个功能是跟秒表功能一起展示的,所以当你发现开启秒表功能时,指针和区段指示就会变化。
    这里测试的模型是假设你跑完1公里(出厂默认,可以自己设置,如果设置了,下面讲的计算方法也要对应调整)所用的秒数。
    速度计可用于计算经过一公里所需要的时间(60 秒内),然后用得到的结果来确定大致的平均(小时)速度。
    假设你1KM,用了11.039s,计算出来是326.116KM/h,那么速度区段部分就是3块,表示300,指针是26左右,整体表示326km/h。

W600/W800之WebServer页面修改

在路径 \Src\App\web 下我们能看到相关的web页面,是一些简单的web配置页面。

需要修改时,参考:http://www.wdyichen.cn/?log=blog&id=68

文中写的已经算比较清楚了,需要补充的是,除了文章中提到的makefs还有另外一个命令goall,这些都是linux 脚本,需要在linux环境下执行,区别也很简单,自己点看看内容就能明了。

原文引用:

web server也即http server,在w600官方sdk中默认就有一个,主要被用来softap下网页配网,遗憾的是官方一点没有其webserver二次开发的教程,大多数小白朋友看着那个丑陋的网页完全无法下手修改,所以本文就以web server如何进行二次开发来一番介绍。

先说下这种嵌入式webserver的特点,因为w600没有文件系统,而通常我们用的webserver都是要访问server根目录下的网页文件的,所以这个webserver就对网页文件做了一点特殊处理,那就是直接把网页文件转化成c语言的数组在编译时直接编进代码中去,这样就相当于形成了一个内存文件系统,webserver在收到访问请求时,直接在内存中查找到这个网页文件,回馈给用户。当然你也可以拿spi flash或者tf/sd这些搞个实际的文件系统,本文不在讨论。

webserver主要就是前端的网页式样和后端的代码处理。其源码在在Src/App/web目录下,这里面像web.c、httpd.c、fs.c是代码实现,而fs_ap_config这种文件夹下存放的是网页(或者其它的fs*文件)。

所以当你想修改网页式样的时候,就在fs文件夹下的网页中去改,改完之后,使用web目录下的那个makefs脚本把网页转化为c数组。如:./makefs ./fs_ap_config ./fsdata_ap_config.c(当然最后面的./fs_ap_config.c可以不写就会默认生成一个叫fsdata_lwip.c的文件),最后不管你起的啥名或者用默认的名字,只要你把它在fs.c中这个地方:#include "fsdata_ap_config.c"填写的名称保持一致就行。最后我想说的是这个makefs脚本是需要在shell环境下去执行,是linux这种shell环境,不是windows下的cmd里面搞。还有就是修改网页的时候,最好不要改的太大,要考虑嵌入式资源,如果你把网页搞得太大,c数组也就很大,最后搞出来的w600固件也就很大而没法烧进去了。

改完网页之后,通常你的网页不会只是一个静态显示页面,总会需要显示一点实时信息,更有甚者还需要交互操作,所以还需要改webserver让其支持你的各种表单请求交互操作。这个webserver仅支持最简单的html,所以网页交互就是靠html 表单了,如果你对表单的概念一脸懵逼不懂我在说啥,那么我建议你花十来分钟去看看html语法,这是世界上最简单的语法了,学会它你才能进行下一部开发。

访问网页时,必然会走到这里Web_parse_line,所以网页被访问时,需要读取的实时数据就是在这里更新的;当表单提交之后,必然会走到这里do_cgi_webindex,所以需要更新给模块的数据都是在这里进行解析处理。这里需要注意web_id_tbl这个表,其IdName就是用来和网页中的各id进行匹配的所以要填一样,Value_Offset是数出来的长度如果不是固定的那我建议直接填个0起调更快捷。

最后,启动webserver就是使用httpd_init,停止就使用httpd_deinit。至于为啥不用tls_webserver_init,是因w600没有deinit我感觉比较别扭所以不想用~~~

find issue in windows command line

编译rda8910的代码时,突然提示错误,之前都是正常的:

find: ‘/I’: No such file or directory
find: ‘;xxxx\\..\\prebuilts\\win32\\bin;’: No such file or directory

先根据 /I 的关键字,在项目找到了对应的命令行:

(echo ";%PATH%;" | find /C /I ";%1;" > nul) || set "PATH=%1;%PATH%"

很显然,出错的原因是 find 没有识别 /I 选项,导致 %1前面的;号被识别到了后面的有效路径上。

知道原因了,就有解决思路了:
用搜索工具搜了下整机,找到不同路径的几个版本的find.exe,然后针对不同的find 用 /I 进行测试,发现c盘系统路径下的正常,而Git 下的find会提示跟上面错误类似的提示,基本判断find可能因为环境变量的原因使用的是Git下对应的版本。

解决

把不不出错的find.exe的版本的路径加到 Path 环境变量里:

C:\Windows\SysWOW64;C:\Windows\System32;

退出当前命令行,重进,再编译,正常了。。。

windows7禁用管理员批准模式

环境

windows7,windows10 不一定适用。

问题

不知道是不是被电脑管家修改的缘故,突然之间很多的程序执行都需要右键管理员权限才可以。
导致的一个问题是,很多编译脚本调用的工具或者命令行,都会提示没有权限,出现大量告警日志。

禁用

secpol.msc =》本地策略=》安全选项=》
用户控制:以管理员批准模式运行所有管理员

设置成禁用,然后重启

如何在unraid的linux vm中安装群晖synology

参考

  1. https://post.smzdm.com/p/az50d36r/
  2. https://www.bilibili.com/video/av86018391/
    以上两个内容关于系统安装主要不一样的地方是vDisk Bus的选择,一个选的是USB,一个推荐的是SATA,这个需要网友们根据自己配置,自己确认下哪个合适。

安装盘

  1. img 引导盘
  2. pat 系统盘
    具体下载点可以网上自己找,有很多不同的版本。

要点

  1. 在xml下改网卡model type 为e1000。
  2. 安装成功的界面是这个:
    file
    这个只是表示系统起来了,但是你能不能通过默认的5000端口访问还不一定,比如你的网卡配置不对等。
  3. 通过Synology Assistant工具或者 http://find.synology.com/ 在线扫描,寻找有效的群晖主机IP。

只知道一个手机号,如何对其定位?[骗局揭秘]

现实中,一些人受影视剧影响,想通过电话号码定位一个人,结果被各种套路,骗了钱,还影响了心情。所以今天很有必要就这种骗局做些介绍,避免有更多的人受骗。因为除了大众能感受到的金钱的受骗,其实还有一个更重要的危害就是隐私位置泄露。

在网上搜索"手机号定位",能搜出来很多号称只要输入手机号,就能定位对方位置的网站或者APP,很多网站看似很正规,app也评价好几万,很多网友因为不了解技术原理,所以心存侥幸,于是就放松了警惕,上当受骗。

一般这种网站和APP刚开始都是免费的,骗你试用,你发现根本不好用后,对方就通过提示暗示或者客服电话诱导你付费升级,因为你心存幻想,也很着急,于是就被诱导着各种充值,于是很多人就交了费,最后发现被骗了,但一切都晚了,客服电话没人接或者微信qq被拉黑。

那么从科学技术原理上,只通过手机号能精准定位吗(这里说的是只有一个手机号,跟基站定位技术没关系,因为基站定位技术还是要获取基线相关的运营商和小区号等,不是我们讨论的单单只有手机号而已)?

答案是,对国家或者有关部门和电信运营商可以,但对普通人答案是否定的。

一般套路是这样的,你通过搜索引擎关键字被诱导下载某个app或者进入某个网址页面,然后输入你想要定位的人的电话号码,想知道这个手机号码主人当前的位置,实际操作时却被套路一步步诱骗。而且即使你交了钱,也发现根本定不到真实位置,或者定出来一个没有意义的地址。

怎么回事?市面上凡是声称能通过手机号码查到对方位置的,前提是要对方曾经因为某种原因使用过这个APP软件或者网站,泄漏了位置,你才可能查到对方当时泄漏的位置。这种软件或者网站在提供所谓定位别人的功能的同时,会要求使用人开启位置权限,私自收集使用者位置暴露给第三方查询。你查别人的位置时,同时也就上传了你自己的位置。同时,所谓的能定位,只是碰概率,理论上你查到了,也不是实时的,只是大概的老旧时间位置,如果查不到,平台或者APP收集了你的位置,也许别人就可以查到你了。总之这种平台或者软件要么骗到你的钱,要么收集到你的隐私位置,供别人查询。

所以这种软件千万不要碰,这种软件都是利用大家不懂技术原理猎奇的心里,对技术存在幻想,贩卖大家的隐私。应避之,弃之,抵制之。

如果有人说收钱帮你定位,就更要警惕了,能做到这个的只有电信内部系统和国家相关部门了,不要心存幻想,才能从根本避免被骗。

最后希望大家明白能对对方定位的唯一方式,都是双方安装同样的定位软件,并且对方同意位置授权和数据网络权限,这样才能获取到对方的位置,比如我们日常使用的微信位置分享功能,这个也是建立在对方安装了微信这样的app的前提下并且同意加为好友,才能定位的,而不是只知道对方一个电话号码,就幻想能定位。苹果 APP store有很多类似的定位软件,但是真正好用的寥寥,需要大家仔细去甄选和验证,然后双方共同使用,成为好友,授权合法使用位置。

好了,技术原理就讲到这里了,不知道是否大家都明白其中的原理了。

如果你因为看到了本文,而避免一次可能的受骗,可以告诉小编,也让小编一起高兴和欣慰下。

unraid 增加Docker磁盘空间

默认20G,所以没用多久,你就会看到类似的提示:

Docker image disk utilization of 93%
Docker utilization of image file /mnt/user/system/docker/docker.img

container瘦身

docker system prune --all --volumes

这样会瘦身些,但是一般小不了多少。

增大image size

在unraid 主界面:settings-->docker
Enable Docker 选择No,在Yes时,你无法看到设置size的选项。
file

修改后,告警消失了:)