20 Apr 2024
前言
最近一个月一直在学高可用的东西,其中 WSFC 是其中一个重要的组成部分。在学习 WSFC 的过程中,我发现了一个很重要的概念:Quorum,这个概念网上一找全是照着微软官方文档写的 仲裁配置选项。问有什么模型的时候头头是道,什么节点多数无见证啊、仅磁盘见证啊什么的,一问啥是仲裁(Quorum)和见证(Witness)的时候傻眼了。所以我决定写一篇文章来总结一下我对 Quorum 的理解。
仲裁(Quorum)是什么
仲裁(Quorum)是 WSFC 中的一个重要概念,它是用来保证群集中的节点之间能够达成一致的一个机制。在 WSFC 中,仲裁是通过仲裁资源来实现的,这个资源可以是磁盘、文件共享、或者是其他的仲裁资源。在 WSFC 中,仲裁资源的作用是用来保证群集中的节点之间能够达成一致,从而保证群集的正常运行。
依我看,Quorum 其实应该翻译成 有效参与仲裁的设备(数),因为 Quorum 本来就翻译成 法定人数/出席会议最小人数,不应该直接叫 仲裁。
现在涉及到 仲裁 这个法律概念,所以我们可以引入法律属于去解释。在法律中,仲裁 是指一种解决纠纷的方式,当纠纷发生时,双方可以通过仲裁的方式来解决纠纷。在法律仲裁中,仲裁员是一个独立的第三方,他们会根据法律和事实来做出裁决。但在 WSFC 中,仲裁员(节点/服务器/虚拟机)既是当事人(所有节点),又参与仲裁庭,它们会根据法律和事实(仲裁模型)来做出裁决,是用来保证群集中的节点之间能够达成一致的。
节点多数,无见证:由节点组织“合议制仲裁庭”,当事人(所有参与群集的节点/服务器)约定由奇数名仲裁员(节点)组成仲裁庭(偶数节点就使其中一个节点下线),其中一名为首席仲裁员(主节点/服务器);如果是双节点就采取“独任制仲裁庭”,只推举一名仲裁员(一个节点做主服务器,另外一个下线)。
磁盘、文件共享见证:见证人是证人之外知道案件情况的当事人(所以磁盘、文件共享见证需要对所有节点可见,在注册表中节点文件是Cluster,见证文件是0.Cluster,可以证明见证确实是“当事人”)。见证人不参与仲裁庭,但是可以提供证据(见证文件)。
总结来说:
节点多数,无见证:
合议庭:集群的所有活动节点。
仲裁庭成员:每个节点都可以投票决定集群状态,若节点总数为偶数,可能需要让一个节点下线以避免平票。
首席仲裁员(主节点):在实际的WSFC中,通常没有固定的“首席仲裁员”或主节点,所有节点理论上是平等的,但在实践中,某些节点可能因为资源位置或网络优势暂时承担更多责任。
双节点集群的“独任制”:
这种情况下,通常需要额外的见证(磁盘或文件共享见证),因为单纯的两个节点在一个节点失效时无法决定集群状态。如果不使用见证,确实可能会推举一个节点为主导,另一个则在主节点活跃时处于待命状态。
磁盘、文件共享见证:
见证人:在这种情况下,见证(文件共享或磁盘)充当了“知情人”,它存储关于集群配置的关键信息,确保在节点间的意见不一致时提供“证据”来帮助做出决策。见证的存在特别在节点数为偶数时非常关键,以避免平票问题。
但是大多数人对法律仲裁制度不了解,而且法律仲裁制度和 WSFC 中的仲裁机制有很大的不同,所以我觉得这个比喻不太合适。
所以我决定引入日常生活,比如双节点集群就像情侣之间决定晚餐吃什么,引入磁盘见证相当于三口之家中孩子的存在,这样比喻起来更加贴近生活,也更容易理解。
原文如下:
Mode
Description
Node majority (no witness) 节点多数
Only nodes have votes. No quorum witness is configured. The cluster quorum is the majority of voting nodes in the active cluster membership.
Node majority with witness (disk or file share) 节点多数+见证
Nodes have votes. In addition, a quorum witness has a vote. The cluster quorum is the majority of voting nodes in the active cluster membership plus a witness vote. A quorum witness can be a designated disk witness or a designated file share witness.
No majority (disk witness only) 仅磁盘见证
No nodes have votes. Only a disk witness has a vote. The cluster quorum is determined by the state of the disk witness. Generally, this mode is not recommended, and it should not be selected because it creates a single point of failure for the cluster.
我们可以这样理解:
仲裁模型
描述
男生女生二人决定晚餐 节点多数
【双节点】男生让渡(即其中一节点下线,有一票投票权但动态见证干预其不投票),让女生(主节点/服务器/虚拟机 Owner Node)来选择点什么外卖或者出去吃什么餐馆。你就负责买单就行。 【三节点及以上】女生带闺蜜来了,女生和闺蜜手拉手胳膊挽胳膊掌握晚餐选择主动权(即具有集群的控制权,在一个三节点集群中,通常需要至少两个节点在线并相互通信,以维持集群的正常操作)。象征性问你一下想吃什么。所以你还是负责买单的小丑。
核心家庭(三口之家)或扩展家庭(爸妈或者和爷爷奶奶外公外婆一起为节点,孩子为见证) 节点多数+见证
爸妈想吃啥就做啥,你的意见仅供参考 因为爷爷奶奶外公外婆说孩子想吃这个那个,所以爸妈做饭就做了大家都爱吃的东西。(换句话说见证也参与,而不仅仅是节点多数)
你过生日那天 仅磁盘见证
“妈,我生日想吃开封菜。” “不行,油炸食品不健康。” (别看上面的见证是你,但是这一条就不是你了)
总结
给我写乐了。宿舍停水了,舍友用我的博客洗完了澡。
20 Jan 2024
注:下文中 Intel Arduino/Genuino 101 简称为 Arduino 101
Arduino 101
Arduino/Genuino 101 的由来
2015年10月16日1,距离世界上第一台商用可编程计算器 Olivetti Programma 1012 问世过去了整整50年。为了致敬这个伟大的项目,英特尔和 Massimo Banzi3(Arduino项目的联合创始人)在 Maker Faire 宣布推出一款新的开发板,名为Arduino/Genuino 101 —— 一款专为教育用途、创客世界和首次接触编程的人设计的开发板。
Olivetti Programma 101
Arduino/Genuino 101 的硬件和软件
Arduino 101是一款学习和开发板,以入门级价格提供英特尔® Curie™ 模块的性能和低功耗以及 Arduino 的简单性。它保留了与 UNO 相同的强大外形和外设列表,并增加了板载低功耗蓝牙®(Bluetooth Low Energy,BLE,Nordic 的 nRF512822)功能和 6 轴加速度计/陀螺仪(Bosch 的 BMI160)。
Arduino 101 使用的 Curie™ 模块属于异构双核,包含两个微型内核,一个 x86 (Quark SE,SE 即 Second Edition) 和一个 32 位 ARC 架构内核,时钟频率均为 32MHz。英特尔工具链可在两个内核上以最佳方式编译 Arduino 草图,以完成要求最苛刻的任务。英特尔开发的实时操作系统 (Zephyr) 和框架是开源的。其中,ARC架构是一种32位的RISC处理器架构,由 Synopsys(新思科技)开发。
101 带有 14 个数字输入/输出引脚(其中 4 个可用作 PWM 输出)、6 个模拟输入、一个用于串行通信和草图上传的 USB 连接器、一个电源插孔、一个带 SPI 信号的 ICSP 接头和 I2C 专用引脚。电路板工作电压和 I/O 为 3.3V,但所有引脚均具有 5V 过压保护。
相较于标准 Arduino Uno, Arduino 101 采用的异构双核的 Curie™ 模块比 8位的 Atmel 328p 微控制器更强大,存储空间也更大(Intel 官方的 Curie 规格是 384KB Flash 与 80KB SRAM ,但相关报导写 196KB Flash 与 24KB RAM,Arduino 官网写 384KB Flash 与 80KB SRAM,但 SRAM 部分注明只有 24KB 可供应用程序 Sketch 使用。因此,推估之所以写 196KB Flash,应该也是系统占据一部分,真正可供运用的是 196KB。除此之外电路板上似乎又增设2MB Flash 可供 Curie 使用)
在2016年4月21日,英特尔发布 Arduino 101 固件源代码。包含用于 101 上 Curie 处理器的完整 BSP(板级支持包)。它允许您编译和修改核心操作系统和固件,以管理更新和引导加载程序。固件在 Curie 模块内的 x86 芯片上运行,并使用 回调 与 ARC 内核(运行 Arduino 程序)进行通信。x86 内核负责处理低功耗蓝牙® (BLE) 和 USB 通信,从而减轻 ARC 内核的负担。4
技术规格5
Microcontroller
Intel Curie
Operating Voltage
3.3V (5V tolerant I/O)
Input Voltage (recommended)
7-12V
Input Voltage (limit)
7-17V
Digital I/O Pins
14 (of which 4 provide PWM output)
PWM Digital I/O Pins
4
Analog Input Pins
6
DC Current per I/O Pin
20 mA
Flash Memory
196 kB
SRAM
24 kB
Clock Speed
32MHz
LED_BUILTIN
13
Features
Bluetooth® Low Energy, 6-axis accelerometer/gyro
Length
68.6 mm
Width
53.4 mm
Weight
34 gr.
Arduino 代码实现
Blink
#include <Arduino.h>
void setup()
{
Serial.begin(9600);
while (!Serial)
{
delay(10);
// wait for serial port to connect. Needed for native USB port only
}
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("LED ON!");
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
Serial.println("LED OFF!");
delay(1000);
}
读取板载 IMU
#include <Arduino.h>
#include "CurieIMU.h"
void setup()
{
Serial.begin(9600);
while (!Serial)
{
delay(10);
}
// Start the acceleromter
CurieIMU.begin();
// Set the accelerometer range to 2G
CurieIMU.setAccelerometerRange(2);
}
void loop()
{
// read accelerometer:
int x = CurieIMU.readAccelerometer(X_AXIS);
int y = CurieIMU.readAccelerometer(Y_AXIS);
int z = CurieIMU.readAccelerometer(Z_AXIS);
Serial.print("x: ");
Serial.print(x);
Serial.print(" y: ");
Serial.print(y);
Serial.print(" z: ");
Serial.print(z);
Serial.println("");
}
读取板载 RTC
#include <Arduino.h>
#include <CurieTime.h>
void setup()
{
Serial.begin(9600);
while (!Serial)
{
delay(10);
}
setTime(1, 23, 24, 25, 1, 2024);
}
void loop()
{
//create a character array of 16 characters for the time
char clockTime[16];
//use sprintf to create a time string of the hour, minte and seconds
sprintf(clockTime, "%2d:%2d:%2d", hour(), minute(), second());
//create a character array of 15 characters for the date
char dateTime[16];
//use sprintf to create a date string from month, day and year
sprintf(dateTime, "%2d/%2d/%4d", month(), day(), year());
//print the time and date to the serial monitor
Serial.print(clockTime);
Serial.println(dateTime);
delay(1000);
}
使用板载 BLE 控制 LED
需要配合Nordic nRF Connect使用,可以在 Google Play Store 或 App Store 下载
#include <Arduino.h>
#include <CurieBLE.h>
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service
// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEUnsignedCharCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
const int ledPin = 13; // pin to use for the LED
void setup()
{
Serial.begin(9600);
// set LED pin to output mode
pinMode(ledPin, OUTPUT);
// begin initialization
BLE.begin();
// set advertised local name and service UUID:
BLE.setLocalName("Arduino 101");
BLE.setAdvertisedService(ledService);
// add the characteristic to the service
ledService.addCharacteristic(switchCharacteristic);
// add service
BLE.addService(ledService);
// set the initial value for the characeristic:
switchCharacteristic.setValue(0);
// start advertising
BLE.advertise();
Serial.println("BLE LED Peripheral");
}
void loop()
{
// listen for BLE peripherals to connect:
BLEDevice central = BLE.central();
// if a central is connected to peripheral:
if (central)
{
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// while the central is still connected to peripheral:
while (central.connected())
{
// if the remote device wrote to the characteristic,
// use the value to control the LED:
if (switchCharacteristic.written())
{
if (switchCharacteristic.value())
{ // any value other than 0
Serial.println("LED on");
digitalWrite(ledPin, HIGH); // will turn the LED on
}
else
{ // a 0 value
Serial.println(F("LED off"));
digitalWrite(ledPin, LOW); // will turn the LED off
}
}
}
// when the central disconnects, print it out:
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
}
后记
Arduino 101 于 2016年 Q1 季度发布。仅仅过去一年有余,在英特尔宣布 Galileo,Edison 和 Joule 模块停产一个月后,也草草停产 Curie 模块(07/17/2017)6,只能说是非常可惜,英特尔宏图壮志准备在 IoT 领域大展拳脚,但是却因为种种原因,最终只能黯然收场。也导致诸多使用 Curie 模块的企业被迫更换产品线,比如小米智能跑鞋。
图片源自Intel Curie Module, Arduino 101 Board Are Being Discontinued (Too) - CNX Software
《Arduino程序设计基础》 的作者 陈吕洲 先生对 Arduino 101 抱有极高的评价:Genuino 101是一个极具特色的Arduino开发板,它基于Intel Curie模组,不仅有着和Arduino UNO一样特性和外设,还集成了低功耗蓝牙(BLE)和六轴姿态传感器(IMU)功能,借助intel Curie模组上模式匹配引擎,甚至可以进行机器学习操作。因此使用Genuino 101,可以完成一些传统单片机或者Arduino难以胜任的工作,制作更为惊艳的作品。为此他本人还专门为 Arduino 101 著书 —— 《Arduino 101 开发入门》7。
不过 Arduino 101 也有三点比标准 Arduino Uno 差8:
只有4组 PWM 脉宽调变输出,Uno 有6组;
没有任何的 EEPROM 存储,Uno 至少还有1KB可以使用;
单一 I/O 的电流驱动能力最高仅4mA,Uno 可到20mA。
所以 Curie 只是引脚排列与 Arduino 相仿,不能完全保证原有设计电路或者 Arduino Shield可完全相容(兼容)沿用、续用。
如果再与 MediaTek 的 LinkIt ONE 小比一下,LinkIt One也有效能更佳的处理器核心与更多容量的存储,且依然提供EEPROM 可用,但 PWM 方面则只有2组。当然,LinkIt ONE 强在无线通讯(日后会测评一下),如 GPRS、Wi-Fi、GPS等,Curie 略强在惯性感测。
英特尔似乎在 IoT 领域并没有取得太大的成就,但是英特尔的 x86 芯片却是世界上最流行的 CPU 架构,这也是英特尔的核心竞争力,所以英特尔在 IoT 领域的失败并不会影响到英特尔的核心业务,但是英特尔的 IoT 产品却是非常有趣的,比如 Edison、Galileo、Curie、Arduino 101 等等,这些产品都是英特尔的 IoT 产品,但是英特尔并没有将这些产品做成一个系列,而是分散在各个不同的系列中,这也是英特尔在 IoT 领域失败的一个原因。
笔者手上的 Genuino 101 是 2021年在 SeeedStudio 任职时,从 FAE 仓库里找到的,当时已经停产了,但是还是有一些库存,所以就拿了一块回来,但是一直没有时间去折腾,直到最近才拿出来玩一玩,但是发现 Arduino 101 的资料实在是太少了,所以就写了这篇文章,谨此纪念一家伟大的公司一个伟大的产品。
引用
List of Arduino boards and compatible systems - Wikipedia
Programma 101 - Wikipedia
Massimo Banzi - massimobanzi.com
Intel releases the Arduino 101 firmware source code - Arduino
Arduino 101 - Arduino
Arduino 101 - Intel
《Arduino 101 开发入门》 - XX到此一游
Arduino 101擁抱Intel Curie核心 優缺點比一比 - 陸向陽 MakerPro
16 Jan 2024
前些日子翻出来自己高中写的安卓应用,安装上去看看,但是发现小米的 HyperOS 装不上去,一直报错:
安装失败 (-29)
失败原因
安装包与系统不兼容
我第一反应应该是因为应用的目标 SDK 版本(19)太低了,先用 App Cloner 改改参数,改到 SDK26 看看。
还是不行,打开是能打开但是白屏。
最后看看用 adb 侧载算了:
安全性
最低可安装的目标 API 级别
从 Android 14 开始,targetSdkVersion 低于 23 的应用无法安装。要求应用满足这些最低目标 API 级别要求有助于提高用户的安全性和隐私性。
恶意软件通常会以较旧的 API 级别为目标平台,以绕过在较新版本 Android 中引入的安全和隐私保护机制。例如,有些恶意软件应用使用 targetSdkVersion 22,以避免受到 Android 6.0 Marshmallow(API 级别 23)在 2015 年引入的运行时权限模型的约束。这项 Android 14 变更使恶意软件更难以规避安全和隐私权方面的改进限制。尝试安装以较低 API 级别为目标平台的应用将导致安装失败,并且 Logcat 中会显示以下消息:
INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 23, but found 7
在升级到 Android 14 的设备上,targetSdkVersion 低于 23 的所有应用都将继续保持安装状态。
如果您需要测试以旧版 API 级别为目标平台的应用,请使用以下 ADB 命令:
adb install --bypass-low-target-sdk-block FILENAME.apk
22 Dec 2023
Git 是个很神奇的东西,发掘的越深,好玩的越多。
git push 到两个地址的仓库
好比我这个博客仓库,在国内因为某些不可抗力,github 无法访问,所以我在 gitee 上也有一个仓库,这样就可以在国内访问了。但是我每次都要推送两次,很麻烦。或者要登陆 gitee 的仓库,然后按一下同步按钮,也很麻烦。
所以我就想,能不能只推送一次,然后两个仓库都更新呢?
# 原始推送地址 https://github.com/IcingTomato/icing.fun.git
# 添加第二个推送地址
git remote set-url --add origin https://gitee.com/IcingTomato/icing.fun.git
# 查看推送/拉取地址
git remote -v
# origin https://github.com/IcingTomato/icing.fun.git (fetch)
# origin https://github.com/IcingTomato/icing.fun.git (push)
# origin https://gitee.com/IcingTomato/icing.fun.git (push)
# 推送
git push
Git 不公开邮箱账户
之前貌似更新了什么,好像是将保密你的邮箱地址,并在执行基于 Web WebIDE 的 Git 操作中,使用 xxxx@user.noreply.xxx.com 作为你的邮箱地址。如果你希望命令行 Git 操作使用你的私人邮箱地址,你必须在 Git 中设置你的邮箱地址。
# 我经常用 GitHub 的邮箱,全局就设置成这个了
git config --global user.email "xxxx@users.noreply.github.com"
# cd 到 icing.fun 仓库目录下
git config user.email "xxxx@users.noreply.github.com"
git config user.email "xxxx@users.noreply.gitee.com"
13 Dec 2023
在 GitHub 上处理 Pull Requests(PRs)时,有三种主要的合并策略:创建合并提交(Merge Commit)、挤压合并(Squash and Merge)、变基合并(Rebase and Merge)。下面简要解释每种策略的特点及其区别:
1. 创建合并提交(Merge Commit)
操作:当你选择创建合并提交时,GitHub 会创建一个新的合并提交来将 PR 的更改合并到基分支(如 main 或 master)。这个合并提交会包含一个特殊的提交信息,通常包括一个指向 PR 的引用。
结果:在基分支的提交历史中,PR 的所有提交都将被保留,并附加一个额外的合并提交。这保持了完整的历史记录和PR的独立性。
适用场景:当你想保留对 PR 的每一次单独提交的完整历史时。
2. 挤压合并(Squash and Merge)
操作:挤压合并会将 PR 中的所有提交合并成一个单独的提交,然后将这个提交合并到基分支。
结果:基分支的提交历史更简洁,因为它只包含一个代表整个 PR 的提交。但这意味着PR中原始提交的细节被压缩。
适用场景:适用于PR包含许多小的、渐进的更改,但你想在基分支上保持一份干净、未混杂的历史记录。
3. 变基合并(Rebase and Merge)
操作:变基合并首先会将 PR 的提交历史变基到目标分支的最新提交上,然后将这些提交直接加入到基分支,而不创建额外的合并提交。
结果:这在基分支上产生一条线性的提交历史,但不会保留 PR 作为独立实体的信息。
适用场景:当你希望保持线性历史且避免合并提交时。这通常适用于较小的、清晰的更改。
总结
创建合并提交保留了所有的提交历史和PR的独立性,增加了一个额外的合并提交。
挤压合并将PR的所有提交压缩成一个单独的提交,使历史更干净。
变基合并保持了线性的提交历史,但不会创建合并提交。
选择哪种策略取决于你的项目团队如何希望管理其版本控制历史的清晰度和连贯性。
09 Dec 2023
树莓派学习第一步,探究树莓派的启动流程。
树莓派的启动流程
相较于一般/通常的 ARM SoC 来说,树莓派1/2/3/Zero的启动流程有些不同,这里简单的记录一下。
树莓派1/2/3/Zero的启动流程
在开机时,CPU是离线的,由GPU上的一个小型RISC核心负责启动SoC,因此大部分启动组件实际上是在GPU代码上运行,而不是CPU上。
启动顺序如下:
第一阶段引导程序:用于挂载SD卡上的FAT32启动分区,以便可以访问第二阶段引导程序。它在制造树莓派时已经烧录到SoC本身,并且用户无法重新编程。
第二阶段引导程序(bootcode.bin):用于从SD卡检索GPU固件,加载固件,然后启动GPU。
GPU固件(start.elf):一经加载,允许GPU启动CPU。另一个文件fixup.dat用于配置GPU和CPU之间的SDRAM分区。此时,CPU从复位模式释放并转移到CPU上执行。
用户代码(User Code):这可以是任何数量的二进制文件之一。默认情况下,它是Linux内核(通常命名为kernel.img),但它也可以是另一个引导程序(例如U-Boot)或一个简单的应用程序。
在2012年10月19日之前,曾经还有第三阶段引导程序(loader.bin),现已废除。
下面是原文elinux.org/RPi_Software
At power-up, the CPU is offline, and a small RISC core on the GPU is responsible for booting the SoC, therefore most of the boot components are actually run on the GPU code, not the CPU.
The boot order and components are as follows:
First stage bootloader - This is used to mount the FAT32 boot partition on the SD card so that the second stage bootloader can be accessed. It is programmed into the SoC itself during manufacture of the RPi and cannot be reprogrammed by a user.
Second stage bootloader (bootcode.bin) - This is used to retrieve the GPU firmware from the SD card, program the firmware, then start the GPU.
GPU firmware (start.elf) - Once loaded, this allows the GPU to start up the CPU. An additional file, fixup.dat, is used to configure the SDRAM partition between the GPU and the CPU. At this point, the CPU is release from reset and execution is transferred over.
User code - This can be one of any number of binaries. By default, it is the Linux kernel (usually named kernel.img), but it can also be another bootloader (e.g. U-Boot), or a bare-bones application.
Prior to 19th October 2012, there was previously also a third stage bootloader (loader.bin) but this is no longer required.[1]
树莓派4B(BCM2711)的启动流程
树莓派4B(BCM2711)因为某些硬件升级导致启动流程复杂了不是一丁半点[2]。
当树莓派4开机时,引导过程涉及BCM2711 VideoCore VI 处理器单元(VPU)的操作。以下是引导过程的步骤概述:
VPU核心0的初始化:
开机时,BCM2711芯片的VPU核心0开始运行。
程序计数器设置为0x60000000,映射到片上启动ROM。
VPU频率和启动ROM:
最初,VPU的频率设置为振荡器频率,树莓派4上为54.0 MHz。
这个低频率足以完成初始引导任务。
读取OTP寄存器:
启动ROM读取某些一次性可编程(OTP)寄存器(17/18, 66, 和 67)。
这些寄存器与树莓派3相比有不同的含义。更多信息可以在这个GitHub问题中找到。
引导指示引脚:
如果配置了“引导指示引脚”,则它会被激活几毫秒。
USB设备模式恢复:
如果配置了USB设备模式强制引导引脚且激活,某些步骤会被跳过。
这是一种从USB启动恢复的机制。
SD卡引导:
如果SD卡引导引脚处于激活状态或未配置,启动ROM尝试从SD卡的第一个FAT分区加载recovery.bin。
这种机制有助于在EEPROM损坏时恢复板子。更多细节可以在树莓派硬件文档中找到。
从EEPROM加载固件:
BootROM尝试从EEPROM芯片加载固件,通常是通过SPI0在GPIO 40–43接口的Winbond W25X40芯片。
USB设备模式:
如果前面的步骤失败,芯片进入通过Type-C连接器的USB设备模式。
它等待从USB主机获取恢复映像,需要在主机上更新usbboot。更多信息可以在这个拉取请求中找到。
在这种模式下,VPU的频率提升到100 MHz。
固件映像签名:
需要在固件映像中附加一个20字节的签名,这是使用存储在OTP中的通用密钥的映像的HMAC-SHA1散列。
这个密钥无法通过树莓派提供的固件的API访问。
这种机制最初在树莓派3上是可选的,现在则是强制性的,尽管它并不提供安全保护,因为存在一个通用的recovery.bin映像。
这个引导过程突出显示了确保树莓派4能够成功引导并从潜在的固件问题中恢复的各种机制。
When the Raspberry Pi 4 is powered on, the BCM2711 VPU core 0 gets started. The program counter is set to 0x60000000. This address maps to the on-chip boot ROM. Note that the VPU frequency is set to the oscillator (54.0 MHz on RPi4), so it’s not very fast, but it does not do a lot of things either:
Read boot-related OTP registers (17/18, 66 and 67). Note that these registers have a different meaning than on Raspberry Pi 3. More information can be found here.
If a “boot indication pin” is configured, it is activated for some milliseconds.
If USB device-mode recovery force boot pin is configured and active, steps 4 and 5 are skipped.
If SD card boot pin is either active or not configured, the boot ROM tries to load recovery.bin from the first FAT partition. This provides a mechanism to unbrick your board if the EEPROM gets corrupted. More details can be found here.
Next, the boot ROM tries to load firmware from the EEPROM chip. This is a standard Winbond W25X40 chip, access through SPI0 on GPIO 40–43.
If everything else fails, the chip enters USB device mode (on the Type-C connector) and waits to get the recovery image from the USB host. You need an updated usbboot on the host to use this method. See also this pull request.
The VPU frequency is increased to 100 MHz for the USB device mode.
Note that a 20-byte signature must be appended to the firmware image. It is an HMAC-SHA1 hash of the image using a universal key that is also stored in the OTP, but not accessible using the Foundation firmware APIs. A similar mechanism was available as an optional feature on Raspberry Pi3. I originally assumed that the key is unique for each Raspberry Pi, but since there is one universal recovery.bin image that works for all, there must be only one key. Given that it provides no security, I’m not sure why this hash is now mandatory.
06 Dec 2023
Jekyll/Liquid 博客学习记录(连载)
Jekyll博客配置教程
我是LNMP派,因为我不会用Apache配置。
然而静态博客没必要MySQL, MariaDB, PHP。所以我们只安装Jekyll所有必需的依赖项。
sudo apt-get install ruby-full build-essential zlib1g-dev nginx
sudo apt-get install gcc g++ make
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
然而Ubuntu 16.04太老了,ruby的版本不支持Jekyll 4。所以我们要手动安装Ruby 3.0.0。
第一步是为Ruby安装一些依赖项。一步一步运行。
sudo apt install curl
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install git-core zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common libffi-dev nodejs yarn
接下来,我们将使用以下三种方法之一安装Ruby。每个都有自己的好处,如今大多数人都喜欢使用rbenv,但是如果您熟悉rvm,也可以按照这些步骤进行操作。我也提供了从源代码安装的说明,但是一般而言,您需要选择rbenv或rvm。
方法一:使用rbenv安装。首先安装rbenv,然后安装ruby-build:
cd
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL
rbenv install 3.0.0
rbenv global 3.0.0
ruby -v
方法二:RVM安装
sudo apt-get install libgdbm-dev libncurses5-dev automake libtool bison libffi-dev
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
source ~/.rvm/scripts/rvm
rvm install 3.0.0
rvm use 3.0.0 --default
ruby -v
方法三:Ruby源码安装
cd
wget http://ftp.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.tar.gz
tar -xzvf ruby-3.0.0.tar.gz
cd ruby-3.0.0/
./configure
make
sudo make install
ruby -v
Ruby服务器在国外,我的博客服务器在国内,所以换个Ruby源
gem source -r https://rubygems.org/
gem source --add https://gems.ruby-china.com/
gem source -u
最后一步是安装Bundler
gem install bundler jekyll github-pages jekyll-paginate webrick
安装完之后就可以将博客从GitHub或Gitee上git clone下来了。
接着完成对nginx的配置
安装nginx
sudo apt-get install nginx
然后定位到nginx的配置文件:
sudo vim /etc/nginx/sites-enabled/default
配置文件在下面:
pi@ubuntu:~cat /etc/nginx/sites-enabled/default
server {
# 监听80端口,我嫌麻烦就懒得加SSL了
listen 80 default_server;
listen [::]:80 default_server;
# 网页在本地的根目录
root /var/www/html;
# 显示的主页
index index.html;
# 你的域名
server_name domain.yours;
# 404,403配置文件
# 主要目的是当出现404或403时直接回显200
error_page 404 =200 /404.html;
# 404
location /404.html {
root /var/www/html/;
internal;
}
# 403
error_page 403 =200 /offline.html;
# 404
location /offline.html {
root /var/www/html/;
internal;
}
}
保存好之后重启nginx
sudo systemctl restart nginx
Jekyll博客维护教程
博客的维护教程修改自 Hux 和 BY_Blog
环境
如果你安装了 Jekyll,那你只需要在命令行输入jekyll serve 或 jekyll s就能在本地浏览器中输入http://127.0.0.1:4000/预览主题,对主题的修改也能实时展示(需要强刷浏览器,Ctrl+F5)。
开始
你可以通用修改 _config.yml文件来轻松的开始搭建自己的博客:
# Site settings
title: 啥玩意儿啊这 # 你的博客网站标题
SEOTitle: 啥玩意儿 | What's this # SEO 标题
description: "Hey" # 随便说点,描述一下
# SNS settings
github_username: null # 你的github账号
# Build settings
# paginate: 100 # 一页你准备放几篇文章
Jekyll官方网站还有很多的参数可以调,比如设置文章的链接形式…网址在这里:Jekyll - Official Site 中文版的在这里:Jekyll中文.
撰写博文
要发表的文章一般以 Markdown 的格式放在这里_posts/,你只要看看这篇模板里的文章你就立刻明白该如何设置。
yaml 头文件长这样:
---
layout: post
title: 硕人其颀 衣锦褧衣
subtitle: Quark核心板的GPIO推算过程
date: 2021-02-01
author: null
header-img: img/2021/02/01/01/title.jpg
catalog: true
tags:
- Quark
- GPIO
- Linux
- Project-Quantum
- Nano Pi
---
侧边栏
看右边
设置是在 _config.yml文件里面的Sidebar settings那块。
# Sidebar settings
sidebar: true #添加侧边栏
sidebar-about-description: "简单的描述一下你自己"
sidebar-avatar: /img/avatar-by.jpg #你的大头贴,请使用绝对地址.注意:名字区分大小写!后缀名也是
侧边栏是响应式布局的,当屏幕尺寸小于992px的时候,侧边栏就会移动到底部。具体请见bootstrap栅格系统
Mini About Me
Mini-About-Me 这个模块将在你的头像下面,展示你所有的社交账号。这个也是响应式布局,当屏幕变小时候,会将其移动到页面底部,只不过会稍微有点小变化,具体请看代码。
Featured Tags
看到这个网站 Medium 的推荐标签非常的炫酷,所以我将他加了进来。
这个模块现在是独立的,可以呈现在所有页面,包括主页和发表的每一篇文章标题的头上。
# Featured Tags
featured-tags: true
featured-condition-size: 1 # A tag will be featured if the size of it is more than this condition value
唯一需要注意的是featured-condition-size: 如果一个标签的 SIZE,也就是使用该标签的文章数大于上面设定的条件值,这个标签就会在首页上被推荐。
内部有一个条件模板 {% if tag[1].size > {{ site.featured-condition-size}} %} 是用来做筛选过滤的.
Social-media Account
# SNS settings
RSS: true
bilibili_username: bilibili_uid
zhihu_username: username
facebook_username: username
github_username: username
weibo_username: username
Friends
友链部分。这会在全部页面显示。
设置是在 _config.yml文件里面的Friends那块,自己加吧。
# Friends
friends: [
{
title: "huohuo",
href: "http://null.fun/"
},
{
title: "Apple",
href: "https://apple.com/"
}
]
Keynote Layout
HTML5幻灯片的排版:
这部分是用于占用html格式的幻灯片的,一般用到的是 Reveal.js, Impress.js, Slides, Prezi 等等.我认为一个现代化的博客怎么能少了放html幻灯的功能呢~
其主要原理是添加一个 iframe,在里面加入外部链接。你可以直接写到头文件里面去,详情请见下面的yaml头文件的写法。
---
layout: keynote
iframe: "http://huangxuan.me/js-module-7day/"
---
iframe在不同的设备中,将会自动的调整大小。保留内边距是为了让手机用户可以向下滑动,以及添加更多的内容。
Comment
博客不仅支持 Disqus 评论系统,还加入了 Gitalk 评论系统,支持 Markdwon 语法,cool~
Disqus
优点:国际比较流行,界面也很大气、简洁,如果有人评论,还能实时通知,直接回复通知的邮件就行了;
缺点:评论必须要去注册一个disqus账号,分享一般只有Facebook和Twitter,另外在墙内加载速度略慢了一点。想要知道长啥样,可以看以前的版本点这里 最下面就可以看到。
Note:有很多人反映 Disqus 插件加载不出来,可能墙又架高了,有条件的话翻个墙就好了~
使用:
首先,你需要去注册一个Disqus帐号。
其次,你只需要在下面的 yaml 头文件中设置一下就可以了。
# 评论系统
# Disqus(https://disqus.com/)
disqus_username:
Gitalk
优点:界面干净简洁,利用 Github issue API 做的评论插件,使用 Github 帐号进行登录和评论,最喜欢的支持 Markdown 语法,对于程序员来说真是太 cool 了。
缺点:配置比较繁琐,每篇文章的评论都需要初始化。
使用:
参考我的这篇文章:《屡顾尔仆 不输尔载-Jekyll博客迁移计划:Gitalk 插件与 Google Analytics 的配置》
Analytics
网站分析,现在支持百度统计和Google Analytics。需要去官方网站注册一下,然后将返回的code贴在下面:
# Baidu Analytics
ba_track_id:
#
# Google Analytics
ga_track_id: 'UA-' # 你用Google账号去注册一个就会给你一个这样的id
ga_domain: # 默认的是 auto, 这里我是自定义了的域名,你如果没有自己的域名,需要改成auto。
Customization
如果你喜欢折腾,你可以去自定义这个模板的 Code。
如果你可以理解 _include/ 和 _layouts/文件夹下的代码(这里是整个界面布局的地方),你就可以使用 Jekyll 使用的模版引擎 Liquid的语法直接修改/添加代码,来进行更有创意的自定义界面啦!
Header Image
博客每页的标题底图是可以自己选的,看看几篇示例post你就知道如何设置了。
标题底图的选取完全是看个人的审美了。每一篇文章可以有不同的底图,你想放什么就放什么,最后宽度要够,大小不要太大,否则加载慢啊。
上传的图片最好先压缩,这里推荐 imageOptim 图片压缩软件,让你的博客起飞。
但是需要注意的是本模板的标题是白色的,所以背景色要设置为灰色或者黑色,总之深色系就对了。当然你还可以自定义修改字体颜色,总之,用github pages就是可以完全的个性定制自己的博客。
SEO Title
我的博客标题是 呐啥 ,但是我想要在搜索的时候显示 哦豁 ,这个就需要 SEO Title 来定义了。
其实这个 SEO Title 就是定义了 <head><title>标题</title></head> 这个里面的东西和多说分享的标题,可以自行修改的。
增加阅读时间和字数统计
注意:以下代码中出现的全角花括号要改成半角花括号。不要问我为什么,问就是这个影响我全局代码编译。
Displaying a post’s word count is rather common when creating a blog, but usually those techniques rely on JavaScript to work. The script reads the post’s text, counts the words and displays the result accordingly. That was the way I did things on this blog first as well, but then I set out to find a better way.
Showing the word count
Luckily Jekyll provides a handy liquid filter called number_of_words. So displaying the actual word count is as simple as that:
{{ page.content | number_of_words }}
While this works just nicely it’s not very solid. You might want to hide word counts on shorter posts, for example as they’re of little value in such posts. This is a little more complex as you can not directly use Liquid filters in a conditional block.
Variables in Liquid
In Liquid there are two ways to create variables. You can {% assign %} a variable and you can {% capture %} a variable. The difference might not be obvious, but it’s simple once you get it.
Assigning a value to a variable means that you take any kind of data (e.g. a string, a number, a boolean) and Liquid knows that you want to access that exact data when you refer to this variable. An assigned variable is fixed, that means you can not use the value returned from other Liquid tags.
{% assign awesome = true %}
{% if awesome %}
<p>Yay, awesome!</p>
{% endif %}
But what if you want to store a Liquid tags’s return value in a variable? That’s exactly what the {% capture %} block is for. Unlike assigned variables, captured variables can only hold strings — which will cause us some trouble later on. This is simply because Liquid tags return strings by default.
{% capture value %}
{{ page.title | upcase }} from {{ page.date | date: "%b %d, %y" }}
{% endcapture %}
As you can see in the above example, you can capture any number of strings into a variable, be it strings returned from a Liquid tag or fixed strings.
Making the word count conditional
Now that you know about {% assign %} and {% capture %} we can move on to store our word count in a variable. The question remains, do we assign the variable or do we capture it?
It should be clear by now that we’ll have to capture the value as it’s returned from a Liquid tag. That gives us something like this:
{% capture words %}
{{ page.content | number_of_words }}
{% endcapture %}
Let’s say we considered posts that are shorter than 250 words not worthy of getting the word count. A good example for this would be ‘link list’-style post that consist of mostly a quote from the original article and a comment spanning a sentence or two. Ideally, this would be taken care of using a simple conditional block.
{% if words > 250 %}
{{ words }}
{% endif %}
But you’ll soon see that this won’t work as intended as Jekyll will throw you this error an error saying you’ve attempted to compare a string (the words) with a number (250), which is entirely true, and also, sadly, entirely not possible. There is, however, a simple workaround.
{% capture words %}
{{ page.content | number_of_words | minus: 250 }}
{% endcapture %}
{% unless words contains "-" %}
{{ words | plus: 250 }}
{% endunless %}
You can use Liquid filters to substract your minimum number from the word count to see if it falls below 0. If it does it will contain a ‘-‘ at the beginning, which means the post is too short and won’t get the word number displayed. If our variable doesn’t contain a ‘-‘ we can simply add our minimum number back to the word count and display it. Quite simple, right?
Customising the output
Now that we finally have our word number along with the conditional to hide it from short posts we can move on to make the output a bit nicer. You do this using Liquid filters like append or prepend. For a complete list of available filters you can check Shopify’s Liquid for Designers guide.
{{ words | plus: 250 | append: " words" }}
The above snippet results in something like ‘There are 250 words in this post’. You can go crazy with filters, they offer lots of possibilities.
Calculating the reading time
You might have noticed that I display an estimated reading time on this blog instead of just a word count. Personally, I just think this is a more useful guideline. Doing this is as easy as putting the divided_by filter into our final word count construct. The number to divide by is arbitrary, but 180 is the avarage number of words a person reads per minute.
{{ words | plus: 250 | divided_by: 180 | append: " minutes to read" }}
Summing it up
{% capture words %}
{{ page.content | number_of_words | minus: 250 }}
{% endcapture %}
{% unless words contains "-" %}
{{ words | plus: 250 | append: " words" }}
{% endunless %}
{% capture words %}
{{ page.content | number_of_words | minus: 250 }}
{% endcapture %}
{% unless words contains "-" %}
{{ words | plus: 250 | divided_by: 180 | append: " minute read" }}
{% endunless %}
这是我用的参数
在/_include下新建read_time.html和word_count.html
<!-- Add Read Time and word count, by chiya 2021.02.06-->
{% capture words %}
{{ content | number_of_words | minus: 0 }}
{% endcapture %}
{% unless words contains '-' %}
{{ words | plus: 200 | divided_by: 100 | append: ' minute(s)' }}
{% endunless %}
<!-- Add Read Time and word count, chiya 2021.02.06-->
{% capture words %}
{{ page.content | number_of_words | minus: 10 }}
{% endcapture %}
{% unless words contains "-" %}
{{ words | plus: 10 | append: " words" }}
{% endunless %}
然后编辑./_layouts/post.html,大概在43行处。
<header class="intro-header" >
<div class="header-mask"></div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-heading">
<div class="tags">
{% for tag in page.tags %}
<a class="tag" href="{{ site.baseurl }}/tags/#{{ tag }}" title="{{ tag }}">{{ tag }}</a>
{% endfor %}
</div>
<h1>{{ page.title }}</h1>
{% comment %}
always create a h2 for keeping the margin , Hux
{% endcomment %}
{% comment %} if page.subtitle {% endcomment %}
<h2 class="subheading">{{ page.subtitle }}</h2>
{% comment %} endif {% endcomment %}
<!-- Add Read Time and word count, by chiya 2021.02.06-->
<p class="meta">
<span>Posted by {% if page.author %}{{ page.author }}{% else %}{{ site.title }}{% endif %} on {{ page.date | date: "%B %-d, %Y" }}</span>
<span>- {% include word_count.html %}, {% include read_time.html %} to read</span>
</p>
</div>
</div>
</div>
</div>
</header>
最终使用
如果配置好nginx和Jekyll的话
cd 文件夹
git clone 仓库地址
git pull origin master
jekyll build -d /var/www/html/
现在我单独写了个脚本用于自动拉取编译以及发布:
#!/bin/bash
cd /var/www/html/
rm -rf /var/www/html/blog/
cd /root/icing.fun
git pull origin master
jekyll build -s /root/icing.fun -d /var/www/html/blog/
然后
chmod +x deploy.sh
rvm cron setup
crontab -e
# 编辑
* * * * * /bin/bash /root/push_blog.sh
每分钟就能拉取一次编译发布。
29 Nov 2023
补记
电源计划 卓越性能,启动!
powercfg -duplicatescheme e9a42b02-d5df-448d-aa00-03f14749eb61
显示成功。但在电源计划里依然没有显示卓越性能。
此时需要修改注册表的CSEnabled值,但CSEnabled不见了(之前有的),所以应该在管理员模式下的 cmdlet 敲
reg add HKLM\System\CurrentControlSet\Control\Power /v PlatformAoAcOverride /t REG_DWORD /d 0
问了一下 Premier 事业部的同事,他们说目前据了解20H2取消了csenable更改来设置高性能,需要指令调用。
====================================
如何优雅地使用 Windows 作为开发环境。
如何使用 WSL 在 Windows 上优雅地安装 Linux
检视你电脑的版本
必须是运行 Windows 10 版本 2004 及更高版本(内部版本 19041 及更高版本)或 Windows 11 的电脑才能优雅。其他的版本可以参阅手动安装页,但是不优雅。
安装 WSL 优雅的命令
现在,可以使用单个命令安装运行 WSL 所需的一切内容。 在管理员模式下打开 PowerShell 或 Windows 命令提示符,方法是右键单击并选择“以管理员身份运行”,输入 wsl --install 命令,然后重启计算机。
wsl --install
此命令将启用运行 WSL 并安装 Linux 的 Ubuntu 发行版所需的功能。 (可以更改此默认发行版)。
如果你运行的是旧版,或只是不想使用 install 命令并希望获得分步指引,请参阅旧版 WSL 手动安装步骤。
首次启动新安装的 Linux 发行版时,将打开一个控制台窗口,要求你等待将文件解压缩并存储到计算机上。 未来的所有启动时间应不到一秒。
上述命令仅在完全未安装 WSL 时才有效,如果运行 wsl –install 并查看 WSL 帮助文本,请尝试运行 wsl –list –online 以查看可用发行版列表并运行 wsl –install -d 以安装发行版。 若要卸载 WSL,请参阅卸载旧版 WSL 或注销或卸载 Linux 发行版。
更改默认安装的 Linux 发行版
默认情况下,安装的 Linux 分发版为 Ubuntu。 可以使用 -d 标志进行更改。
若要更改安装的发行版,请输入:wsl --install -d <Distribution Name>。 将 <Distribution Name> 替换为要安装的发行版的名称。
若要查看可通过在线商店下载的可用 Linux 发行版列表,请输入:wsl --list --online 或 wsl -l -o。
若要在初始安装后安装其他 Linux 发行版,还可使用命令:wsl --install -d <Distribution Name>。
如果要通过 Linux/Bash 命令行(而不是通过 PowerShell 或命令提示符)安装其他发行版,必须在命令中使用 .exe:wsl.exe --install -d <Distribution Name> 或若要列出可用发行版,则使用:wsl.exe -l -o。
Ubuntu 不够你用是吧?
将版本从 WSL 1 升级到 WSL 2
使用 wsl --install 命令安装的新 Linux 安装将默认设置为 WSL 2。
wsl --set-version 命令可用于从 WSL 2 降级到 WSL 1,或将以前安装的 Linux 发行版从 WSL 1 更新到 WSL 2。
要查看 Linux 发行版是设置为 WSL 1 还是 WSL 2,请使用命令 wsl -l -v。
要更改版本,请使用 wsl --set-version <distro name> 2 命令将 <distro name> 替换为要更新的 Linux 发行版的名称。 例如,wsl --set-version Ubuntu-20.04 2 会将 Ubuntu 20.04 发行版设置为使用 WSL 2。
如果在 wsl --install 命令可用之前手动安装了 WSL,则可能还需要启用 WSL 2 所使用的虚拟机可选组件并安装内核包(如果尚未这样做)。
WSL 子系统访问宿主机的 Proxy
在 WSL 里面新建一个 setProxy.sh , 然后把这个复制进去:
#!/bin/bash
hostip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
wslip=$(hostname -I | awk '{print $1}')
port=7890
PROXY_HTTP="http://${hostip}:${port}"
set_proxy(){
export http_proxy="${PROXY_HTTP}"
export HTTP_PROXY="${PROXY_HTTP}"
export https_proxy="${PROXY_HTTP}"
export HTTPS_PROXY="${PROXY_HTTP}"
git config --global http.proxy "${PROXY_HTTP}"
git config --global https.proxy "${PROXY_HTTP}"
# 设置APT代理
echo "Acquire::http::Proxy \"${PROXY_HTTP}\";" | sudo tee /etc/apt/apt.conf.d/95proxies > /dev/null
echo "Acquire::https::Proxy \"${PROXY_HTTP}\";" | sudo tee -a /etc/apt/apt.conf.d/95proxies > /dev/null
}
unset_proxy(){
unset http_proxy
unset HTTP_PROXY
unset https_proxy
unset HTTPS_PROXY
git config --global --unset http.proxy
git config --global --unset https.proxy
# 移除APT代理设置
sudo rm /etc/apt/apt.conf.d/95proxies
}
test_setting(){
echo "Host ip:" ${hostip}
echo "WSL ip:" ${wslip}
echo "Current proxy:" $https_proxy
}
if [ "$1" = "set" ]
then
set_proxy
elif [ "$1" = "unset" ]
then
unset_proxy
elif [ "$1" = "test" ]
then
test_setting
else
echo "Unsupported arguments."
fi
理论上是所有系统都可以这样做
然后 chmod +x setProxy.sh , 最后要设置的时候就 source ./setProxy.sh set 就行了。
PowerShell 美化
Scoop包管理器:
Scoop 是 Windows 的命令行安装程序。使用 Scoop,可以为终端安装程序和插件。
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
irm get.scoop.sh | iex
scoop search - 搜索软件
scoop install - 安装软件
scoop info - 查看软件详细信息
scoop list - 查看已安装软件
scoop uninstall - 卸载软件,-p删除配置文件。
scoop update - 更新 scoop 本体和软件列表
scoop update - 更新指定软件
scoop update * - 更新所有已安装的软件
scoop checkup - 检查 scoop 的问题并给出解决问题的建议
scoop help - 查看命令列表
scoop help - 查看命令帮助说明*
gsudo(提权)
gsudo 是 sudo 在 Windows 的等价物,具有与原始 Unix/Linux sudo 相似的用户体验。允许在当前控制台窗口或新控制台窗口中以提升的权限运行命令,或提升当前 shell。
只需 gsudo 将(或sudo别名)添加到您的命令中,它就会以提升的方式运行。
###GSUDO
#安装:
scoop install gsudo
#导入配置文件内$PROFILE:
# 添加以下这行
Import-Module (Get-Command 'gsudoModule.psd1').Source
# 或者运行这行命令:
Get-Command gsudoModule.psd1 | % { Write-Output "`nImport-Module `"$($_.Source)`"" | Add-Content $PROFILE }
#在PowerShell中执行notepad $PROFILE,打开文件。
#在其中添加:
Set-alias 'su' 'gsudo'
Set-alias 'sudo' 'gsudo'
.$PROFILE使配置生效
# gsudo如果用户选择启用缓存,则可以提升多次,仅显示一个 UAC 弹出窗口。
# 凭据缓存
使用 手动启动/停止缓存会话gsudo cache {on | off}。
使用 停止所有缓存会话gsudo -k。
可用的缓存模式:
Disabled:每次提权都会显示一个 UAC 弹出窗口。
Explicit:(默认)每次提权都会显示一个 UAC 弹出窗口,除非缓存会话以gsudo cache on
Auto:类似于 unix-sudo。第一个提权显示 UAC 弹出窗口并自动启动缓存会话。
使用更改缓存模式gsudo config CacheMode Disabled|Explicit|Auto
Git 和 posh-git
###SCOOP安装GIT
scoop bucket add main
scoop install git
#验证GIT安装:
git --version
#模块安装posh-git
Install-Module posh-git -Scope AllUser -Force
#notepad $PROFILE打开配置档案,添加以下:
Import-Module posh-git
#配置完成后,运行.$PROFILE,使得修改生效
# 克隆任何 GitHub 存储库,以测试在输入常用 git 命令时 posh-git的反映:
git clone https://github.com/dahlbyk/posh-git
cd posh-git
PSReadline 语法定制
PSReadLine 是微软创建的一个模块,用于自定义 PowerShell 中的命令行编辑环境。它提供了大量的定制,可以改变命令行编辑器以多种方式呈现数据的方式。
# 安装
Install-Module PSReadLine
# 配置文件:
Import-Module PSReadLine
fzf
fzf 是一个用于命令行的模糊文件查找器。
这将为当前文件夹层次结构中的文件启用搜索机制,或者能够查看您之前使用的先前命令。
要使用 PSFzf,您必须先安装 fzf。
# 首先,需要通过SCOOP安装
scoop install fzf
# 第二步,安装模块:
Install-Module PSFzf
# 配置文件:
Import-Module PSFzf
Set-PsFzfOption -PSReadLineChordProvider ‘Ctrl+f’ -PSReadLineChordReverseHistory ‘Ctrl+r’
###
#Ctrl+f您可以在当前文件夹和子文件夹中搜索文件。
#您可以通过Ctrl+r列表查看使用过的命令的历史记录。
z
z 可让您根据cd命令历史记录在 PowerShell 中快速浏览文件系统。
z 也是经常使用的模块之一,它有助于快速导航到常用目录,
Install-Module -Name z
Neovim
scoop install neovim
Powershell 升级
iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI"
Git 一键推送
新建一个 git_push.ps1:
# PowerShell Script to Perform Git Operations with User-Inputted Path
# Prompt for the path to the Git repository
$repoPath = Read-Host -Prompt "Enter the path to your git repository"
# Change to the specified directory
cd $repoPath
# Update git
git pull
# Add all changes to staging
git add --all
# Prompt for a commit message
$commitMessage = Read-Host -Prompt "Enter your commit message"
# Commit the changes
git commit -m "$commitMessage"
# Push the changes to the remote repository
git push
# Back to the origin folder
cd ..
倒叙之前因后果
11月月初俺爹斥巨资给我换了个笔记本电脑
可能有人要“素质三连”了
Surface Pro 9 不是有酷睿版吗?SQ3 版不是很垃圾吗?有这个钱为什么不买苹果?
首先就是全功能 Type-C 接口,两个接口可以提供视频,音频,数据传输,更重要的是可以充电。这不比原装的那个方便?带个小米67W就可以搞定手机和电脑的充电了。酷睿版就八行,只能拿那个笨笨的充电器充电。
5G 网络说实在真的很香,之前在学校办的移动的号,大流量卡,装这个上面,基本上是全天在线,很舒服。
之前去上海面试的时候,在高铁上就可以用电脑来办公,还能追追剧。
随身WiFi稍微麻烦了点,比如我现在也在用华为的。
再来就是这个屏幕了,这个屏幕香不香我不知道,主要是能触屏,MacBook那么多年也不能触屏。(估计有人就要骂我,说苹果触控板好用,我只能说,我不喜欢,我喜欢触屏)
说它是个大号平板也不为过,我现在就是拿着它在写这篇文章,很舒服。安卓平板根本打不过,如果说我要用安卓应用,Windows还有安卓子系统。
8cx Gen 3 跑分啥的对我来说确实不重要,抛开实际体验的跑分都是耍流氓。
实际体验下来没啥用不了的应用,转译慢就慢我还能摸摸鱼。Python脚本可以跑,我用的是 Anaconda 的环境,没啥问题。IDE用的 VSCode,有原生 ARM64 版本,也没啥问题。VS也能用,还能编译x64/x86的程序,也没啥问题。
28 Nov 2023
【阅板无数】LinkIt™ Smart 7688/Duo 使用手册
MT7688 是一个由联发科技(MediaTek)开发的高性能无线SoC(System on Chip)。它主要用于驱动智能家居和物联网(IoT)设备。MT7688 芯片支持 802.11n Wi-Fi 标准,能够提供高速的无线连接。此外,它通常包括多种接口和功能,比如 USB、GPIO、以太网接口,以及内存和存储接口,这使得它能够灵活地应用于各种设备和应用场景中。
参考网站
(MIPS 24KEc) MT7688 (LinkIt Smart 7688) Build OpenWRT - 司徒的教學網站
LinkIt Smart 7688/Duo - Mediatek
LinkIt Smart 7688/Duo - SeeedStudio Wiki
讲真,Seeed 做的东西都是好东西,但是就是不好好维护
编译 OpenWRT
截至博客发布日期,我按照网上的教程编译来编译去都用不了,服了
最后通过 Internet Archive 找到了原始镜像和硬件电路图
IcingTomato/embedded_linux_dev - GitHub
# MD5 Check
51107d057bda7ac71baeac3277e6e3d1 Hardware_Schematics.zip
4e40f19c968e45aaa2cc9d36c3095f03 LinkIt_Smart_7688_Firmware_upgrade.zip
2438f95e0466a454d491c8029e509d6e Manual.zip
1fb86b892294d3082d8a05d450108c76 MediaTek_LinkIt_Smart_7688_bootloader_v0.8.2.zip
40717f554a8f455df62b238274db1fe4 MediaTek_LinkIt_Smart_7688_firmware_v0.9.2.zip
9e8a7237d8f0c55add7e685a12cf7d12 swapsd.sh
其中 swapsd.sh 用于将系统从内置闪存切换到外置 SD 卡,并添加 swap 分区
15 Aug 2022
如何用 ESP32 制作一个语音助手
Amazon Alexa for M5Stack M5Core2(ESP32)
0. Briefing of Alexa
Amazon Alexa, also known simply as Alexa, is a virtual assistant technology largely based on a Polish speech synthesiser named Ivona, bought by Amazon in 2013. It was first used in the Amazon Echo smart speaker and the Echo Dot, Echo Studio and Amazon Tap speakers developed by Amazon Lab126. It is capable of voice interaction, music playback, making to-do lists, setting alarms, streaming podcasts, playing audiobooks, and providing weather, traffic, sports, and other real-time information, such as news. Alexa can also control several smart devices using itself as a home automation system. Users are able to extend the Alexa capabilities by installing “skills” (additional functionality developed by third-party vendors, in other settings more commonly called apps) such as weather programs and audio features. It uses automatic speech recognition, natural language processing, and other forms of weak AI to perform these tasks.
Most devices with Alexa allow users to activate the device using a wake-word (such as Alexa or Amazon); other devices (such as the Amazon mobile app on iOS or Android and Amazon Dash Wand) require the user to click a button to activate Alexa’s listening mode, although, some phones also allow a user to say a command, such as “Alexa” or “Alexa wake”.
1. Introduction
Source Code is here
Amazon Alexa on M5Core2 and M5Core2 for AWS
You can use M5Core2Alexa like using a real Amazon Echo (sometimes, not always). You can ask M5Alexa questions like “Alexa, what time is sunrise?” or ask her into Japanese 「アレクサ、今何時ですか?」, or maybe you can control your lights and fans (I don’t have any Alexa-supported IoT devices).
2. Development Setup
This sections talks about setting up your development host, fetching the git repositories, and instructions for build and flash.
2.1 Host Setup
You should install drivers and support packages for your development host. Windows, Linux and Mac OS-X, are supported development hosts. Please see Get Started for the host setup instructions.
2.2 Getting the Repositories
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf; git checkout release/v4.2; git submodule init; git submodule update --init --recursive;
./install.sh
cd ..
git clone https://github.com/IcingTomato/AlexaM5Core2.git
2.3 Building the Firmware
cd AlexaM5Core2/examples/amazon_alexa/
export ESPPORT=/dev/ttyUSB0 (or /dev/ttycu.SLAB_USBtoUART macOS or COMxx on MinGW)
export IDF_PATH=/path/to/esp-idf
. $IDF_PATH/export.sh
Set audio_board path for M5Core2 and AWS_EDUKIT_PATH:
export AUDIO_BOARD_PATH=/path/to/AlexaM5Core2/components/audio_hal/audio_board/audio_board_m5_core2_aws
export AWS_EDUKIT_PATH=/path/to/AlexaM5Core2/components/core2forAWS
Menuconfig is avaliable, also you can change some components:
idf.py menuconfig
3. Configuration Steps
Here are the steps to configure the M5Core2:
On first boot-up, the M5Core2 is in configuration mode. This is indicated by Orange LED pattern. Please ensure that the LED pattern is seen as described above, before you proceed.
Launch the phone app.
Select the option Add New Device.
A list of devices that are in configuration mode is displayed. Note that the devices are discoverable over BLE (Bluetooth Low Energy). Please ensure that the phone app has the appropriate permissions to access Bluetooth (on Android the Location permission is also required for enabling Bluetooth).
Now you can sign-in to your Amazon Alexa account. If you have Amazon Shopping app installed on the same phone, app will automatically sign-in with the account the shopping app is signed in to. Otherwise it will open a login page on the phone’s default browser. (It is recommended to install the Amazon Shopping app on your phone to avoid any other browser related errors.)
You can now select the Wi-Fi network that the M5Core2 should connect with, and enter the credentials for this Wi-Fi network.
On successful Wi-Fi connection, you will see a list of few of the voice queries that you can try with the M5Core2.
You are now fully setup. You can now say “Alexa” followed by the query you wish to ask.
4. Troubleshooting
4.1 Music and radio playback (Audible or Podcast) are not supported on this device.
According to Espressif Official, music and radio playback (Audible or Podcast) services are not supported on Non-Amazon-Official products. Unfortunately, Amazon music functionality needs whitelisted product. Only the commercial products are whitelisted by Amazon. Let us know if you are going to commercialise it.
4.2 Alarm Dismiss doesn’t take effect.
When the alarm on, you cannot say “Alexa, stop alarm” to dismiss the alarm. I dno’t know why… So, if you want to stop the alarm, you can touch the middle “button” on M5Core2. The middle “button” can also wake up Alexa.